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
package/dist/platform.js
ADDED
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { promises as fs } from 'fs';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import { satisfies } from 'semver';
|
|
5
|
+
import { fileURLToPath } from 'url';
|
|
6
|
+
import { parseConfig } from './config.js';
|
|
7
|
+
import { PLATFORM_NAME, PLUGIN_NAME } from './settings.js';
|
|
8
|
+
import { lookup, lookupCharacteristicNameByUUID, isObjectLike } from './utils.js';
|
|
9
|
+
import create from './devices/create.js';
|
|
10
|
+
import DeviceManager from './devices/deviceManager.js';
|
|
11
|
+
import PythonChecker from './python/pythonChecker.js';
|
|
12
|
+
let packageConfig;
|
|
13
|
+
try {
|
|
14
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
15
|
+
const packageConfigPath = path.join(__dirname, '..', 'package.json');
|
|
16
|
+
const packageConfigData = await fs.readFile(packageConfigPath, 'utf8');
|
|
17
|
+
packageConfig = JSON.parse(packageConfigData);
|
|
18
|
+
}
|
|
19
|
+
catch (error) {
|
|
20
|
+
// eslint-disable-next-line no-console
|
|
21
|
+
console.error('Error reading package.json: %s', error);
|
|
22
|
+
}
|
|
23
|
+
export default class KasaPythonPlatform {
|
|
24
|
+
log;
|
|
25
|
+
api;
|
|
26
|
+
Service;
|
|
27
|
+
Characteristic;
|
|
28
|
+
config;
|
|
29
|
+
configuredAccessories = new Map();
|
|
30
|
+
homekitDevicesById = new Map();
|
|
31
|
+
storagePath;
|
|
32
|
+
venvPythonExecutable;
|
|
33
|
+
deviceManager;
|
|
34
|
+
constructor(log, config, api) {
|
|
35
|
+
this.log = log;
|
|
36
|
+
this.api = api;
|
|
37
|
+
this.api = api;
|
|
38
|
+
this.storagePath = this.api.user.storagePath();
|
|
39
|
+
this.venvPythonExecutable = path.join(this.storagePath, 'kasa-python', '.venv', 'bin', 'python3');
|
|
40
|
+
this.deviceManager = new DeviceManager(this);
|
|
41
|
+
this.log.info('%s v%s, node %s, homebridge v%s, api v%s Initializing...', packageConfig.name, packageConfig.version, process.version, this.api.serverVersion, this.api.version);
|
|
42
|
+
if (!satisfies(process.version, packageConfig.engines.node)) {
|
|
43
|
+
this.log.error('Error: not using minimum node version %s', packageConfig.engines.node);
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
this.log.debug('Using minimum node version or better: %s', packageConfig.engines.node);
|
|
47
|
+
}
|
|
48
|
+
if (this.api.versionGreaterOrEqual === null ||
|
|
49
|
+
!this.api.versionGreaterOrEqual('1.8.3')) {
|
|
50
|
+
this.log.error(`homebridge-kasa-python requires homebridge >= 1.8.3. Currently running: ${this.api.serverVersion}`);
|
|
51
|
+
throw new Error(`homebridge-kasa-python requires homebridge >= 1.8.3. Currently running: ${this.api.serverVersion}`);
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
this.log.debug('Using minimum homebridge version or better: %s', this.api.serverVersion);
|
|
55
|
+
}
|
|
56
|
+
this.Service = this.api.hap.Service;
|
|
57
|
+
this.Characteristic = this.api.hap.Characteristic;
|
|
58
|
+
this.log.debug('config.json: %j', config);
|
|
59
|
+
this.config = parseConfig(config);
|
|
60
|
+
this.log.debug('config: %j', this.config);
|
|
61
|
+
this.log.info('%s v%s, node %s, homebridge v%s, api v%s Finished Initializing.', packageConfig.name, packageConfig.version, process.version, this.api.serverVersion, this.api.version);
|
|
62
|
+
this.api.on('didFinishLaunching', async () => {
|
|
63
|
+
this.log.info('Did Finish Launching Event Received');
|
|
64
|
+
try {
|
|
65
|
+
await this.checkPython().catch(error => {
|
|
66
|
+
this.log.error('Error checking python environment: %s', error);
|
|
67
|
+
});
|
|
68
|
+
await this.deviceManager.discoverDevices().catch(error => {
|
|
69
|
+
this.log.error('Error discovering devices: %s', error);
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
catch (error) {
|
|
73
|
+
this.log.error('An error occurred during startup: %s', error);
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Function invoked when checking python environment.
|
|
79
|
+
*/
|
|
80
|
+
async checkPython() {
|
|
81
|
+
this.log.info('Executing Python Checker...');
|
|
82
|
+
await new PythonChecker(this, this.storagePath, this.config.pythonExecutable)
|
|
83
|
+
.allInOne(this.config.forceVenvRecreate).catch((error) => {
|
|
84
|
+
this.log.error('Error checking python environment: %s', error);
|
|
85
|
+
});
|
|
86
|
+
this.log.info('Python Checker finished, environment is ready.');
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Return string representation of Service/Characteristic for logging
|
|
90
|
+
*
|
|
91
|
+
* @internal
|
|
92
|
+
*/
|
|
93
|
+
lsc(serviceOrCharacteristic, characteristic) {
|
|
94
|
+
let serviceName;
|
|
95
|
+
let characteristicName;
|
|
96
|
+
if (serviceOrCharacteristic instanceof this.api.hap.Service) {
|
|
97
|
+
serviceName = this.getServiceName(serviceOrCharacteristic);
|
|
98
|
+
}
|
|
99
|
+
else if (serviceOrCharacteristic instanceof this.api.hap.Characteristic ||
|
|
100
|
+
('UUID' in serviceOrCharacteristic &&
|
|
101
|
+
typeof serviceOrCharacteristic.UUID === 'string')) {
|
|
102
|
+
characteristicName = this.getCharacteristicName(serviceOrCharacteristic);
|
|
103
|
+
}
|
|
104
|
+
if (characteristic instanceof this.api.hap.Characteristic) {
|
|
105
|
+
characteristicName = this.getCharacteristicName(characteristic);
|
|
106
|
+
}
|
|
107
|
+
if (serviceName !== null && characteristicName !== null) {
|
|
108
|
+
return `[${chalk.yellow(serviceName)}.${chalk.green(characteristicName)}]`;
|
|
109
|
+
}
|
|
110
|
+
if (serviceName !== undefined) {
|
|
111
|
+
return `[${chalk.yellow(serviceName)}]`;
|
|
112
|
+
}
|
|
113
|
+
return `[${chalk.green(characteristicName)}]`;
|
|
114
|
+
}
|
|
115
|
+
createHomekitDevice(accessory, kasaDevice) {
|
|
116
|
+
return create(this, this.config, accessory, kasaDevice);
|
|
117
|
+
}
|
|
118
|
+
getCategoryName(category) {
|
|
119
|
+
// @ts-expect-error: this should work
|
|
120
|
+
return this.api.hap.Accessory.Categories[category];
|
|
121
|
+
}
|
|
122
|
+
getServiceName(service) {
|
|
123
|
+
return lookup(this.api.hap.Service, (thisKeyValue, value) => isObjectLike(thisKeyValue) &&
|
|
124
|
+
'UUID' in thisKeyValue &&
|
|
125
|
+
thisKeyValue.UUID === value, service.UUID);
|
|
126
|
+
}
|
|
127
|
+
getCharacteristicName(characteristic) {
|
|
128
|
+
if ('name' in characteristic && characteristic.name !== undefined) {
|
|
129
|
+
return characteristic.name;
|
|
130
|
+
}
|
|
131
|
+
if ('displayName' in characteristic &&
|
|
132
|
+
characteristic.displayName !== undefined) {
|
|
133
|
+
return characteristic.displayName;
|
|
134
|
+
}
|
|
135
|
+
if ('UUID' in characteristic) {
|
|
136
|
+
return lookupCharacteristicNameByUUID(this.api.hap.Characteristic, characteristic.UUID);
|
|
137
|
+
}
|
|
138
|
+
return undefined;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Registers a Homebridge PlatformAccessory.
|
|
142
|
+
*
|
|
143
|
+
* Calls {@link external:homebridge.API#registerPlatformAccessories}
|
|
144
|
+
*/
|
|
145
|
+
registerPlatformAccessory(platformAccessory) {
|
|
146
|
+
this.log.debug(`registerPlatformAccessory(${chalk.blue(`[${platformAccessory.displayName}]`)})`);
|
|
147
|
+
this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [
|
|
148
|
+
platformAccessory,
|
|
149
|
+
]);
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Function invoked when homebridge tries to restore cached accessory
|
|
153
|
+
*/
|
|
154
|
+
configureAccessory(accessory) {
|
|
155
|
+
this.log.info(`Configuring cached accessory: ${chalk.blue(`[${accessory.displayName}]`)} UUID: ${accessory.UUID} deviceId: %s `, accessory.context?.deviceId);
|
|
156
|
+
this.log.debug('%O', accessory.context);
|
|
157
|
+
this.configuredAccessories.set(accessory.UUID, accessory);
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Adds a new device.
|
|
161
|
+
*/
|
|
162
|
+
foundDevice(device) {
|
|
163
|
+
const deviceId = device.sys_info.deviceId;
|
|
164
|
+
const deviceAlias = device.alias;
|
|
165
|
+
const deviceHost = device.host;
|
|
166
|
+
const deviceType = device.sys_info.mic_type;
|
|
167
|
+
if (deviceId === null || deviceId.length === 0) {
|
|
168
|
+
this.log.error('Missing deviceId: %s', deviceHost);
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
if (this.homekitDevicesById.get(deviceId) !== undefined) {
|
|
172
|
+
this.log.info(`Device already added: ${chalk.blue(`[${deviceAlias}]`)} %s [%s]`, deviceType, deviceId);
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
this.log.info(`Adding: ${chalk.blue(`[${deviceAlias}]`)} %s [%s]`, deviceType, deviceId);
|
|
176
|
+
this.log.info('Generating UUID for device: %s', deviceId);
|
|
177
|
+
const uuid = this.api.hap.uuid.generate(deviceId);
|
|
178
|
+
const accessory = this.configuredAccessories.get(uuid);
|
|
179
|
+
this.homekitDevicesById.set(deviceId, this.createHomekitDevice(accessory, device));
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
//# sourceMappingURL=platform.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"platform.js","sourceRoot":"","sources":["../src/platform.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
from kasa import Discover
|
|
3
|
+
import json
|
|
4
|
+
|
|
5
|
+
def custom_device_serializer(device):
|
|
6
|
+
device_info = {}
|
|
7
|
+
for attr in dir(device):
|
|
8
|
+
if not attr.startswith("_") and not callable(getattr(device, attr)):
|
|
9
|
+
try:
|
|
10
|
+
json.dumps(getattr(device, attr))
|
|
11
|
+
device_info[attr] = getattr(device, attr)
|
|
12
|
+
except TypeError:
|
|
13
|
+
continue
|
|
14
|
+
return device_info
|
|
15
|
+
|
|
16
|
+
async def discover_devices():
|
|
17
|
+
devices = await Discover.discover()
|
|
18
|
+
all_device_info = {}
|
|
19
|
+
for ip, dev in devices.items():
|
|
20
|
+
dev = await Discover.discover_single(ip)
|
|
21
|
+
await dev.update()
|
|
22
|
+
|
|
23
|
+
device_info = custom_device_serializer(dev)
|
|
24
|
+
device_config = dev.config.to_dict()
|
|
25
|
+
|
|
26
|
+
all_device_info[f"{ip}"] = {
|
|
27
|
+
"device_info": device_info,
|
|
28
|
+
"device_config": device_config
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
try:
|
|
32
|
+
json_data = json.dumps(all_device_info, indent=4)
|
|
33
|
+
print(json_data)
|
|
34
|
+
except TypeError as e:
|
|
35
|
+
print(f"Error serializing device information: {e}")
|
|
36
|
+
|
|
37
|
+
if __name__ == "__main__":
|
|
38
|
+
asyncio.run(discover_devices())
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
from kasa import Device
|
|
3
|
+
import json
|
|
4
|
+
import sys
|
|
5
|
+
|
|
6
|
+
def custom_device_serializer(device):
|
|
7
|
+
device_info = {}
|
|
8
|
+
for attr in dir(device):
|
|
9
|
+
if not attr.startswith("_") and not callable(getattr(device, attr)):
|
|
10
|
+
try:
|
|
11
|
+
json.dumps(getattr(device, attr))
|
|
12
|
+
device_info[attr] = getattr(device, attr)
|
|
13
|
+
except TypeError:
|
|
14
|
+
continue
|
|
15
|
+
return device_info
|
|
16
|
+
|
|
17
|
+
async def get_sys_info(device_config):
|
|
18
|
+
try:
|
|
19
|
+
dev = await Device.connect(config=Device.Config.from_dict(device_config))
|
|
20
|
+
await dev.update()
|
|
21
|
+
all_device_info = {}
|
|
22
|
+
|
|
23
|
+
device_info = custom_device_serializer(dev)
|
|
24
|
+
|
|
25
|
+
all_device_info = {
|
|
26
|
+
"device_info": device_info,
|
|
27
|
+
}
|
|
28
|
+
await dev.disconnect()
|
|
29
|
+
|
|
30
|
+
json_data = json.dumps(all_device_info, indent=4)
|
|
31
|
+
print(json_data)
|
|
32
|
+
except TypeError as e:
|
|
33
|
+
print(f"Error serializing device information: {e}")
|
|
34
|
+
|
|
35
|
+
if __name__ == "__main__":
|
|
36
|
+
device_config_json = sys.argv[1].strip("'")
|
|
37
|
+
device_config = json.loads(device_config_json)
|
|
38
|
+
|
|
39
|
+
asyncio.run(get_sys_info(device_config))
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type KasaPythonPlatform from '../platform.js';
|
|
2
|
+
declare class PythonChecker {
|
|
3
|
+
private readonly log;
|
|
4
|
+
private readonly platform;
|
|
5
|
+
private readonly pythonExecutable;
|
|
6
|
+
private readonly pluginDirPath;
|
|
7
|
+
private readonly venvPath;
|
|
8
|
+
private readonly venvPipExecutable;
|
|
9
|
+
private readonly venvPythonExecutable;
|
|
10
|
+
private readonly venvConfigPath;
|
|
11
|
+
private readonly requirementsPath;
|
|
12
|
+
constructor(platform: KasaPythonPlatform, storagePath: string, pythonExecutable?: string);
|
|
13
|
+
allInOne(forceVenvRecreate?: boolean): Promise<void>;
|
|
14
|
+
private ensurePluginDir;
|
|
15
|
+
private ensurePythonVersion;
|
|
16
|
+
private ensureVenvCreated;
|
|
17
|
+
private isVenvCreated;
|
|
18
|
+
private createVenv;
|
|
19
|
+
private ensureVenvUsesCorrectPythonHome;
|
|
20
|
+
private getPythonHome;
|
|
21
|
+
private ensureVenvPipUpToDate;
|
|
22
|
+
private updatePip;
|
|
23
|
+
private ensureVenvRequirementsSatisfied;
|
|
24
|
+
private areRequirementsSatisfied;
|
|
25
|
+
private freezeStringToObject;
|
|
26
|
+
private installRequirements;
|
|
27
|
+
private getSystemPythonVersion;
|
|
28
|
+
private getVenvPipVersion;
|
|
29
|
+
private getMostRecentPipVersion;
|
|
30
|
+
}
|
|
31
|
+
export default PythonChecker;
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import axios from 'axios';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import fs from 'fs';
|
|
4
|
+
import * as path from 'path';
|
|
5
|
+
import { fileURLToPath } from 'url';
|
|
6
|
+
import { delay, prefixLogger, runCommand } from '../utils.js';
|
|
7
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
8
|
+
const SUPPORTED_PYTHON_VERSIONS = [
|
|
9
|
+
'3.9',
|
|
10
|
+
'3.10',
|
|
11
|
+
'3.11',
|
|
12
|
+
'3.12',
|
|
13
|
+
];
|
|
14
|
+
class PythonChecker {
|
|
15
|
+
log;
|
|
16
|
+
platform;
|
|
17
|
+
pythonExecutable;
|
|
18
|
+
pluginDirPath;
|
|
19
|
+
venvPath;
|
|
20
|
+
venvPipExecutable;
|
|
21
|
+
venvPythonExecutable;
|
|
22
|
+
venvConfigPath;
|
|
23
|
+
requirementsPath = path.join(__dirname, '..', '..', 'requirements.txt');
|
|
24
|
+
constructor(platform, storagePath, pythonExecutable) {
|
|
25
|
+
this.platform = platform;
|
|
26
|
+
this.log = prefixLogger(this.platform.log, () => `${chalk.blue('[Python Check]')}`);
|
|
27
|
+
this.pythonExecutable = pythonExecutable || 'python3';
|
|
28
|
+
this.log.debug(`Using ${this.pythonExecutable} as the python executable`);
|
|
29
|
+
this.pluginDirPath = path.join(storagePath, 'kasa-python');
|
|
30
|
+
this.venvPath = path.join(this.pluginDirPath, '.venv');
|
|
31
|
+
this.venvPythonExecutable = path.join(this.venvPath, 'bin', 'python3');
|
|
32
|
+
this.venvPipExecutable = path.join(this.venvPath, 'bin', 'pip3');
|
|
33
|
+
this.venvConfigPath = path.join(this.venvPath, 'pyvenv.cfg');
|
|
34
|
+
}
|
|
35
|
+
async allInOne(forceVenvRecreate = false) {
|
|
36
|
+
this.log.info('Starting python evironment check...');
|
|
37
|
+
this.ensurePluginDir();
|
|
38
|
+
await this.ensurePythonVersion();
|
|
39
|
+
await this.ensureVenvCreated(forceVenvRecreate);
|
|
40
|
+
await this.ensureVenvUsesCorrectPythonHome();
|
|
41
|
+
await this.ensureVenvPipUpToDate();
|
|
42
|
+
await this.ensureVenvRequirementsSatisfied();
|
|
43
|
+
this.log.info('Finished python environment check.');
|
|
44
|
+
}
|
|
45
|
+
ensurePluginDir() {
|
|
46
|
+
this.log.debug('Checking if plugin directory exists...');
|
|
47
|
+
if (!fs.existsSync(this.pluginDirPath)) {
|
|
48
|
+
this.log.debug('Plugin directory does not exist, Creating plugin dir...');
|
|
49
|
+
fs.mkdirSync(this.pluginDirPath);
|
|
50
|
+
this.log.debug('Plugin directory created. Continuing...');
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
this.log.debug('Plugin directory already exists. Continuing...');
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
async ensurePythonVersion() {
|
|
57
|
+
this.log.debug('Getting python version...');
|
|
58
|
+
const version = await this.getSystemPythonVersion();
|
|
59
|
+
if (SUPPORTED_PYTHON_VERSIONS.findIndex((e) => version.includes(e)) === -1) {
|
|
60
|
+
while (true) {
|
|
61
|
+
this.log.error(`Python ${version} is installed. However, only Python \
|
|
62
|
+
${SUPPORTED_PYTHON_VERSIONS[0]} to ${SUPPORTED_PYTHON_VERSIONS[SUPPORTED_PYTHON_VERSIONS.length - 1]} is supported.`);
|
|
63
|
+
await delay(300000);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
this.log.debug(`Python ${version} is installed and supported by the plugin. Continuing...`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
async ensureVenvCreated(forceVenvRecreate) {
|
|
71
|
+
this.log.debug('Checking if python virtual environment exists...');
|
|
72
|
+
if (forceVenvRecreate) {
|
|
73
|
+
this.log.warn('Python virtual environment is being force recreated...');
|
|
74
|
+
await this.createVenv();
|
|
75
|
+
}
|
|
76
|
+
else if (this.isVenvCreated() === false) {
|
|
77
|
+
this.log.info('Python virtual environment does not exist. Creating now...');
|
|
78
|
+
await this.createVenv();
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
this.log.info('Python virtual environment already exists. Continuing...');
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
isVenvCreated() {
|
|
85
|
+
return fs.existsSync(this.venvPipExecutable) &&
|
|
86
|
+
fs.existsSync(this.venvConfigPath) &&
|
|
87
|
+
fs.existsSync(this.venvPythonExecutable);
|
|
88
|
+
}
|
|
89
|
+
async createVenv() {
|
|
90
|
+
const [stdout] = await runCommand(this.log, this.pythonExecutable, ['-m', 'venv', this.venvPath, '--clear'], undefined, true);
|
|
91
|
+
if (stdout.includes('not created successfully') || !this.isVenvCreated()) {
|
|
92
|
+
while (true) {
|
|
93
|
+
this.log.error('virtualenv python module is not installed. If you have installed homebridge via the apt package manager, \
|
|
94
|
+
update the homebridge apt package to 1.1.4 or above (this applies for installations based on the Raspberry Pi OS iamge as well). \
|
|
95
|
+
When using the official docker image, update the image to version 2023-11-28 or above. Otherwise install the python virtualenv \
|
|
96
|
+
module manually.');
|
|
97
|
+
await delay(300000);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
else if (stdout.trim() !== '') {
|
|
101
|
+
this.log.warn(stdout);
|
|
102
|
+
}
|
|
103
|
+
this.log.debug('Python virtual environment (re)created. Continuing...');
|
|
104
|
+
}
|
|
105
|
+
async ensureVenvUsesCorrectPythonHome() {
|
|
106
|
+
this.log.debug('Checking if python virtual environment uses the python system environment...');
|
|
107
|
+
this.log.debug('Getting python home for python virtual environment...');
|
|
108
|
+
const venvPythonHome = await this.getPythonHome(this.venvPythonExecutable);
|
|
109
|
+
this.log.debug('Getting python home for python system environment...');
|
|
110
|
+
const pythonHome = await this.getPythonHome(this.pythonExecutable);
|
|
111
|
+
if (venvPythonHome !== pythonHome) {
|
|
112
|
+
this.log.warn('Python virtual environment does not use the python system environment.\
|
|
113
|
+
Recreating virtual environment...');
|
|
114
|
+
this.log.debug(`Python System Environment: ${pythonHome}; Python Virtual Environment: ${venvPythonHome}`);
|
|
115
|
+
await this.createVenv();
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
this.log.debug('Python virtual environment is using the python system environment. Continuing ...');
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
async getPythonHome(executable) {
|
|
122
|
+
const [venvPythonHome] = await runCommand(this.log, executable, [path.join(__dirname, 'pythonHome.py')], undefined, true);
|
|
123
|
+
return venvPythonHome.trim();
|
|
124
|
+
}
|
|
125
|
+
async ensureVenvPipUpToDate() {
|
|
126
|
+
this.log.debug('Checking if python virtual environment pip is up-to-date...');
|
|
127
|
+
const venvPipVersion = await this.getVenvPipVersion();
|
|
128
|
+
this.log.debug(`Python virtual environment pip version: ${venvPipVersion}`);
|
|
129
|
+
this.log.debug('Checking if there is an update for python virtual environment pip...');
|
|
130
|
+
if (venvPipVersion === await this.getMostRecentPipVersion()) {
|
|
131
|
+
this.log.debug('Python virtual environment pip is up-to-date. Continuing...');
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
this.log.warn('Python virtual environment pip is outdated. Updating now...');
|
|
135
|
+
await this.updatePip();
|
|
136
|
+
this.log.debug('Python virtual environment pip updated. Continuing...');
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
async updatePip() {
|
|
140
|
+
await runCommand(this.log, this.venvPipExecutable, ['install', '--upgrade', 'pip'], undefined, true);
|
|
141
|
+
}
|
|
142
|
+
async ensureVenvRequirementsSatisfied() {
|
|
143
|
+
if (await this.areRequirementsSatisfied()) {
|
|
144
|
+
this.log.debug('Python requirements are satisfied. Continuing...');
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
this.log.warn('Python requirements are not satisfied. Installing them now...');
|
|
148
|
+
await this.installRequirements();
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
async areRequirementsSatisfied() {
|
|
152
|
+
const [freezeStdout] = await runCommand(this.log, this.venvPipExecutable, ['freeze'], undefined, true);
|
|
153
|
+
const freeze = this.freezeStringToObject(freezeStdout);
|
|
154
|
+
const requirements = this.freezeStringToObject(fs.readFileSync(this.requirementsPath).toString());
|
|
155
|
+
for (const pkg in requirements) {
|
|
156
|
+
if (freeze[pkg] !== requirements[pkg]) {
|
|
157
|
+
return false;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
return true;
|
|
161
|
+
}
|
|
162
|
+
freezeStringToObject(value) {
|
|
163
|
+
const lines = value.trim().split('\n');
|
|
164
|
+
const packages = {};
|
|
165
|
+
for (const line of lines) {
|
|
166
|
+
const [pkg, version] = line.split('==');
|
|
167
|
+
packages[pkg.replaceAll('_', '-')] = version;
|
|
168
|
+
}
|
|
169
|
+
return packages;
|
|
170
|
+
}
|
|
171
|
+
async installRequirements() {
|
|
172
|
+
await runCommand(this.log, this.venvPipExecutable, ['install', '-r', this.requirementsPath], undefined, true);
|
|
173
|
+
this.log.debug('Python requirements installed. Continuing...');
|
|
174
|
+
}
|
|
175
|
+
async getSystemPythonVersion() {
|
|
176
|
+
const [version] = await runCommand(this.log, this.pythonExecutable, ['--version'], undefined, true);
|
|
177
|
+
return version.trim().replace('Python ', '');
|
|
178
|
+
}
|
|
179
|
+
async getVenvPipVersion() {
|
|
180
|
+
const [version] = await runCommand(this.log, this.venvPipExecutable, ['--version'], undefined, true);
|
|
181
|
+
return version.trim().replace('pip ', '').split(' ')[0];
|
|
182
|
+
}
|
|
183
|
+
async getMostRecentPipVersion() {
|
|
184
|
+
try {
|
|
185
|
+
const response = await axios.get('https://pypi.org/pypi/pip/json');
|
|
186
|
+
return response.data.info.version;
|
|
187
|
+
}
|
|
188
|
+
catch (e) {
|
|
189
|
+
this.log.error(e);
|
|
190
|
+
return 'error';
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
export default PythonChecker;
|
|
195
|
+
//# sourceMappingURL=pythonChecker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pythonChecker.js","sourceRoot":"","sources":["../../src/python/pythonChecker.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
from kasa import Device
|
|
3
|
+
import json
|
|
4
|
+
import sys
|
|
5
|
+
|
|
6
|
+
async def turn_off(device_config):
|
|
7
|
+
try:
|
|
8
|
+
kasa_device = await Device.connect(config=Device.Config.from_dict(device_config))
|
|
9
|
+
await kasa_device.turn_off()
|
|
10
|
+
await kasa_device.update()
|
|
11
|
+
print(json.dumps(kasa_device.is_off))
|
|
12
|
+
await kasa_device.disconnect()
|
|
13
|
+
except Exception as e:
|
|
14
|
+
print(f"Error turning off device: {e}")
|
|
15
|
+
|
|
16
|
+
if __name__ == "__main__":
|
|
17
|
+
device_config_json = sys.argv[1]
|
|
18
|
+
device_config = json.loads(device_config_json)
|
|
19
|
+
|
|
20
|
+
asyncio.run(turn_off(device_config))
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
from kasa import Device
|
|
3
|
+
import json
|
|
4
|
+
import sys
|
|
5
|
+
|
|
6
|
+
async def turn_off_child(device_config, child_num):
|
|
7
|
+
try:
|
|
8
|
+
kasa_device = await Device.connect(config=Device.Config.from_dict(device_config))
|
|
9
|
+
await kasa_device.children[child_num].turn_off()
|
|
10
|
+
await kasa_device.update()
|
|
11
|
+
print(json.dumps(kasa_device.children[child_num].is_off))
|
|
12
|
+
await kasa_device.disconnect()
|
|
13
|
+
except Exception as e:
|
|
14
|
+
print(f"Error turning off device: {e}")
|
|
15
|
+
|
|
16
|
+
if __name__ == "__main__":
|
|
17
|
+
device_config_json = sys.argv[1]
|
|
18
|
+
child_num_json = sys.argv[2]
|
|
19
|
+
device_config = json.loads(device_config_json)
|
|
20
|
+
child_num = json.loads(child_num_json)
|
|
21
|
+
|
|
22
|
+
asyncio.run(turn_off_child(device_config, child_num))
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
from kasa import Device
|
|
3
|
+
import json
|
|
4
|
+
import sys
|
|
5
|
+
|
|
6
|
+
async def turn_on(device_config):
|
|
7
|
+
try:
|
|
8
|
+
kasa_device = await Device.connect(config=Device.Config.from_dict(device_config))
|
|
9
|
+
await kasa_device.turn_on()
|
|
10
|
+
await kasa_device.update()
|
|
11
|
+
print(json.dumps(kasa_device.is_on))
|
|
12
|
+
await kasa_device.disconnect()
|
|
13
|
+
except Exception as e:
|
|
14
|
+
print(f"Error turning on device: {e}")
|
|
15
|
+
|
|
16
|
+
if __name__ == "__main__":
|
|
17
|
+
device_config_json = sys.argv[1]
|
|
18
|
+
device_config = json.loads(device_config_json)
|
|
19
|
+
|
|
20
|
+
asyncio.run(turn_on(device_config))
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
from kasa import Device
|
|
3
|
+
import json
|
|
4
|
+
import sys
|
|
5
|
+
|
|
6
|
+
async def turn_on_child(device_config, child_num):
|
|
7
|
+
try:
|
|
8
|
+
kasa_device = await Device.connect(config=Device.Config.from_dict(device_config))
|
|
9
|
+
await kasa_device.children[child_num].turn_on()
|
|
10
|
+
await kasa_device.update()
|
|
11
|
+
print(json.dumps(kasa_device.children[child_num].is_on))
|
|
12
|
+
await kasa_device.disconnect()
|
|
13
|
+
except Exception as e:
|
|
14
|
+
print(f"Error turning on device: {e}")
|
|
15
|
+
|
|
16
|
+
if __name__ == "__main__":
|
|
17
|
+
device_config_json = sys.argv[1]
|
|
18
|
+
child_num_json = sys.argv[2]
|
|
19
|
+
device_config = json.loads(device_config_json)
|
|
20
|
+
child_num = json.loads(child_num_json)
|
|
21
|
+
|
|
22
|
+
asyncio.run(turn_on_child(device_config, child_num))
|
package/dist/settings.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"settings.js","sourceRoot":"","sources":["../src/settings.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,aAAa,GAAG,YAAY,CAAC;AAC1C,MAAM,CAAC,MAAM,WAAW,GAAG,wBAAwB,CAAC"}
|
package/dist/utils.d.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { Characteristic, Logger, Logging, Service, WithUUID } from 'homebridge';
|
|
2
|
+
import { SpawnOptionsWithoutStdio } from 'child_process';
|
|
3
|
+
import type { Plug, Powerstrip } from './devices/kasaDevices.js';
|
|
4
|
+
export type KasaDevice = Plug | Powerstrip;
|
|
5
|
+
export declare function isObjectLike(candidate: unknown): candidate is Record<string, unknown>;
|
|
6
|
+
/**
|
|
7
|
+
* Creates a function that will "batch" calls that are within the `timeout`
|
|
8
|
+
*
|
|
9
|
+
* The first time the function that is created is called, it will wait the `timeout` for additional calls.
|
|
10
|
+
* After the `timeout` expires the result of one execution of `fn` will be resolved to all calls during the `timeout`.
|
|
11
|
+
*
|
|
12
|
+
* If `runNowFn` is specified it will be run synchronously without a timeout. Useful for functions that are used to set rather than get.
|
|
13
|
+
*
|
|
14
|
+
* @param {() => Promise<T>} fn
|
|
15
|
+
* @param {number} timeout (ms)
|
|
16
|
+
* @param {(arg: U) => void} [runNowFn]
|
|
17
|
+
* @returns {(arg?: U) => Promise<T>}
|
|
18
|
+
*/
|
|
19
|
+
export declare function deferAndCombine<T, U>(fn: (requestCount: number) => Promise<T>, timeout: number, runNowFn?: (arg: U) => void): (arg?: U) => Promise<T>;
|
|
20
|
+
export declare function delay(ms: number): Promise<void>;
|
|
21
|
+
export declare function getOrAddCharacteristic(service: Service, characteristic: WithUUID<new () => Characteristic>): Characteristic;
|
|
22
|
+
export declare function hasCharacteristic(characteristics: Array<Characteristic>, characteristic: WithUUID<{
|
|
23
|
+
new (): Characteristic;
|
|
24
|
+
}>): boolean;
|
|
25
|
+
export declare function kelvinToMired(kelvin: number): number;
|
|
26
|
+
export declare function lookup<T>(object: unknown, compareFn: undefined | ((objectProp: unknown, search: T) => boolean), value: T): string | undefined;
|
|
27
|
+
export declare function lookupCharacteristicNameByUUID(characteristic: typeof Characteristic, uuid: string): string | undefined;
|
|
28
|
+
export declare function miredToKelvin(mired: number): number;
|
|
29
|
+
export declare function runCommand(logger: Logger, command: string, args?: readonly string[], options?: SpawnOptionsWithoutStdio, hideStdout?: boolean, hideStderr?: boolean): Promise<[string, string, number | null]>;
|
|
30
|
+
export declare function prefixLogger(logger: Logger, prefix: string | (() => string)): Logging;
|