tplinkrouterc6u 4.1.1__tar.gz → 4.2.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-4.1.1 → tplinkrouterc6u-4.2.0}/PKG-INFO +3 -1
- {tplinkrouterc6u-4.1.1 → tplinkrouterc6u-4.2.0}/README.md +2 -0
- {tplinkrouterc6u-4.1.1 → tplinkrouterc6u-4.2.0}/setup.py +1 -1
- {tplinkrouterc6u-4.1.1 → tplinkrouterc6u-4.2.0}/test/test_client.py +4 -1
- tplinkrouterc6u-4.2.0/test/test_client_c1200.py +141 -0
- {tplinkrouterc6u-4.1.1 → tplinkrouterc6u-4.2.0}/tplinkrouterc6u/client.py +78 -3
- {tplinkrouterc6u-4.1.1 → tplinkrouterc6u-4.2.0}/tplinkrouterc6u/dataclass.py +0 -1
- {tplinkrouterc6u-4.1.1 → tplinkrouterc6u-4.2.0}/tplinkrouterc6u.egg-info/PKG-INFO +3 -1
- {tplinkrouterc6u-4.1.1 → tplinkrouterc6u-4.2.0}/tplinkrouterc6u.egg-info/SOURCES.txt +1 -0
- {tplinkrouterc6u-4.1.1 → tplinkrouterc6u-4.2.0}/LICENSE +0 -0
- {tplinkrouterc6u-4.1.1 → tplinkrouterc6u-4.2.0}/setup.cfg +0 -0
- {tplinkrouterc6u-4.1.1 → tplinkrouterc6u-4.2.0}/test/__init__.py +0 -0
- {tplinkrouterc6u-4.1.1 → tplinkrouterc6u-4.2.0}/test/test_client_deco.py +0 -0
- {tplinkrouterc6u-4.1.1 → tplinkrouterc6u-4.2.0}/test/test_client_mr.py +0 -0
- {tplinkrouterc6u-4.1.1 → tplinkrouterc6u-4.2.0}/tplinkrouterc6u/__init__.py +0 -0
- {tplinkrouterc6u-4.1.1 → tplinkrouterc6u-4.2.0}/tplinkrouterc6u/encryption.py +0 -0
- {tplinkrouterc6u-4.1.1 → tplinkrouterc6u-4.2.0}/tplinkrouterc6u/enum.py +0 -0
- {tplinkrouterc6u-4.1.1 → tplinkrouterc6u-4.2.0}/tplinkrouterc6u/exception.py +0 -0
- {tplinkrouterc6u-4.1.1 → tplinkrouterc6u-4.2.0}/tplinkrouterc6u.egg-info/dependency_links.txt +0 -0
- {tplinkrouterc6u-4.1.1 → tplinkrouterc6u-4.2.0}/tplinkrouterc6u.egg-info/requires.txt +0 -0
- {tplinkrouterc6u-4.1.1 → tplinkrouterc6u-4.2.0}/tplinkrouterc6u.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: tplinkrouterc6u
|
|
3
|
-
Version: 4.
|
|
3
|
+
Version: 4.2.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
|
|
@@ -227,6 +227,7 @@ or you have TP-link C1200 V2 or similar router you need to get web encrypted pas
|
|
|
227
227
|
- Archer AX10 v1.0
|
|
228
228
|
- Archer AX12 v1.0
|
|
229
229
|
- Archer AX20 v1.0
|
|
230
|
+
- Archer AX20 v3.0
|
|
230
231
|
- Archer AX21 v1.20
|
|
231
232
|
- Archer AX23 v1.0
|
|
232
233
|
- Archer AX50 v1.0
|
|
@@ -237,6 +238,7 @@ or you have TP-link C1200 V2 or similar router you need to get web encrypted pas
|
|
|
237
238
|
- Archer AX73 V1
|
|
238
239
|
- Archer AX75 V1
|
|
239
240
|
- Archer AXE75 V1
|
|
241
|
+
- Archer AXE16000
|
|
240
242
|
- Archer AX3000 V1
|
|
241
243
|
- Archer AX6000 V1
|
|
242
244
|
- Archer AX11000 V1
|
|
@@ -206,6 +206,7 @@ or you have TP-link C1200 V2 or similar router you need to get web encrypted pas
|
|
|
206
206
|
- Archer AX10 v1.0
|
|
207
207
|
- Archer AX12 v1.0
|
|
208
208
|
- Archer AX20 v1.0
|
|
209
|
+
- Archer AX20 v3.0
|
|
209
210
|
- Archer AX21 v1.20
|
|
210
211
|
- Archer AX23 v1.0
|
|
211
212
|
- Archer AX50 v1.0
|
|
@@ -216,6 +217,7 @@ or you have TP-link C1200 V2 or similar router you need to get web encrypted pas
|
|
|
216
217
|
- Archer AX73 V1
|
|
217
218
|
- Archer AX75 V1
|
|
218
219
|
- Archer AXE75 V1
|
|
220
|
+
- Archer AXE16000
|
|
219
221
|
- Archer AX3000 V1
|
|
220
222
|
- Archer AX6000 V1
|
|
221
223
|
- Archer AX11000 V1
|
|
@@ -425,7 +425,8 @@ class TestTPLinkClient(unittest.TestCase):
|
|
|
425
425
|
response_game_accelerator = '''
|
|
426
426
|
{
|
|
427
427
|
"data": [
|
|
428
|
-
{"mac": "06:82:9d:2b:8f:c6", "deviceTag":"2.4G", "isGuest":false, "ip":"192.168.1.186", "deviceName":"name1"
|
|
428
|
+
{"mac": "06:82:9d:2b:8f:c6", "deviceTag":"2.4G", "isGuest":false, "ip":"192.168.1.186", "deviceName":"name1",
|
|
429
|
+
"uploadSpeed":12, "downloadSpeed":77},
|
|
429
430
|
{"mac": "fb:90:b8:2a:8a:b1", "deviceTag":"iot_2.4G", "isGuest":false, "ip":"192.168.1.187", "deviceName":"name2"},
|
|
430
431
|
{"mac": "54:b3:a2:f7:be:ea", "deviceTag":"iot_5G", "isGuest":false, "ip":"192.168.1.188", "deviceName":"name3"},
|
|
431
432
|
{"mac": "3c:ae:e1:83:94:9d", "deviceTag":"iot_6G", "isGuest":false, "ip":"192.168.1.189", "deviceName":"name4"}
|
|
@@ -524,6 +525,8 @@ class TestTPLinkClient(unittest.TestCase):
|
|
|
524
525
|
self.assertEqual(status.devices[2].hostname, 'UNKNOWN')
|
|
525
526
|
self.assertEqual(status.devices[2].packets_sent, 450333)
|
|
526
527
|
self.assertEqual(status.devices[2].packets_received, 4867482)
|
|
528
|
+
self.assertEqual(status.devices[2].up_speed, 12)
|
|
529
|
+
self.assertEqual(status.devices[2].down_speed, 77)
|
|
527
530
|
self.assertIsInstance(status.devices[3], Device)
|
|
528
531
|
self.assertEqual(status.devices[3].type, Connection.IOT_2G)
|
|
529
532
|
self.assertEqual(status.devices[3].macaddr, 'FB-90-B8-2A-8A-B1')
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
import json
|
|
3
|
+
from tplinkrouterc6u import (
|
|
4
|
+
TplinkC1200Router,
|
|
5
|
+
Connection,
|
|
6
|
+
ClientException
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
class TestTPLinkC1200Client(unittest.TestCase):
|
|
10
|
+
|
|
11
|
+
def test_set_led_on(self) -> None:
|
|
12
|
+
|
|
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(self, path: str, data: str,
|
|
31
|
+
ignore_response: bool = False, ignore_errors: bool = False) -> dict | None:
|
|
32
|
+
if path == 'admin/ledgeneral?form=setting&operation=read':
|
|
33
|
+
return json.loads(response_led_general_read)
|
|
34
|
+
if path == 'admin/ledgeneral?form=setting&operation=write':
|
|
35
|
+
self.captured_path = path
|
|
36
|
+
return json.loads(response_led_general_write)
|
|
37
|
+
raise ClientException()
|
|
38
|
+
|
|
39
|
+
client = TPLinkRouterTest('', '')
|
|
40
|
+
|
|
41
|
+
client.set_led(True)
|
|
42
|
+
|
|
43
|
+
expected_path = "admin/ledgeneral?form=setting&operation=write"
|
|
44
|
+
|
|
45
|
+
self.assertEqual(client.captured_path, expected_path)
|
|
46
|
+
|
|
47
|
+
def test_set_led_off(self) -> None:
|
|
48
|
+
|
|
49
|
+
response_led_general_read = '''
|
|
50
|
+
{
|
|
51
|
+
"enable": "on",
|
|
52
|
+
"time_set": "yes",
|
|
53
|
+
"ledpm_support": "yes"
|
|
54
|
+
}
|
|
55
|
+
'''
|
|
56
|
+
|
|
57
|
+
response_led_general_write = '''
|
|
58
|
+
{
|
|
59
|
+
"enable": "off",
|
|
60
|
+
"time_set": "yes",
|
|
61
|
+
"ledpm_support": "yes"
|
|
62
|
+
}
|
|
63
|
+
'''
|
|
64
|
+
|
|
65
|
+
class TPLinkRouterTest(TplinkC1200Router):
|
|
66
|
+
def request(self, path: str, data: str,
|
|
67
|
+
ignore_response: bool = False, ignore_errors: bool = False) -> dict | None:
|
|
68
|
+
if path == 'admin/ledgeneral?form=setting&operation=read':
|
|
69
|
+
return json.loads(response_led_general_read)
|
|
70
|
+
elif path == 'admin/ledgeneral?form=setting&operation=write':
|
|
71
|
+
self.captured_path = path
|
|
72
|
+
return json.loads(response_led_general_write)
|
|
73
|
+
raise ClientException()
|
|
74
|
+
|
|
75
|
+
client = TPLinkRouterTest('', '')
|
|
76
|
+
|
|
77
|
+
client.set_led(False)
|
|
78
|
+
|
|
79
|
+
expected_path = "admin/ledgeneral?form=setting&operation=write"
|
|
80
|
+
|
|
81
|
+
self.assertEqual(client.captured_path, expected_path)
|
|
82
|
+
|
|
83
|
+
def test_led_status(self) -> None:
|
|
84
|
+
|
|
85
|
+
response_led_general_read = '''
|
|
86
|
+
{
|
|
87
|
+
"enable": "on",
|
|
88
|
+
"time_set": "yes",
|
|
89
|
+
"ledpm_support": "yes"
|
|
90
|
+
}
|
|
91
|
+
'''
|
|
92
|
+
|
|
93
|
+
class TPLinkRouterTest(TplinkC1200Router):
|
|
94
|
+
def request(self, path: str, data: str,
|
|
95
|
+
ignore_response: bool = False, ignore_errors: bool = False) -> dict | None:
|
|
96
|
+
if path == 'admin/ledgeneral?form=setting&operation=read':
|
|
97
|
+
return json.loads(response_led_general_read)
|
|
98
|
+
raise ClientException()
|
|
99
|
+
|
|
100
|
+
client = TPLinkRouterTest('', '')
|
|
101
|
+
|
|
102
|
+
led_status = client.get_led()
|
|
103
|
+
self.assertTrue(led_status)
|
|
104
|
+
|
|
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
|
+
if __name__ == '__main__':
|
|
141
|
+
unittest.main()
|
|
@@ -317,6 +317,7 @@ class TplinkBaseRouter(AbstractRouter, TplinkRequest):
|
|
|
317
317
|
|
|
318
318
|
def get_status(self) -> Status:
|
|
319
319
|
data = self.request('admin/status?form=all&operation=read', 'operation=read')
|
|
320
|
+
|
|
320
321
|
status = Status()
|
|
321
322
|
status._wan_macaddr = macaddress.EUI48(data['wan_macaddr']) if 'wan_macaddr' in data else None
|
|
322
323
|
status._lan_macaddr = macaddress.EUI48(data['lan_macaddr'])
|
|
@@ -386,6 +387,9 @@ class TplinkBaseRouter(AbstractRouter, TplinkRequest):
|
|
|
386
387
|
status.iot_clients_total = 0
|
|
387
388
|
status.iot_clients_total += 1
|
|
388
389
|
|
|
390
|
+
devices[item['mac']].down_speed = item.get('downloadSpeed')
|
|
391
|
+
devices[item['mac']].up_speed = item.get('uploadSpeed')
|
|
392
|
+
|
|
389
393
|
for item in self.request('admin/wireless?form=statistics', 'operation=load'):
|
|
390
394
|
if item['mac'] not in devices:
|
|
391
395
|
status.wifi_clients_total += 1
|
|
@@ -576,9 +580,9 @@ class TPLinkDecoClient(TplinkEncryption, AbstractRouter):
|
|
|
576
580
|
|
|
577
581
|
ip = item['ip'] if item.get('ip') else '0.0.0.0'
|
|
578
582
|
device = Device(conn,
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
583
|
+
macaddress.EUI48(item['mac']),
|
|
584
|
+
ipaddress.IPv4Address(ip),
|
|
585
|
+
base64.b64decode(item['name']).decode())
|
|
582
586
|
device.down_speed = item.get('down_speed')
|
|
583
587
|
device.up_speed = item.get('up_speed')
|
|
584
588
|
devices.append(device)
|
|
@@ -706,6 +710,77 @@ class TplinkC1200Router(TplinkBaseRouter):
|
|
|
706
710
|
self._logger.error(error)
|
|
707
711
|
raise ClientException(error)
|
|
708
712
|
|
|
713
|
+
def set_led(self, enable: bool) -> None:
|
|
714
|
+
current_state = (self.request('admin/ledgeneral?form=setting&operation=read', 'operation=read')
|
|
715
|
+
.get('enable', 'off') == 'on')
|
|
716
|
+
if current_state != enable:
|
|
717
|
+
self.request('admin/ledgeneral?form=setting&operation=write', 'operation=write')
|
|
718
|
+
|
|
719
|
+
def get_led(self) -> bool:
|
|
720
|
+
|
|
721
|
+
data = self.request('admin/ledgeneral?form=setting&operation=read', 'operation=read')
|
|
722
|
+
led_status = data.get('enable') if 'enable' in data else None
|
|
723
|
+
if led_status == 'on':
|
|
724
|
+
return True
|
|
725
|
+
elif led_status == 'off':
|
|
726
|
+
return False
|
|
727
|
+
else:
|
|
728
|
+
return None
|
|
729
|
+
|
|
730
|
+
def set_wifi(self, wifi: Connection, enable: bool = None, ssid: str = None, hidden: str = None,
|
|
731
|
+
encryption: str = None, psk_version: str = None, psk_cipher: str = None, psk_key: str = None,
|
|
732
|
+
hwmode: str = None, htmode: str = None, channel: int = None, txpower: str = None,
|
|
733
|
+
disabled_all: str = None) -> None:
|
|
734
|
+
values = {
|
|
735
|
+
Connection.HOST_2G: 'wireless_2g',
|
|
736
|
+
Connection.HOST_5G: 'wireless_5g',
|
|
737
|
+
Connection.HOST_6G: 'wireless_6g',
|
|
738
|
+
Connection.GUEST_2G: 'guest_2g',
|
|
739
|
+
Connection.GUEST_5G: 'guest_5g',
|
|
740
|
+
Connection.GUEST_6G: 'guest_6g',
|
|
741
|
+
Connection.IOT_2G: 'iot_2g',
|
|
742
|
+
Connection.IOT_5G: 'iot_5g',
|
|
743
|
+
Connection.IOT_6G: 'iot_6g',
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
value = values.get(wifi)
|
|
747
|
+
if not value:
|
|
748
|
+
raise ValueError(f"Invalid Wi-Fi connection type: {wifi}")
|
|
749
|
+
|
|
750
|
+
if enable is None and ssid is None and hidden is None and encryption is None and psk_version is None and psk_cipher is None and psk_key is None and hwmode is None and htmode is None and channel is None and txpower is None and disabled_all is None:
|
|
751
|
+
raise ValueError("At least one wireless setting must be provided")
|
|
752
|
+
|
|
753
|
+
data = "operation=write"
|
|
754
|
+
|
|
755
|
+
if enable is not None:
|
|
756
|
+
data += f"&enable={'on' if enable else 'off'}"
|
|
757
|
+
if ssid is not None:
|
|
758
|
+
data += f"&ssid={ssid}"
|
|
759
|
+
if hidden is not None:
|
|
760
|
+
data += f"&hidden={hidden}"
|
|
761
|
+
if encryption is not None:
|
|
762
|
+
data += f"&encryption={encryption}"
|
|
763
|
+
if psk_version is not None:
|
|
764
|
+
data += f"&psk_version={psk_version}"
|
|
765
|
+
if psk_cipher is not None:
|
|
766
|
+
data += f"&psk_cipher={psk_cipher}"
|
|
767
|
+
if psk_key is not None:
|
|
768
|
+
data += f"&psk_key={psk_key}"
|
|
769
|
+
if hwmode is not None:
|
|
770
|
+
data += f"&hwmode={hwmode}"
|
|
771
|
+
if htmode is not None:
|
|
772
|
+
data += f"&htmode={htmode}"
|
|
773
|
+
if channel is not None:
|
|
774
|
+
data += f"&channel={channel}"
|
|
775
|
+
if txpower is not None:
|
|
776
|
+
data += f"&txpower={txpower}"
|
|
777
|
+
if disabled_all is not None:
|
|
778
|
+
data += f"&disabled_all={disabled_all}"
|
|
779
|
+
|
|
780
|
+
path = f"admin/wireless?form={value}&{data}"
|
|
781
|
+
|
|
782
|
+
self.request(path, data)
|
|
783
|
+
|
|
709
784
|
|
|
710
785
|
class TPLinkMRClient(AbstractRouter):
|
|
711
786
|
REQUEST_RETRIES = 3
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: tplinkrouterc6u
|
|
3
|
-
Version: 4.
|
|
3
|
+
Version: 4.2.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
|
|
@@ -227,6 +227,7 @@ or you have TP-link C1200 V2 or similar router you need to get web encrypted pas
|
|
|
227
227
|
- Archer AX10 v1.0
|
|
228
228
|
- Archer AX12 v1.0
|
|
229
229
|
- Archer AX20 v1.0
|
|
230
|
+
- Archer AX20 v3.0
|
|
230
231
|
- Archer AX21 v1.20
|
|
231
232
|
- Archer AX23 v1.0
|
|
232
233
|
- Archer AX50 v1.0
|
|
@@ -237,6 +238,7 @@ or you have TP-link C1200 V2 or similar router you need to get web encrypted pas
|
|
|
237
238
|
- Archer AX73 V1
|
|
238
239
|
- Archer AX75 V1
|
|
239
240
|
- Archer AXE75 V1
|
|
241
|
+
- Archer AXE16000
|
|
240
242
|
- Archer AX3000 V1
|
|
241
243
|
- Archer AX6000 V1
|
|
242
244
|
- Archer AX11000 V1
|
|
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-4.1.1 → tplinkrouterc6u-4.2.0}/tplinkrouterc6u.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|