homebridge-kasa-python 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 +21 -0
- package/README.md +398 -0
- package/config.schema.json +214 -0
- package/dist/accessoryInformation.d.ts +3 -0
- package/dist/accessoryInformation.js +24 -0
- package/dist/accessoryInformation.js.map +1 -0
- package/dist/config.d.ts +186 -0
- package/dist/config.js +154 -0
- package/dist/config.js.map +1 -0
- package/dist/devices/create.d.ts +10 -0
- package/dist/devices/create.js +20 -0
- package/dist/devices/create.js.map +1 -0
- package/dist/devices/deviceManager.d.ts +15 -0
- package/dist/devices/deviceManager.js +157 -0
- package/dist/devices/deviceManager.js.map +1 -0
- package/dist/devices/homekitPlug.d.ts +23 -0
- package/dist/devices/homekitPlug.js +101 -0
- package/dist/devices/homekitPlug.js.map +1 -0
- package/dist/devices/homekitPowerstrip.d.ts +23 -0
- package/dist/devices/homekitPowerstrip.js +103 -0
- package/dist/devices/homekitPowerstrip.js.map +1 -0
- package/dist/devices/index.d.ts +36 -0
- package/dist/devices/index.js +118 -0
- package/dist/devices/index.js.map +1 -0
- package/dist/devices/kasaDevices.d.ts +48 -0
- package/dist/devices/kasaDevices.js +2 -0
- package/dist/devices/kasaDevices.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/platform.d.ts +57 -0
- package/dist/platform.js +182 -0
- package/dist/platform.js.map +1 -0
- package/dist/python/discover.py +38 -0
- package/dist/python/getSysInfo.py +39 -0
- package/dist/python/pythonChecker.d.ts +31 -0
- package/dist/python/pythonChecker.js +195 -0
- package/dist/python/pythonChecker.js.map +1 -0
- package/dist/python/pythonHome.py +3 -0
- package/dist/python/turnOff.py +20 -0
- package/dist/python/turnOffChild.py +22 -0
- package/dist/python/turnOn.py +20 -0
- package/dist/python/turnOnChild.py +22 -0
- package/dist/settings.d.ts +2 -0
- package/dist/settings.js +3 -0
- package/dist/settings.js.map +1 -0
- package/dist/utils.d.ts +30 -0
- package/dist/utils.js +172 -0
- package/dist/utils.js.map +1 -0
- package/package.json +79 -0
- package/requirements.txt +1 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export default function accessoryInformation(hap) {
|
|
2
|
+
const { Characteristic } = hap;
|
|
3
|
+
return (accessory, hkDevice) => {
|
|
4
|
+
const infoService = accessory.getService(hap.Service.AccessoryInformation);
|
|
5
|
+
if (infoService === undefined) {
|
|
6
|
+
return undefined;
|
|
7
|
+
}
|
|
8
|
+
if (!infoService.getCharacteristic(Characteristic.FirmwareRevision)) {
|
|
9
|
+
infoService.addCharacteristic(Characteristic.FirmwareRevision);
|
|
10
|
+
}
|
|
11
|
+
if (!infoService.getCharacteristic(Characteristic.HardwareRevision)) {
|
|
12
|
+
infoService.addCharacteristic(Characteristic.HardwareRevision);
|
|
13
|
+
}
|
|
14
|
+
infoService
|
|
15
|
+
.setCharacteristic(Characteristic.Name, hkDevice.name)
|
|
16
|
+
.setCharacteristic(Characteristic.Manufacturer, hkDevice.manufacturer)
|
|
17
|
+
.setCharacteristic(Characteristic.Model, hkDevice.model)
|
|
18
|
+
.setCharacteristic(Characteristic.SerialNumber, hkDevice.serialNumber)
|
|
19
|
+
.setCharacteristic(Characteristic.FirmwareRevision, hkDevice.firmwareRevision)
|
|
20
|
+
.setCharacteristic(Characteristic.HardwareRevision, hkDevice.hardwareRevision);
|
|
21
|
+
return infoService;
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=accessoryInformation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"accessoryInformation.js","sourceRoot":"","sources":["../src/accessoryInformation.ts"],"names":[],"mappings":"AAGA,MAAM,CAAC,OAAO,UAAU,oBAAoB,CAC1C,GAAQ;IAKR,MAAM,EAAE,cAAc,EAAE,GAAG,GAAG,CAAC;IAE/B,OAAO,CAAC,SAA4B,EAAE,QAAuB,EAAE,EAAE;QAC/D,MAAM,WAAW,GAAG,SAAS,CAAC,UAAU,CAAC,GAAG,CAAC,OAAO,CAAC,oBAAoB,CAAC,CAAC;QAC3E,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;YAC9B,OAAO,SAAS,CAAC;QACnB,CAAC;QAED,IAAI,CAAC,WAAW,CAAC,iBAAiB,CAAC,cAAc,CAAC,gBAAgB,CAAC,EAAE,CAAC;YACpE,WAAW,CAAC,iBAAiB,CAAC,cAAc,CAAC,gBAAgB,CAAC,CAAC;QACjE,CAAC;QACD,IAAI,CAAC,WAAW,CAAC,iBAAiB,CAAC,cAAc,CAAC,gBAAgB,CAAC,EAAE,CAAC;YACpE,WAAW,CAAC,iBAAiB,CAAC,cAAc,CAAC,gBAAgB,CAAC,CAAC;QACjE,CAAC;QACD,WAAW;aACR,iBAAiB,CAAC,cAAc,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,CAAC;aACrD,iBAAiB,CAAC,cAAc,CAAC,YAAY,EAAE,QAAQ,CAAC,YAAY,CAAC;aACrE,iBAAiB,CAAC,cAAc,CAAC,KAAK,EAAE,QAAQ,CAAC,KAAK,CAAC;aACvD,iBAAiB,CAAC,cAAc,CAAC,YAAY,EAAE,QAAQ,CAAC,YAAY,CAAC;aACrE,iBAAiB,CAChB,cAAc,CAAC,gBAAgB,EAC/B,QAAQ,CAAC,gBAAgB,CAC1B;aACA,iBAAiB,CAChB,cAAc,CAAC,gBAAgB,EAC/B,QAAQ,CAAC,gBAAgB,CAC1B,CAAC;QAEJ,OAAO,WAAW,CAAC;IACrB,CAAC,CAAC;AACJ,CAAC"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import { ErrorObject as AjvErrorObject } from 'ajv';
|
|
2
|
+
export declare class ConfigParseError extends Error {
|
|
3
|
+
readonly errors?: AjvErrorObject<string, Record<string, unknown>, unknown>[] | null | undefined;
|
|
4
|
+
readonly unknownError?: unknown | undefined;
|
|
5
|
+
/**
|
|
6
|
+
* Set by `Error.captureStackTrace`
|
|
7
|
+
*/
|
|
8
|
+
readonly stack = "";
|
|
9
|
+
constructor(message: string, errors?: AjvErrorObject<string, Record<string, unknown>, unknown>[] | null | undefined, unknownError?: unknown | undefined);
|
|
10
|
+
}
|
|
11
|
+
export interface DeviceConfigInput {
|
|
12
|
+
host: string;
|
|
13
|
+
port?: number | undefined;
|
|
14
|
+
}
|
|
15
|
+
export interface KasaPythonConfigInput {
|
|
16
|
+
/**
|
|
17
|
+
* Username. If discovering devices is not working, try setting this to your Kasa Cloud Username.
|
|
18
|
+
* This is required for the following devices:
|
|
19
|
+
* EP25
|
|
20
|
+
- Hardware: 2.6 (US) / Firmware: 1.0.1
|
|
21
|
+
- Hardware: 2.6 (US) / Firmware: 1.0.2
|
|
22
|
+
HS100
|
|
23
|
+
- Hardware: 4.1 (UK) / Firmware: 1.1.0
|
|
24
|
+
KP125M
|
|
25
|
+
- Hardware: 1.0 (US) / Firmware: 1.1.3
|
|
26
|
+
HS220
|
|
27
|
+
- Hardware: 3.26 (US) / Firmware: 1.0.1
|
|
28
|
+
KS205
|
|
29
|
+
- Hardware: 1.0 (US) / Firmware: 1.0.2
|
|
30
|
+
- Hardware: 1.0 (US) / Firmware: 1.1.0
|
|
31
|
+
KS225
|
|
32
|
+
- Hardware: 1.0 (US) / Firmware: 1.0.2
|
|
33
|
+
- Hardware: 1.0 (US) / Firmware: 1.1.0
|
|
34
|
+
KS240
|
|
35
|
+
- Hardware: 1.0 (US) / Firmware: 1.0.4
|
|
36
|
+
- Hardware: 1.0 (US) / Firmware: 1.0.5
|
|
37
|
+
KH100
|
|
38
|
+
- Hardware: 1.0 (UK) / Firmware: 1.5.6
|
|
39
|
+
KE100
|
|
40
|
+
- Hardware: 1.0 (EU) / Firmware: 2.4.0
|
|
41
|
+
- Hardware: 1.0 (EU) / Firmware: 2.8.0
|
|
42
|
+
- Hardware: 1.0 (UK) / Firmware: 2.8.0
|
|
43
|
+
* @defaultValue ''
|
|
44
|
+
*/
|
|
45
|
+
username?: string;
|
|
46
|
+
/**
|
|
47
|
+
* Password. If discovering devices is not working, try setting this to your Kasa Cloud Password.
|
|
48
|
+
* This is required for the following devices:
|
|
49
|
+
* EP25
|
|
50
|
+
- Hardware: 2.6 (US) / Firmware: 1.0.1
|
|
51
|
+
- Hardware: 2.6 (US) / Firmware: 1.0.2
|
|
52
|
+
HS100
|
|
53
|
+
- Hardware: 4.1 (UK) / Firmware: 1.1.0
|
|
54
|
+
KP125M
|
|
55
|
+
- Hardware: 1.0 (US) / Firmware: 1.1.3
|
|
56
|
+
HS220
|
|
57
|
+
- Hardware: 3.26 (US) / Firmware: 1.0.1
|
|
58
|
+
KS205
|
|
59
|
+
- Hardware: 1.0 (US) / Firmware: 1.0.2
|
|
60
|
+
- Hardware: 1.0 (US) / Firmware: 1.1.0
|
|
61
|
+
KS225
|
|
62
|
+
- Hardware: 1.0 (US) / Firmware: 1.0.2
|
|
63
|
+
- Hardware: 1.0 (US) / Firmware: 1.1.0
|
|
64
|
+
KS240
|
|
65
|
+
- Hardware: 1.0 (US) / Firmware: 1.0.4
|
|
66
|
+
- Hardware: 1.0 (US) / Firmware: 1.0.5
|
|
67
|
+
KH100
|
|
68
|
+
- Hardware: 1.0 (UK) / Firmware: 1.5.6
|
|
69
|
+
KE100
|
|
70
|
+
- Hardware: 1.0 (EU) / Firmware: 2.4.0
|
|
71
|
+
- Hardware: 1.0 (EU) / Firmware: 2.8.0
|
|
72
|
+
- Hardware: 1.0 (UK) / Firmware: 2.8.0
|
|
73
|
+
* @defaultValue ''
|
|
74
|
+
*/
|
|
75
|
+
password?: string;
|
|
76
|
+
/**
|
|
77
|
+
* Create Multi-Outlet Devices as a Power Strip.
|
|
78
|
+
* Enable to create a single power strip accessory with multiple outlets, used for models HS107, KP200, HS300, KP303, KP400, and EP40.
|
|
79
|
+
* @defaultValue false
|
|
80
|
+
*/
|
|
81
|
+
powerStrip?: boolean;
|
|
82
|
+
/**
|
|
83
|
+
* Port to bind UDP socket for discovery.
|
|
84
|
+
* If port is not specified or is 0, the operating system will attempt to bind to a random port.
|
|
85
|
+
* @defaultValue 0
|
|
86
|
+
*/
|
|
87
|
+
discoveryPort?: number;
|
|
88
|
+
/**
|
|
89
|
+
* Broadcast Address. If discovery is not working, tweak to match your subnet, eg: 192.168.1.255
|
|
90
|
+
* @defaultValue '255.255.255.255'
|
|
91
|
+
*/
|
|
92
|
+
broadcastAddress?: string;
|
|
93
|
+
/**
|
|
94
|
+
* How often to check device status in the background (seconds)
|
|
95
|
+
* @defaultValue 10
|
|
96
|
+
*/
|
|
97
|
+
pollingInterval?: number;
|
|
98
|
+
/**
|
|
99
|
+
* Allow-list of MAC Addresses to include. If specified will ignore other devices.
|
|
100
|
+
* MAC Addresses are normalized, special characters are removed and made uppercase for comparison.
|
|
101
|
+
* Supports glob-style patterns
|
|
102
|
+
*/
|
|
103
|
+
includeMacAddress?: Array<string>;
|
|
104
|
+
/**
|
|
105
|
+
* Deny-list of MAC Addresses to exclude.
|
|
106
|
+
* MAC Addresses are normalized, special characters are removed and made uppercase for comparison.
|
|
107
|
+
* Supports glob-style patterns
|
|
108
|
+
*/
|
|
109
|
+
excludeMacAddresses?: Array<string>;
|
|
110
|
+
/**
|
|
111
|
+
* Manual list of devices Before resorting to manually specifying devices.
|
|
112
|
+
* Try setting the broadcast address and check your router/switch/firewall configuration.
|
|
113
|
+
* You must assign static IP addresses to your devices to use this configuration.
|
|
114
|
+
*/
|
|
115
|
+
devices?: Array<DeviceConfigInput>;
|
|
116
|
+
/**
|
|
117
|
+
* Force Venv Recreation
|
|
118
|
+
* Set this to force to recreate the virtual python environment with the next restart of the plugin.
|
|
119
|
+
* @defaultValue false
|
|
120
|
+
*/
|
|
121
|
+
forceVenvRecreate?: boolean;
|
|
122
|
+
/**
|
|
123
|
+
* Python Executable
|
|
124
|
+
* Here you can specify a path that points to a python executable. The plugin uses the systems default python as default. Setting a
|
|
125
|
+
* specific python executable here may be required if your systems default python version is too current for the plugin.
|
|
126
|
+
*/
|
|
127
|
+
pythonExecutable?: string;
|
|
128
|
+
/**
|
|
129
|
+
* Communication Timeout (seconds)
|
|
130
|
+
* @defaultValue 15
|
|
131
|
+
*/
|
|
132
|
+
timeout?: number;
|
|
133
|
+
/**
|
|
134
|
+
* The time to wait to combine similar commands for a device before sending a command to a device (milliseconds)
|
|
135
|
+
* @defaultValue 100
|
|
136
|
+
*/
|
|
137
|
+
waitTimeUpdate?: number;
|
|
138
|
+
}
|
|
139
|
+
type KasaPythonConfigDefault = {
|
|
140
|
+
username: string;
|
|
141
|
+
password: string;
|
|
142
|
+
powerStrip: boolean;
|
|
143
|
+
discoveryPort: number;
|
|
144
|
+
broadcastAddress: string;
|
|
145
|
+
pollingInterval: number;
|
|
146
|
+
includeMacAddress?: Array<string>;
|
|
147
|
+
excludeMacAddresses?: Array<string>;
|
|
148
|
+
devices?: Array<{
|
|
149
|
+
host: string;
|
|
150
|
+
port?: number | undefined;
|
|
151
|
+
}>;
|
|
152
|
+
forceVenvRecreate: boolean;
|
|
153
|
+
pythonExecutable?: string;
|
|
154
|
+
timeout: number;
|
|
155
|
+
waitTimeUpdate: number;
|
|
156
|
+
};
|
|
157
|
+
export type KasaPythonConfig = {
|
|
158
|
+
username: string;
|
|
159
|
+
password: string;
|
|
160
|
+
forceVenvRecreate: boolean;
|
|
161
|
+
pythonExecutable?: string;
|
|
162
|
+
waitTimeUpdate: number;
|
|
163
|
+
powerStrip: boolean;
|
|
164
|
+
defaultSendOptions: {
|
|
165
|
+
timeout: number;
|
|
166
|
+
};
|
|
167
|
+
discoveryOptions: {
|
|
168
|
+
port: number | undefined;
|
|
169
|
+
broadcastAddress: string;
|
|
170
|
+
pollingInterval: number;
|
|
171
|
+
deviceOptions: {
|
|
172
|
+
defaultSendOptions: {
|
|
173
|
+
timeout: number;
|
|
174
|
+
};
|
|
175
|
+
};
|
|
176
|
+
includeMacAddress?: Array<string>;
|
|
177
|
+
excludeMacAddresses?: Array<string>;
|
|
178
|
+
devices?: Array<{
|
|
179
|
+
host: string;
|
|
180
|
+
port?: number | undefined;
|
|
181
|
+
}>;
|
|
182
|
+
};
|
|
183
|
+
};
|
|
184
|
+
export declare const defaultConfig: KasaPythonConfigDefault;
|
|
185
|
+
export declare function parseConfig(config: Record<string, unknown>): KasaPythonConfig;
|
|
186
|
+
export {};
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import Ajv from 'ajv';
|
|
2
|
+
import addFormats from 'ajv-formats';
|
|
3
|
+
import * as fs from 'fs';
|
|
4
|
+
import defaults from 'lodash.defaults';
|
|
5
|
+
import * as path from 'path';
|
|
6
|
+
import { fileURLToPath } from 'url';
|
|
7
|
+
import { isObjectLike } from './utils.js';
|
|
8
|
+
export class ConfigParseError extends Error {
|
|
9
|
+
errors;
|
|
10
|
+
unknownError;
|
|
11
|
+
/**
|
|
12
|
+
* Set by `Error.captureStackTrace`
|
|
13
|
+
*/
|
|
14
|
+
stack = '';
|
|
15
|
+
constructor(message, errors, unknownError) {
|
|
16
|
+
super(message);
|
|
17
|
+
this.errors = errors;
|
|
18
|
+
this.unknownError = unknownError;
|
|
19
|
+
const errorsAsString = errors !== null && errors !== undefined
|
|
20
|
+
? errors
|
|
21
|
+
.map((e) => {
|
|
22
|
+
let msg = `\`${e.instancePath.replace(/^\//, '')}\` ${e.message}`;
|
|
23
|
+
if ('allowedValues' in e.params) {
|
|
24
|
+
msg += `. Allowed values: ${JSON.stringify(e.params.allowedValues)}`;
|
|
25
|
+
}
|
|
26
|
+
return msg;
|
|
27
|
+
})
|
|
28
|
+
.join('\n')
|
|
29
|
+
: '';
|
|
30
|
+
this.name = 'ConfigParseError';
|
|
31
|
+
if (errorsAsString === '') {
|
|
32
|
+
this.message = message;
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
this.message = `${message}:\n${errorsAsString}`;
|
|
36
|
+
}
|
|
37
|
+
if (unknownError instanceof Error) {
|
|
38
|
+
this.message += `\nAdditional Error: ${unknownError.message}`;
|
|
39
|
+
}
|
|
40
|
+
else if (unknownError) {
|
|
41
|
+
this.message += `\nAdditional Error: [Error details not available: ${unknownError}]`;
|
|
42
|
+
}
|
|
43
|
+
Error.captureStackTrace(this, this.constructor);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
export const defaultConfig = {
|
|
47
|
+
username: '',
|
|
48
|
+
password: '',
|
|
49
|
+
powerStrip: false,
|
|
50
|
+
discoveryPort: 0,
|
|
51
|
+
broadcastAddress: '255.255.255.255',
|
|
52
|
+
pollingInterval: 10,
|
|
53
|
+
includeMacAddress: undefined,
|
|
54
|
+
excludeMacAddresses: undefined,
|
|
55
|
+
devices: undefined,
|
|
56
|
+
forceVenvRecreate: false,
|
|
57
|
+
pythonExecutable: undefined,
|
|
58
|
+
timeout: 15,
|
|
59
|
+
waitTimeUpdate: 100,
|
|
60
|
+
};
|
|
61
|
+
function isArrayOfStrings(value) {
|
|
62
|
+
return (Array.isArray(value) && value.every((item) => typeof item === 'string'));
|
|
63
|
+
}
|
|
64
|
+
function isDeviceConfigInput(value) {
|
|
65
|
+
return (isObjectLike(value) &&
|
|
66
|
+
'host' in value &&
|
|
67
|
+
typeof value.host === 'string' &&
|
|
68
|
+
(!('port' in value) || typeof value.port === 'number'));
|
|
69
|
+
}
|
|
70
|
+
function isArrayOfDeviceConfigInput(value) {
|
|
71
|
+
return (Array.isArray(value) && value.every((item) => isDeviceConfigInput(item)));
|
|
72
|
+
}
|
|
73
|
+
function isKasaPythonConfigInput(c) {
|
|
74
|
+
return (isObjectLike(c) &&
|
|
75
|
+
(!('username' in c) || typeof c.username === 'string') &&
|
|
76
|
+
(!('password' in c) || typeof c.password === 'string') &&
|
|
77
|
+
(!('powerStrip' in c) || typeof c.powerStrip === 'boolean') &&
|
|
78
|
+
(!('discoveryPort' in c) || typeof c.discoveryPort === 'number') &&
|
|
79
|
+
(!('broadcastAddress' in c) || typeof c.broadcastAddress === 'string') &&
|
|
80
|
+
(!('pollingInterval' in c) || typeof c.pollingInterval === 'number') &&
|
|
81
|
+
(!('includeMacAddress' in c) ||
|
|
82
|
+
isArrayOfStrings(c.includeMacAddress) ||
|
|
83
|
+
c.includeMacAddress === undefined) &&
|
|
84
|
+
(!('excludeMacAddresses' in c) ||
|
|
85
|
+
isArrayOfStrings(c.excludeMacAddresses) ||
|
|
86
|
+
c.excludeMacAddresses === undefined) &&
|
|
87
|
+
(!('devices' in c) ||
|
|
88
|
+
isArrayOfDeviceConfigInput(c.devices) ||
|
|
89
|
+
c.devices === undefined) &&
|
|
90
|
+
(!('forceVenvRecreate' in c) || typeof c.forceVenvRecreate === 'boolean') &&
|
|
91
|
+
(!('pythonExecutable' in c) ||
|
|
92
|
+
typeof c.pythonExecutable === 'string' ||
|
|
93
|
+
c.pythonExecutable === undefined) &&
|
|
94
|
+
(!('timeout' in c) || typeof c.timeout === 'number') &&
|
|
95
|
+
(!('waitTimeUpdate' in c) || typeof c.waitTimeUpdate === 'number'));
|
|
96
|
+
}
|
|
97
|
+
export function parseConfig(config) {
|
|
98
|
+
const ajv = new Ajv({ allErrors: true, strict: 'log' });
|
|
99
|
+
addFormats(ajv);
|
|
100
|
+
ajv.addVocabulary([
|
|
101
|
+
'placeholder',
|
|
102
|
+
'titleMap',
|
|
103
|
+
'pluginAlias',
|
|
104
|
+
'pluginType',
|
|
105
|
+
'singular',
|
|
106
|
+
'headerDisplay',
|
|
107
|
+
'footerDisplay',
|
|
108
|
+
'schema',
|
|
109
|
+
'layout',
|
|
110
|
+
]);
|
|
111
|
+
let schema;
|
|
112
|
+
try {
|
|
113
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
114
|
+
const schemaPath = path.join(__dirname, '../config.schema.json');
|
|
115
|
+
const schemaData = fs.readFileSync(schemaPath, 'utf8');
|
|
116
|
+
schema = JSON.parse(schemaData);
|
|
117
|
+
}
|
|
118
|
+
catch (error) {
|
|
119
|
+
throw new ConfigParseError('Error reading schema', undefined, error);
|
|
120
|
+
}
|
|
121
|
+
const validate = ajv.compile(schema);
|
|
122
|
+
const valid = validate(config);
|
|
123
|
+
if (!valid) {
|
|
124
|
+
throw new ConfigParseError('Error parsing config', validate.errors);
|
|
125
|
+
}
|
|
126
|
+
if (!isKasaPythonConfigInput(config)) {
|
|
127
|
+
throw new ConfigParseError('Error parsing config');
|
|
128
|
+
}
|
|
129
|
+
const c = defaults(config, defaultConfig);
|
|
130
|
+
const defaultSendOptions = {
|
|
131
|
+
timeout: c.timeout * 1000,
|
|
132
|
+
};
|
|
133
|
+
return {
|
|
134
|
+
username: c.username,
|
|
135
|
+
password: c.password,
|
|
136
|
+
powerStrip: c.powerStrip,
|
|
137
|
+
forceVenvRecreate: c.forceVenvRecreate,
|
|
138
|
+
pythonExecutable: c.pythonExecutable,
|
|
139
|
+
waitTimeUpdate: c.waitTimeUpdate,
|
|
140
|
+
defaultSendOptions,
|
|
141
|
+
discoveryOptions: {
|
|
142
|
+
port: c.discoveryPort,
|
|
143
|
+
broadcastAddress: c.broadcastAddress,
|
|
144
|
+
pollingInterval: c.pollingInterval * 1000,
|
|
145
|
+
deviceOptions: {
|
|
146
|
+
defaultSendOptions,
|
|
147
|
+
},
|
|
148
|
+
includeMacAddress: c.includeMacAddress,
|
|
149
|
+
excludeMacAddresses: c.excludeMacAddresses,
|
|
150
|
+
devices: c.devices,
|
|
151
|
+
},
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { PlatformAccessory } from 'homebridge';
|
|
2
|
+
import { KasaPythonConfig } from '../config.js';
|
|
3
|
+
import type KasaPythonPlatform from '../platform.js';
|
|
4
|
+
import type { KasaPythonAccessoryContext } from '../platform.js';
|
|
5
|
+
import type { KasaDevice } from '../utils.js';
|
|
6
|
+
import HomekitDevice from './index.js';
|
|
7
|
+
/**
|
|
8
|
+
* Factory method to create a HomeKitDevicePlug or HomeKitDevicePowerstrip.
|
|
9
|
+
*/
|
|
10
|
+
export default function create(platform: KasaPythonPlatform, config: KasaPythonConfig, homebridgeAccessory: PlatformAccessory<KasaPythonAccessoryContext> | undefined, KasaDevice: KasaDevice): HomekitDevice | undefined;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import HomeKitDevicePlug from './homekitPlug.js';
|
|
2
|
+
import HomeKitDevicePowerStrip from './homekitPowerstrip.js';
|
|
3
|
+
function isPlug(device) {
|
|
4
|
+
return 'children' in device && Array.isArray(device.children) && device.children.length === 0;
|
|
5
|
+
}
|
|
6
|
+
function isPowerStrip(device) {
|
|
7
|
+
return device.sys_info.child_num !== undefined && device.sys_info.child_num > 1 && Array.isArray(device.sys_info.children);
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Factory method to create a HomeKitDevicePlug or HomeKitDevicePowerstrip.
|
|
11
|
+
*/
|
|
12
|
+
export default function create(platform, config, homebridgeAccessory, KasaDevice) {
|
|
13
|
+
if (isPowerStrip(KasaDevice)) {
|
|
14
|
+
return new HomeKitDevicePowerStrip(platform, config, homebridgeAccessory, KasaDevice, KasaDevice.device_config);
|
|
15
|
+
}
|
|
16
|
+
else if (isPlug(KasaDevice)) {
|
|
17
|
+
return new HomeKitDevicePlug(platform, config, homebridgeAccessory, KasaDevice, KasaDevice.device_config);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=create.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create.js","sourceRoot":"","sources":["../../src/devices/create.ts"],"names":[],"mappings":"AAQA,OAAO,iBAAiB,MAAM,kBAAkB,CAAC;AACjD,OAAO,uBAAuB,MAAM,wBAAwB,CAAC;AAG7D,SAAS,MAAM,CAAC,MAAkB;IAChC,OAAO,UAAU,IAAI,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,CAAC;AAChG,CAAC;AAED,SAAS,YAAY,CAAC,MAAkB;IACtC,OAAO,MAAM,CAAC,QAAQ,CAAC,SAAS,KAAK,SAAS,IAAI,MAAM,CAAC,QAAQ,CAAC,SAAS,GAAG,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;AAC7H,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,OAAO,UAAU,MAAM,CAC5B,QAA4B,EAC5B,MAAwB,EACxB,mBAA8E,EAC9E,UAAsB;IAEtB,IAAI,YAAY,CAAC,UAAU,CAAC,EAAE,CAAC;QAC7B,OAAO,IAAI,uBAAuB,CAChC,QAAQ,EACR,MAAM,EACN,mBAAmB,EACnB,UAAU,EACV,UAAU,CAAC,aAAa,CACzB,CAAC;IACJ,CAAC;SAAM,IAAI,MAAM,CAAC,UAAU,CAAC,EAAE,CAAC;QAC9B,OAAO,IAAI,iBAAiB,CAC1B,QAAQ,EACR,MAAM,EACN,mBAAmB,EACnB,UAAU,EACV,UAAU,CAAC,aAAa,CACzB,CAAC;IACJ,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import KasaPythonPlatform from '../platform.js';
|
|
2
|
+
import { KasaDevice } from '../utils.js';
|
|
3
|
+
import HomekitDevice from './index.js';
|
|
4
|
+
export default class DeviceManager {
|
|
5
|
+
private log;
|
|
6
|
+
private platform;
|
|
7
|
+
constructor(platform: KasaPythonPlatform);
|
|
8
|
+
private executePythonScript;
|
|
9
|
+
discoverDevices(): Promise<void>;
|
|
10
|
+
getSysInfo(device: HomekitDevice): Promise<KasaDevice | undefined>;
|
|
11
|
+
turnOn(device: HomekitDevice): Promise<void>;
|
|
12
|
+
turnOff(device: HomekitDevice): Promise<void>;
|
|
13
|
+
turnOnChild(device: HomekitDevice, child_num: number): Promise<void>;
|
|
14
|
+
turnOffChild(device: HomekitDevice, child_num: number): Promise<void>;
|
|
15
|
+
}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
import * as util from 'util';
|
|
3
|
+
import { runCommand } from '../utils.js';
|
|
4
|
+
const readFileAsync = util.promisify(fs.readFile);
|
|
5
|
+
export default class DeviceManager {
|
|
6
|
+
log;
|
|
7
|
+
platform;
|
|
8
|
+
constructor(platform) {
|
|
9
|
+
this.log = platform.log;
|
|
10
|
+
this.platform = platform;
|
|
11
|
+
}
|
|
12
|
+
async executePythonScript(scriptName, deviceId, deviceConfigJson, childNumber, outputToFile) {
|
|
13
|
+
const scriptPath = `${this.platform.storagePath}/node_modules/homebridge-kasa-python/dist/python/${scriptName}.py`;
|
|
14
|
+
const args = [scriptPath];
|
|
15
|
+
if (deviceConfigJson) {
|
|
16
|
+
args.push(deviceConfigJson);
|
|
17
|
+
}
|
|
18
|
+
if (childNumber) {
|
|
19
|
+
args.push(childNumber);
|
|
20
|
+
}
|
|
21
|
+
if (outputToFile) {
|
|
22
|
+
const outputFileName = deviceId ? `${deviceId}_${scriptName}_output.json` : `${scriptName}_output.json`;
|
|
23
|
+
args.push(`> ${this.platform.storagePath}/kasa-python/${outputFileName}`);
|
|
24
|
+
}
|
|
25
|
+
return await runCommand(this.log, this.platform.venvPythonExecutable, args);
|
|
26
|
+
}
|
|
27
|
+
async discoverDevices() {
|
|
28
|
+
this.log.info('Discovering devices...');
|
|
29
|
+
try {
|
|
30
|
+
const [stdout, stderr, exitCode] = await this.executePythonScript('discover', undefined, undefined, undefined, true);
|
|
31
|
+
const outputPath = `${this.platform.storagePath}/kasa-python/discover_output.json`;
|
|
32
|
+
if (exitCode !== 0) {
|
|
33
|
+
this.log.error(`Error executing discovery script: ${stderr}. Output: ${stdout}`);
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
if (fs.existsSync(outputPath)) {
|
|
37
|
+
try {
|
|
38
|
+
const data = await readFileAsync(outputPath, 'utf8');
|
|
39
|
+
const devices = JSON.parse(data);
|
|
40
|
+
let index = 0;
|
|
41
|
+
Object.keys(devices).forEach(ip => {
|
|
42
|
+
const device = devices[ip].device_info;
|
|
43
|
+
device.device_config = devices[ip].device_config;
|
|
44
|
+
this.platform.foundDevice(device);
|
|
45
|
+
index += 1;
|
|
46
|
+
});
|
|
47
|
+
this.log.info('Discovered %d devices.', index);
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
this.log.error(`An error occurred during device discovery: ${error}`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
this.log.error(`Discovery script did not output to ${outputPath}`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
this.log.error(`An error occurred during device discovery: ${error}`);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
async getSysInfo(device) {
|
|
62
|
+
this.log.info('Getting system info for device: %s', device.name);
|
|
63
|
+
try {
|
|
64
|
+
const deviceConfigJson = `'${JSON.stringify(device.deviceConfig)}'`;
|
|
65
|
+
const [stdout, stderr, exitCode] = await this.executePythonScript('getSysInfo', device.id, deviceConfigJson, undefined, true);
|
|
66
|
+
const outputPath = `${this.platform.storagePath}/kasa-python/${device.id}_getSysInfo_output.json`;
|
|
67
|
+
if (exitCode !== 0) {
|
|
68
|
+
this.log.error(`Error executing getSysInfo script: ${stderr}. Output: ${stdout}`);
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
if (fs.existsSync(outputPath)) {
|
|
72
|
+
try {
|
|
73
|
+
const data = await readFileAsync(outputPath, 'utf8');
|
|
74
|
+
const device_info = JSON.parse(data);
|
|
75
|
+
const new_device = device_info.device_info;
|
|
76
|
+
return new_device;
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
this.log.error(`An error occurred during device getSysInfo: ${error}`);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
this.log.error(`GetSysInfo script did not output to ${outputPath}`);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
catch (error) {
|
|
87
|
+
this.log.error(`An error occurred during device getSysInfo: ${error}`);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
async turnOn(device) {
|
|
91
|
+
this.log.info('Turning on device: %s', device.name);
|
|
92
|
+
try {
|
|
93
|
+
const deviceConfigJson = JSON.stringify(device.deviceConfig);
|
|
94
|
+
const [stdout, stderr, exitCode] = await this.executePythonScript('turnOn', undefined, deviceConfigJson);
|
|
95
|
+
if (exitCode !== 0) {
|
|
96
|
+
this.log.error(`Error executing turnOn script: ${stderr}`);
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
const state = JSON.parse(stdout);
|
|
100
|
+
this.log.debug('Device %s turnOn is %s', device.name, state);
|
|
101
|
+
}
|
|
102
|
+
catch (error) {
|
|
103
|
+
this.log.error('An error occurred turning on device %s: %s', device.name, error);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
async turnOff(device) {
|
|
107
|
+
this.log.info('Turning off device: %s', device.name);
|
|
108
|
+
try {
|
|
109
|
+
const deviceConfigJson = JSON.stringify(device.deviceConfig);
|
|
110
|
+
const [stdout, stderr, exitCode] = await this.executePythonScript('turnOff', undefined, deviceConfigJson);
|
|
111
|
+
if (exitCode !== 0) {
|
|
112
|
+
this.log.error(`Error executing turnOff script: ${stderr}`);
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
const state = JSON.parse(stdout);
|
|
116
|
+
this.log.debug('Device %s turnOff is %s', device.name, state);
|
|
117
|
+
}
|
|
118
|
+
catch (error) {
|
|
119
|
+
this.log.error('An error occurred turning off device %s: %s', device.name, error);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
async turnOnChild(device, child_num) {
|
|
123
|
+
this.log.info('Turning on device %s: child %s', device.name, child_num);
|
|
124
|
+
try {
|
|
125
|
+
const childNumberJson = JSON.stringify(child_num);
|
|
126
|
+
const deviceConfigJson = JSON.stringify(device.deviceConfig);
|
|
127
|
+
const [stdout, stderr, exitCode] = await this.executePythonScript('turnOnChild', undefined, deviceConfigJson, childNumberJson);
|
|
128
|
+
if (exitCode !== 0) {
|
|
129
|
+
this.log.error(`Error executing turnOnChild script: ${stderr}`);
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
const state = JSON.parse(stdout);
|
|
133
|
+
this.log.debug('Device %s Child %s turnOn is %s', device.name, child_num, state);
|
|
134
|
+
}
|
|
135
|
+
catch (error) {
|
|
136
|
+
this.log.error('An error occurred turning on device %s child %s: %s', device.name, child_num, error);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
async turnOffChild(device, child_num) {
|
|
140
|
+
this.log.info('Turning off device %s: child %s', device.name, child_num);
|
|
141
|
+
try {
|
|
142
|
+
const childNumberJson = JSON.stringify(child_num);
|
|
143
|
+
const deviceConfigJson = JSON.stringify(device.deviceConfig);
|
|
144
|
+
const [stdout, stderr, exitCode] = await this.executePythonScript('turnOffChild', undefined, deviceConfigJson, childNumberJson);
|
|
145
|
+
if (exitCode !== 0) {
|
|
146
|
+
this.log.error(`Error executing turnOffChild script: ${stderr}`);
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
const state = JSON.parse(stdout);
|
|
150
|
+
this.log.debug('Device %s Child %s turnOff is %s', device.name, child_num, state);
|
|
151
|
+
}
|
|
152
|
+
catch (error) {
|
|
153
|
+
this.log.error('An error occurred turning off device %s child %s: %s', device.name, child_num, error);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
//# sourceMappingURL=deviceManager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deviceManager.js","sourceRoot":"","sources":["../../src/devices/deviceManager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { PlatformAccessory } from 'homebridge';
|
|
2
|
+
import HomekitDevice from './index.js';
|
|
3
|
+
import { KasaPythonConfig } from '../config.js';
|
|
4
|
+
import DeviceManager from './deviceManager.js';
|
|
5
|
+
import type KasaPythonPlatform from '../platform.js';
|
|
6
|
+
import type { KasaPythonAccessoryContext } from '../platform.js';
|
|
7
|
+
import type { DeviceConfig, Plug } from './kasaDevices.js';
|
|
8
|
+
export default class HomeKitDevicePlug extends HomekitDevice {
|
|
9
|
+
readonly config: KasaPythonConfig;
|
|
10
|
+
readonly kasaDevice: Plug;
|
|
11
|
+
readonly deviceConfig: DeviceConfig;
|
|
12
|
+
constructor(platform: KasaPythonPlatform, config: KasaPythonConfig, homebridgeAccessory: PlatformAccessory<KasaPythonAccessoryContext> | undefined, kasaDevice: Plug, deviceConfig: DeviceConfig, deviceManager?: DeviceManager);
|
|
13
|
+
/**
|
|
14
|
+
* Aggregates getSysInfo requests
|
|
15
|
+
*
|
|
16
|
+
* @private
|
|
17
|
+
*/
|
|
18
|
+
private getSysInfo;
|
|
19
|
+
private addOutletService;
|
|
20
|
+
private addOnCharacteristic;
|
|
21
|
+
private addOutletInUseCharacteristic;
|
|
22
|
+
identify(): void;
|
|
23
|
+
}
|