-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathPlug_Controller.cpp
executable file
·216 lines (173 loc) · 6.8 KB
/
Plug_Controller.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
// #############################################################################
// #############################################################################
// #############################################################################
// TP-Link HS100/HS110 SmartPlug Controller for ESP8266/ESP32
// by Miraculix200 (not affiliated with TP-Link)
// License: MIT
// Code may stop working any time if TP-Link changes their firmware
// List of other commands:
// https://github.com/softScheck/tplink-smartplug/blob/master/tplink-smarthome-commands.txt
// #############################################################################
// #############################################################################
// #############################################################################
#include "Plug_Controller.h"
// #############################################################################
PlugController::PlugController(IPAddress ip, uint16_t port)
{
targetIP = ip;
targetPort = port;
}
// #############################################################################
void PlugController::serializeUint32(char (&buf)[4], uint32_t val)
{
buf[0] = (val >> 24) & 0xff;
buf[1] = (val >> 16) & 0xff;
buf[2] = (val >> 8) & 0xff;
buf[3] = val & 0xff;
}
// #############################################################################
void PlugController::decrypt(char* input, uint16_t length)
{
uint8_t key = 171;
uint8_t next_key;
for (uint16_t i = 0; i < length; i++) {
next_key = input[i];
input[i] = key ^ input[i];
key = next_key;
}
}
// #############################################################################
void PlugController::encrypt(char* data, uint16_t length)
{
uint8_t key = 171;
for (uint16_t i = 0; i < length + 1; i++) {
data[i] = key ^ data[i];
key = data[i];
}
}
// #############################################################################
void PlugController::encryptWithHeader(char* out, char* data, uint16_t length)
{
char serialized[4];
serializeUint32(serialized, length);
encrypt(data, length);
memcpy(out, &serialized, 4);
memcpy(out + 4, data, length);
}
// #############################################################################
String PlugController::getInfo()
{
const String cmd = "{\"system\":{\"get_sysinfo\":{}}}";
return sendCmd(cmd);
}
// #############################################################################
String PlugController::on()
{
const String cmd = "{\"system\":{\"set_relay_state\":{\"state\":1}}}";
return sendCmd(cmd);
}
// #############################################################################
String PlugController::off()
{
const String cmd = "{\"system\":{\"set_relay_state\":{\"state\":0}}}";
return sendCmd(cmd);
}
// #############################################################################
String PlugController::eraseEmeterStats()
{
const String cmd = "{\"emeter\":{\"erase_emeter_stat\":null}}";
return sendCmd(cmd);
}
// #############################################################################
String PlugController::countDown(uint16_t seconds, bool act)
{
String cmd = "{\"count_down\":{\"add_rule\":{\"enable\":1,\"delay\":";
cmd += String(seconds);
cmd += ",\"act\":";
if (act)
cmd += "1,\"name\":\"turn on\"}}}";
else
cmd += "0,\"name\":\"turn off\"}}}";
const String delete_all_rules = "{\"count_down\":{\"delete_all_rules\":null}}";
sendCmd(delete_all_rules);
return sendCmd(cmd);
}
// #############################################################################
String PlugController::getEmeter()
{
const String cmd = "{\"emeter\":{\"get_realtime\":{}}}";
return sendCmd(cmd);
}
// #############################################################################
String PlugController::setLed(bool power)
{
String cmd = "{\"system\":{\"set_led_off\":{\"off\":1}}}";
if (power) {
cmd = "{\"system\":{\"set_led_off\":{\"off\":0}}}";
}
return sendCmd(cmd);
}
// #############################################################################
String PlugController::sendCmd(String cmd)
{
char encrypted[cmd.length() + 4];
encryptWithHeader(encrypted, const_cast<char*>(cmd.c_str()), cmd.length());
char response[2048] = { 0 };
uint16_t length = this->tcpConnect(response, encrypted, cmd.length() + 4, 5000);
if (length > 0)
decrypt(response, length - 4);
else
return String("");
return String(response);
}
// #############################################################################
uint16_t PlugController::tcpConnect(char* out, const char* cmd, uint16_t length, unsigned long timeout_millis)
{
WiFiClient plug_client;
if (plug_client.connect(this->targetIP, this->targetPort))
{
delay(10);
plug_client.write(cmd, length);
// give the plug some time to think about its response ^^
// otherwise there may be no response
// while waiting, pat the dog for ESP8266
unsigned long start = millis();
while(millis() - start < 500)
{
delay(10); // this includes yield() to pat the dog
}
start = millis();
char buf[2048] = { 0 };
while (plug_client.connected()) {
if (plug_client.available()) {
delay(10);
int len = plug_client.read((uint8_t*)buf, 2048);
// necessary for decryption
// buf + 4 strips 4 byte header
// valread - 3 leaves 1 byte for terminating null character
strncpy(out, buf + 4, len - 3);
delay(10);
plug_client.flush();
return len;
}
if (millis() - start >= timeout_millis) {
// connection timeout
break;
}
delay(0);
}
// timeout/not connected
delay(10);
plug_client.flush();
}
return 0;
}
// #############################################################################
// #############################################################################
// #############################################################################
// Taxation == theft
// Contracts without >=2 matching declarations of intent are void
// Freedom of speech > your ego/feelings
// #############################################################################
// #############################################################################
// #############################################################################