tplinkrouterc6u 5.4.1__tar.gz → 5.5.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {tplinkrouterc6u-5.4.1 → tplinkrouterc6u-5.5.0}/PKG-INFO +5 -1
- {tplinkrouterc6u-5.4.1 → tplinkrouterc6u-5.5.0}/README.md +4 -0
- {tplinkrouterc6u-5.4.1 → tplinkrouterc6u-5.5.0}/setup.py +1 -1
- {tplinkrouterc6u-5.4.1 → tplinkrouterc6u-5.5.0}/test/test_client_c6u.py +2 -0
- {tplinkrouterc6u-5.4.1 → tplinkrouterc6u-5.5.0}/test/test_client_ex.py +29 -0
- {tplinkrouterc6u-5.4.1 → tplinkrouterc6u-5.5.0}/test/test_client_mr.py +2 -0
- {tplinkrouterc6u-5.4.1 → tplinkrouterc6u-5.5.0}/tplinkrouterc6u/__init__.py +1 -0
- {tplinkrouterc6u-5.4.1 → tplinkrouterc6u-5.5.0}/tplinkrouterc6u/client/c6u.py +2 -1
- {tplinkrouterc6u-5.4.1 → tplinkrouterc6u-5.5.0}/tplinkrouterc6u/client/c6v4.py +4 -1
- {tplinkrouterc6u-5.4.1 → tplinkrouterc6u-5.5.0}/tplinkrouterc6u/client/deco.py +1 -1
- {tplinkrouterc6u-5.4.1 → tplinkrouterc6u-5.5.0}/tplinkrouterc6u/client/ex.py +14 -14
- {tplinkrouterc6u-5.4.1 → tplinkrouterc6u-5.5.0}/tplinkrouterc6u/client/mr.py +210 -209
- tplinkrouterc6u-5.5.0/tplinkrouterc6u/client/vr.py +129 -0
- {tplinkrouterc6u-5.4.1 → tplinkrouterc6u-5.5.0}/tplinkrouterc6u/client_abstract.py +5 -1
- {tplinkrouterc6u-5.4.1 → tplinkrouterc6u-5.5.0}/tplinkrouterc6u/common/dataclass.py +6 -1
- {tplinkrouterc6u-5.4.1 → tplinkrouterc6u-5.5.0}/tplinkrouterc6u/common/helper.py +2 -2
- {tplinkrouterc6u-5.4.1 → tplinkrouterc6u-5.5.0}/tplinkrouterc6u/provider.py +20 -14
- {tplinkrouterc6u-5.4.1 → tplinkrouterc6u-5.5.0}/tplinkrouterc6u.egg-info/PKG-INFO +5 -1
- {tplinkrouterc6u-5.4.1 → tplinkrouterc6u-5.5.0}/tplinkrouterc6u.egg-info/SOURCES.txt +1 -0
- {tplinkrouterc6u-5.4.1 → tplinkrouterc6u-5.5.0}/LICENSE +0 -0
- {tplinkrouterc6u-5.4.1 → tplinkrouterc6u-5.5.0}/setup.cfg +0 -0
- {tplinkrouterc6u-5.4.1 → tplinkrouterc6u-5.5.0}/test/__init__.py +0 -0
- {tplinkrouterc6u-5.4.1 → tplinkrouterc6u-5.5.0}/test/test_client_c1200.py +0 -0
- {tplinkrouterc6u-5.4.1 → tplinkrouterc6u-5.5.0}/test/test_client_deco.py +0 -0
- {tplinkrouterc6u-5.4.1 → tplinkrouterc6u-5.5.0}/test/test_client_xdr.py +0 -0
- {tplinkrouterc6u-5.4.1 → tplinkrouterc6u-5.5.0}/tplinkrouterc6u/client/__init__.py +0 -0
- {tplinkrouterc6u-5.4.1 → tplinkrouterc6u-5.5.0}/tplinkrouterc6u/client/c1200.py +0 -0
- {tplinkrouterc6u-5.4.1 → tplinkrouterc6u-5.5.0}/tplinkrouterc6u/client/c5400x.py +0 -0
- {tplinkrouterc6u-5.4.1 → tplinkrouterc6u-5.5.0}/tplinkrouterc6u/client/xdr.py +0 -0
- {tplinkrouterc6u-5.4.1 → tplinkrouterc6u-5.5.0}/tplinkrouterc6u/common/__init__.py +0 -0
- {tplinkrouterc6u-5.4.1 → tplinkrouterc6u-5.5.0}/tplinkrouterc6u/common/encryption.py +0 -0
- {tplinkrouterc6u-5.4.1 → tplinkrouterc6u-5.5.0}/tplinkrouterc6u/common/exception.py +0 -0
- {tplinkrouterc6u-5.4.1 → tplinkrouterc6u-5.5.0}/tplinkrouterc6u/common/package_enum.py +0 -0
- {tplinkrouterc6u-5.4.1 → tplinkrouterc6u-5.5.0}/tplinkrouterc6u.egg-info/dependency_links.txt +0 -0
- {tplinkrouterc6u-5.4.1 → tplinkrouterc6u-5.5.0}/tplinkrouterc6u.egg-info/requires.txt +0 -0
- {tplinkrouterc6u-5.4.1 → tplinkrouterc6u-5.5.0}/tplinkrouterc6u.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: tplinkrouterc6u
|
|
3
|
-
Version: 5.
|
|
3
|
+
Version: 5.5.0
|
|
4
4
|
Summary: TP-Link Router API
|
|
5
5
|
Home-page: https://github.com/AlexandrErohin/TP-Link-Archer-C6U
|
|
6
6
|
Author: Alex Erohin
|
|
@@ -53,6 +53,7 @@ from tplinkrouterc6u import (
|
|
|
53
53
|
TplinkC1200Router,
|
|
54
54
|
TplinkC5400XRouter,
|
|
55
55
|
TPLinkMRClient,
|
|
56
|
+
TPLinkVRClient,
|
|
56
57
|
TPLinkEXClient,
|
|
57
58
|
TPLinkXDRClient,
|
|
58
59
|
TPLinkDecoClient,
|
|
@@ -167,6 +168,7 @@ or you have TP-link C5400X or similar router you need to get web encrypted passw
|
|
|
167
168
|
| wan_ipv4_uptime | Internet Uptime | int, None |
|
|
168
169
|
| mem_usage | Memory usage in percentage between 0 and 1 | float, None |
|
|
169
170
|
| cpu_usage | CPU usage in percentage between 0 and 1 | float, None |
|
|
171
|
+
| conn_type | Connection type | str, None |
|
|
170
172
|
| devices | List of all connectedd devices | list[[Device](#device)] |
|
|
171
173
|
|
|
172
174
|
### <a id="device">Device</a>
|
|
@@ -318,7 +320,9 @@ or you have TP-link C5400X or similar router you need to get web encrypted passw
|
|
|
318
320
|
- Archer MR600 (v1, v2, v3)
|
|
319
321
|
- Archer VR600 v3
|
|
320
322
|
- Archer VR900v
|
|
323
|
+
- Archer VR1200v v1
|
|
321
324
|
- Archer VR2100v v1
|
|
325
|
+
- Archer VX1800v v1.0
|
|
322
326
|
- Deco M4 2.0
|
|
323
327
|
- Deco M4R 2.0
|
|
324
328
|
- Deco M5 v3
|
|
@@ -22,6 +22,7 @@ from tplinkrouterc6u import (
|
|
|
22
22
|
TplinkC1200Router,
|
|
23
23
|
TplinkC5400XRouter,
|
|
24
24
|
TPLinkMRClient,
|
|
25
|
+
TPLinkVRClient,
|
|
25
26
|
TPLinkEXClient,
|
|
26
27
|
TPLinkXDRClient,
|
|
27
28
|
TPLinkDecoClient,
|
|
@@ -136,6 +137,7 @@ or you have TP-link C5400X or similar router you need to get web encrypted passw
|
|
|
136
137
|
| wan_ipv4_uptime | Internet Uptime | int, None |
|
|
137
138
|
| mem_usage | Memory usage in percentage between 0 and 1 | float, None |
|
|
138
139
|
| cpu_usage | CPU usage in percentage between 0 and 1 | float, None |
|
|
140
|
+
| conn_type | Connection type | str, None |
|
|
139
141
|
| devices | List of all connectedd devices | list[[Device](#device)] |
|
|
140
142
|
|
|
141
143
|
### <a id="device">Device</a>
|
|
@@ -287,7 +289,9 @@ or you have TP-link C5400X or similar router you need to get web encrypted passw
|
|
|
287
289
|
- Archer MR600 (v1, v2, v3)
|
|
288
290
|
- Archer VR600 v3
|
|
289
291
|
- Archer VR900v
|
|
292
|
+
- Archer VR1200v v1
|
|
290
293
|
- Archer VR2100v v1
|
|
294
|
+
- Archer VX1800v v1.0
|
|
291
295
|
- Deco M4 2.0
|
|
292
296
|
- Deco M4R 2.0
|
|
293
297
|
- Deco M5 v3
|
|
@@ -64,6 +64,7 @@ class TestTPLinkClient(TestCase):
|
|
|
64
64
|
],
|
|
65
65
|
"guest_5g_psk_key": "",
|
|
66
66
|
"cpu_usage": 0.28,
|
|
67
|
+
"conn_type": "1",
|
|
67
68
|
"guest_2g_encryption": "none",
|
|
68
69
|
"wireless_5g_encryption": "psk",
|
|
69
70
|
"guest_5g_ssid": "TP-Link_Guest_21CC_5G",
|
|
@@ -244,6 +245,7 @@ class TestTPLinkClient(TestCase):
|
|
|
244
245
|
self.assertEqual(status.wifi_5g_enable, True)
|
|
245
246
|
self.assertEqual(status.wan_ipv4_uptime, None)
|
|
246
247
|
self.assertEqual(status.mem_usage, 0.43)
|
|
248
|
+
self.assertEqual(status.conn_type, '1')
|
|
247
249
|
self.assertEqual(status.cpu_usage, 0.28)
|
|
248
250
|
self.assertEqual(len(status.devices), 5)
|
|
249
251
|
self.assertIsInstance(status.devices[0], Device)
|
|
@@ -277,6 +277,35 @@ class TestTPLinkEXClient(TestCase):
|
|
|
277
277
|
self.assertEqual(result.lan_ipv4_dhcp_enable, True)
|
|
278
278
|
self.assertEqual(result.remote, None)
|
|
279
279
|
|
|
280
|
+
def test_get_ipv4_status_empty(self) -> None:
|
|
281
|
+
|
|
282
|
+
DEV2_ADT_LAN = ('{"data":[],"operation":"gl","oid":"DEV2_ADT_LAN","success":true}')
|
|
283
|
+
DEV2_ADT_WAN = ('{"data":[],"operation":"gl","oid":"DEV2_ADT_WAN","success":true}')
|
|
284
|
+
|
|
285
|
+
class TPLinkEXClientTest(TPLinkEXClient):
|
|
286
|
+
self._token = True
|
|
287
|
+
|
|
288
|
+
def _request(self, url, method='POST', data_str=None, encrypt=False):
|
|
289
|
+
if 'DEV2_ADT_LAN' in data_str:
|
|
290
|
+
return 200, DEV2_ADT_LAN
|
|
291
|
+
elif 'DEV2_ADT_WAN' in data_str:
|
|
292
|
+
return 200, DEV2_ADT_WAN
|
|
293
|
+
raise ClientException()
|
|
294
|
+
|
|
295
|
+
client = TPLinkEXClientTest('', '')
|
|
296
|
+
result = client.get_ipv4_status()
|
|
297
|
+
|
|
298
|
+
self.assertIsInstance(result, IPv4Status)
|
|
299
|
+
self.assertEqual(result.wan_ipv4_ipaddr, None)
|
|
300
|
+
self.assertEqual(result.wan_ipv4_gateway, None)
|
|
301
|
+
self.assertEqual(result.wan_ipv4_netmask, None)
|
|
302
|
+
self.assertEqual(result.wan_ipv4_conntype, '')
|
|
303
|
+
self.assertEqual(result.lan_macaddr, '00-00-00-00-00-00')
|
|
304
|
+
self.assertEqual(result.lan_ipv4_ipaddr, '0.0.0.0')
|
|
305
|
+
self.assertEqual(result.lan_ipv4_netmask, '0.0.0.0')
|
|
306
|
+
self.assertEqual(result.lan_ipv4_dhcp_enable, False)
|
|
307
|
+
self.assertEqual(result.remote, None)
|
|
308
|
+
|
|
280
309
|
def test_get_ipv4_status_one_wlan(self) -> None:
|
|
281
310
|
|
|
282
311
|
DEV2_ADT_LAN = ('{"data":[{"MACAddress":"bf:75:44:4c:dc:9e","IPAddress":"192.168.5.1",'
|
|
@@ -310,6 +310,7 @@ X_TP_TotalPacketsReceived=467
|
|
|
310
310
|
self.assertEqual(status.wan_ipv4_addr, '192.168.30.55')
|
|
311
311
|
self.assertEqual(status.lan_ipv4_addr, '192.168.4.1')
|
|
312
312
|
self.assertEqual(status.wan_ipv4_gateway, '192.168.30.1')
|
|
313
|
+
self.assertEqual(status.conn_type, 'ipoe_1_d')
|
|
313
314
|
self.assertEqual(status.wired_total, 0)
|
|
314
315
|
self.assertEqual(status.wifi_clients_total, 1)
|
|
315
316
|
self.assertEqual(status.guest_clients_total, 0)
|
|
@@ -618,6 +619,7 @@ DNSServers=7.7.7.7,2.2.2.2
|
|
|
618
619
|
|
|
619
620
|
self.assertIsInstance(result, IPv4Status)
|
|
620
621
|
self.assertEqual(result.lan_macaddr, '00-00-00-00-00-00')
|
|
622
|
+
self.assertEqual(result.wan_ipv4_conntype, '')
|
|
621
623
|
self.assertEqual(result.lan_ipv4_ipaddr, '0.0.0.0')
|
|
622
624
|
self.assertEqual(result.lan_ipv4_netmask, '0.0.0.0')
|
|
623
625
|
self.assertEqual(result.lan_ipv4_dhcp_enable, False)
|
|
@@ -3,6 +3,7 @@ from tplinkrouterc6u.client.deco import TPLinkDecoClient
|
|
|
3
3
|
from tplinkrouterc6u.client_abstract import AbstractRouter
|
|
4
4
|
from tplinkrouterc6u.client.mr import TPLinkMRClient
|
|
5
5
|
from tplinkrouterc6u.client.ex import TPLinkEXClient
|
|
6
|
+
from tplinkrouterc6u.client.vr import TPLinkVRClient
|
|
6
7
|
from tplinkrouterc6u.client.c6v4 import TplinkC6V4Router
|
|
7
8
|
from tplinkrouterc6u.client.c5400x import TplinkC5400XRouter
|
|
8
9
|
from tplinkrouterc6u.client.c1200 import TplinkC1200Router
|
|
@@ -284,6 +284,7 @@ class TplinkBaseRouter(AbstractRouter, TplinkRequest):
|
|
|
284
284
|
status.wan_ipv4_uptime = data.get('wan_ipv4_uptime')
|
|
285
285
|
status.mem_usage = data.get('mem_usage')
|
|
286
286
|
status.cpu_usage = data.get('cpu_usage')
|
|
287
|
+
status.conn_type = data.get('conn_type')
|
|
287
288
|
status.wired_total = len(data.get('access_devices_wired', []))
|
|
288
289
|
status.wifi_clients_total = len(data.get('access_devices_wireless_host', []))
|
|
289
290
|
status.guest_clients_total = len(data.get('access_devices_wireless_guest', []))
|
|
@@ -366,7 +367,7 @@ class TplinkBaseRouter(AbstractRouter, TplinkRequest):
|
|
|
366
367
|
ipv4_status._wan_macaddr = get_mac(data.get('wan_macaddr', '00:00:00:00:00:00'))
|
|
367
368
|
ipv4_status._wan_ipv4_ipaddr = get_ip(data.get('wan_ipv4_ipaddr', '0.0.0.0'))
|
|
368
369
|
ipv4_status._wan_ipv4_gateway = get_ip(data.get('wan_ipv4_gateway', '0.0.0.0'))
|
|
369
|
-
ipv4_status.
|
|
370
|
+
ipv4_status._wan_ipv4_conntype = data.get('wan_ipv4_conntype', '')
|
|
370
371
|
ipv4_status._wan_ipv4_netmask = get_ip(data.get('wan_ipv4_netmask', '0.0.0.0'))
|
|
371
372
|
ipv4_status._wan_ipv4_pridns = get_ip(data.get('wan_ipv4_pridns', '0.0.0.0'))
|
|
372
373
|
ipv4_status._wan_ipv4_snddns = get_ip(data.get('wan_ipv4_snddns', '0.0.0.0'))
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from requests import post
|
|
2
2
|
from tplinkrouterc6u.common.package_enum import Connection
|
|
3
|
-
from tplinkrouterc6u.common.dataclass import Firmware, Status
|
|
3
|
+
from tplinkrouterc6u.common.dataclass import Firmware, Status, IPv4Status
|
|
4
4
|
from tplinkrouterc6u.common.exception import ClientException
|
|
5
5
|
from tplinkrouterc6u.client_abstract import AbstractRouter
|
|
6
6
|
|
|
@@ -31,6 +31,9 @@ class TplinkC6V4Router(AbstractRouter):
|
|
|
31
31
|
def get_status(self) -> Status:
|
|
32
32
|
raise ClientException('Not Implemented')
|
|
33
33
|
|
|
34
|
+
def get_ipv4_status(self) -> IPv4Status:
|
|
35
|
+
raise ClientException('Not Implemented')
|
|
36
|
+
|
|
34
37
|
def reboot(self) -> None:
|
|
35
38
|
raise ClientException('Not Implemented')
|
|
36
39
|
|
|
@@ -132,7 +132,7 @@ class TPLinkDecoClient(TplinkEncryption, AbstractRouter):
|
|
|
132
132
|
element = get_value(data, ['wan', 'ip_info', 'gateway'])
|
|
133
133
|
ipv4_status._wan_ipv4_gateway = IPv4Address(element) if element else None
|
|
134
134
|
element = get_value(data, ['wan', 'dial_type'])
|
|
135
|
-
ipv4_status.
|
|
135
|
+
ipv4_status._wan_ipv4_conntype = element if element else ''
|
|
136
136
|
element = get_value(data, ['wan', 'ip_info', 'mask'])
|
|
137
137
|
ipv4_status._wan_ipv4_netmask = IPv4Address(element) if element else None
|
|
138
138
|
element = get_value(data, ['wan', 'ip_info', 'dns1'])
|
|
@@ -5,6 +5,7 @@ from macaddress import EUI48
|
|
|
5
5
|
from ipaddress import IPv4Address
|
|
6
6
|
from logging import Logger
|
|
7
7
|
from tplinkrouterc6u.common.package_enum import Connection, VPN
|
|
8
|
+
from tplinkrouterc6u.common.helper import get_ip, get_mac, get_value
|
|
8
9
|
from tplinkrouterc6u.common.dataclass import (
|
|
9
10
|
Firmware,
|
|
10
11
|
Status,
|
|
@@ -48,7 +49,6 @@ class TPLinkEXClient(TPLinkMRClientBase):
|
|
|
48
49
|
verify_ssl: bool = True, timeout: int = 30) -> None:
|
|
49
50
|
super().__init__(host, password, username, logger, verify_ssl, timeout)
|
|
50
51
|
|
|
51
|
-
self.username = 'user'
|
|
52
52
|
self._url_rsa_key = 'cgi/getGDPRParm'
|
|
53
53
|
|
|
54
54
|
def logout(self) -> None:
|
|
@@ -203,26 +203,26 @@ class TPLinkEXClient(TPLinkMRClientBase):
|
|
|
203
203
|
]
|
|
204
204
|
_, values = self.req_act(acts)
|
|
205
205
|
|
|
206
|
-
if values[0].__class__ == list:
|
|
206
|
+
if values[0].__class__ == list and len(values[0]) > 0:
|
|
207
207
|
values[0] = values[0][0]
|
|
208
208
|
|
|
209
209
|
ipv4_status = IPv4Status()
|
|
210
|
-
ipv4_status._lan_macaddr =
|
|
211
|
-
ipv4_status._lan_ipv4_ipaddr =
|
|
212
|
-
ipv4_status._lan_ipv4_netmask =
|
|
213
|
-
ipv4_status.lan_ipv4_dhcp_enable = bool(int(values[0
|
|
210
|
+
ipv4_status._lan_macaddr = get_mac(get_value(values, [0, 'MACAddress'], '00:00:00:00:00:00'))
|
|
211
|
+
ipv4_status._lan_ipv4_ipaddr = get_ip(get_value(values, [0, 'IPAddress'], '0.0.0.0'))
|
|
212
|
+
ipv4_status._lan_ipv4_netmask = get_ip(get_value(values, [0, 'IPSubnetMask'], '0.0.0.0'))
|
|
213
|
+
ipv4_status.lan_ipv4_dhcp_enable = bool(int(get_value(values, [0, 'DHCPv4Enable'], '0')))
|
|
214
214
|
|
|
215
215
|
for item in values[1]:
|
|
216
216
|
if int(item['enable']) == 0 and values[1].__class__ == list:
|
|
217
217
|
continue
|
|
218
|
-
ipv4_status._wan_macaddr =
|
|
219
|
-
ipv4_status._wan_ipv4_ipaddr =
|
|
220
|
-
ipv4_status._wan_ipv4_gateway =
|
|
221
|
-
ipv4_status.
|
|
222
|
-
ipv4_status._wan_ipv4_netmask =
|
|
223
|
-
dns = item['connIPv4DnsServer'].split(',')
|
|
224
|
-
ipv4_status._wan_ipv4_pridns =
|
|
225
|
-
ipv4_status._wan_ipv4_snddns =
|
|
218
|
+
ipv4_status._wan_macaddr = get_mac(get_value(item, ['MACAddr'], '00:00:00:00:00:00'))
|
|
219
|
+
ipv4_status._wan_ipv4_ipaddr = get_ip(get_value(item, ['connIPv4Address'], '0.0.0.0'))
|
|
220
|
+
ipv4_status._wan_ipv4_gateway = get_ip(get_value(item, ['connIPv4Gateway'], '0.0.0.0'))
|
|
221
|
+
ipv4_status._wan_ipv4_conntype = get_value(item, ['name'], '')
|
|
222
|
+
ipv4_status._wan_ipv4_netmask = get_ip(get_value(item, ['connIPv4SubnetMask'], '0.0.0.0'))
|
|
223
|
+
dns = get_value(item, ['connIPv4DnsServer'], '').split(',')
|
|
224
|
+
ipv4_status._wan_ipv4_pridns = get_ip(dns[0] if len(dns) > 0 else '0.0.0.0')
|
|
225
|
+
ipv4_status._wan_ipv4_snddns = get_ip(dns[1] if len(dns) > 1 else '0.0.0.0')
|
|
226
226
|
|
|
227
227
|
return ipv4_status
|
|
228
228
|
|
|
@@ -7,7 +7,7 @@ from datetime import timedelta, datetime
|
|
|
7
7
|
from macaddress import EUI48
|
|
8
8
|
from ipaddress import IPv4Address
|
|
9
9
|
from logging import Logger
|
|
10
|
-
from tplinkrouterc6u.common.helper import get_ip, get_mac
|
|
10
|
+
from tplinkrouterc6u.common.helper import get_ip, get_mac, get_value
|
|
11
11
|
from tplinkrouterc6u.common.encryption import EncryptionWrapperMR
|
|
12
12
|
from tplinkrouterc6u.common.package_enum import Connection, VPN
|
|
13
13
|
from tplinkrouterc6u.common.dataclass import (
|
|
@@ -114,6 +114,213 @@ class TPLinkMRClientBase(AbstractRouter):
|
|
|
114
114
|
]
|
|
115
115
|
self.req_act(acts)
|
|
116
116
|
|
|
117
|
+
def get_firmware(self) -> Firmware:
|
|
118
|
+
acts = [
|
|
119
|
+
self.ActItem(self.ActItem.GET, 'IGD_DEV_INFO', attrs=[
|
|
120
|
+
'hardwareVersion',
|
|
121
|
+
'modelName',
|
|
122
|
+
'softwareVersion'
|
|
123
|
+
])
|
|
124
|
+
]
|
|
125
|
+
_, values = self.req_act(acts)
|
|
126
|
+
|
|
127
|
+
firmware = Firmware(values.get('hardwareVersion', ''), values.get('modelName', ''),
|
|
128
|
+
values.get('softwareVersion', ''))
|
|
129
|
+
|
|
130
|
+
return firmware
|
|
131
|
+
|
|
132
|
+
def get_status(self) -> Status:
|
|
133
|
+
status = Status()
|
|
134
|
+
acts = [
|
|
135
|
+
self.ActItem(self.ActItem.GS, 'LAN_IP_INTF', attrs=['X_TP_MACAddress', 'IPInterfaceIPAddress']),
|
|
136
|
+
self.ActItem(self.ActItem.GS, 'WAN_IP_CONN',
|
|
137
|
+
attrs=['enable', 'MACAddress', 'externalIPAddress', 'defaultGateway', 'name']),
|
|
138
|
+
self.ActItem(self.ActItem.GL, 'LAN_WLAN', attrs=['enable', 'X_TP_Band']),
|
|
139
|
+
self.ActItem(self.ActItem.GL, 'LAN_WLAN_GUESTNET', attrs=['enable', 'name']),
|
|
140
|
+
self.ActItem(self.ActItem.GL, 'LAN_HOST_ENTRY', attrs=[
|
|
141
|
+
'IPAddress',
|
|
142
|
+
'MACAddress',
|
|
143
|
+
'hostName',
|
|
144
|
+
'X_TP_ConnType',
|
|
145
|
+
'active',
|
|
146
|
+
]),
|
|
147
|
+
self.ActItem(self.ActItem.GS, 'LAN_WLAN_ASSOC_DEV', attrs=[
|
|
148
|
+
'associatedDeviceMACAddress',
|
|
149
|
+
'X_TP_TotalPacketsSent',
|
|
150
|
+
'X_TP_TotalPacketsReceived',
|
|
151
|
+
]),
|
|
152
|
+
]
|
|
153
|
+
_, values = self.req_act(acts)
|
|
154
|
+
|
|
155
|
+
if values['0'].__class__ == list:
|
|
156
|
+
values['0'] = values['0'][0]
|
|
157
|
+
|
|
158
|
+
status._lan_macaddr = EUI48(values['0']['X_TP_MACAddress'])
|
|
159
|
+
status._lan_ipv4_addr = IPv4Address(values['0']['IPInterfaceIPAddress'])
|
|
160
|
+
|
|
161
|
+
for item in self._to_list(values.get('1')):
|
|
162
|
+
if int(item['enable']) == 0 and values.get('1').__class__ == list:
|
|
163
|
+
continue
|
|
164
|
+
status._wan_macaddr = EUI48(item['MACAddress']) if item.get('MACAddress') else None
|
|
165
|
+
status._wan_ipv4_addr = IPv4Address(item['externalIPAddress'])
|
|
166
|
+
status._wan_ipv4_gateway = IPv4Address(item['defaultGateway'])
|
|
167
|
+
status.conn_type = item.get('name', '')
|
|
168
|
+
|
|
169
|
+
if values['2'].__class__ != list:
|
|
170
|
+
status.wifi_2g_enable = bool(int(values['2']['enable']))
|
|
171
|
+
else:
|
|
172
|
+
status.wifi_2g_enable = bool(int(values['2'][0]['enable']))
|
|
173
|
+
status.wifi_5g_enable = bool(int(values['2'][1]['enable']))
|
|
174
|
+
|
|
175
|
+
if values['3'].__class__ != list:
|
|
176
|
+
status.guest_2g_enable = bool(int(values['3']['enable']))
|
|
177
|
+
else:
|
|
178
|
+
status.guest_2g_enable = bool(int(values['3'][0]['enable']))
|
|
179
|
+
status.guest_5g_enable = bool(int(values['3'][1]['enable']))
|
|
180
|
+
|
|
181
|
+
devices = {}
|
|
182
|
+
for val in self._to_list(values.get('4')):
|
|
183
|
+
if int(val['active']) == 0:
|
|
184
|
+
continue
|
|
185
|
+
conn = self.CLIENT_TYPES.get(int(val['X_TP_ConnType']))
|
|
186
|
+
if conn is None:
|
|
187
|
+
continue
|
|
188
|
+
elif conn == Connection.WIRED:
|
|
189
|
+
status.wired_total += 1
|
|
190
|
+
elif conn.is_guest_wifi():
|
|
191
|
+
status.guest_clients_total += 1
|
|
192
|
+
elif conn.is_host_wifi():
|
|
193
|
+
status.wifi_clients_total += 1
|
|
194
|
+
devices[val['MACAddress']] = Device(conn,
|
|
195
|
+
EUI48(val['MACAddress']),
|
|
196
|
+
IPv4Address(val['IPAddress']),
|
|
197
|
+
val['hostName'])
|
|
198
|
+
|
|
199
|
+
for val in self._to_list(values.get('5')):
|
|
200
|
+
if val['associatedDeviceMACAddress'] not in devices:
|
|
201
|
+
status.wifi_clients_total += 1
|
|
202
|
+
devices[val['associatedDeviceMACAddress']] = Device(
|
|
203
|
+
Connection.HOST_2G,
|
|
204
|
+
EUI48(val['associatedDeviceMACAddress']),
|
|
205
|
+
IPv4Address('0.0.0.0'),
|
|
206
|
+
'')
|
|
207
|
+
devices[val['associatedDeviceMACAddress']].packets_sent = int(val['X_TP_TotalPacketsSent'])
|
|
208
|
+
devices[val['associatedDeviceMACAddress']].packets_received = int(val['X_TP_TotalPacketsReceived'])
|
|
209
|
+
|
|
210
|
+
status.devices = list(devices.values())
|
|
211
|
+
status.clients_total = status.wired_total + status.wifi_clients_total + status.guest_clients_total
|
|
212
|
+
|
|
213
|
+
return status
|
|
214
|
+
|
|
215
|
+
def get_ipv4_reservations(self) -> [IPv4Reservation]:
|
|
216
|
+
acts = [
|
|
217
|
+
self.ActItem(self.ActItem.GL, 'LAN_DHCP_STATIC_ADDR', attrs=['enable', 'chaddr', 'yiaddr']),
|
|
218
|
+
]
|
|
219
|
+
_, values = self.req_act(acts)
|
|
220
|
+
|
|
221
|
+
ipv4_reservations = []
|
|
222
|
+
for item in self._to_list(values):
|
|
223
|
+
ipv4_reservations.append(
|
|
224
|
+
IPv4Reservation(
|
|
225
|
+
EUI48(item['chaddr']),
|
|
226
|
+
IPv4Address(item['yiaddr']),
|
|
227
|
+
'',
|
|
228
|
+
bool(int(item['enable']))
|
|
229
|
+
))
|
|
230
|
+
|
|
231
|
+
return ipv4_reservations
|
|
232
|
+
|
|
233
|
+
def get_ipv4_dhcp_leases(self) -> [IPv4DHCPLease]:
|
|
234
|
+
acts = [
|
|
235
|
+
self.ActItem(self.ActItem.GL, 'LAN_HOST_ENTRY', attrs=['IPAddress', 'MACAddress', 'hostName',
|
|
236
|
+
'leaseTimeRemaining']),
|
|
237
|
+
]
|
|
238
|
+
_, values = self.req_act(acts)
|
|
239
|
+
|
|
240
|
+
dhcp_leases = []
|
|
241
|
+
for item in self._to_list(values):
|
|
242
|
+
lease_time = item['leaseTimeRemaining']
|
|
243
|
+
dhcp_leases.append(
|
|
244
|
+
IPv4DHCPLease(
|
|
245
|
+
EUI48(item['MACAddress']),
|
|
246
|
+
IPv4Address(item['IPAddress']),
|
|
247
|
+
item['hostName'],
|
|
248
|
+
str(timedelta(seconds=int(lease_time))) if lease_time.isdigit() else 'Permanent',
|
|
249
|
+
))
|
|
250
|
+
|
|
251
|
+
return dhcp_leases
|
|
252
|
+
|
|
253
|
+
def get_ipv4_status(self) -> IPv4Status:
|
|
254
|
+
acts = [
|
|
255
|
+
self.ActItem(self.ActItem.GS, 'LAN_IP_INTF',
|
|
256
|
+
attrs=['X_TP_MACAddress', 'IPInterfaceIPAddress', 'IPInterfaceSubnetMask']),
|
|
257
|
+
self.ActItem(self.ActItem.GET, 'LAN_HOST_CFG', '1,0,0,0,0,0', attrs=['DHCPServerEnable']),
|
|
258
|
+
self.ActItem(self.ActItem.GS, 'WAN_IP_CONN',
|
|
259
|
+
attrs=['enable', 'MACAddress', 'externalIPAddress', 'defaultGateway', 'name', 'subnetMask',
|
|
260
|
+
'DNSServers']),
|
|
261
|
+
]
|
|
262
|
+
_, values = self.req_act(acts)
|
|
263
|
+
|
|
264
|
+
ipv4_status = IPv4Status()
|
|
265
|
+
ipv4_status._lan_macaddr = get_mac(get_value(values, ['0', 'X_TP_MACAddress'], '00:00:00:00:00:00'))
|
|
266
|
+
ipv4_status._lan_ipv4_ipaddr = get_ip(get_value(values, ['0', 'IPInterfaceIPAddress'], '0.0.0.0'))
|
|
267
|
+
ipv4_status._lan_ipv4_netmask = get_ip(get_value(values, ['0', 'IPInterfaceSubnetMask'], '0.0.0.0'))
|
|
268
|
+
ipv4_status.lan_ipv4_dhcp_enable = bool(int(get_value(values, ['1', 'DHCPServerEnable'], '0')))
|
|
269
|
+
|
|
270
|
+
for item in self._to_list(values.get('2')):
|
|
271
|
+
if int(item.get('enable', '0')) == 0 and values.get('2').__class__ == list:
|
|
272
|
+
continue
|
|
273
|
+
ipv4_status._wan_macaddr = get_mac(item.get('MACAddress', '00:00:00:00:00:00'))
|
|
274
|
+
ipv4_status._wan_ipv4_ipaddr = get_ip(item.get('externalIPAddress', '0.0.0.0'))
|
|
275
|
+
ipv4_status._wan_ipv4_gateway = get_ip(item.get('defaultGateway', '0.0.0.0'))
|
|
276
|
+
ipv4_status._wan_ipv4_conntype = item.get('name', '')
|
|
277
|
+
ipv4_status._wan_ipv4_netmask = get_ip(item.get('subnetMask', '0.0.0.0'))
|
|
278
|
+
dns = item.get('DNSServers', '').split(',')
|
|
279
|
+
ipv4_status._wan_ipv4_pridns = get_ip(dns[0] if len(dns) > 0 else '0.0.0.0')
|
|
280
|
+
ipv4_status._wan_ipv4_snddns = get_ip(dns[1] if len(dns) > 1 else '0.0.0.0')
|
|
281
|
+
|
|
282
|
+
return ipv4_status
|
|
283
|
+
|
|
284
|
+
def set_wifi(self, wifi: Connection, enable: bool) -> None:
|
|
285
|
+
acts = [
|
|
286
|
+
self.ActItem(
|
|
287
|
+
self.ActItem.SET,
|
|
288
|
+
'LAN_WLAN' if wifi in [Connection.HOST_2G, Connection.HOST_5G] else 'LAN_WLAN_MSSIDENTRY',
|
|
289
|
+
self.WIFI_SET[wifi],
|
|
290
|
+
attrs=['enable={}'.format(int(enable))]),
|
|
291
|
+
]
|
|
292
|
+
self.req_act(acts)
|
|
293
|
+
|
|
294
|
+
def get_vpn_status(self) -> VPNStatus:
|
|
295
|
+
status = VPNStatus()
|
|
296
|
+
acts = [
|
|
297
|
+
self.ActItem(self.ActItem.GET, 'OPENVPN', attrs=['enable']),
|
|
298
|
+
self.ActItem(self.ActItem.GET, 'PPTPVPN', attrs=['enable']),
|
|
299
|
+
self.ActItem(self.ActItem.GL, 'OVPN_CLIENT', attrs=['connAct']),
|
|
300
|
+
self.ActItem(self.ActItem.GL, 'PVPN_CLIENT', attrs=['connAct']),
|
|
301
|
+
]
|
|
302
|
+
_, values = self.req_act(acts)
|
|
303
|
+
|
|
304
|
+
status.openvpn_enable = values['0']['enable'] == '1'
|
|
305
|
+
status.pptpvpn_enable = values['1']['enable'] == '1'
|
|
306
|
+
|
|
307
|
+
for item in values['2']:
|
|
308
|
+
if item['connAct'] == '1':
|
|
309
|
+
status.openvpn_clients_total += 1
|
|
310
|
+
|
|
311
|
+
for item in values['3']:
|
|
312
|
+
if item['connAct'] == '1':
|
|
313
|
+
status.pptpvpn_clients_total += 1
|
|
314
|
+
|
|
315
|
+
return status
|
|
316
|
+
|
|
317
|
+
def set_vpn(self, vpn: VPN, enable: bool) -> None:
|
|
318
|
+
acts = [
|
|
319
|
+
self.ActItem(self.ActItem.SET, vpn.value, attrs=['enable={}'.format(int(enable))])
|
|
320
|
+
]
|
|
321
|
+
|
|
322
|
+
self.req_act(acts)
|
|
323
|
+
|
|
117
324
|
def req_act(self, acts: list):
|
|
118
325
|
'''
|
|
119
326
|
Requests ACTs via the cgi_gdpr proxy
|
|
@@ -303,7 +510,7 @@ class TPLinkMRClientBase(AbstractRouter):
|
|
|
303
510
|
self._logger.debug(error)
|
|
304
511
|
raise ClientException(error)
|
|
305
512
|
|
|
306
|
-
def _request(self, url, method='POST', data_str=None, encrypt=False):
|
|
513
|
+
def _request(self, url, method='POST', data_str=None, encrypt=False, is_login=False):
|
|
307
514
|
'''
|
|
308
515
|
Prepares and sends an HTTP request to the host
|
|
309
516
|
- sets up the headers, handles token auth
|
|
@@ -325,7 +532,7 @@ class TPLinkMRClientBase(AbstractRouter):
|
|
|
325
532
|
|
|
326
533
|
# encrypt request data if needed (for the /cgi_gdpr endpoint)
|
|
327
534
|
if encrypt:
|
|
328
|
-
sign, data = self._prepare_data(data_str,
|
|
535
|
+
sign, data = self._prepare_data(data_str, is_login)
|
|
329
536
|
data = 'sign={}\r\ndata={}\r\n'.format(sign, data)
|
|
330
537
|
else:
|
|
331
538
|
data = data_str
|
|
@@ -396,182 +603,6 @@ class TPLinkMRClient(TPLinkMRClientBase):
|
|
|
396
603
|
if ret_code == self.HTTP_RET_OK:
|
|
397
604
|
self._token = None
|
|
398
605
|
|
|
399
|
-
def get_firmware(self) -> Firmware:
|
|
400
|
-
acts = [
|
|
401
|
-
self.ActItem(self.ActItem.GET, 'IGD_DEV_INFO', attrs=[
|
|
402
|
-
'hardwareVersion',
|
|
403
|
-
'modelName',
|
|
404
|
-
'softwareVersion'
|
|
405
|
-
])
|
|
406
|
-
]
|
|
407
|
-
_, values = self.req_act(acts)
|
|
408
|
-
|
|
409
|
-
firmware = Firmware(values.get('hardwareVersion', ''), values.get('modelName', ''),
|
|
410
|
-
values.get('softwareVersion', ''))
|
|
411
|
-
|
|
412
|
-
return firmware
|
|
413
|
-
|
|
414
|
-
def get_status(self) -> Status:
|
|
415
|
-
status = Status()
|
|
416
|
-
acts = [
|
|
417
|
-
self.ActItem(self.ActItem.GS, 'LAN_IP_INTF', attrs=['X_TP_MACAddress', 'IPInterfaceIPAddress']),
|
|
418
|
-
self.ActItem(self.ActItem.GS, 'WAN_IP_CONN',
|
|
419
|
-
attrs=['enable', 'MACAddress', 'externalIPAddress', 'defaultGateway']),
|
|
420
|
-
self.ActItem(self.ActItem.GL, 'LAN_WLAN', attrs=['enable', 'X_TP_Band']),
|
|
421
|
-
self.ActItem(self.ActItem.GL, 'LAN_WLAN_GUESTNET', attrs=['enable', 'name']),
|
|
422
|
-
self.ActItem(self.ActItem.GL, 'LAN_HOST_ENTRY', attrs=[
|
|
423
|
-
'IPAddress',
|
|
424
|
-
'MACAddress',
|
|
425
|
-
'hostName',
|
|
426
|
-
'X_TP_ConnType',
|
|
427
|
-
'active',
|
|
428
|
-
]),
|
|
429
|
-
self.ActItem(self.ActItem.GS, 'LAN_WLAN_ASSOC_DEV', attrs=[
|
|
430
|
-
'associatedDeviceMACAddress',
|
|
431
|
-
'X_TP_TotalPacketsSent',
|
|
432
|
-
'X_TP_TotalPacketsReceived',
|
|
433
|
-
]),
|
|
434
|
-
]
|
|
435
|
-
_, values = self.req_act(acts)
|
|
436
|
-
|
|
437
|
-
if values['0'].__class__ == list:
|
|
438
|
-
values['0'] = values['0'][0]
|
|
439
|
-
|
|
440
|
-
status._lan_macaddr = EUI48(values['0']['X_TP_MACAddress'])
|
|
441
|
-
status._lan_ipv4_addr = IPv4Address(values['0']['IPInterfaceIPAddress'])
|
|
442
|
-
|
|
443
|
-
for item in self._to_list(values.get('1')):
|
|
444
|
-
if int(item['enable']) == 0 and values.get('1').__class__ == list:
|
|
445
|
-
continue
|
|
446
|
-
status._wan_macaddr = EUI48(item['MACAddress']) if item.get('MACAddress') else None
|
|
447
|
-
status._wan_ipv4_addr = IPv4Address(item['externalIPAddress'])
|
|
448
|
-
status._wan_ipv4_gateway = IPv4Address(item['defaultGateway'])
|
|
449
|
-
|
|
450
|
-
if values['2'].__class__ != list:
|
|
451
|
-
status.wifi_2g_enable = bool(int(values['2']['enable']))
|
|
452
|
-
else:
|
|
453
|
-
status.wifi_2g_enable = bool(int(values['2'][0]['enable']))
|
|
454
|
-
status.wifi_5g_enable = bool(int(values['2'][1]['enable']))
|
|
455
|
-
|
|
456
|
-
if values['3'].__class__ != list:
|
|
457
|
-
status.guest_2g_enable = bool(int(values['3']['enable']))
|
|
458
|
-
else:
|
|
459
|
-
status.guest_2g_enable = bool(int(values['3'][0]['enable']))
|
|
460
|
-
status.guest_5g_enable = bool(int(values['3'][1]['enable']))
|
|
461
|
-
|
|
462
|
-
devices = {}
|
|
463
|
-
for val in self._to_list(values.get('4')):
|
|
464
|
-
if int(val['active']) == 0:
|
|
465
|
-
continue
|
|
466
|
-
conn = self.CLIENT_TYPES.get(int(val['X_TP_ConnType']))
|
|
467
|
-
if conn is None:
|
|
468
|
-
continue
|
|
469
|
-
elif conn == Connection.WIRED:
|
|
470
|
-
status.wired_total += 1
|
|
471
|
-
elif conn.is_guest_wifi():
|
|
472
|
-
status.guest_clients_total += 1
|
|
473
|
-
elif conn.is_host_wifi():
|
|
474
|
-
status.wifi_clients_total += 1
|
|
475
|
-
devices[val['MACAddress']] = Device(conn,
|
|
476
|
-
EUI48(val['MACAddress']),
|
|
477
|
-
IPv4Address(val['IPAddress']),
|
|
478
|
-
val['hostName'])
|
|
479
|
-
|
|
480
|
-
for val in self._to_list(values.get('5')):
|
|
481
|
-
if val['associatedDeviceMACAddress'] not in devices:
|
|
482
|
-
status.wifi_clients_total += 1
|
|
483
|
-
devices[val['associatedDeviceMACAddress']] = Device(
|
|
484
|
-
Connection.HOST_2G,
|
|
485
|
-
EUI48(val['associatedDeviceMACAddress']),
|
|
486
|
-
IPv4Address('0.0.0.0'),
|
|
487
|
-
'')
|
|
488
|
-
devices[val['associatedDeviceMACAddress']].packets_sent = int(val['X_TP_TotalPacketsSent'])
|
|
489
|
-
devices[val['associatedDeviceMACAddress']].packets_received = int(val['X_TP_TotalPacketsReceived'])
|
|
490
|
-
|
|
491
|
-
status.devices = list(devices.values())
|
|
492
|
-
status.clients_total = status.wired_total + status.wifi_clients_total + status.guest_clients_total
|
|
493
|
-
|
|
494
|
-
return status
|
|
495
|
-
|
|
496
|
-
def get_ipv4_reservations(self) -> [IPv4Reservation]:
|
|
497
|
-
acts = [
|
|
498
|
-
self.ActItem(self.ActItem.GL, 'LAN_DHCP_STATIC_ADDR', attrs=['enable', 'chaddr', 'yiaddr']),
|
|
499
|
-
]
|
|
500
|
-
_, values = self.req_act(acts)
|
|
501
|
-
|
|
502
|
-
ipv4_reservations = []
|
|
503
|
-
for item in self._to_list(values):
|
|
504
|
-
ipv4_reservations.append(
|
|
505
|
-
IPv4Reservation(
|
|
506
|
-
EUI48(item['chaddr']),
|
|
507
|
-
IPv4Address(item['yiaddr']),
|
|
508
|
-
'',
|
|
509
|
-
bool(int(item['enable']))
|
|
510
|
-
))
|
|
511
|
-
|
|
512
|
-
return ipv4_reservations
|
|
513
|
-
|
|
514
|
-
def get_ipv4_dhcp_leases(self) -> [IPv4DHCPLease]:
|
|
515
|
-
acts = [
|
|
516
|
-
self.ActItem(self.ActItem.GL, 'LAN_HOST_ENTRY', attrs=['IPAddress', 'MACAddress', 'hostName',
|
|
517
|
-
'leaseTimeRemaining']),
|
|
518
|
-
]
|
|
519
|
-
_, values = self.req_act(acts)
|
|
520
|
-
|
|
521
|
-
dhcp_leases = []
|
|
522
|
-
for item in self._to_list(values):
|
|
523
|
-
lease_time = item['leaseTimeRemaining']
|
|
524
|
-
dhcp_leases.append(
|
|
525
|
-
IPv4DHCPLease(
|
|
526
|
-
EUI48(item['MACAddress']),
|
|
527
|
-
IPv4Address(item['IPAddress']),
|
|
528
|
-
item['hostName'],
|
|
529
|
-
str(timedelta(seconds=int(lease_time))) if lease_time.isdigit() else 'Permanent',
|
|
530
|
-
))
|
|
531
|
-
|
|
532
|
-
return dhcp_leases
|
|
533
|
-
|
|
534
|
-
def get_ipv4_status(self) -> IPv4Status:
|
|
535
|
-
acts = [
|
|
536
|
-
self.ActItem(self.ActItem.GS, 'LAN_IP_INTF',
|
|
537
|
-
attrs=['X_TP_MACAddress', 'IPInterfaceIPAddress', 'IPInterfaceSubnetMask']),
|
|
538
|
-
self.ActItem(self.ActItem.GET, 'LAN_HOST_CFG', '1,0,0,0,0,0', attrs=['DHCPServerEnable']),
|
|
539
|
-
self.ActItem(self.ActItem.GS, 'WAN_IP_CONN',
|
|
540
|
-
attrs=['enable', 'MACAddress', 'externalIPAddress', 'defaultGateway', 'name', 'subnetMask',
|
|
541
|
-
'DNSServers']),
|
|
542
|
-
]
|
|
543
|
-
_, values = self.req_act(acts)
|
|
544
|
-
|
|
545
|
-
ipv4_status = IPv4Status()
|
|
546
|
-
ipv4_status._lan_macaddr = get_mac(values.get('0', {}).get('X_TP_MACAddress', '00:00:00:00:00:00'))
|
|
547
|
-
ipv4_status._lan_ipv4_ipaddr = get_ip(values.get('0', {}).get('IPInterfaceIPAddress', '0.0.0.0'))
|
|
548
|
-
ipv4_status._lan_ipv4_netmask = get_ip(values.get('0', {}).get('IPInterfaceSubnetMask', '0.0.0.0'))
|
|
549
|
-
ipv4_status.lan_ipv4_dhcp_enable = bool(int(values.get('1', {}).get('DHCPServerEnable', '0')))
|
|
550
|
-
|
|
551
|
-
for item in self._to_list(values.get('2')):
|
|
552
|
-
if int(item.get('enable', '0')) == 0 and values.get('2').__class__ == list:
|
|
553
|
-
continue
|
|
554
|
-
ipv4_status._wan_macaddr = get_mac(item.get('MACAddress', '00:00:00:00:00:00'))
|
|
555
|
-
ipv4_status._wan_ipv4_ipaddr = get_ip(item.get('externalIPAddress', '0.0.0.0'))
|
|
556
|
-
ipv4_status._wan_ipv4_gateway = get_ip(item.get('defaultGateway', '0.0.0.0'))
|
|
557
|
-
ipv4_status.wan_ipv4_conntype = item.get('name', '')
|
|
558
|
-
ipv4_status._wan_ipv4_netmask = get_ip(item.get('subnetMask', '0.0.0.0'))
|
|
559
|
-
dns = item.get('DNSServers', '').split(',')
|
|
560
|
-
ipv4_status._wan_ipv4_pridns = get_ip(dns[0] if len(dns) == 2 else '0.0.0.0')
|
|
561
|
-
ipv4_status._wan_ipv4_snddns = get_ip(dns[1] if len(dns) == 2 else '0.0.0.0')
|
|
562
|
-
|
|
563
|
-
return ipv4_status
|
|
564
|
-
|
|
565
|
-
def set_wifi(self, wifi: Connection, enable: bool) -> None:
|
|
566
|
-
acts = [
|
|
567
|
-
self.ActItem(
|
|
568
|
-
self.ActItem.SET,
|
|
569
|
-
'LAN_WLAN' if wifi in [Connection.HOST_2G, Connection.HOST_5G] else 'LAN_WLAN_MSSIDENTRY',
|
|
570
|
-
self.WIFI_SET[wifi],
|
|
571
|
-
attrs=['enable={}'.format(int(enable))]),
|
|
572
|
-
]
|
|
573
|
-
self.req_act(acts)
|
|
574
|
-
|
|
575
606
|
def send_sms(self, phone_number: str, message: str) -> None:
|
|
576
607
|
acts = [
|
|
577
608
|
self.ActItem(
|
|
@@ -681,33 +712,3 @@ class TPLinkMRClient(TPLinkMRClientBase):
|
|
|
681
712
|
status.isp_name = values['3']['ispName']
|
|
682
713
|
|
|
683
714
|
return status
|
|
684
|
-
|
|
685
|
-
def get_vpn_status(self) -> VPNStatus:
|
|
686
|
-
status = VPNStatus()
|
|
687
|
-
acts = [
|
|
688
|
-
self.ActItem(self.ActItem.GET, 'OPENVPN', attrs=['enable']),
|
|
689
|
-
self.ActItem(self.ActItem.GET, 'PPTPVPN', attrs=['enable']),
|
|
690
|
-
self.ActItem(self.ActItem.GL, 'OVPN_CLIENT', attrs=['connAct']),
|
|
691
|
-
self.ActItem(self.ActItem.GL, 'PVPN_CLIENT', attrs=['connAct']),
|
|
692
|
-
]
|
|
693
|
-
_, values = self.req_act(acts)
|
|
694
|
-
|
|
695
|
-
status.openvpn_enable = values['0']['enable'] == '1'
|
|
696
|
-
status.pptpvpn_enable = values['1']['enable'] == '1'
|
|
697
|
-
|
|
698
|
-
for item in values['2']:
|
|
699
|
-
if item['connAct'] == '1':
|
|
700
|
-
status.openvpn_clients_total += 1
|
|
701
|
-
|
|
702
|
-
for item in values['3']:
|
|
703
|
-
if item['connAct'] == '1':
|
|
704
|
-
status.pptpvpn_clients_total += 1
|
|
705
|
-
|
|
706
|
-
return status
|
|
707
|
-
|
|
708
|
-
def set_vpn(self, vpn: VPN, enable: bool) -> None:
|
|
709
|
-
acts = [
|
|
710
|
-
self.ActItem(self.ActItem.SET, vpn.value, attrs=['enable={}'.format(int(enable))])
|
|
711
|
-
]
|
|
712
|
-
|
|
713
|
-
self.req_act(acts)
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import base64
|
|
2
|
+
from http import HTTPStatus
|
|
3
|
+
from tplinkrouterc6u.client.mr import TPLinkMRClientBase
|
|
4
|
+
from tplinkrouterc6u.common.exception import ClientException
|
|
5
|
+
from logging import Logger
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class TPLinkVRClient(TPLinkMRClientBase):
|
|
9
|
+
def __init__(self, host: str, password: str, username: str = 'admin', logger: Logger = None,
|
|
10
|
+
verify_ssl: bool = True, timeout: int = 30):
|
|
11
|
+
super().__init__(host, password, username, logger, verify_ssl, timeout)
|
|
12
|
+
self._url_rsa_key = 'cgi/getGDPRParm'
|
|
13
|
+
|
|
14
|
+
def supports(self):
|
|
15
|
+
return self._verify_router() and super().supports()
|
|
16
|
+
|
|
17
|
+
def _verify_router(self) -> bool:
|
|
18
|
+
"""
|
|
19
|
+
Verifies if the connected router is a supported TP-Link VR model.
|
|
20
|
+
|
|
21
|
+
This function checks if the router is a TP-Link VR model by sending a GET request
|
|
22
|
+
to the host and analyzing the response. It verifies the presence of specific
|
|
23
|
+
keywords and endpoints in the response to determine the model type.
|
|
24
|
+
|
|
25
|
+
Returns:
|
|
26
|
+
bool: True if the router is a supported TP-Link VR model and supports the RSA key endpoint,
|
|
27
|
+
otherwise False.
|
|
28
|
+
|
|
29
|
+
Raises:
|
|
30
|
+
Exception: If an error occurs during the request process, it logs the error
|
|
31
|
+
and returns False.
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
is_VR = False
|
|
35
|
+
has_url_rsa_endpoint = False
|
|
36
|
+
|
|
37
|
+
try:
|
|
38
|
+
status_code, response = self._request(self.host, method='GET')
|
|
39
|
+
except Exception as e:
|
|
40
|
+
if self._logger is not None:
|
|
41
|
+
self._logger.error("Error while checking modem: {}".format(e))
|
|
42
|
+
|
|
43
|
+
return False
|
|
44
|
+
|
|
45
|
+
if status_code == HTTPStatus.OK:
|
|
46
|
+
is_VR = "Archer VR" in response
|
|
47
|
+
has_url_rsa_endpoint = self._url_rsa_key in response
|
|
48
|
+
|
|
49
|
+
if has_url_rsa_endpoint and is_VR:
|
|
50
|
+
return True
|
|
51
|
+
elif is_VR:
|
|
52
|
+
# check if lib.js is present. If response code is 200, it is okay. Check if self._url_rsa_key is present
|
|
53
|
+
try:
|
|
54
|
+
status_code, response = self._request("{}/js/lib.js".format(self.host), method='GET')
|
|
55
|
+
except Exception as e:
|
|
56
|
+
if self._logger is not None:
|
|
57
|
+
self._logger.error("Error while checking if lib.js is present in modem: {}".format(e))
|
|
58
|
+
|
|
59
|
+
# if lib.js is not present, return False. Are API not compatible to this class?
|
|
60
|
+
return False
|
|
61
|
+
|
|
62
|
+
if status_code == HTTPStatus.OK:
|
|
63
|
+
has_url_rsa_endpoint = (self._url_rsa_key in response)
|
|
64
|
+
|
|
65
|
+
return is_VR and has_url_rsa_endpoint
|
|
66
|
+
else:
|
|
67
|
+
# modem is not VR
|
|
68
|
+
return False
|
|
69
|
+
|
|
70
|
+
def logout(self) -> None:
|
|
71
|
+
'''
|
|
72
|
+
Logs out from the host
|
|
73
|
+
'''
|
|
74
|
+
acts = [
|
|
75
|
+
self.ActItem(self.ActItem.CGI, '/cgi/logout')
|
|
76
|
+
]
|
|
77
|
+
|
|
78
|
+
response, _ = self.req_act(acts)
|
|
79
|
+
|
|
80
|
+
if response == '[cgi]0\n[error]0\n':
|
|
81
|
+
self._token = None
|
|
82
|
+
|
|
83
|
+
def _req_login(self) -> None:
|
|
84
|
+
'''
|
|
85
|
+
Authenticates to the host
|
|
86
|
+
- sets the session token after successful login
|
|
87
|
+
- data/signature is passed as a GET parameter, NOT as a raw request data
|
|
88
|
+
(unlike for regular encrypted requests to the /cgi_gdpr endpoint)
|
|
89
|
+
|
|
90
|
+
Example session token (set as a cookie):
|
|
91
|
+
{'JSESSIONID': '4d786fede0164d7613411c7b6ec61e'}
|
|
92
|
+
'''
|
|
93
|
+
# self.password to base64 string
|
|
94
|
+
base64pwd = base64.b64encode(self.password.encode('utf-8')).decode('utf-8')
|
|
95
|
+
# sign, data = self._prepare_data(self.username + '\n' + str(base64pwd), True)
|
|
96
|
+
|
|
97
|
+
data_list = []
|
|
98
|
+
data_list.append("UserName={}".format(self.username))
|
|
99
|
+
data_list.append("Passwd={}".format(base64pwd))
|
|
100
|
+
|
|
101
|
+
actItem = self.ActItem(self.ActItem.CGI, '/cgi/login', attrs=data_list)
|
|
102
|
+
response, _ = self.req_act([actItem])
|
|
103
|
+
|
|
104
|
+
ret_code = self._parse_ret_val(response)
|
|
105
|
+
if ret_code == self.HTTP_RET_OK:
|
|
106
|
+
return
|
|
107
|
+
|
|
108
|
+
if ret_code == self.HTTP_ERR_USER_PWD_NOT_CORRECT:
|
|
109
|
+
|
|
110
|
+
error = 'TplinkRouter - VR - Login failed, wrong password.'
|
|
111
|
+
if self._logger:
|
|
112
|
+
self._logger.debug(error)
|
|
113
|
+
raise ClientException(error)
|
|
114
|
+
|
|
115
|
+
if ret_code == self.HTTP_ERR_USER_BAD_REQUEST:
|
|
116
|
+
error = 'TplinkRouter - VR - Login failed. Generic error code: {}'.format(ret_code)
|
|
117
|
+
if self._logger:
|
|
118
|
+
self._logger.debug(error)
|
|
119
|
+
raise ClientException(error)
|
|
120
|
+
|
|
121
|
+
# unknown error
|
|
122
|
+
error = 'TplinkRouter - VR - Login failed. Unknown error code: {}'.format(ret_code)
|
|
123
|
+
if self._logger:
|
|
124
|
+
self._logger.debug(error)
|
|
125
|
+
raise ClientException(error)
|
|
126
|
+
|
|
127
|
+
def _request(self, url, method='POST', data_str=None, encrypt=False, is_login=False):
|
|
128
|
+
is_login = encrypt and '/cgi/login' in data_str
|
|
129
|
+
return super()._request(url, method, data_str, encrypt, is_login)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from requests.packages import urllib3
|
|
2
2
|
from logging import Logger
|
|
3
3
|
from tplinkrouterc6u.common.package_enum import Connection
|
|
4
|
-
from tplinkrouterc6u.common.dataclass import Firmware, Status
|
|
4
|
+
from tplinkrouterc6u.common.dataclass import Firmware, Status, IPv4Status
|
|
5
5
|
from abc import ABC, abstractmethod
|
|
6
6
|
|
|
7
7
|
|
|
@@ -39,6 +39,10 @@ class AbstractRouter(ABC):
|
|
|
39
39
|
def get_status(self) -> Status:
|
|
40
40
|
pass
|
|
41
41
|
|
|
42
|
+
@abstractmethod
|
|
43
|
+
def get_ipv4_status(self) -> IPv4Status:
|
|
44
|
+
pass
|
|
45
|
+
|
|
42
46
|
@abstractmethod
|
|
43
47
|
def reboot(self) -> None:
|
|
44
48
|
pass
|
|
@@ -68,6 +68,7 @@ class Status:
|
|
|
68
68
|
self.wan_ipv4_uptime: int | None = None
|
|
69
69
|
self.mem_usage: float | None = None
|
|
70
70
|
self.cpu_usage: float | None = None
|
|
71
|
+
self.conn_type: str | None = None
|
|
71
72
|
self.devices: list[Device] = []
|
|
72
73
|
|
|
73
74
|
@property
|
|
@@ -167,7 +168,7 @@ class IPv4Status:
|
|
|
167
168
|
self._wan_macaddr: EUI48
|
|
168
169
|
self._wan_ipv4_ipaddr: IPv4Address | None = None
|
|
169
170
|
self._wan_ipv4_gateway: IPv4Address | None = None
|
|
170
|
-
self.
|
|
171
|
+
self._wan_ipv4_conntype: str
|
|
171
172
|
self._wan_ipv4_netmask: IPv4Address | None = None
|
|
172
173
|
self._wan_ipv4_pridns: IPv4Address
|
|
173
174
|
self._wan_ipv4_snddns: IPv4Address
|
|
@@ -189,6 +190,10 @@ class IPv4Status:
|
|
|
189
190
|
def wan_ipv4_ipaddr(self):
|
|
190
191
|
return str(self._wan_ipv4_ipaddr) if self._wan_ipv4_ipaddr else None
|
|
191
192
|
|
|
193
|
+
@property
|
|
194
|
+
def wan_ipv4_conntype(self):
|
|
195
|
+
return self._wan_ipv4_conntype if hasattr(self, '_wan_ipv4_conntype') else ''
|
|
196
|
+
|
|
192
197
|
@property
|
|
193
198
|
def wan_ipv4_ipaddress(self):
|
|
194
199
|
return self._wan_ipv4_ipaddr
|
|
@@ -16,12 +16,12 @@ def get_mac(mac: str) -> EUI48:
|
|
|
16
16
|
return EUI48('00:00:00:00:00:00')
|
|
17
17
|
|
|
18
18
|
|
|
19
|
-
def get_value(dictionary
|
|
19
|
+
def get_value(dictionary, keys: list, default=None):
|
|
20
20
|
nested_dict = dictionary
|
|
21
21
|
|
|
22
22
|
for key in keys:
|
|
23
23
|
try:
|
|
24
24
|
nested_dict = nested_dict[key]
|
|
25
25
|
except Exception:
|
|
26
|
-
return
|
|
26
|
+
return default
|
|
27
27
|
return nested_dict
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from logging import Logger
|
|
2
2
|
|
|
3
3
|
from tplinkrouterc6u import TPLinkXDRClient
|
|
4
|
-
from tplinkrouterc6u.common.exception import ClientException
|
|
4
|
+
from tplinkrouterc6u.common.exception import ClientException
|
|
5
5
|
from tplinkrouterc6u.client.c6u import TplinkRouter
|
|
6
6
|
from tplinkrouterc6u.client.deco import TPLinkDecoClient
|
|
7
7
|
from tplinkrouterc6u.client_abstract import AbstractRouter
|
|
@@ -10,30 +10,36 @@ from tplinkrouterc6u.client.ex import TPLinkEXClient
|
|
|
10
10
|
from tplinkrouterc6u.client.c6v4 import TplinkC6V4Router
|
|
11
11
|
from tplinkrouterc6u.client.c5400x import TplinkC5400XRouter
|
|
12
12
|
from tplinkrouterc6u.client.c1200 import TplinkC1200Router
|
|
13
|
+
from tplinkrouterc6u.client.vr import TPLinkVRClient
|
|
13
14
|
|
|
14
15
|
|
|
15
16
|
class TplinkRouterProvider:
|
|
16
17
|
@staticmethod
|
|
17
18
|
def get_client(host: str, password: str, username: str = 'admin', logger: Logger = None,
|
|
18
19
|
verify_ssl: bool = True, timeout: int = 30) -> AbstractRouter:
|
|
19
|
-
for client in [TplinkC5400XRouter, TPLinkEXClient, TPLinkMRClient, TplinkC6V4Router,
|
|
20
|
-
TPLinkXDRClient, TplinkRouter]:
|
|
20
|
+
for client in [TplinkC5400XRouter, TPLinkVRClient, TPLinkEXClient, TPLinkMRClient, TplinkC6V4Router,
|
|
21
|
+
TPLinkDecoClient, TPLinkXDRClient, TplinkRouter]:
|
|
21
22
|
router = client(host, password, username, logger, verify_ssl, timeout)
|
|
22
23
|
if router.supports():
|
|
23
24
|
return router
|
|
24
25
|
|
|
26
|
+
message = ('Login failed! Please check if your router local password is correct or '
|
|
27
|
+
'try to use web encrypted password instead. Check the documentation!')
|
|
25
28
|
router = TplinkC1200Router(host, password, username, logger, verify_ssl, timeout)
|
|
26
29
|
try:
|
|
27
30
|
router.authorize()
|
|
28
31
|
return router
|
|
29
|
-
except
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
32
|
+
except Exception:
|
|
33
|
+
pass
|
|
34
|
+
|
|
35
|
+
for client in [TPLinkVRClient, TPLinkXDRClient]:
|
|
36
|
+
router = client(host, password, username, None, verify_ssl, timeout)
|
|
37
|
+
try:
|
|
38
|
+
router.authorize()
|
|
39
|
+
message = ('Your router might be supported by {}. Please open the issue here '
|
|
40
|
+
'https://github.com/AlexandrErohin/TP-Link-Archer-C6U').format(router.__class__)
|
|
41
|
+
break
|
|
42
|
+
except Exception:
|
|
43
|
+
pass
|
|
44
|
+
|
|
45
|
+
raise ClientException(message)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: tplinkrouterc6u
|
|
3
|
-
Version: 5.
|
|
3
|
+
Version: 5.5.0
|
|
4
4
|
Summary: TP-Link Router API
|
|
5
5
|
Home-page: https://github.com/AlexandrErohin/TP-Link-Archer-C6U
|
|
6
6
|
Author: Alex Erohin
|
|
@@ -53,6 +53,7 @@ from tplinkrouterc6u import (
|
|
|
53
53
|
TplinkC1200Router,
|
|
54
54
|
TplinkC5400XRouter,
|
|
55
55
|
TPLinkMRClient,
|
|
56
|
+
TPLinkVRClient,
|
|
56
57
|
TPLinkEXClient,
|
|
57
58
|
TPLinkXDRClient,
|
|
58
59
|
TPLinkDecoClient,
|
|
@@ -167,6 +168,7 @@ or you have TP-link C5400X or similar router you need to get web encrypted passw
|
|
|
167
168
|
| wan_ipv4_uptime | Internet Uptime | int, None |
|
|
168
169
|
| mem_usage | Memory usage in percentage between 0 and 1 | float, None |
|
|
169
170
|
| cpu_usage | CPU usage in percentage between 0 and 1 | float, None |
|
|
171
|
+
| conn_type | Connection type | str, None |
|
|
170
172
|
| devices | List of all connectedd devices | list[[Device](#device)] |
|
|
171
173
|
|
|
172
174
|
### <a id="device">Device</a>
|
|
@@ -318,7 +320,9 @@ or you have TP-link C5400X or similar router you need to get web encrypted passw
|
|
|
318
320
|
- Archer MR600 (v1, v2, v3)
|
|
319
321
|
- Archer VR600 v3
|
|
320
322
|
- Archer VR900v
|
|
323
|
+
- Archer VR1200v v1
|
|
321
324
|
- Archer VR2100v v1
|
|
325
|
+
- Archer VX1800v v1.0
|
|
322
326
|
- Deco M4 2.0
|
|
323
327
|
- Deco M4R 2.0
|
|
324
328
|
- Deco M5 v3
|
|
@@ -24,6 +24,7 @@ tplinkrouterc6u/client/c6v4.py
|
|
|
24
24
|
tplinkrouterc6u/client/deco.py
|
|
25
25
|
tplinkrouterc6u/client/ex.py
|
|
26
26
|
tplinkrouterc6u/client/mr.py
|
|
27
|
+
tplinkrouterc6u/client/vr.py
|
|
27
28
|
tplinkrouterc6u/client/xdr.py
|
|
28
29
|
tplinkrouterc6u/common/__init__.py
|
|
29
30
|
tplinkrouterc6u/common/dataclass.py
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tplinkrouterc6u-5.4.1 → tplinkrouterc6u-5.5.0}/tplinkrouterc6u.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|