tplinkrouterc6u 5.3.0__tar.gz → 5.4.1__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.
Files changed (36) hide show
  1. {tplinkrouterc6u-5.3.0 → tplinkrouterc6u-5.4.1}/PKG-INFO +17 -5
  2. {tplinkrouterc6u-5.3.0 → tplinkrouterc6u-5.4.1}/README.md +6 -3
  3. {tplinkrouterc6u-5.3.0 → tplinkrouterc6u-5.4.1}/setup.py +1 -1
  4. tplinkrouterc6u-5.4.1/test/test_client_c1200.py +259 -0
  5. {tplinkrouterc6u-5.3.0 → tplinkrouterc6u-5.4.1}/test/test_client_c6u.py +28 -0
  6. {tplinkrouterc6u-5.3.0 → tplinkrouterc6u-5.4.1}/test/test_client_deco.py +26 -0
  7. {tplinkrouterc6u-5.3.0 → tplinkrouterc6u-5.4.1}/test/test_client_mr.py +23 -0
  8. {tplinkrouterc6u-5.3.0 → tplinkrouterc6u-5.4.1}/test/test_client_xdr.py +46 -0
  9. {tplinkrouterc6u-5.3.0 → tplinkrouterc6u-5.4.1}/tplinkrouterc6u/client/c1200.py +36 -0
  10. {tplinkrouterc6u-5.3.0 → tplinkrouterc6u-5.4.1}/tplinkrouterc6u/client/c6u.py +12 -12
  11. {tplinkrouterc6u-5.3.0 → tplinkrouterc6u-5.4.1}/tplinkrouterc6u/client/deco.py +30 -34
  12. {tplinkrouterc6u-5.3.0 → tplinkrouterc6u-5.4.1}/tplinkrouterc6u/client/mr.py +14 -13
  13. {tplinkrouterc6u-5.3.0 → tplinkrouterc6u-5.4.1}/tplinkrouterc6u/client/xdr.py +18 -10
  14. {tplinkrouterc6u-5.3.0 → tplinkrouterc6u-5.4.1}/tplinkrouterc6u/common/helper.py +11 -0
  15. {tplinkrouterc6u-5.3.0 → tplinkrouterc6u-5.4.1}/tplinkrouterc6u/common/package_enum.py +5 -0
  16. {tplinkrouterc6u-5.3.0 → tplinkrouterc6u-5.4.1}/tplinkrouterc6u.egg-info/PKG-INFO +17 -5
  17. tplinkrouterc6u-5.3.0/test/test_client_c1200.py +0 -142
  18. {tplinkrouterc6u-5.3.0 → tplinkrouterc6u-5.4.1}/LICENSE +0 -0
  19. {tplinkrouterc6u-5.3.0 → tplinkrouterc6u-5.4.1}/setup.cfg +0 -0
  20. {tplinkrouterc6u-5.3.0 → tplinkrouterc6u-5.4.1}/test/__init__.py +0 -0
  21. {tplinkrouterc6u-5.3.0 → tplinkrouterc6u-5.4.1}/test/test_client_ex.py +0 -0
  22. {tplinkrouterc6u-5.3.0 → tplinkrouterc6u-5.4.1}/tplinkrouterc6u/__init__.py +0 -0
  23. {tplinkrouterc6u-5.3.0 → tplinkrouterc6u-5.4.1}/tplinkrouterc6u/client/__init__.py +0 -0
  24. {tplinkrouterc6u-5.3.0 → tplinkrouterc6u-5.4.1}/tplinkrouterc6u/client/c5400x.py +0 -0
  25. {tplinkrouterc6u-5.3.0 → tplinkrouterc6u-5.4.1}/tplinkrouterc6u/client/c6v4.py +0 -0
  26. {tplinkrouterc6u-5.3.0 → tplinkrouterc6u-5.4.1}/tplinkrouterc6u/client/ex.py +0 -0
  27. {tplinkrouterc6u-5.3.0 → tplinkrouterc6u-5.4.1}/tplinkrouterc6u/client_abstract.py +0 -0
  28. {tplinkrouterc6u-5.3.0 → tplinkrouterc6u-5.4.1}/tplinkrouterc6u/common/__init__.py +0 -0
  29. {tplinkrouterc6u-5.3.0 → tplinkrouterc6u-5.4.1}/tplinkrouterc6u/common/dataclass.py +0 -0
  30. {tplinkrouterc6u-5.3.0 → tplinkrouterc6u-5.4.1}/tplinkrouterc6u/common/encryption.py +0 -0
  31. {tplinkrouterc6u-5.3.0 → tplinkrouterc6u-5.4.1}/tplinkrouterc6u/common/exception.py +0 -0
  32. {tplinkrouterc6u-5.3.0 → tplinkrouterc6u-5.4.1}/tplinkrouterc6u/provider.py +0 -0
  33. {tplinkrouterc6u-5.3.0 → tplinkrouterc6u-5.4.1}/tplinkrouterc6u.egg-info/SOURCES.txt +0 -0
  34. {tplinkrouterc6u-5.3.0 → tplinkrouterc6u-5.4.1}/tplinkrouterc6u.egg-info/dependency_links.txt +0 -0
  35. {tplinkrouterc6u-5.3.0 → tplinkrouterc6u-5.4.1}/tplinkrouterc6u.egg-info/requires.txt +0 -0
  36. {tplinkrouterc6u-5.3.0 → tplinkrouterc6u-5.4.1}/tplinkrouterc6u.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: tplinkrouterc6u
3
- Version: 5.3.0
3
+ Version: 5.4.1
4
4
  Summary: TP-Link Router API
5
5
  Home-page: https://github.com/AlexandrErohin/TP-Link-Archer-C6U
6
6
  Author: Alex Erohin
@@ -19,6 +19,15 @@ License-File: LICENSE
19
19
  Requires-Dist: requests
20
20
  Requires-Dist: pycryptodome
21
21
  Requires-Dist: macaddress
22
+ Dynamic: author
23
+ Dynamic: author-email
24
+ Dynamic: classifier
25
+ Dynamic: description
26
+ Dynamic: description-content-type
27
+ Dynamic: home-page
28
+ Dynamic: requires-dist
29
+ Dynamic: requires-python
30
+ Dynamic: summary
22
31
 
23
32
  # TP-Link Router API
24
33
  Python package for API access and management for TP-Link Routers. See [Supported routers](#supports)
@@ -280,7 +289,7 @@ or you have TP-link C5400X or similar router you need to get web encrypted passw
280
289
  - Archer AX20 v1.0
281
290
  - Archer AX20 v3.0
282
291
  - Archer AX21 (v1.20, v3.0)
283
- - Archer AX23 v1.0
292
+ - Archer AX23 (v1.0, v1.2)
284
293
  - Archer AX50 v1.0
285
294
  - Archer AX53 v2
286
295
  - Archer AX55 (v1.0, V1.60, v4.0)
@@ -290,6 +299,7 @@ or you have TP-link C5400X or similar router you need to get web encrypted passw
290
299
  - Archer AX90 V1.20
291
300
  - Archer AXE75 V1
292
301
  - Archer AXE16000
302
+ - Archer AX1800
293
303
  - Archer AX3000 V1
294
304
  - Archer AX6000 V1
295
305
  - Archer AX11000 V1
@@ -303,7 +313,7 @@ or you have TP-link C5400X or similar router you need to get web encrypted passw
303
313
  - Archer C7 (v4.0, v5.0)
304
314
  - Archer C5400X V1
305
315
  - Archer GX90 v1.0
306
- - Archer MR200 (v5, v5.3)
316
+ - Archer MR200 (v5, v5.3, v6.0)
307
317
  - Archer MR550 v1
308
318
  - Archer MR600 (v1, v2, v3)
309
319
  - Archer VR600 v3
@@ -321,13 +331,15 @@ or you have TP-link C5400X or similar router you need to get web encrypted passw
321
331
  - Deco X90
322
332
  - Deco XE75 (v1.0, v2.0)
323
333
  - EX511 v2.0
334
+ - HX510 v1.0
335
+ - NX510v v1.0
324
336
  - TD-W9960 (v1, V1.20)
325
337
  - TL-MR100 v2.0
326
338
  - TL-MR105
327
339
  - TL-MR6400 (v5, v5.3)
328
340
  - TL-MR6500v
329
- - TL-XDR3010 V2
330
341
  - TL-WA3001 v1.0
342
+ - TL-XDR3010 V2
331
343
 
332
344
  ### Not fully tested Hardware Versions
333
345
  - AD7200 V2
@@ -258,7 +258,7 @@ or you have TP-link C5400X or similar router you need to get web encrypted passw
258
258
  - Archer AX20 v1.0
259
259
  - Archer AX20 v3.0
260
260
  - Archer AX21 (v1.20, v3.0)
261
- - Archer AX23 v1.0
261
+ - Archer AX23 (v1.0, v1.2)
262
262
  - Archer AX50 v1.0
263
263
  - Archer AX53 v2
264
264
  - Archer AX55 (v1.0, V1.60, v4.0)
@@ -268,6 +268,7 @@ or you have TP-link C5400X or similar router you need to get web encrypted passw
268
268
  - Archer AX90 V1.20
269
269
  - Archer AXE75 V1
270
270
  - Archer AXE16000
271
+ - Archer AX1800
271
272
  - Archer AX3000 V1
272
273
  - Archer AX6000 V1
273
274
  - Archer AX11000 V1
@@ -281,7 +282,7 @@ or you have TP-link C5400X or similar router you need to get web encrypted passw
281
282
  - Archer C7 (v4.0, v5.0)
282
283
  - Archer C5400X V1
283
284
  - Archer GX90 v1.0
284
- - Archer MR200 (v5, v5.3)
285
+ - Archer MR200 (v5, v5.3, v6.0)
285
286
  - Archer MR550 v1
286
287
  - Archer MR600 (v1, v2, v3)
287
288
  - Archer VR600 v3
@@ -299,13 +300,15 @@ or you have TP-link C5400X or similar router you need to get web encrypted passw
299
300
  - Deco X90
300
301
  - Deco XE75 (v1.0, v2.0)
301
302
  - EX511 v2.0
303
+ - HX510 v1.0
304
+ - NX510v v1.0
302
305
  - TD-W9960 (v1, V1.20)
303
306
  - TL-MR100 v2.0
304
307
  - TL-MR105
305
308
  - TL-MR6400 (v5, v5.3)
306
309
  - TL-MR6500v
307
- - TL-XDR3010 V2
308
310
  - TL-WA3001 v1.0
311
+ - TL-XDR3010 V2
309
312
 
310
313
  ### Not fully tested Hardware Versions
311
314
  - AD7200 V2
@@ -5,7 +5,7 @@ with open("README.md", "r") as fh:
5
5
 
6
6
  setuptools.setup(
7
7
  name="tplinkrouterc6u",
8
- version="5.3.0",
8
+ version="5.4.1",
9
9
  author="Alex Erohin",
10
10
  author_email="alexanderErohin@yandex.ru",
11
11
  description="TP-Link Router API",
@@ -0,0 +1,259 @@
1
+ from unittest import main, TestCase
2
+ from json import loads
3
+ from tplinkrouterc6u import (
4
+ TplinkC1200Router,
5
+ Connection,
6
+ ClientException,
7
+ )
8
+ from tplinkrouterc6u.common.package_enum import VPN
9
+
10
+
11
+ class TestTPLinkC1200Client(TestCase):
12
+ def test_set_led_on(self) -> None:
13
+ response_led_general_read = """
14
+ {
15
+ "enable": "off",
16
+ "time_set": "yes",
17
+ "ledpm_support": "yes"
18
+ }
19
+ """
20
+
21
+ response_led_general_write = """
22
+ {
23
+ "enable": "on",
24
+ "time_set": "yes",
25
+ "ledpm_support": "yes"
26
+ }
27
+ """
28
+
29
+ class TPLinkRouterTest(TplinkC1200Router):
30
+ def request(
31
+ self,
32
+ path: str,
33
+ data: str,
34
+ ignore_response: bool = False,
35
+ ignore_errors: bool = False,
36
+ ) -> dict | None:
37
+ if path == "admin/ledgeneral?form=setting&operation=read":
38
+ return loads(response_led_general_read)
39
+ if path == "admin/ledgeneral?form=setting&operation=write":
40
+ self.captured_path = path
41
+ return loads(response_led_general_write)
42
+ raise ClientException()
43
+
44
+ client = TPLinkRouterTest("", "")
45
+
46
+ client.set_led(True)
47
+
48
+ expected_path = "admin/ledgeneral?form=setting&operation=write"
49
+
50
+ self.assertEqual(client.captured_path, expected_path)
51
+
52
+ def test_set_led_off(self) -> None:
53
+ response_led_general_read = """
54
+ {
55
+ "enable": "on",
56
+ "time_set": "yes",
57
+ "ledpm_support": "yes"
58
+ }
59
+ """
60
+
61
+ response_led_general_write = """
62
+ {
63
+ "enable": "off",
64
+ "time_set": "yes",
65
+ "ledpm_support": "yes"
66
+ }
67
+ """
68
+
69
+ class TPLinkRouterTest(TplinkC1200Router):
70
+ def request(
71
+ self,
72
+ path: str,
73
+ data: str,
74
+ ignore_response: bool = False,
75
+ ignore_errors: bool = False,
76
+ ) -> dict | None:
77
+ if path == "admin/ledgeneral?form=setting&operation=read":
78
+ return loads(response_led_general_read)
79
+ if path == "admin/ledgeneral?form=setting&operation=write":
80
+ self.captured_path = path
81
+ return loads(response_led_general_write)
82
+ raise ClientException()
83
+
84
+ client = TPLinkRouterTest("", "")
85
+
86
+ client.set_led(False)
87
+
88
+ expected_path = "admin/ledgeneral?form=setting&operation=write"
89
+
90
+ self.assertEqual(client.captured_path, expected_path)
91
+
92
+ def test_led_status(self) -> None:
93
+ response_led_general_read = """
94
+ {
95
+ "enable": "on",
96
+ "time_set": "yes",
97
+ "ledpm_support": "yes"
98
+ }
99
+ """
100
+
101
+ class TPLinkRouterTest(TplinkC1200Router):
102
+ def request(
103
+ self,
104
+ path: str,
105
+ data: str,
106
+ ignore_response: bool = False,
107
+ ignore_errors: bool = False,
108
+ ) -> dict | None:
109
+ if path == "admin/ledgeneral?form=setting&operation=read":
110
+ return loads(response_led_general_read)
111
+ raise ClientException()
112
+
113
+ client = TPLinkRouterTest("", "")
114
+
115
+ led_status = client.get_led()
116
+ self.assertTrue(led_status)
117
+
118
+ def test_set_wifi(self) -> None:
119
+ class TPLinkRouterTest(TplinkC1200Router):
120
+ def request(
121
+ self,
122
+ path: str,
123
+ data: str,
124
+ ignore_response: bool = False,
125
+ ignore_errors: bool = False,
126
+ ) -> dict | None:
127
+ self.captured_path = path
128
+ self.captured_data = data
129
+
130
+ client = TPLinkRouterTest("", "")
131
+ client.set_wifi(
132
+ Connection.HOST_5G,
133
+ enable=True,
134
+ ssid="TestSSID",
135
+ hidden="no",
136
+ encryption="WPA3-PSK",
137
+ psk_version="2",
138
+ psk_cipher="AES",
139
+ psk_key="testkey123",
140
+ hwmode="11ac",
141
+ htmode="VHT20",
142
+ channel=36,
143
+ txpower="20",
144
+ disabled_all="no",
145
+ )
146
+
147
+ expected_data = (
148
+ "operation=write&enable=on&ssid=TestSSID&hidden=no&encryption=WPA3-PSK&"
149
+ "psk_version=2&psk_cipher=AES&psk_key=testkey123&hwmode=11ac&"
150
+ "htmode=VHT20&channel=36&txpower=20&disabled_all=no"
151
+ )
152
+ expected_path = f"admin/wireless?form=wireless_5g&{expected_data}"
153
+
154
+ self.assertEqual(client.captured_path, expected_path)
155
+ self.assertEqual(client.captured_data, expected_data)
156
+
157
+ def test_vpn_status(self) -> None:
158
+ response_openvpn_read = """
159
+ {
160
+ "enabled": "on",
161
+ "proto": "udp",
162
+ "access": "home",
163
+ "cert_exist": true,
164
+ "mask": "255.255.255.0",
165
+ "port": "1194",
166
+ "serverip": "10.8.0.0"
167
+ }
168
+ """
169
+
170
+ response_pptp_read = """
171
+ {
172
+ "enabled": "off",
173
+ "unencrypted_access": "on",
174
+ "samba_access": "on",
175
+ "netbios_pass": "on",
176
+ "remoteip": "10.0.0.11-20"
177
+ }
178
+ """
179
+
180
+ respone_vpnconn_openvpn = """[
181
+ {"username": "admin", "remote_ip": "192.168.0.200", "ipaddr": "10.0.0.11",
182
+ "extra": "7450", "vpntype": "openvpn", "key": "7450"},
183
+ {"username": "admin", "remote_ip": "192.168.0.200", "ipaddr": "10.0.0.11",
184
+ "extra": "7450", "vpntype": "openvpn", "key": "7450"}
185
+ ]"""
186
+
187
+ respone_vpnconn_pptpvpn = """[
188
+ {"username": "admin", "remote_ip": "192.168.0.200", "ipaddr": "10.0.0.11",
189
+ "extra": "7450", "vpntype": "pptp", "key": "7450"},
190
+ {"username": "admin", "remote_ip": "192.168.0.200", "ipaddr": "10.0.0.11",
191
+ "extra": "7450", "vpntype": "pptp", "key": "7450"},
192
+ {"username": "admin", "remote_ip": "192.168.0.200", "ipaddr": "10.0.0.11",
193
+ "extra": "7450", "vpntype": "pptp", "key": "7450"}
194
+ ]"""
195
+
196
+ class TPLinkRouterTest(TplinkC1200Router):
197
+ def request(
198
+ self,
199
+ path: str,
200
+ data: str,
201
+ ignore_response: bool = False,
202
+ ignore_errors: bool = False,
203
+ ) -> dict | None:
204
+ if path == "/admin/openvpn?form=config&operation=read":
205
+ return loads(response_openvpn_read)
206
+ if path == "/admin/pptpd?form=config&operation=read":
207
+ return loads(response_pptp_read)
208
+ if path == "/admin/vpnconn?form=config&operation=list&vpntype=openvpn":
209
+ return loads(respone_vpnconn_openvpn)
210
+ if path == "/admin/vpnconn?form=config&operation=list&vpntype=pptp":
211
+ return loads(respone_vpnconn_pptpvpn)
212
+ raise ClientException()
213
+
214
+ client = TPLinkRouterTest("", "")
215
+
216
+ vpn_status = client.get_vpn_status()
217
+ self.assertTrue(vpn_status.openvpn_enable)
218
+ self.assertFalse(vpn_status.pptpvpn_enable)
219
+ self.assertEqual(vpn_status.openvpn_clients_total, 2)
220
+ self.assertEqual(vpn_status.pptpvpn_clients_total, 3)
221
+
222
+ def test_set_vpn(self) -> None:
223
+ response_openvpn_read = """
224
+ {
225
+ "enabled": "on",
226
+ "proto": "udp",
227
+ "access": "home",
228
+ "cert_exist": true,
229
+ "mask": "255.255.255.0",
230
+ "port": "1194",
231
+ "serverip": "10.8.0.0"
232
+ }
233
+ """
234
+
235
+ class TPLinkRouterTest(TplinkC1200Router):
236
+ def request(
237
+ self,
238
+ path: str,
239
+ data: str,
240
+ ignore_response: bool = False,
241
+ ignore_errors: bool = False,
242
+ ) -> dict | None:
243
+ if path == "/admin/openvpn?form=config&operation=read":
244
+ return loads(response_openvpn_read)
245
+ self.captured_path = path
246
+
247
+ client = TPLinkRouterTest("", "")
248
+ client.set_vpn(VPN.OPEN_VPN, True)
249
+
250
+ expected_path = (
251
+ "/admin/openvpn?form=config&operation=write&enabled=on"
252
+ "&proto=udp&access=home&cert_exist=True"
253
+ "&mask=255.255.255.0&port=1194&serverip=10.8.0.0"
254
+ )
255
+ self.assertEqual(client.captured_path, expected_path)
256
+
257
+
258
+ if __name__ == "__main__":
259
+ main()
@@ -6,6 +6,7 @@ from tplinkrouterc6u import (
6
6
  TplinkRouter,
7
7
  Connection,
8
8
  Status,
9
+ IPv4Status,
9
10
  Device,
10
11
  ClientException,
11
12
  )
@@ -694,6 +695,33 @@ class TestTPLinkClient(TestCase):
694
695
  self.assertEqual(check_url, 'admin/wireless?&form=guest&form=iot_6g')
695
696
  self.assertEqual(check_data, 'operation=write&iot_6g_enable=on')
696
697
 
698
+ def test_get_ipv4_status_empty(self) -> None:
699
+ response_network = '{"result": {}, "error_code": 0}'
700
+
701
+ class TPLinkRouterTest(TplinkRouter):
702
+ def request(self, path: str, data: str,
703
+ ignore_response: bool = False, ignore_errors: bool = False) -> dict | None:
704
+ if path == 'admin/network?form=status_ipv4&operation=read':
705
+ return loads(response_network)['result']
706
+ raise ClientException()
707
+
708
+ client = TPLinkRouterTest('', '')
709
+ result = client.get_ipv4_status()
710
+
711
+ self.assertIsInstance(result, IPv4Status)
712
+ self.assertEqual(result.wan_macaddr, '00-00-00-00-00-00')
713
+ self.assertEqual(result.wan_ipv4_ipaddr, '0.0.0.0')
714
+ self.assertEqual(result.wan_ipv4_gateway, '0.0.0.0')
715
+ self.assertEqual(result.wan_ipv4_conntype, '')
716
+ self.assertEqual(result.wan_ipv4_netmask, '0.0.0.0')
717
+ self.assertEqual(result.wan_ipv4_pridns, '0.0.0.0')
718
+ self.assertEqual(result.wan_ipv4_snddns, '0.0.0.0')
719
+ self.assertEqual(result.lan_macaddr, '00-00-00-00-00-00')
720
+ self.assertEqual(result.lan_ipv4_ipaddr, '0.0.0.0')
721
+ self.assertEqual(result.lan_ipv4_netmask, '0.0.0.0')
722
+ self.assertEqual(result.lan_ipv4_dhcp_enable, False)
723
+ self.assertEqual(result.remote, None)
724
+
697
725
 
698
726
  if __name__ == '__main__':
699
727
  main()
@@ -365,6 +365,32 @@ class TestTPLinkDecoClient(TestCase):
365
365
  self.assertEqual(result.lan_ipv4_dhcp_enable, False)
366
366
  self.assertEqual(result.remote, None)
367
367
 
368
+ def test_get_ipv4_status_empty(self) -> None:
369
+ response_network = '{"result": {}, "error_code": 0}'
370
+
371
+ class TPLinkRouterTest(TPLinkDecoClient):
372
+ def request(self, path: str, data: str,
373
+ ignore_response: bool = False, ignore_errors: bool = False) -> dict | None:
374
+ if path == 'admin/network?form=wan_ipv4':
375
+ return loads(response_network)['result']
376
+
377
+ client = TPLinkRouterTest('', '')
378
+ result = client.get_ipv4_status()
379
+
380
+ self.assertIsInstance(result, IPv4Status)
381
+ self.assertEqual(result.wan_macaddr, '00-00-00-00-00-00')
382
+ self.assertEqual(result.wan_ipv4_ipaddr, None)
383
+ self.assertEqual(result.wan_ipv4_gateway, None)
384
+ self.assertEqual(result.wan_ipv4_conntype, '')
385
+ self.assertEqual(result.wan_ipv4_netmask, None)
386
+ self.assertEqual(result.wan_ipv4_pridns, '0.0.0.0')
387
+ self.assertEqual(result.wan_ipv4_snddns, '0.0.0.0')
388
+ self.assertEqual(result.lan_macaddr, '00-00-00-00-00-00')
389
+ self.assertEqual(result.lan_ipv4_ipaddr, '0.0.0.0')
390
+ self.assertEqual(result.lan_ipv4_netmask, '0.0.0.0')
391
+ self.assertEqual(result.lan_ipv4_dhcp_enable, False)
392
+ self.assertEqual(result.remote, None)
393
+
368
394
  def test_get_ipv4_status_no_internet(self) -> None:
369
395
  response_network = '''
370
396
  {"result": {
@@ -599,6 +599,29 @@ DNSServers=7.7.7.7,2.2.2.2
599
599
  self.assertEqual(result.lan_ipv4_dhcp_enable, True)
600
600
  self.assertEqual(result.remote, None)
601
601
 
602
+ def test_get_ipv4_status_empty(self) -> None:
603
+ response = '''
604
+ [1,1,0,0,0,0]0
605
+ [1,1,0,0,0,0]1
606
+ [1,1,1,0,0,0]2
607
+ [2,1,1,0,0,0]2
608
+ [error]0
609
+
610
+ '''
611
+
612
+ class TPLinkMRClientTest(TPLinkMRClient):
613
+ def _request(self, url, method='POST', data_str=None, encrypt=False):
614
+ return 200, response
615
+
616
+ client = TPLinkMRClientTest('', '')
617
+ result = client.get_ipv4_status()
618
+
619
+ self.assertIsInstance(result, IPv4Status)
620
+ self.assertEqual(result.lan_macaddr, '00-00-00-00-00-00')
621
+ self.assertEqual(result.lan_ipv4_ipaddr, '0.0.0.0')
622
+ self.assertEqual(result.lan_ipv4_netmask, '0.0.0.0')
623
+ self.assertEqual(result.lan_ipv4_dhcp_enable, False)
624
+
602
625
  def test_get_ipv4_status_one_wlan(self) -> None:
603
626
  response = '''
604
627
  [1,1,0,0,0,0]0
@@ -579,6 +579,52 @@ maximum-scale=2.0, user-scalable=yes" />
579
579
  self.assertIsInstance(ipv4_status.lan_ipv4_netmask_address, IPv4Address)
580
580
  self.assertEqual(ipv4_status.lan_ipv4_netmask_address, get_ip('255.255.255.0'))
581
581
 
582
+ def test_get_ipv4_status_empty(self):
583
+ mock_data = json.loads('{"error_code": 0}')
584
+ check_payload = {}
585
+
586
+ class TPLinkXDRClientTest(TPLinkXDRClient):
587
+ def _request(self, payload: dict) -> dict:
588
+ nonlocal check_payload
589
+ check_payload = payload
590
+ return mock_data
591
+
592
+ client = TPLinkXDRClientTest('', '')
593
+ ipv4_status = client.get_ipv4_status()
594
+
595
+ self.assertEqual(check_payload['method'], 'get')
596
+ self.assertIsInstance(check_payload['dhcpd'], dict)
597
+ self.assertEqual(check_payload['dhcpd']['name'], 'udhcpd')
598
+ self.assertIsInstance(check_payload['network'], dict)
599
+ self.assertEqual(check_payload['network']['name'], ['lan', 'wan_status'])
600
+
601
+ self.assertIsInstance(ipv4_status, IPv4Status)
602
+ self.assertEqual(ipv4_status.wan_ipv4_ipaddr, '0.0.0.0')
603
+ self.assertIsInstance(ipv4_status.wan_ipv4_ipaddress, IPv4Address)
604
+ self.assertEqual(ipv4_status.wan_ipv4_ipaddress, get_ip('0.0.0.0'))
605
+ self.assertEqual(ipv4_status.wan_ipv4_gateway, '0.0.0.0')
606
+ self.assertIsInstance(ipv4_status.wan_ipv4_gateway_address, IPv4Address)
607
+ self.assertEqual(ipv4_status.wan_ipv4_gateway_address, get_ip('0.0.0.0'))
608
+ self.assertEqual(ipv4_status.wan_ipv4_netmask, '0.0.0.0')
609
+ self.assertIsInstance(ipv4_status.wan_ipv4_netmask_address, IPv4Address)
610
+ self.assertEqual(ipv4_status.wan_ipv4_netmask_address, get_ip('0.0.0.0'))
611
+ self.assertEqual(ipv4_status.wan_ipv4_pridns, '0.0.0.0')
612
+ self.assertIsInstance(ipv4_status.wan_ipv4_pridns_address, IPv4Address)
613
+ self.assertEqual(ipv4_status.wan_ipv4_pridns_address, get_ip('0.0.0.0'))
614
+ self.assertEqual(ipv4_status.wan_ipv4_snddns, '0.0.0.0')
615
+ self.assertIsInstance(ipv4_status.wan_ipv4_snddns_address, IPv4Address)
616
+ self.assertEqual(ipv4_status.wan_ipv4_snddns_address, get_ip('0.0.0.0'))
617
+ self.assertEqual(ipv4_status.lan_macaddr, '00-00-00-00-00-00')
618
+ self.assertIsInstance(ipv4_status.lan_macaddress, EUI48)
619
+ self.assertEqual(ipv4_status.lan_macaddress, get_mac('00-00-00-00-00-00'))
620
+ self.assertEqual(ipv4_status.lan_ipv4_ipaddr, '0.0.0.0')
621
+ self.assertIsInstance(ipv4_status.lan_ipv4_ipaddress, IPv4Address)
622
+ self.assertEqual(ipv4_status.lan_ipv4_ipaddress, get_ip('0.0.0.0'))
623
+ self.assertEqual(ipv4_status.lan_ipv4_dhcp_enable, False)
624
+ self.assertEqual(ipv4_status.lan_ipv4_netmask, '0.0.0.0')
625
+ self.assertIsInstance(ipv4_status.lan_ipv4_netmask_address, IPv4Address)
626
+ self.assertEqual(ipv4_status.lan_ipv4_netmask_address, get_ip('0.0.0.0'))
627
+
582
628
 
583
629
  if __name__ == '__main__':
584
630
  main()
@@ -1,8 +1,11 @@
1
1
  from re import search
2
2
  from requests import post, Response
3
+ from urllib.parse import urlencode
3
4
  from tplinkrouterc6u.common.encryption import EncryptionWrapper
4
5
  from tplinkrouterc6u.common.exception import ClientException, AuthorizeError
5
6
  from tplinkrouterc6u.client.c5400x import TplinkC5400XRouter
7
+ from tplinkrouterc6u.common.dataclass import VPNStatus
8
+ from tplinkrouterc6u.common.package_enum import VPN
6
9
 
7
10
 
8
11
  class TplinkC1200Router(TplinkC5400XRouter):
@@ -100,3 +103,36 @@ class TplinkC1200Router(TplinkC5400XRouter):
100
103
  @staticmethod
101
104
  def _get_login_data(crypted_pwd: str) -> str:
102
105
  return 'operation=login&password={}'.format(crypted_pwd)
106
+
107
+ def get_vpn_status(self) -> VPNStatus:
108
+ status = VPNStatus()
109
+
110
+ values = [
111
+ self.request("/admin/openvpn?form=config&operation=read", "operation=read"),
112
+ self.request("/admin/pptpd?form=config&operation=read", "operation=read"),
113
+ self.request("/admin/vpnconn?form=config&operation=list&vpntype=openvpn",
114
+ "operation=list&operation=list&vpntype=openvpn"),
115
+ self.request("/admin/vpnconn?form=config&operation=list&vpntype=pptp",
116
+ "operation=list&operation=list&vpntype=pptp"),
117
+ ]
118
+
119
+ status.openvpn_enable = values[0]['enabled'] == 'on'
120
+ status.pptpvpn_enable = values[1]['enabled'] == 'on'
121
+
122
+ if isinstance(values[2], list):
123
+ status.openvpn_clients_total = len(values[2])
124
+ status.pptpvpn_clients_total = len(values[3])
125
+ else:
126
+ status.openvpn_clients_total = 0
127
+ status.pptpvpn_clients_total = 0
128
+
129
+ return status
130
+
131
+ def set_vpn(self, vpn: VPN, enable: bool) -> None:
132
+ path = "/admin/{}?form=config&operation=read".format(vpn.lowercase)
133
+ current_config = self.request(path, "operation=read")
134
+ current_config['enabled'] = "on" if enable else "off"
135
+ data = urlencode(current_config)
136
+ data = "&operation=write&{}".format(data)
137
+ path = "/admin/{}?form=config{}".format(vpn.lowercase, data)
138
+ self.request(path, data)
@@ -363,18 +363,18 @@ class TplinkBaseRouter(AbstractRouter, TplinkRequest):
363
363
  def get_ipv4_status(self) -> IPv4Status:
364
364
  ipv4_status = IPv4Status()
365
365
  data = self.request('admin/network?form=status_ipv4&operation=read', 'operation=read')
366
- ipv4_status._wan_macaddr = EUI48(data['wan_macaddr'])
367
- ipv4_status._wan_ipv4_ipaddr = IPv4Address(data['wan_ipv4_ipaddr'])
368
- ipv4_status._wan_ipv4_gateway = IPv4Address(data['wan_ipv4_gateway'])
369
- ipv4_status.wan_ipv4_conntype = data['wan_ipv4_conntype']
370
- ipv4_status._wan_ipv4_netmask = IPv4Address(data['wan_ipv4_netmask'])
371
- ipv4_status._wan_ipv4_pridns = IPv4Address(data['wan_ipv4_pridns'])
372
- ipv4_status._wan_ipv4_snddns = IPv4Address(data['wan_ipv4_snddns'])
373
- ipv4_status._lan_macaddr = EUI48(data['lan_macaddr'])
374
- ipv4_status._lan_ipv4_ipaddr = IPv4Address(data['lan_ipv4_ipaddr'])
375
- ipv4_status.lan_ipv4_dhcp_enable = self._str2bool(data['lan_ipv4_dhcp_enable'])
376
- ipv4_status._lan_ipv4_netmask = IPv4Address(data['lan_ipv4_netmask'])
377
- ipv4_status.remote = self._str2bool(data.get('remote'))
366
+ ipv4_status._wan_macaddr = get_mac(data.get('wan_macaddr', '00:00:00:00:00:00'))
367
+ ipv4_status._wan_ipv4_ipaddr = get_ip(data.get('wan_ipv4_ipaddr', '0.0.0.0'))
368
+ ipv4_status._wan_ipv4_gateway = get_ip(data.get('wan_ipv4_gateway', '0.0.0.0'))
369
+ ipv4_status.wan_ipv4_conntype = data.get('wan_ipv4_conntype', '')
370
+ ipv4_status._wan_ipv4_netmask = get_ip(data.get('wan_ipv4_netmask', '0.0.0.0'))
371
+ ipv4_status._wan_ipv4_pridns = get_ip(data.get('wan_ipv4_pridns', '0.0.0.0'))
372
+ ipv4_status._wan_ipv4_snddns = get_ip(data.get('wan_ipv4_snddns', '0.0.0.0'))
373
+ ipv4_status._lan_macaddr = get_mac(data.get('lan_macaddr', '00:00:00:00:00:00'))
374
+ ipv4_status._lan_ipv4_ipaddr = get_ip(data.get('lan_ipv4_ipaddr', '0.0.0.0'))
375
+ ipv4_status.lan_ipv4_dhcp_enable = self._str2bool(data.get('lan_ipv4_dhcp_enable', ''))
376
+ ipv4_status._lan_ipv4_netmask = get_ip(data.get('lan_ipv4_netmask', '0.0.0.0'))
377
+ ipv4_status.remote = self._str2bool(data.get('remote', '')) if data.get('remote') else None
378
378
 
379
379
  return ipv4_status
380
380
 
@@ -3,7 +3,7 @@ from json import dumps
3
3
  from macaddress import EUI48
4
4
  from ipaddress import IPv4Address
5
5
  from logging import Logger
6
- from tplinkrouterc6u.common.helper import get_ip, get_mac
6
+ from tplinkrouterc6u.common.helper import get_ip, get_mac, get_value
7
7
  from tplinkrouterc6u.common.package_enum import Connection
8
8
  from tplinkrouterc6u.common.dataclass import Firmware, Status, Device, IPv4Status
9
9
  from tplinkrouterc6u.client_abstract import AbstractRouter
@@ -67,14 +67,14 @@ class TPLinkDecoClient(TplinkEncryption, AbstractRouter):
67
67
  data = self.request('admin/network?form=wan_ipv4', dumps({'operation': 'read'}))
68
68
 
69
69
  status = Status()
70
- element = self._get_value(data, ['wan', 'ip_info', 'mac'])
70
+ element = get_value(data, ['wan', 'ip_info', 'mac'])
71
71
  status._wan_macaddr = EUI48(element) if element else None
72
- status._lan_macaddr = EUI48(self._get_value(data, ['lan', 'ip_info', 'mac']))
73
- element = self._get_value(data, ['wan', 'ip_info', 'ip'])
72
+ status._lan_macaddr = EUI48(get_value(data, ['lan', 'ip_info', 'mac']))
73
+ element = get_value(data, ['wan', 'ip_info', 'ip'])
74
74
  status._wan_ipv4_addr = IPv4Address(element) if element else None
75
- element = self._get_value(data, ['lan', 'ip_info', 'ip'])
75
+ element = get_value(data, ['lan', 'ip_info', 'ip'])
76
76
  status._lan_ipv4_addr = IPv4Address(element) if element else None
77
- element = self._get_value(data, ['wan', 'ip_info', 'gateway'])
77
+ element = get_value(data, ['wan', 'ip_info', 'gateway'])
78
78
  status._wan_ipv4_gateway = IPv4Address(element) if element else None
79
79
 
80
80
  data = self.request('admin/network?form=performance', dumps({"operation": "read"}))
@@ -82,12 +82,12 @@ class TPLinkDecoClient(TplinkEncryption, AbstractRouter):
82
82
  status.cpu_usage = data.get('cpu_usage')
83
83
 
84
84
  data = self.request('admin/wireless?form=wlan', dumps({'operation': 'read'}))
85
- status.wifi_2g_enable = self._get_value(data, ['band2_4', 'host', 'enable'])
86
- status.guest_2g_enable = self._get_value(data, ['band2_4', 'guest', 'enable'])
87
- status.wifi_5g_enable = self._get_value(data, ['band5_1', 'host', 'enable'])
88
- status.guest_5g_enable = self._get_value(data, ['band5_1', 'guest', 'enable'])
89
- status.wifi_6g_enable = self._get_value(data, ['band6', 'host', 'enable'])
90
- status.guest_6g_enable = self._get_value(data, ['band6', 'guest', 'enable'])
85
+ status.wifi_2g_enable = get_value(data, ['band2_4', 'host', 'enable'])
86
+ status.guest_2g_enable = get_value(data, ['band2_4', 'guest', 'enable'])
87
+ status.wifi_5g_enable = get_value(data, ['band5_1', 'host', 'enable'])
88
+ status.guest_5g_enable = get_value(data, ['band5_1', 'guest', 'enable'])
89
+ status.wifi_6g_enable = get_value(data, ['band6', 'host', 'enable'])
90
+ status.guest_6g_enable = get_value(data, ['band6', 'guest', 'enable'])
91
91
 
92
92
  devices = []
93
93
  data = self.request('admin/client?form=client_list', dumps(
@@ -125,34 +125,30 @@ class TPLinkDecoClient(TplinkEncryption, AbstractRouter):
125
125
  def get_ipv4_status(self) -> IPv4Status:
126
126
  ipv4_status = IPv4Status()
127
127
  data = self.request('admin/network?form=wan_ipv4', dumps({'operation': 'read'}))
128
- ipv4_status._wan_macaddr = EUI48(self._get_value(data, ['wan', 'ip_info', 'mac']))
129
- element = self._get_value(data, ['wan', 'ip_info', 'ip'])
128
+ element = get_value(data, ['wan', 'ip_info', 'mac'])
129
+ ipv4_status._wan_macaddr = get_mac(element if element else '00:00:00:00:00:00')
130
+ element = get_value(data, ['wan', 'ip_info', 'ip'])
130
131
  ipv4_status._wan_ipv4_ipaddr = IPv4Address(element) if element else None
131
- element = self._get_value(data, ['wan', 'ip_info', 'gateway'])
132
+ element = get_value(data, ['wan', 'ip_info', 'gateway'])
132
133
  ipv4_status._wan_ipv4_gateway = IPv4Address(element) if element else None
133
- ipv4_status.wan_ipv4_conntype = self._get_value(data, ['wan', 'dial_type'])
134
- element = self._get_value(data, ['wan', 'ip_info', 'mask'])
134
+ element = get_value(data, ['wan', 'dial_type'])
135
+ ipv4_status.wan_ipv4_conntype = element if element else ''
136
+ element = get_value(data, ['wan', 'ip_info', 'mask'])
135
137
  ipv4_status._wan_ipv4_netmask = IPv4Address(element) if element else None
136
- ipv4_status._wan_ipv4_pridns = IPv4Address(self._get_value(data, ['wan', 'ip_info', 'dns1']))
137
- ipv4_status._wan_ipv4_snddns = IPv4Address(self._get_value(data, ['wan', 'ip_info', 'dns2']))
138
- ipv4_status._lan_macaddr = EUI48(self._get_value(data, ['lan', 'ip_info', 'mac']))
139
- ipv4_status._lan_ipv4_ipaddr = IPv4Address(self._get_value(data, ['lan', 'ip_info', 'ip']))
138
+ element = get_value(data, ['wan', 'ip_info', 'dns1'])
139
+ ipv4_status._wan_ipv4_pridns = get_ip(element if element else '0.0.0.0')
140
+ element = get_value(data, ['wan', 'ip_info', 'dns2'])
141
+ ipv4_status._wan_ipv4_snddns = get_ip(element if element else '0.0.0.0')
142
+ element = get_value(data, ['lan', 'ip_info', 'mac'])
143
+ ipv4_status._lan_macaddr = get_mac(element if element else '00:00:00:00:00:00')
144
+ element = get_value(data, ['lan', 'ip_info', 'ip'])
145
+ ipv4_status._lan_ipv4_ipaddr = get_ip(element if element else '0.0.0.0')
140
146
  ipv4_status.lan_ipv4_dhcp_enable = False
141
- ipv4_status._lan_ipv4_netmask = IPv4Address(self._get_value(data, ['lan', 'ip_info', 'mask']))
147
+ element = get_value(data, ['lan', 'ip_info', 'mask'])
148
+ ipv4_status._lan_ipv4_netmask = get_ip(element if element else '0.0.0.0')
142
149
 
143
150
  return ipv4_status
144
151
 
145
- @staticmethod
146
- def _get_value(dictionary: dict, keys: list):
147
- nested_dict = dictionary
148
-
149
- for key in keys:
150
- try:
151
- nested_dict = nested_dict[key]
152
- except Exception:
153
- return None
154
- return nested_dict
155
-
156
152
  def _map_wire_type(self, data: dict) -> Connection:
157
153
  if data.get('wire_type') == 'wired':
158
154
  return Connection.WIRED
@@ -160,7 +156,7 @@ class TPLinkDecoClient(TplinkEncryption, AbstractRouter):
160
156
  'band5': {'main': Connection.HOST_5G, 'guest': Connection.GUEST_5G, 'iot': Connection.IOT_5G},
161
157
  'band6': {'main': Connection.HOST_6G, 'guest': Connection.GUEST_6G, 'iot': Connection.IOT_6G}
162
158
  }
163
- result = self._get_value(mapping, [data.get('connection_type'), data.get('interface')])
159
+ result = get_value(mapping, [data.get('connection_type'), data.get('interface')])
164
160
 
165
161
  return result if result else Connection.UNKNOWN
166
162
 
@@ -7,6 +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
11
  from tplinkrouterc6u.common.encryption import EncryptionWrapperMR
11
12
  from tplinkrouterc6u.common.package_enum import Connection, VPN
12
13
  from tplinkrouterc6u.common.dataclass import (
@@ -542,22 +543,22 @@ class TPLinkMRClient(TPLinkMRClientBase):
542
543
  _, values = self.req_act(acts)
543
544
 
544
545
  ipv4_status = IPv4Status()
545
- ipv4_status._lan_macaddr = EUI48(values['0']['X_TP_MACAddress'])
546
- ipv4_status._lan_ipv4_ipaddr = IPv4Address(values['0']['IPInterfaceIPAddress'])
547
- ipv4_status._lan_ipv4_netmask = IPv4Address(values['0']['IPInterfaceSubnetMask'])
548
- ipv4_status.lan_ipv4_dhcp_enable = bool(int(values['1']['DHCPServerEnable']))
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')))
549
550
 
550
551
  for item in self._to_list(values.get('2')):
551
- if int(item['enable']) == 0 and values.get('2').__class__ == list:
552
+ if int(item.get('enable', '0')) == 0 and values.get('2').__class__ == list:
552
553
  continue
553
- ipv4_status._wan_macaddr = EUI48(item['MACAddress'])
554
- ipv4_status._wan_ipv4_ipaddr = IPv4Address(item['externalIPAddress'])
555
- ipv4_status._wan_ipv4_gateway = IPv4Address(item['defaultGateway'])
556
- ipv4_status.wan_ipv4_conntype = item['name']
557
- ipv4_status._wan_ipv4_netmask = IPv4Address(item['subnetMask'])
558
- dns = item['DNSServers'].split(',')
559
- ipv4_status._wan_ipv4_pridns = IPv4Address(dns[0])
560
- ipv4_status._wan_ipv4_snddns = IPv4Address(dns[1])
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')
561
562
 
562
563
  return ipv4_status
563
564
 
@@ -11,7 +11,7 @@ from tplinkrouterc6u.common.dataclass import (Device, Firmware, IPv4DHCPLease,
11
11
  IPv4Reservation, IPv4Status,
12
12
  Status)
13
13
  from tplinkrouterc6u.common.exception import ClientException
14
- from tplinkrouterc6u.common.helper import get_ip, get_mac
14
+ from tplinkrouterc6u.common.helper import get_ip, get_mac, get_value
15
15
  from tplinkrouterc6u.common.package_enum import Connection
16
16
 
17
17
 
@@ -170,15 +170,23 @@ class TPLinkXDRClient(AbstractRouter):
170
170
  })
171
171
 
172
172
  ipv4_status = IPv4Status()
173
- ipv4_status._wan_ipv4_ipaddr = get_ip(data['network']['wan_status']['ipaddr'])
174
- ipv4_status._wan_ipv4_gateway = get_ip(data['network']['wan_status']['gateway'])
175
- ipv4_status._wan_ipv4_netmask = get_ip(data['network']['wan_status']['netmask'])
176
- ipv4_status._wan_ipv4_pridns = get_ip(data['network']['wan_status']['pri_dns'])
177
- ipv4_status._wan_ipv4_snddns = get_ip(data['network']['wan_status']['snd_dns'])
178
- ipv4_status._lan_macaddr = get_mac(data['network']['lan']['macaddr'])
179
- ipv4_status._lan_ipv4_ipaddr = get_ip(data['network']['lan']['ipaddr'])
180
- ipv4_status.lan_ipv4_dhcp_enable = data['dhcpd']['udhcpd']['enable'] == '1'
181
- ipv4_status._lan_ipv4_netmask = get_ip(data['network']['lan']['netmask'])
173
+ element = get_value(data, ['network', 'wan_status', 'ipaddr'])
174
+ ipv4_status._wan_ipv4_ipaddr = get_ip(element if element else '0.0.0.0')
175
+ element = get_value(data, ['network', 'wan_status', 'gateway'])
176
+ ipv4_status._wan_ipv4_gateway = get_ip(element if element else '0.0.0.0')
177
+ element = get_value(data, ['network', 'wan_status', 'netmask'])
178
+ ipv4_status._wan_ipv4_netmask = get_ip(element if element else '0.0.0.0')
179
+ element = get_value(data, ['network', 'wan_status', 'pri_dns'])
180
+ ipv4_status._wan_ipv4_pridns = get_ip(element if element else '0.0.0.0')
181
+ element = get_value(data, ['network', 'wan_status', 'snd_dns'])
182
+ ipv4_status._wan_ipv4_snddns = get_ip(element if element else '0.0.0.0')
183
+ element = get_value(data, ['network', 'lan', 'macaddr'])
184
+ ipv4_status._lan_macaddr = get_mac(element if element else '00:00:00:00:00:00')
185
+ element = get_value(data, ['network', 'lan', 'ipaddr'])
186
+ ipv4_status._lan_ipv4_ipaddr = get_ip(element if element else '0.0.0.0')
187
+ ipv4_status.lan_ipv4_dhcp_enable = get_value(data, ['dhcpd', 'udhcpd', 'enable']) == '1'
188
+ element = get_value(data, ['network', 'lan', 'netmask'])
189
+ ipv4_status._lan_ipv4_netmask = get_ip(element if element else '0.0.0.0')
182
190
  return ipv4_status
183
191
 
184
192
  def reboot(self) -> None:
@@ -14,3 +14,14 @@ def get_mac(mac: str) -> EUI48:
14
14
  return EUI48(mac)
15
15
  except Exception:
16
16
  return EUI48('00:00:00:00:00:00')
17
+
18
+
19
+ def get_value(dictionary: dict, keys: list):
20
+ nested_dict = dictionary
21
+
22
+ for key in keys:
23
+ try:
24
+ nested_dict = nested_dict[key]
25
+ except Exception:
26
+ return None
27
+ return nested_dict
@@ -49,3 +49,8 @@ class Connection(Enum):
49
49
  class VPN(Enum):
50
50
  OPEN_VPN = 'OPENVPN'
51
51
  PPTP_VPN = 'PPTPVPN'
52
+
53
+ @property
54
+ def lowercase(self) -> str:
55
+ """Returns the lowercase version of the enum value. Needed for the c1200 router."""
56
+ return self.value.lower()
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: tplinkrouterc6u
3
- Version: 5.3.0
3
+ Version: 5.4.1
4
4
  Summary: TP-Link Router API
5
5
  Home-page: https://github.com/AlexandrErohin/TP-Link-Archer-C6U
6
6
  Author: Alex Erohin
@@ -19,6 +19,15 @@ License-File: LICENSE
19
19
  Requires-Dist: requests
20
20
  Requires-Dist: pycryptodome
21
21
  Requires-Dist: macaddress
22
+ Dynamic: author
23
+ Dynamic: author-email
24
+ Dynamic: classifier
25
+ Dynamic: description
26
+ Dynamic: description-content-type
27
+ Dynamic: home-page
28
+ Dynamic: requires-dist
29
+ Dynamic: requires-python
30
+ Dynamic: summary
22
31
 
23
32
  # TP-Link Router API
24
33
  Python package for API access and management for TP-Link Routers. See [Supported routers](#supports)
@@ -280,7 +289,7 @@ or you have TP-link C5400X or similar router you need to get web encrypted passw
280
289
  - Archer AX20 v1.0
281
290
  - Archer AX20 v3.0
282
291
  - Archer AX21 (v1.20, v3.0)
283
- - Archer AX23 v1.0
292
+ - Archer AX23 (v1.0, v1.2)
284
293
  - Archer AX50 v1.0
285
294
  - Archer AX53 v2
286
295
  - Archer AX55 (v1.0, V1.60, v4.0)
@@ -290,6 +299,7 @@ or you have TP-link C5400X or similar router you need to get web encrypted passw
290
299
  - Archer AX90 V1.20
291
300
  - Archer AXE75 V1
292
301
  - Archer AXE16000
302
+ - Archer AX1800
293
303
  - Archer AX3000 V1
294
304
  - Archer AX6000 V1
295
305
  - Archer AX11000 V1
@@ -303,7 +313,7 @@ or you have TP-link C5400X or similar router you need to get web encrypted passw
303
313
  - Archer C7 (v4.0, v5.0)
304
314
  - Archer C5400X V1
305
315
  - Archer GX90 v1.0
306
- - Archer MR200 (v5, v5.3)
316
+ - Archer MR200 (v5, v5.3, v6.0)
307
317
  - Archer MR550 v1
308
318
  - Archer MR600 (v1, v2, v3)
309
319
  - Archer VR600 v3
@@ -321,13 +331,15 @@ or you have TP-link C5400X or similar router you need to get web encrypted passw
321
331
  - Deco X90
322
332
  - Deco XE75 (v1.0, v2.0)
323
333
  - EX511 v2.0
334
+ - HX510 v1.0
335
+ - NX510v v1.0
324
336
  - TD-W9960 (v1, V1.20)
325
337
  - TL-MR100 v2.0
326
338
  - TL-MR105
327
339
  - TL-MR6400 (v5, v5.3)
328
340
  - TL-MR6500v
329
- - TL-XDR3010 V2
330
341
  - TL-WA3001 v1.0
342
+ - TL-XDR3010 V2
331
343
 
332
344
  ### Not fully tested Hardware Versions
333
345
  - AD7200 V2
@@ -1,142 +0,0 @@
1
- from unittest import main, TestCase
2
- from json import loads
3
- from tplinkrouterc6u import (
4
- TplinkC1200Router,
5
- Connection,
6
- ClientException
7
- )
8
-
9
-
10
- class TestTPLinkC1200Client(TestCase):
11
-
12
- def test_set_led_on(self) -> None:
13
-
14
- response_led_general_read = '''
15
- {
16
- "enable": "off",
17
- "time_set": "yes",
18
- "ledpm_support": "yes"
19
- }
20
- '''
21
-
22
- response_led_general_write = '''
23
- {
24
- "enable": "on",
25
- "time_set": "yes",
26
- "ledpm_support": "yes"
27
- }
28
- '''
29
-
30
- class TPLinkRouterTest(TplinkC1200Router):
31
- def request(self, path: str, data: str,
32
- ignore_response: bool = False, ignore_errors: bool = False) -> dict | None:
33
- if path == 'admin/ledgeneral?form=setting&operation=read':
34
- return loads(response_led_general_read)
35
- if path == 'admin/ledgeneral?form=setting&operation=write':
36
- self.captured_path = path
37
- return loads(response_led_general_write)
38
- raise ClientException()
39
-
40
- client = TPLinkRouterTest('', '')
41
-
42
- client.set_led(True)
43
-
44
- expected_path = "admin/ledgeneral?form=setting&operation=write"
45
-
46
- self.assertEqual(client.captured_path, expected_path)
47
-
48
- def test_set_led_off(self) -> None:
49
-
50
- response_led_general_read = '''
51
- {
52
- "enable": "on",
53
- "time_set": "yes",
54
- "ledpm_support": "yes"
55
- }
56
- '''
57
-
58
- response_led_general_write = '''
59
- {
60
- "enable": "off",
61
- "time_set": "yes",
62
- "ledpm_support": "yes"
63
- }
64
- '''
65
-
66
- class TPLinkRouterTest(TplinkC1200Router):
67
- def request(self, path: str, data: str,
68
- ignore_response: bool = False, ignore_errors: bool = False) -> dict | None:
69
- if path == 'admin/ledgeneral?form=setting&operation=read':
70
- return loads(response_led_general_read)
71
- elif path == 'admin/ledgeneral?form=setting&operation=write':
72
- self.captured_path = path
73
- return loads(response_led_general_write)
74
- raise ClientException()
75
-
76
- client = TPLinkRouterTest('', '')
77
-
78
- client.set_led(False)
79
-
80
- expected_path = "admin/ledgeneral?form=setting&operation=write"
81
-
82
- self.assertEqual(client.captured_path, expected_path)
83
-
84
- def test_led_status(self) -> None:
85
-
86
- response_led_general_read = '''
87
- {
88
- "enable": "on",
89
- "time_set": "yes",
90
- "ledpm_support": "yes"
91
- }
92
- '''
93
-
94
- class TPLinkRouterTest(TplinkC1200Router):
95
- def request(self, path: str, data: str,
96
- ignore_response: bool = False, ignore_errors: bool = False) -> dict | None:
97
- if path == 'admin/ledgeneral?form=setting&operation=read':
98
- return loads(response_led_general_read)
99
- raise ClientException()
100
-
101
- client = TPLinkRouterTest('', '')
102
-
103
- led_status = client.get_led()
104
- self.assertTrue(led_status)
105
-
106
- def test_set_wifi(self) -> None:
107
-
108
- class TPLinkRouterTest(TplinkC1200Router):
109
- def request(self, path: str, data: str,
110
- ignore_response: bool = False, ignore_errors: bool = False) -> dict | None:
111
-
112
- self.captured_path = path
113
- self.captured_data = data
114
-
115
- client = TPLinkRouterTest('', '')
116
- client.set_wifi(
117
- Connection.HOST_5G,
118
- enable=True,
119
- ssid="TestSSID",
120
- hidden="no",
121
- encryption="WPA3-PSK",
122
- psk_version="2",
123
- psk_cipher="AES",
124
- psk_key="testkey123",
125
- hwmode="11ac",
126
- htmode="VHT20",
127
- channel=36,
128
- txpower="20",
129
- disabled_all="no"
130
- )
131
-
132
- expected_data = ("operation=write&enable=on&ssid=TestSSID&hidden=no&encryption=WPA3-PSK&"
133
- "psk_version=2&psk_cipher=AES&psk_key=testkey123&hwmode=11ac&"
134
- "htmode=VHT20&channel=36&txpower=20&disabled_all=no")
135
- expected_path = f"admin/wireless?form=wireless_5g&{expected_data}"
136
-
137
- self.assertEqual(client.captured_path, expected_path)
138
- self.assertEqual(client.captured_data, expected_data)
139
-
140
-
141
- if __name__ == '__main__':
142
- main()
File without changes