homebridge-rainpoint 1.0.0
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.
- package/LICENSE +176 -0
- package/README.md +143 -0
- package/config.schema.json +148 -0
- package/dist/IrrigationSystemAccessory.d.ts +26 -0
- package/dist/IrrigationSystemAccessory.d.ts.map +1 -0
- package/dist/IrrigationSystemAccessory.js +168 -0
- package/dist/IrrigationSystemAccessory.js.map +1 -0
- package/dist/SensorAccessory.d.ts +22 -0
- package/dist/SensorAccessory.d.ts.map +1 -0
- package/dist/SensorAccessory.js +74 -0
- package/dist/SensorAccessory.js.map +1 -0
- package/dist/ValveAccessory.d.ts +25 -0
- package/dist/ValveAccessory.d.ts.map +1 -0
- package/dist/ValveAccessory.js +119 -0
- package/dist/ValveAccessory.js.map +1 -0
- package/dist/api/RainPointClientInterface.d.ts +65 -0
- package/dist/api/RainPointClientInterface.d.ts.map +1 -0
- package/dist/api/RainPointClientInterface.js +3 -0
- package/dist/api/RainPointClientInterface.js.map +1 -0
- package/dist/api/RainPointHomeClient.d.ts +36 -0
- package/dist/api/RainPointHomeClient.d.ts.map +1 -0
- package/dist/api/RainPointHomeClient.js +359 -0
- package/dist/api/RainPointHomeClient.js.map +1 -0
- package/dist/api/RainPointTyClient.d.ts +113 -0
- package/dist/api/RainPointTyClient.d.ts.map +1 -0
- package/dist/api/RainPointTyClient.js +947 -0
- package/dist/api/RainPointTyClient.js.map +1 -0
- package/dist/api/constants.d.ts +53 -0
- package/dist/api/constants.d.ts.map +1 -0
- package/dist/api/constants.js +105 -0
- package/dist/api/constants.js.map +1 -0
- package/dist/api/dp-parser.d.ts +14 -0
- package/dist/api/dp-parser.d.ts.map +1 -0
- package/dist/api/dp-parser.js +100 -0
- package/dist/api/dp-parser.js.map +1 -0
- package/dist/api/index.d.ts +7 -0
- package/dist/api/index.d.ts.map +1 -0
- package/dist/api/index.js +23 -0
- package/dist/api/index.js.map +1 -0
- package/dist/api/types.d.ts +330 -0
- package/dist/api/types.d.ts.map +1 -0
- package/dist/api/types.js +3 -0
- package/dist/api/types.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/naming.d.ts +14 -0
- package/dist/naming.d.ts.map +1 -0
- package/dist/naming.js +22 -0
- package/dist/naming.js.map +1 -0
- package/dist/platform.d.ts +52 -0
- package/dist/platform.d.ts.map +1 -0
- package/dist/platform.js +277 -0
- package/dist/platform.js.map +1 -0
- package/dist/settings.d.ts +3 -0
- package/dist/settings.d.ts.map +1 -0
- package/dist/settings.js +6 -0
- package/dist/settings.js.map +1 -0
- package/package.json +59 -0
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.RainPointHomeClient = void 0;
|
|
7
|
+
const https_1 = __importDefault(require("https"));
|
|
8
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
9
|
+
const os_1 = __importDefault(require("os"));
|
|
10
|
+
const constants_1 = require("./constants");
|
|
11
|
+
function md5(input) {
|
|
12
|
+
return crypto_1.default.createHash('md5').update(input, 'utf8').digest('hex');
|
|
13
|
+
}
|
|
14
|
+
class RainPointHomeClient {
|
|
15
|
+
constructor(config, log) {
|
|
16
|
+
this.config = config;
|
|
17
|
+
this.log = log;
|
|
18
|
+
this.token = '';
|
|
19
|
+
this.refreshTokenValue = '';
|
|
20
|
+
this.tokenExpired = 0;
|
|
21
|
+
this.hid = '';
|
|
22
|
+
this.userDeviceName = '';
|
|
23
|
+
this.userProductKey = '';
|
|
24
|
+
this.baseUrl = (0, constants_1.getBaseUrl)(config.region);
|
|
25
|
+
this.deviceId = RainPointHomeClient.getOrCreateDeviceId();
|
|
26
|
+
}
|
|
27
|
+
static getOrCreateDeviceId() {
|
|
28
|
+
if (RainPointHomeClient.deviceIdStorage) {
|
|
29
|
+
return RainPointHomeClient.deviceIdStorage;
|
|
30
|
+
}
|
|
31
|
+
const uuid = crypto_1.default.randomUUID().replace(/-/g, '');
|
|
32
|
+
RainPointHomeClient.deviceIdStorage = uuid;
|
|
33
|
+
return uuid;
|
|
34
|
+
}
|
|
35
|
+
async login() {
|
|
36
|
+
const isocode = this.config.region === 'CN' ? 'CN' : 'US';
|
|
37
|
+
const areaCode = this.config.region === 'CN' ? '86' : '1';
|
|
38
|
+
const hashedPassword = md5(this.config.password);
|
|
39
|
+
const response = await this.request('POST', '/auth/basic/app/login', {
|
|
40
|
+
areaCode,
|
|
41
|
+
phoneOrEmail: this.config.email,
|
|
42
|
+
password: hashedPassword,
|
|
43
|
+
pushId: '',
|
|
44
|
+
deviceType: 1,
|
|
45
|
+
deviceModel: os_1.default.hostname() || 'homebridge',
|
|
46
|
+
language: 'en',
|
|
47
|
+
isocode,
|
|
48
|
+
deviceId: this.deviceId,
|
|
49
|
+
osVersion: 33,
|
|
50
|
+
}, false);
|
|
51
|
+
this.token = response.data.token;
|
|
52
|
+
this.refreshTokenValue = response.data.refreshToken;
|
|
53
|
+
this.tokenExpired = response.data.tokenExpired;
|
|
54
|
+
this.userDeviceName = response.data.user.deviceName;
|
|
55
|
+
this.userProductKey = response.data.user.productKey;
|
|
56
|
+
this.log.info('Logged in to RainPoint Home API as %s', this.config.email);
|
|
57
|
+
}
|
|
58
|
+
async ensureAuthenticated() {
|
|
59
|
+
if (Date.now() >= this.tokenExpired) {
|
|
60
|
+
await this.refreshAccessToken();
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
async refreshAccessToken() {
|
|
64
|
+
try {
|
|
65
|
+
const response = await this.request('POST', '/auth/basic/app/token/refresh', { refreshToken: this.refreshTokenValue }, false);
|
|
66
|
+
this.token = response.data.token;
|
|
67
|
+
this.refreshTokenValue = response.data.refreshToken;
|
|
68
|
+
this.tokenExpired = response.data.tokenExpired;
|
|
69
|
+
this.log.debug('Refreshed RainPoint Home access token');
|
|
70
|
+
}
|
|
71
|
+
catch (error) {
|
|
72
|
+
this.log.error('Failed to refresh token, re-authenticating...');
|
|
73
|
+
await this.login();
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
setHome(homeId) {
|
|
77
|
+
this.hid = homeId;
|
|
78
|
+
}
|
|
79
|
+
async getHomes() {
|
|
80
|
+
const response = await this.request('GET', '/app/member/appHome/list');
|
|
81
|
+
return response.data.map(h => ({ id: h.hid, name: h.homeName }));
|
|
82
|
+
}
|
|
83
|
+
async getDevices() {
|
|
84
|
+
const response = await this.request('GET', `/app/device/getDeviceByHid?hid=${encodeURIComponent(this.hid)}`);
|
|
85
|
+
const devices = [];
|
|
86
|
+
for (const device of response.data) {
|
|
87
|
+
const deviceType = (0, constants_1.getDeviceType)(device.model);
|
|
88
|
+
if (deviceType === constants_1.DEVICE_TYPE_GATEWAY)
|
|
89
|
+
continue;
|
|
90
|
+
const zoneNames = this.parsePortDescribe(device.portDescribe, device.portNumber);
|
|
91
|
+
if (deviceType === constants_1.DEVICE_TYPE_SENSOR) {
|
|
92
|
+
devices.push(this.normalizeDevice(device, 0, device.name, false));
|
|
93
|
+
if (device.subDevices) {
|
|
94
|
+
for (const sub of device.subDevices) {
|
|
95
|
+
devices.push(this.normalizeDevice(sub, sub.addr, sub.name || device.name, true, device.mid));
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
devices.push(this.normalizeDevice(device, 0, device.name, false, undefined, zoneNames));
|
|
101
|
+
if (device.subDevices) {
|
|
102
|
+
for (const sub of device.subDevices) {
|
|
103
|
+
const subZoneNames = this.parsePortDescribe(sub.portDescribe, sub.portNumber);
|
|
104
|
+
devices.push(this.normalizeDevice(sub, sub.addr, sub.name || device.name, true, device.mid, subZoneNames));
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return devices;
|
|
109
|
+
}
|
|
110
|
+
async getDeviceStatuses(deviceIds) {
|
|
111
|
+
const result = new Map();
|
|
112
|
+
if (deviceIds.length === 1) {
|
|
113
|
+
const status = await this.getDeviceStatus(deviceIds[0]);
|
|
114
|
+
result.set(status.MID, this.normalizeStatus(status));
|
|
115
|
+
return result;
|
|
116
|
+
}
|
|
117
|
+
const response = await this.request('POST', '/app/device/multipleDeviceStatus', { MIDS: deviceIds });
|
|
118
|
+
for (const multiStatus of response.data) {
|
|
119
|
+
const deviceStatus = this.convertMultipleDeviceStatus(multiStatus);
|
|
120
|
+
result.set(multiStatus.mid, this.normalizeStatus(deviceStatus));
|
|
121
|
+
}
|
|
122
|
+
return result;
|
|
123
|
+
}
|
|
124
|
+
async turnZoneOn(deviceId, port, durationSeconds) {
|
|
125
|
+
const device = await this.findDevice(deviceId);
|
|
126
|
+
if (!device)
|
|
127
|
+
throw new Error(`Device ${deviceId} not found`);
|
|
128
|
+
const userDeviceInfo = this.getUserDeviceInfo();
|
|
129
|
+
const durationMinutes = durationSeconds ? Math.floor(durationSeconds / 60) : 0;
|
|
130
|
+
const isSubDevice = device.isSubDevice;
|
|
131
|
+
const addr = device.addr;
|
|
132
|
+
if (isSubDevice) {
|
|
133
|
+
const mode = durationMinutes > 0 ? constants_1.CONTROL_MODE_MANUAL : constants_1.CONTROL_MODE_NEXT;
|
|
134
|
+
const param = durationMinutes > 0
|
|
135
|
+
? (0, constants_1.buildZoneOnWithDurationParam)(port, durationMinutes)
|
|
136
|
+
: (0, constants_1.buildZoneOnParam)(port);
|
|
137
|
+
await this.controlWorkModeDP({
|
|
138
|
+
mid: deviceId,
|
|
139
|
+
productKey: userDeviceInfo.productKey,
|
|
140
|
+
deviceName: userDeviceInfo.deviceName,
|
|
141
|
+
mode,
|
|
142
|
+
addr,
|
|
143
|
+
port: 0,
|
|
144
|
+
param,
|
|
145
|
+
dpCode: constants_1.DP_CODE_IRRIGATION,
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
await this.controlWorkMode({
|
|
150
|
+
mid: deviceId,
|
|
151
|
+
productKey: userDeviceInfo.productKey,
|
|
152
|
+
deviceName: userDeviceInfo.deviceName,
|
|
153
|
+
mode: constants_1.CONTROL_MODE_NEXT,
|
|
154
|
+
addr: 0,
|
|
155
|
+
port,
|
|
156
|
+
param: '',
|
|
157
|
+
duration: durationMinutes,
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
async turnZoneOff(deviceId, port) {
|
|
162
|
+
const device = await this.findDevice(deviceId);
|
|
163
|
+
if (!device)
|
|
164
|
+
throw new Error(`Device ${deviceId} not found`);
|
|
165
|
+
const userDeviceInfo = this.getUserDeviceInfo();
|
|
166
|
+
const isSubDevice = device.isSubDevice;
|
|
167
|
+
const addr = device.addr;
|
|
168
|
+
if (isSubDevice) {
|
|
169
|
+
await this.controlWorkModeDP({
|
|
170
|
+
mid: deviceId,
|
|
171
|
+
productKey: userDeviceInfo.productKey,
|
|
172
|
+
deviceName: userDeviceInfo.deviceName,
|
|
173
|
+
mode: constants_1.CONTROL_MODE_NEXT,
|
|
174
|
+
addr,
|
|
175
|
+
port: 0,
|
|
176
|
+
param: constants_1.STOP_ALL_PARAM,
|
|
177
|
+
dpCode: constants_1.DP_CODE_IRRIGATION,
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
await this.controlWorkMode({
|
|
182
|
+
mid: deviceId,
|
|
183
|
+
productKey: userDeviceInfo.productKey,
|
|
184
|
+
deviceName: userDeviceInfo.deviceName,
|
|
185
|
+
mode: constants_1.CONTROL_MODE_NEXT,
|
|
186
|
+
addr: 0,
|
|
187
|
+
port: 255,
|
|
188
|
+
param: '',
|
|
189
|
+
duration: 0,
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
async findDevice(deviceId) {
|
|
194
|
+
const devices = await this.getDevices();
|
|
195
|
+
return devices.find(d => d.id === deviceId);
|
|
196
|
+
}
|
|
197
|
+
getUserDeviceInfo() {
|
|
198
|
+
return {
|
|
199
|
+
deviceName: this.userDeviceName,
|
|
200
|
+
productKey: this.userProductKey,
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
normalizeDevice(device, addr, name, isSubDevice, parentId, zoneNames) {
|
|
204
|
+
const portNumber = device.portNumber || 1;
|
|
205
|
+
return {
|
|
206
|
+
id: isSubDevice ? device.sid : device.mid,
|
|
207
|
+
name,
|
|
208
|
+
model: device.model,
|
|
209
|
+
productId: device.productKey ?? '',
|
|
210
|
+
online: device.enabled !== 0,
|
|
211
|
+
portNumber,
|
|
212
|
+
portDescribe: zoneNames ?? this.parsePortDescribe(device.portDescribe, portNumber),
|
|
213
|
+
deviceType: (0, constants_1.getDeviceType)(device.model),
|
|
214
|
+
isSubDevice,
|
|
215
|
+
parentId,
|
|
216
|
+
addr,
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
parsePortDescribe(portDescribe, portNumber) {
|
|
220
|
+
if (!portDescribe) {
|
|
221
|
+
return Array.from({ length: portNumber }, (_, i) => `Zone ${i + 1}`);
|
|
222
|
+
}
|
|
223
|
+
const parts = portDescribe.split('|');
|
|
224
|
+
return Array.from({ length: portNumber }, (_, i) => parts[i]?.trim() || `Zone ${i + 1}`);
|
|
225
|
+
}
|
|
226
|
+
normalizeStatus(status) {
|
|
227
|
+
const zones = [];
|
|
228
|
+
const portNumber = 1;
|
|
229
|
+
const state = status.state || '';
|
|
230
|
+
const firstChar = state.charAt(0);
|
|
231
|
+
const isOnline = firstChar ? parseInt(firstChar) > 0 : false;
|
|
232
|
+
for (let port = 1; port <= portNumber; port++) {
|
|
233
|
+
const portKey = `D${String(port).padStart(2, '0')}`;
|
|
234
|
+
const portValue = status[portKey] || state;
|
|
235
|
+
const portFirstChar = portValue ? portValue.charAt(0) : '0';
|
|
236
|
+
zones.push({
|
|
237
|
+
port,
|
|
238
|
+
name: `Zone ${port}`,
|
|
239
|
+
isOn: portFirstChar ? parseInt(portFirstChar) > 0 : false,
|
|
240
|
+
remainingDuration: 0,
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
return {
|
|
244
|
+
deviceId: status.MID,
|
|
245
|
+
online: isOnline,
|
|
246
|
+
zones,
|
|
247
|
+
moisture: null,
|
|
248
|
+
temperature: null,
|
|
249
|
+
battery: null,
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
convertMultipleDeviceStatus(multiStatus) {
|
|
253
|
+
const status = {
|
|
254
|
+
MID: multiStatus.mid,
|
|
255
|
+
iotId: multiStatus.iotId,
|
|
256
|
+
propVer: multiStatus.propVer,
|
|
257
|
+
state: '',
|
|
258
|
+
connected: '1',
|
|
259
|
+
softVer: '',
|
|
260
|
+
recich: 1,
|
|
261
|
+
updateTime: {},
|
|
262
|
+
timeDiff: 0,
|
|
263
|
+
onlineTimeStamp: 0,
|
|
264
|
+
};
|
|
265
|
+
for (const param of multiStatus.status) {
|
|
266
|
+
status[param.id] = param.value;
|
|
267
|
+
if (param.id === 'state' || param.id === 'State') {
|
|
268
|
+
status['state'] = param.value;
|
|
269
|
+
}
|
|
270
|
+
if (param.id === 'connected' || param.id === 'Connected') {
|
|
271
|
+
status['connected'] = param.value;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
return status;
|
|
275
|
+
}
|
|
276
|
+
async getDeviceStatus(mid) {
|
|
277
|
+
const response = await this.request('GET', `/app/device/getDeviceStatus?mid=${encodeURIComponent(mid)}`);
|
|
278
|
+
return response.data;
|
|
279
|
+
}
|
|
280
|
+
async controlWorkMode(params) {
|
|
281
|
+
const response = await this.request('POST', '/app/device/controlWorkMode', params);
|
|
282
|
+
return response.data;
|
|
283
|
+
}
|
|
284
|
+
async controlWorkModeDP(params) {
|
|
285
|
+
const response = await this.request('POST', '/app/device/controlWorkModeDP', params);
|
|
286
|
+
return response.data;
|
|
287
|
+
}
|
|
288
|
+
async request(method, path, body, requireAuth = true) {
|
|
289
|
+
if (requireAuth) {
|
|
290
|
+
await this.ensureAuthenticated();
|
|
291
|
+
}
|
|
292
|
+
const headers = {
|
|
293
|
+
'Content-Type': 'application/json',
|
|
294
|
+
'lang': 'en',
|
|
295
|
+
'version': constants_1.API_VERSION,
|
|
296
|
+
'appCode': constants_1.APP_CODE,
|
|
297
|
+
'sceneType': constants_1.SCENE_TYPE,
|
|
298
|
+
};
|
|
299
|
+
if (requireAuth && this.token) {
|
|
300
|
+
headers['auth'] = this.token;
|
|
301
|
+
}
|
|
302
|
+
if (this.hid) {
|
|
303
|
+
headers['hid'] = this.hid;
|
|
304
|
+
}
|
|
305
|
+
const url = new URL(path, this.baseUrl);
|
|
306
|
+
const urlStr = url.toString();
|
|
307
|
+
const requestBody = body ? JSON.stringify(body) : undefined;
|
|
308
|
+
this.log.debug('%s %s', method, urlStr);
|
|
309
|
+
if (requestBody) {
|
|
310
|
+
this.log.debug('Request body: %s', requestBody);
|
|
311
|
+
}
|
|
312
|
+
return new Promise((resolve, reject) => {
|
|
313
|
+
const urlObj = new URL(urlStr);
|
|
314
|
+
const options = {
|
|
315
|
+
hostname: urlObj.hostname,
|
|
316
|
+
port: urlObj.port || 443,
|
|
317
|
+
path: urlObj.pathname + urlObj.search,
|
|
318
|
+
method,
|
|
319
|
+
headers,
|
|
320
|
+
rejectUnauthorized: false,
|
|
321
|
+
};
|
|
322
|
+
const req = https_1.default.request(options, (res) => {
|
|
323
|
+
let data = '';
|
|
324
|
+
res.on('data', (chunk) => {
|
|
325
|
+
data += chunk;
|
|
326
|
+
});
|
|
327
|
+
res.on('end', () => {
|
|
328
|
+
try {
|
|
329
|
+
const parsed = JSON.parse(data);
|
|
330
|
+
if (parsed.code !== 0) {
|
|
331
|
+
const error = new Error(`API error ${parsed.code}: ${parsed.msg}`);
|
|
332
|
+
error.code = parsed.code;
|
|
333
|
+
reject(error);
|
|
334
|
+
return;
|
|
335
|
+
}
|
|
336
|
+
this.log.debug('Response: %s', data.substring(0, 500));
|
|
337
|
+
resolve(parsed);
|
|
338
|
+
}
|
|
339
|
+
catch (e) {
|
|
340
|
+
reject(new Error(`Failed to parse API response: ${e}`));
|
|
341
|
+
}
|
|
342
|
+
});
|
|
343
|
+
});
|
|
344
|
+
req.on('error', (e) => {
|
|
345
|
+
reject(new Error(`HTTP request failed: ${e.message}`));
|
|
346
|
+
});
|
|
347
|
+
req.setTimeout(20000, () => {
|
|
348
|
+
req.destroy(new Error('Request timed out'));
|
|
349
|
+
});
|
|
350
|
+
if (requestBody) {
|
|
351
|
+
req.write(requestBody);
|
|
352
|
+
}
|
|
353
|
+
req.end();
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
exports.RainPointHomeClient = RainPointHomeClient;
|
|
358
|
+
RainPointHomeClient.deviceIdStorage = null;
|
|
359
|
+
//# sourceMappingURL=RainPointHomeClient.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RainPointHomeClient.js","sourceRoot":"","sources":["../../src/api/RainPointHomeClient.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { RainPointClient, RainPointClientConfig, Logger, NormalizedDevice, NormalizedDeviceStatus, NormalizedHome } from './RainPointClientInterface';
|
|
2
|
+
export declare class RainPointTyClient implements RainPointClient {
|
|
3
|
+
private config;
|
|
4
|
+
private log;
|
|
5
|
+
private sid;
|
|
6
|
+
private ecode;
|
|
7
|
+
private endpoint;
|
|
8
|
+
private deviceId;
|
|
9
|
+
private readonly countryCode;
|
|
10
|
+
private homeId;
|
|
11
|
+
private static deviceIdStorage;
|
|
12
|
+
private deviceCache;
|
|
13
|
+
private readonly sessionFile;
|
|
14
|
+
private sessionRestored;
|
|
15
|
+
constructor(config: RainPointClientConfig, log: Logger);
|
|
16
|
+
/** Load a saved session (sid/ecode/endpoint) from disk, if present. */
|
|
17
|
+
private loadSession;
|
|
18
|
+
/** Persist the current session (sid/ecode/endpoint) to disk. */
|
|
19
|
+
private saveSession;
|
|
20
|
+
/** Clear the saved session file (called when the server rejects the sid). */
|
|
21
|
+
private clearSession;
|
|
22
|
+
private static getOrCreateDeviceId;
|
|
23
|
+
login(): Promise<void>;
|
|
24
|
+
private loginEx;
|
|
25
|
+
private buildRsaPublicKeyDer;
|
|
26
|
+
private derEncodeLength;
|
|
27
|
+
/**
|
|
28
|
+
* RSA-encrypt the password MD5 hex with PKCS1 v1.5 padding using Tuya's
|
|
29
|
+
* FixedSecureRandom — a deterministic 20-byte seed repeated to fill the
|
|
30
|
+
* padding string. Tuya's server compares the ciphertext, so the padding
|
|
31
|
+
* bytes must match exactly.
|
|
32
|
+
*
|
|
33
|
+
* @param publicKeyDecimal decimal modulus string from token.create
|
|
34
|
+
* @param exponentDecimal decimal exponent string (e.g. "3")
|
|
35
|
+
* @param plaintext the MD5 hex string (lowercase, 32 chars)
|
|
36
|
+
* @returns 256-char lowercase hex ciphertext
|
|
37
|
+
*/
|
|
38
|
+
private rsaEncryptFixedPadding;
|
|
39
|
+
private handleLoginResult;
|
|
40
|
+
ensureAuthenticated(): Promise<void>;
|
|
41
|
+
setHome(homeId: string): void;
|
|
42
|
+
getHomes(): Promise<NormalizedHome[]>;
|
|
43
|
+
getDevices(): Promise<NormalizedDevice[]>;
|
|
44
|
+
getDeviceStatuses(deviceIds: string[]): Promise<Map<string, NormalizedDeviceStatus>>;
|
|
45
|
+
turnZoneOn(deviceId: string, port: number, durationSeconds?: number): Promise<void>;
|
|
46
|
+
turnZoneOff(deviceId: string, port: number): Promise<void>;
|
|
47
|
+
/**
|
|
48
|
+
* Resolve a 1-based zone port number to the device's valve switch DP.
|
|
49
|
+
* Uses the cached device's zoneSwitchDps when available (populated by
|
|
50
|
+
* getDevices); falls back to the port number itself for legacy devices.
|
|
51
|
+
*/
|
|
52
|
+
private resolveSwitchDp;
|
|
53
|
+
/**
|
|
54
|
+
* Classify a TY device. The thing.m.my.group.device.list response has NO
|
|
55
|
+
* `category` field (unlike the classic Tuya device list), so we classify by
|
|
56
|
+
* structure + datapoints instead:
|
|
57
|
+
* - Gateway: deviceTopo is empty/missing AND it's the parent (other devices
|
|
58
|
+
* point at it via deviceTopo.parentDevId). Detected by absence of a
|
|
59
|
+
* parentDevId.
|
|
60
|
+
* - Sensor: a sub-device whose dps has no irrigation valve DP. (RainPoint
|
|
61
|
+
* sensors are rare in this OEM; we currently treat every sub-device as a
|
|
62
|
+
* valve unless its productId/dps indicates otherwise.)
|
|
63
|
+
* - Valve / irrigation: any sub-device with a parentDevId.
|
|
64
|
+
*
|
|
65
|
+
* Returns the HomGar-style device type strings (DEVICE_TYPE_GATEWAY / VALVE /
|
|
66
|
+
* SENSOR / IRRIGATION) so platform.ts's existing routing works unchanged.
|
|
67
|
+
*/
|
|
68
|
+
private classifyDevice;
|
|
69
|
+
/**
|
|
70
|
+
* Detect per-zone valve switch datapoints for a RainPoint TY irrigation device.
|
|
71
|
+
*
|
|
72
|
+
* The RainPoint TY controller exposes each valve as a distinct DP. Observed
|
|
73
|
+
* pattern (from a captured 3-device account):
|
|
74
|
+
* - Single-valve device (Front Garden R/L, productId ew946yrp3pgbaziu):
|
|
75
|
+
* DPs 101-128, valve on/off = DP 104 (boolean).
|
|
76
|
+
* - Split 2-valve device (Back Garden, productId pjnbcfv3bzwg4yyo):
|
|
77
|
+
* DPs 101-128 (zone 1, switch 104) AND DPs 150-167 (zone 2, switch 155,
|
|
78
|
+
* dpName "Right Valve"). The switch DPs pair by +51: 104 <-> 155.
|
|
79
|
+
*
|
|
80
|
+
* IMPORTANT: a valve group's switch DP may be ABSENT from the current dps
|
|
81
|
+
* snapshot when the device is offline (e.g. Back Garden, cloudOnline=false,
|
|
82
|
+
* omits DP 104 even though the valve exists). So zone COUNT is determined by
|
|
83
|
+
* DP-range presence (a group exists if ANY dps fall in its range), NOT by
|
|
84
|
+
* whether the specific switch DP is currently reported. The switch DP is then
|
|
85
|
+
* assigned by the +51 pattern regardless of snapshot presence — status
|
|
86
|
+
* polling reads it if present, else reports the zone as off.
|
|
87
|
+
*
|
|
88
|
+
* Group ranges (each spans ~28 DPs centered on its switch DP):
|
|
89
|
+
* group 1: DPs 90-149 (switch 104)
|
|
90
|
+
* group 2: DPs 141-200 (switch 155) — overlaps group 1, so we instead
|
|
91
|
+
* use non-overlapping buckets: group N owns DPs in [101+51*(N-1), 150+51*(N-1)]
|
|
92
|
+
*
|
|
93
|
+
* We also honor dpName entries containing "Valve" as explicit switch DPs
|
|
94
|
+
* (defensive for future firmware that may use a different pattern).
|
|
95
|
+
*
|
|
96
|
+
* Returns the switch DP IDs (ascending) and per-zone names (from dpName when
|
|
97
|
+
* available, else the device name for single-zone, else "Zone N").
|
|
98
|
+
*/
|
|
99
|
+
private detectValveZones;
|
|
100
|
+
private getDeviceType;
|
|
101
|
+
/**
|
|
102
|
+
* Make a Tuya mobile API request.
|
|
103
|
+
*
|
|
104
|
+
* Based on APK decompilation of ThingApiParams.getRequestBody():
|
|
105
|
+
* - HTTP POST to the bare endpoint URL (no query params)
|
|
106
|
+
* - Body is application/x-www-form-urlencoded
|
|
107
|
+
* - postData in the body is the RAW JSON string (not hashed)
|
|
108
|
+
* - postData in the sign string is mobileHash(postData)
|
|
109
|
+
* - The sign covers both URL params and postData (hashed)
|
|
110
|
+
*/
|
|
111
|
+
private request;
|
|
112
|
+
}
|
|
113
|
+
//# sourceMappingURL=RainPointTyClient.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RainPointTyClient.d.ts","sourceRoot":"","sources":["../../src/api/RainPointTyClient.ts"],"names":[],"mappings":"AAKA,OAAO,EACL,eAAe,EACf,qBAAqB,EACrB,MAAM,EACN,gBAAgB,EAChB,sBAAsB,EACtB,cAAc,EAEf,MAAM,4BAA4B,CAAC;AA4PpC,qBAAa,iBAAkB,YAAW,eAAe;IAgBrD,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,GAAG;IAhBb,OAAO,CAAC,GAAG,CAAc;IACzB,OAAO,CAAC,KAAK,CAAc;IAC3B,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,MAAM,CAAC,eAAe,CAAuB;IAIrD,OAAO,CAAC,WAAW,CAA4C;IAC/D,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAgB;IAC5C,OAAO,CAAC,eAAe,CAAS;gBAGtB,MAAM,EAAE,qBAAqB,EAC7B,GAAG,EAAE,MAAM;IAsBrB,uEAAuE;IACvE,OAAO,CAAC,WAAW;IA0BnB,gEAAgE;IAChE,OAAO,CAAC,WAAW;IAkBnB,6EAA6E;IAC7E,OAAO,CAAC,YAAY;IAiBpB,OAAO,CAAC,MAAM,CAAC,mBAAmB;IAS5B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;YAiBd,OAAO;IA0DrB,OAAO,CAAC,oBAAoB;IAkB5B,OAAO,CAAC,eAAe;IAUvB;;;;;;;;;;OAUG;IACH,OAAO,CAAC,sBAAsB;IAoD9B,OAAO,CAAC,iBAAiB;IAenB,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC;IAM1C,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAIvB,QAAQ,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;IA+BrC,UAAU,IAAI,OAAO,CAAC,gBAAgB,EAAE,CAAC;IAwDzC,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,sBAAsB,CAAC,CAAC;IA4EpF,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,eAAe,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAqBnF,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAUhE;;;;OAIG;IACH,OAAO,CAAC,eAAe;IAQvB;;;;;;;;;;;;;;OAcG;IACH,OAAO,CAAC,cAAc;IAatB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA6BG;IACH,OAAO,CAAC,gBAAgB;IAyExB,OAAO,CAAC,aAAa;IAgBrB;;;;;;;;;OASG;YACW,OAAO;CAuOtB"}
|