homebridge-kasa-python 2.7.0-beta.2 → 2.7.0-beta.4
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/dist/config.js +1 -2
- package/dist/config.js.map +1 -1
- package/dist/devices/deviceManager.d.ts +3 -6
- package/dist/devices/deviceManager.js +25 -69
- package/dist/devices/deviceManager.js.map +1 -1
- package/dist/devices/homekitLightBulb.d.ts +11 -1
- package/dist/devices/homekitLightBulb.js +147 -13
- package/dist/devices/homekitLightBulb.js.map +1 -1
- package/dist/devices/homekitPlug.d.ts +10 -1
- package/dist/devices/homekitPlug.js +112 -7
- package/dist/devices/homekitPlug.js.map +1 -1
- package/dist/devices/homekitPowerStrip.d.ts +10 -1
- package/dist/devices/homekitPowerStrip.js +121 -8
- package/dist/devices/homekitPowerStrip.js.map +1 -1
- package/dist/devices/homekitSwitch.d.ts +11 -1
- package/dist/devices/homekitSwitch.js +118 -8
- package/dist/devices/homekitSwitch.js.map +1 -1
- package/dist/devices/index.d.ts +4 -14
- package/dist/devices/index.js +6 -215
- package/dist/devices/index.js.map +1 -1
- package/dist/devices/kasaDevices.d.ts +4 -6
- package/dist/devices/kasaDevices.js +2 -0
- package/dist/devices/kasaDevices.js.map +1 -1
- package/dist/platform.d.ts +0 -1
- package/dist/platform.js +12 -85
- package/dist/platform.js.map +1 -1
- package/dist/python/kasaApi.py +182 -232
- package/dist/python/pythonChecker.js +6 -10
- package/dist/python/pythonChecker.js.map +1 -1
- package/dist/utils.d.ts +2 -8
- package/dist/utils.js +2 -19
- package/dist/utils.js.map +1 -1
- package/package.json +1 -1
- package/requirements.txt +0 -1
package/dist/python/kasaApi.py
CHANGED
|
@@ -1,45 +1,13 @@
|
|
|
1
1
|
import asyncio
|
|
2
|
-
import os
|
|
3
2
|
import sys
|
|
4
3
|
import uvicorn
|
|
5
4
|
from typing import Any, Dict, List, Optional
|
|
6
5
|
|
|
7
|
-
from aiohttp import ClientSession
|
|
8
6
|
from kasa import Credentials, Device, Discover, Module, UnsupportedDeviceError
|
|
9
|
-
from loguru import logger
|
|
10
7
|
from quart import Quart, jsonify, request
|
|
11
8
|
|
|
12
9
|
app = Quart(__name__)
|
|
13
10
|
|
|
14
|
-
logging_server_url = os.getenv('LOGGING_SERVER_URL')
|
|
15
|
-
|
|
16
|
-
class RemoteLogger:
|
|
17
|
-
def __init__(self, url: str):
|
|
18
|
-
self.url = url
|
|
19
|
-
|
|
20
|
-
async def write(self, message: str):
|
|
21
|
-
if message.strip():
|
|
22
|
-
async with ClientSession() as session:
|
|
23
|
-
await session.post(self.url, json={"level": "debug", "message": message.strip()})
|
|
24
|
-
|
|
25
|
-
class AsyncLogHandler:
|
|
26
|
-
def __init__(self, logger_instance, url):
|
|
27
|
-
self.logger_instance = logger_instance
|
|
28
|
-
self.remote_logger = RemoteLogger(url)
|
|
29
|
-
|
|
30
|
-
async def async_log_writer(self, message: str):
|
|
31
|
-
await self.remote_logger.write(message)
|
|
32
|
-
|
|
33
|
-
def __call__(self, message: str):
|
|
34
|
-
loop = asyncio.get_event_loop()
|
|
35
|
-
if loop.is_running():
|
|
36
|
-
loop.create_task(self.async_log_writer(message))
|
|
37
|
-
else:
|
|
38
|
-
asyncio.run(self.async_log_writer(message))
|
|
39
|
-
|
|
40
|
-
async_log_handler = AsyncLogHandler(logger, logging_server_url)
|
|
41
|
-
logger.add(async_log_handler, level="DEBUG")
|
|
42
|
-
|
|
43
11
|
UNSUPPORTED_TYPES = {
|
|
44
12
|
'SMART.IPCAMERA',
|
|
45
13
|
'SMART.KASAHUB',
|
|
@@ -47,91 +15,101 @@ UNSUPPORTED_TYPES = {
|
|
|
47
15
|
}
|
|
48
16
|
|
|
49
17
|
def get_light_info(light_module: Module) -> Dict[str, Any]:
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
18
|
+
try:
|
|
19
|
+
light_info = {}
|
|
20
|
+
if light_module.is_dimmable:
|
|
21
|
+
light_info["brightness"] = light_module.brightness
|
|
22
|
+
if light_module.is_variable_color_temp:
|
|
23
|
+
light_info["color_temp"] = light_module.color_temp
|
|
24
|
+
if light_module.is_color:
|
|
25
|
+
hue, saturation, _ = light_module.hsv
|
|
26
|
+
light_info["hsv"] = {"hue": hue, "saturation": saturation}
|
|
27
|
+
return light_info
|
|
28
|
+
except Exception as e:
|
|
29
|
+
raise ValueError(f"Error getting light info: {e}")
|
|
59
30
|
|
|
60
31
|
def serialize_child(child: Device) -> Dict[str, Any]:
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
32
|
+
try:
|
|
33
|
+
child_info = {
|
|
34
|
+
"alias": child.alias,
|
|
35
|
+
"id": child.device_id.split("_", 1)[1],
|
|
36
|
+
"state": child.features["state"].value
|
|
37
|
+
}
|
|
38
|
+
light_module = child.modules.get(Module.Light)
|
|
39
|
+
if light_module:
|
|
40
|
+
child_info.update(get_light_info(light_module))
|
|
41
|
+
return child_info
|
|
42
|
+
except Exception as e:
|
|
43
|
+
raise ValueError(f"Error serializing child device {child.alias}: {e}")
|
|
70
44
|
|
|
71
45
|
def custom_sysinfo_config_serializer(device: Device) -> Dict[str, Any]:
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
if child_num > 0:
|
|
87
|
-
sys_info["children"] = [serialize_child(child) for child in device.children]
|
|
88
|
-
else:
|
|
89
|
-
sys_info.update({
|
|
90
|
-
"state": device.features["state"].value
|
|
91
|
-
})
|
|
92
|
-
light_module = device.modules.get(Module.Light)
|
|
93
|
-
if light_module:
|
|
94
|
-
sys_info.update(get_light_info(light_module))
|
|
95
|
-
|
|
96
|
-
device_config = {
|
|
97
|
-
"host": device.config.host,
|
|
98
|
-
"timeout": device.config.timeout,
|
|
99
|
-
"uses_http": device.config.uses_http,
|
|
100
|
-
**({"credentials": {
|
|
101
|
-
"username": device.config.credentials.username,
|
|
102
|
-
"password": device.config.credentials.password
|
|
103
|
-
}} if device.config.credentials else {}),
|
|
104
|
-
"connection_type": {
|
|
105
|
-
"device_family": device.config.connection_type.device_family.value,
|
|
106
|
-
"encryption_type": device.config.connection_type.encryption_type.value,
|
|
107
|
-
"https": device.config.connection_type.https
|
|
46
|
+
try:
|
|
47
|
+
child_num = len(device.children) if device.children else 0
|
|
48
|
+
|
|
49
|
+
sys_info = {
|
|
50
|
+
"alias": device.alias or f'{device.device_type}_{device.host}',
|
|
51
|
+
"child_num": child_num,
|
|
52
|
+
"device_id": device.device_id if device.mac != device.device_id else device.sys_info.get("deviceId"),
|
|
53
|
+
"device_type": device.config.connection_type.device_family.value,
|
|
54
|
+
"host": device.host,
|
|
55
|
+
"hw_ver": device.hw_info["hw_ver"],
|
|
56
|
+
"mac": device.mac,
|
|
57
|
+
"sw_ver": device.hw_info["sw_ver"],
|
|
108
58
|
}
|
|
109
|
-
}
|
|
110
59
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
60
|
+
if child_num > 0:
|
|
61
|
+
sys_info["children"] = [serialize_child(child) for child in device.children]
|
|
62
|
+
else:
|
|
63
|
+
sys_info.update({
|
|
64
|
+
"state": device.features["state"].value
|
|
65
|
+
})
|
|
66
|
+
light_module = device.modules.get(Module.Light)
|
|
67
|
+
if light_module:
|
|
68
|
+
sys_info.update(get_light_info(light_module))
|
|
69
|
+
|
|
70
|
+
device_config = {
|
|
71
|
+
"host": device.config.host,
|
|
72
|
+
"timeout": device.config.timeout,
|
|
73
|
+
"uses_http": device.config.uses_http,
|
|
74
|
+
**({"credentials": {
|
|
75
|
+
"username": device.config.credentials.username,
|
|
76
|
+
"password": device.config.credentials.password
|
|
77
|
+
}} if device.config.credentials else {}),
|
|
78
|
+
"connection_type": {
|
|
79
|
+
"device_family": device.config.connection_type.device_family.value,
|
|
80
|
+
"encryption_type": device.config.connection_type.encryption_type.value,
|
|
81
|
+
"https": device.config.connection_type.https
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return {
|
|
86
|
+
"sys_info": sys_info,
|
|
87
|
+
"device_config": device_config
|
|
88
|
+
}
|
|
89
|
+
except Exception as e:
|
|
90
|
+
raise ValueError(f"Error serializing sysinfo config for device {device.host}: {e}")
|
|
115
91
|
|
|
116
92
|
def custom_discovery_feature_serializer(device: Device) -> Dict[str, Any]:
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
feature_info = {}
|
|
123
|
-
light_module = device.modules.get(Module.Light)
|
|
124
|
-
if light_module:
|
|
125
|
-
feature_info = {
|
|
126
|
-
"brightness": light_module.is_dimmable,
|
|
127
|
-
"color_temp": light_module.is_variable_color_temp,
|
|
128
|
-
"hsv": light_module.is_color
|
|
93
|
+
try:
|
|
94
|
+
disc_info = {
|
|
95
|
+
"model": device._discovery_info.get("device_model") or device.sys_info.get("model")
|
|
129
96
|
}
|
|
130
97
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
98
|
+
feature_info = {}
|
|
99
|
+
light_module = device.modules.get(Module.Light)
|
|
100
|
+
if light_module:
|
|
101
|
+
feature_info = {
|
|
102
|
+
"brightness": light_module.is_dimmable,
|
|
103
|
+
"color_temp": light_module.is_variable_color_temp,
|
|
104
|
+
"hsv": light_module.is_color
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return {
|
|
108
|
+
"disc_info": disc_info,
|
|
109
|
+
"feature_info": feature_info
|
|
110
|
+
}
|
|
111
|
+
except Exception as e:
|
|
112
|
+
raise ValueError(f"Error serializing discovery feature for device {device.host}: {e}")
|
|
135
113
|
|
|
136
114
|
async def discover_devices(
|
|
137
115
|
username: Optional[str] = None,
|
|
@@ -139,89 +117,76 @@ async def discover_devices(
|
|
|
139
117
|
additional_broadcasts: Optional[List[str]] = None,
|
|
140
118
|
manual_devices: Optional[List[str]] = None
|
|
141
119
|
) -> Dict[str, Any]:
|
|
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
|
-
|
|
120
|
+
try:
|
|
121
|
+
devices = {}
|
|
122
|
+
broadcasts = ["255.255.255.255"] + (additional_broadcasts or [])
|
|
123
|
+
creds = Credentials(username, password) if username and password else None
|
|
124
|
+
|
|
125
|
+
async def on_discovered(device: Device):
|
|
126
|
+
try:
|
|
127
|
+
await device.update()
|
|
128
|
+
except UnsupportedDeviceError as e:
|
|
129
|
+
raise ValueError(f"Unsupported device during discovery: {device.host} - {e}")
|
|
130
|
+
except Exception as e:
|
|
131
|
+
raise ValueError(f"Error updating device during discovery: {device.host} - {e}")
|
|
132
|
+
|
|
133
|
+
async def discover_on_broadcast(broadcast: str):
|
|
134
|
+
try:
|
|
135
|
+
discovered = await Discover.discover(
|
|
136
|
+
target=broadcast,
|
|
137
|
+
credentials=creds,
|
|
138
|
+
on_discovered=on_discovered
|
|
139
|
+
)
|
|
140
|
+
devices.update(discovered)
|
|
141
|
+
except Exception as e:
|
|
142
|
+
raise ValueError(f"Error during broadcast discovery {broadcast}: {e}")
|
|
143
|
+
|
|
144
|
+
async def discover_manual_device(host: str):
|
|
145
|
+
if host in devices:
|
|
146
|
+
return
|
|
147
|
+
try:
|
|
148
|
+
device = await Discover.discover_single(host=host, credentials=creds)
|
|
149
|
+
await on_discovered(device)
|
|
150
|
+
devices[host] = device
|
|
151
|
+
except UnsupportedDeviceError as e:
|
|
152
|
+
raise ValueError(f"Unsupported manual device: {host} - {e}")
|
|
153
|
+
except Exception as e:
|
|
154
|
+
raise ValueError(f"Error discovering manual device {host}: {e}")
|
|
155
|
+
|
|
156
|
+
discover_tasks = [discover_on_broadcast(bc) for bc in broadcasts]
|
|
157
|
+
manual_discover_tasks = [discover_manual_device(host) for host in (manual_devices or [])]
|
|
158
|
+
await asyncio.gather(*discover_tasks, *manual_discover_tasks)
|
|
159
|
+
|
|
160
|
+
all_device_info = {}
|
|
161
|
+
update_tasks = []
|
|
162
|
+
|
|
163
|
+
for ip, dev in devices.items():
|
|
164
|
+
try:
|
|
165
|
+
components = await dev._raw_query("component_nego")
|
|
166
|
+
component_list = components.get("component_nego", {}).get("component_list", [])
|
|
167
|
+
homekit_component = next((item for item in component_list if item.get("id") == "homekit"), None)
|
|
168
|
+
if homekit_component:
|
|
169
|
+
continue
|
|
170
|
+
except Exception:
|
|
171
|
+
pass
|
|
172
|
+
|
|
173
|
+
dev_type = dev.sys_info.get("mic_type") or dev.sys_info.get("type")
|
|
174
|
+
if dev_type and dev_type not in UNSUPPORTED_TYPES:
|
|
175
|
+
update_tasks.append(create_device_info(ip, dev))
|
|
176
|
+
|
|
177
|
+
results = await asyncio.gather(*update_tasks, return_exceptions=True)
|
|
178
|
+
|
|
179
|
+
for result in results:
|
|
180
|
+
if isinstance(result, Exception):
|
|
200
181
|
continue
|
|
201
|
-
|
|
202
|
-
|
|
182
|
+
ip, info = result
|
|
183
|
+
all_device_info[ip] = info
|
|
203
184
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
logger.debug(f"Device {ip} added to update tasks")
|
|
208
|
-
else:
|
|
209
|
-
logger.debug(f"Device {ip} is unsupported")
|
|
210
|
-
|
|
211
|
-
results = await asyncio.gather(*update_tasks, return_exceptions=True)
|
|
212
|
-
|
|
213
|
-
for result in results:
|
|
214
|
-
if isinstance(result, Exception):
|
|
215
|
-
logger.error(f"Error in device info creation: {str(result)}")
|
|
216
|
-
continue
|
|
217
|
-
ip, info = result
|
|
218
|
-
all_device_info[ip] = info
|
|
219
|
-
|
|
220
|
-
logger.debug(f"Device discovery completed with {len(all_device_info)} devices")
|
|
221
|
-
return all_device_info
|
|
185
|
+
return all_device_info
|
|
186
|
+
except Exception as e:
|
|
187
|
+
raise ValueError(f"Error during device discovery: {e}")
|
|
222
188
|
|
|
223
189
|
async def create_device_info(ip: str, dev: Device):
|
|
224
|
-
logger.debug(f"Creating device info for {ip}")
|
|
225
190
|
try:
|
|
226
191
|
sys_info_data = custom_sysinfo_config_serializer(dev)
|
|
227
192
|
feature_info_data = custom_discovery_feature_serializer(dev)
|
|
@@ -231,21 +196,17 @@ async def create_device_info(ip: str, dev: Device):
|
|
|
231
196
|
"feature_info": feature_info_data["feature_info"],
|
|
232
197
|
"device_config": sys_info_data["device_config"]
|
|
233
198
|
}
|
|
234
|
-
logger.debug(f"Created device info for {ip}")
|
|
235
199
|
return ip, device_info
|
|
236
200
|
except Exception as e:
|
|
237
|
-
|
|
238
|
-
return ip, {}
|
|
201
|
+
raise ValueError(f"Error creating device info for {ip}: {e}")
|
|
239
202
|
|
|
240
203
|
async def get_sys_info(device_config: Dict[str, Any]) -> Dict[str, Any]:
|
|
241
|
-
logger.debug(f"Fetching system info for device: {device_config['host']}")
|
|
242
204
|
dev = await Device.connect(config=Device.Config.from_dict(device_config))
|
|
243
205
|
try:
|
|
244
206
|
device = custom_sysinfo_config_serializer(dev)
|
|
245
207
|
return {"sys_info": device["sys_info"]}
|
|
246
208
|
except Exception as e:
|
|
247
|
-
|
|
248
|
-
return {}
|
|
209
|
+
raise ValueError(f"Error getting sys info for device {device_config['host']}: {e}")
|
|
249
210
|
finally:
|
|
250
211
|
await dev.disconnect()
|
|
251
212
|
|
|
@@ -256,7 +217,6 @@ async def control_device(
|
|
|
256
217
|
value: Any,
|
|
257
218
|
child_num: Optional[int] = None
|
|
258
219
|
) -> Dict[str, Any]:
|
|
259
|
-
logger.debug(f"Controlling device: {device_config['host']}, feature: {feature}, action: {action}, child_num: {child_num}")
|
|
260
220
|
dev = await Device.connect(config=Device.Config.from_dict(device_config))
|
|
261
221
|
try:
|
|
262
222
|
target = dev.children[child_num] if child_num is not None else dev
|
|
@@ -273,37 +233,45 @@ async def control_device(
|
|
|
273
233
|
else:
|
|
274
234
|
raise ValueError(f"Unsupported feature or missing module: {feature}")
|
|
275
235
|
|
|
276
|
-
|
|
236
|
+
target.update()
|
|
277
237
|
return {"status": "success"}
|
|
278
238
|
except Exception as e:
|
|
279
|
-
|
|
280
|
-
return {"status": "error", "message": str(e)}
|
|
239
|
+
raise ValueError(f"Error controlling device {device_config['host']}: {e}")
|
|
281
240
|
finally:
|
|
282
241
|
await dev.disconnect()
|
|
283
242
|
|
|
284
243
|
async def handle_brightness(target: Device, action: str, value: int):
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
244
|
+
try:
|
|
245
|
+
light = target.modules.get(Module.Light)
|
|
246
|
+
if value == 0:
|
|
247
|
+
await target.turn_off()
|
|
248
|
+
elif 0 < value <= 100:
|
|
249
|
+
await getattr(light, action)(value)
|
|
250
|
+
else:
|
|
251
|
+
await target.turn_on()
|
|
252
|
+
except Exception as e:
|
|
253
|
+
raise ValueError(f"Error handling brightness for device {target.host}: {e}")
|
|
292
254
|
|
|
293
255
|
async def handle_color_temp(target: Device, action: str, value: int):
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
256
|
+
try:
|
|
257
|
+
light = target.modules.get(Module.Light)
|
|
258
|
+
min_temp, max_temp = light.valid_temperature_range
|
|
259
|
+
value = max(min(value, max_temp), min_temp)
|
|
260
|
+
await getattr(light, action)(value)
|
|
261
|
+
except Exception as e:
|
|
262
|
+
raise ValueError(f"Error handling color temperature for device {target.host}: {e}")
|
|
298
263
|
|
|
299
264
|
async def handle_hsv(target: Device, action: str, feature: str, value: Dict[str, int]):
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
265
|
+
try:
|
|
266
|
+
light = target.modules.get(Module.Light)
|
|
267
|
+
hsv = list(light.hsv)
|
|
268
|
+
if feature == "hue":
|
|
269
|
+
hsv[0] = value["hue"]
|
|
270
|
+
elif feature == "saturation":
|
|
271
|
+
hsv[1] = value["saturation"]
|
|
272
|
+
await getattr(light, action)(tuple(hsv))
|
|
273
|
+
except Exception as e:
|
|
274
|
+
raise ValueError(f"Error handling HSV for device {target.host}: {e}")
|
|
307
275
|
|
|
308
276
|
@app.route('/discover', methods=['POST'])
|
|
309
277
|
async def discover_route():
|
|
@@ -314,12 +282,9 @@ async def discover_route():
|
|
|
314
282
|
data = await request.get_json()
|
|
315
283
|
additional_broadcasts = data.get('additionalBroadcasts', [])
|
|
316
284
|
manual_devices = data.get('manualDevices', [])
|
|
317
|
-
logger.debug(f"Received discovery request with broadcasts: {additional_broadcasts} and manual devices: {manual_devices}")
|
|
318
285
|
devices_info = await discover_devices(username, password, additional_broadcasts, manual_devices)
|
|
319
|
-
logger.debug(f"Discovery completed with {len(devices_info)} devices found")
|
|
320
286
|
return jsonify(devices_info)
|
|
321
287
|
except Exception as e:
|
|
322
|
-
logger.exception(f"Error during discovery: {str(e)}")
|
|
323
288
|
return jsonify({"error": str(e)}), 500
|
|
324
289
|
|
|
325
290
|
@app.route('/getSysInfo', methods=['POST'])
|
|
@@ -327,16 +292,9 @@ async def get_sys_info_route():
|
|
|
327
292
|
try:
|
|
328
293
|
data = await request.get_json()
|
|
329
294
|
device_config = data['device_config']
|
|
330
|
-
credentials = device_config.get('credentials')
|
|
331
|
-
if credentials:
|
|
332
|
-
device_config['credentials'] = Credentials(
|
|
333
|
-
username=credentials['username'],
|
|
334
|
-
password=credentials['password']
|
|
335
|
-
)
|
|
336
295
|
sys_info = await get_sys_info(device_config)
|
|
337
296
|
return jsonify(sys_info)
|
|
338
297
|
except Exception as e:
|
|
339
|
-
logger.exception(f"Error getting system info: {str(e)}")
|
|
340
298
|
return jsonify({"error": str(e)}), 500
|
|
341
299
|
|
|
342
300
|
@app.route('/controlDevice', methods=['POST'])
|
|
@@ -344,12 +302,6 @@ async def control_device_route():
|
|
|
344
302
|
try:
|
|
345
303
|
data = await request.get_json()
|
|
346
304
|
device_config = data['device_config']
|
|
347
|
-
credentials = device_config.get('credentials')
|
|
348
|
-
if credentials:
|
|
349
|
-
device_config['credentials'] = Credentials(
|
|
350
|
-
username=credentials['username'],
|
|
351
|
-
password=credentials['password']
|
|
352
|
-
)
|
|
353
305
|
feature = data['feature']
|
|
354
306
|
action = data['action']
|
|
355
307
|
value = data.get('value')
|
|
@@ -357,7 +309,6 @@ async def control_device_route():
|
|
|
357
309
|
result = await control_device(device_config, feature, action, value, child_num)
|
|
358
310
|
return jsonify(result)
|
|
359
311
|
except Exception as e:
|
|
360
|
-
logger.exception(f"Error controlling device: {str(e)}")
|
|
361
312
|
return jsonify({"error": str(e)}), 500
|
|
362
313
|
|
|
363
314
|
@app.route('/health', methods=['GET'])
|
|
@@ -366,5 +317,4 @@ async def health_check():
|
|
|
366
317
|
|
|
367
318
|
if __name__ == '__main__':
|
|
368
319
|
port = int(sys.argv[1])
|
|
369
|
-
logger.info(f"Starting server on port {port}")
|
|
370
320
|
uvicorn.run(app, host="0.0.0.0", port=port, loop="asyncio")
|
|
@@ -42,11 +42,9 @@ class PythonChecker {
|
|
|
42
42
|
}
|
|
43
43
|
async ensurePythonVersion() {
|
|
44
44
|
const version = await this.getSystemPythonVersion();
|
|
45
|
-
if (SUPPORTED_PYTHON_VERSIONS.
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
await delay(300000);
|
|
49
|
-
}
|
|
45
|
+
if (!SUPPORTED_PYTHON_VERSIONS.some(e => version.includes(e))) {
|
|
46
|
+
this.log.error(`Python ${version} is installed. However, only Python ${SUPPORTED_PYTHON_VERSIONS.join(', ')} is supported.`);
|
|
47
|
+
await delay(300000);
|
|
50
48
|
}
|
|
51
49
|
}
|
|
52
50
|
async ensureVenvCreated(isUpgrade) {
|
|
@@ -60,10 +58,8 @@ class PythonChecker {
|
|
|
60
58
|
async createVenv() {
|
|
61
59
|
const [stdout] = await runCommand(this.log, this.pythonExecutable, ['-m', 'venv', this.venvPath, '--clear'], undefined, true);
|
|
62
60
|
if (stdout.includes('not created successfully') || !this.isVenvCreated()) {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
await delay(300000);
|
|
66
|
-
}
|
|
61
|
+
this.log.error('virtualenv python module is not installed.');
|
|
62
|
+
await delay(300000);
|
|
67
63
|
}
|
|
68
64
|
}
|
|
69
65
|
async ensureVenvUsesCorrectPythonHome() {
|
|
@@ -121,7 +117,7 @@ class PythonChecker {
|
|
|
121
117
|
return response.data.info.version;
|
|
122
118
|
}
|
|
123
119
|
catch (e) {
|
|
124
|
-
this.log.error(e);
|
|
120
|
+
this.log.error(`Error fetching most recent pip version: ${e}`);
|
|
125
121
|
return 'error';
|
|
126
122
|
}
|
|
127
123
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pythonChecker.js","sourceRoot":"","sources":["../../src/python/pythonChecker.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAGzC,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9D,MAAM,SAAS,GAAW,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AACvE,MAAM,yBAAyB,GAAa,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;AAErE,MAAM,aAAa;IACA,GAAG,CAAS;IACZ,QAAQ,CAAqB;IAC7B,gBAAgB,CAAS;IACzB,aAAa,CAAS;IACtB,QAAQ,CAAS;IACjB,iBAAiB,CAAS;IAC1B,oBAAoB,CAAS;IAC7B,cAAc,CAAS;IACvB,gBAAgB,GAAW,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,kBAAkB,CAAC,CAAC;IAEjG,YAAmB,QAA4B;QAC7C,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,GAAG,GAAG,YAAY,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,gBAAgB,CAAC,CAAC;QAC7D,IAAI,CAAC,gBAAgB,GAAG,SAAS,CAAC;QAClC,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,WAAW,EAAE,aAAa,CAAC,CAAC;QACzE,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;QACvD,IAAI,CAAC,oBAAoB,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC;QACvE,IAAI,CAAC,iBAAiB,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;QACjE,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;IAC/D,CAAC;IAEM,KAAK,CAAC,QAAQ,CAAC,SAAkB;QACtC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,sCAAsC,CAAC,CAAC;QACvD,IAAI,CAAC,eAAe,EAAE,CAAC;QACvB,MAAM,IAAI,CAAC,mBAAmB,EAAE,CAAC;QACjC,MAAM,IAAI,CAAC,iBAAiB,CAAC,SAAS,CAAC,CAAC;QACxC,MAAM,IAAI,CAAC,+BAA+B,EAAE,CAAC;QAC7C,MAAM,IAAI,CAAC,qBAAqB,EAAE,CAAC;QACnC,MAAM,IAAI,CAAC,+BAA+B,EAAE,CAAC;QAC7C,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,oCAAoC,CAAC,CAAC;IACvD,CAAC;IAEO,eAAe;QACrB,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,aAAa,CAAC,EAAE,CAAC;YACvC,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QACnC,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,mBAAmB;QAC/B,MAAM,OAAO,GAAW,MAAM,IAAI,CAAC,sBAAsB,EAAE,CAAC;QAC5D,IAAI,yBAAyB,CAAC,
|
|
1
|
+
{"version":3,"file":"pythonChecker.js","sourceRoot":"","sources":["../../src/python/pythonChecker.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAGzC,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9D,MAAM,SAAS,GAAW,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AACvE,MAAM,yBAAyB,GAAa,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;AAErE,MAAM,aAAa;IACA,GAAG,CAAS;IACZ,QAAQ,CAAqB;IAC7B,gBAAgB,CAAS;IACzB,aAAa,CAAS;IACtB,QAAQ,CAAS;IACjB,iBAAiB,CAAS;IAC1B,oBAAoB,CAAS;IAC7B,cAAc,CAAS;IACvB,gBAAgB,GAAW,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,kBAAkB,CAAC,CAAC;IAEjG,YAAmB,QAA4B;QAC7C,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,GAAG,GAAG,YAAY,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,gBAAgB,CAAC,CAAC;QAC7D,IAAI,CAAC,gBAAgB,GAAG,SAAS,CAAC;QAClC,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,WAAW,EAAE,aAAa,CAAC,CAAC;QACzE,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;QACvD,IAAI,CAAC,oBAAoB,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC;QACvE,IAAI,CAAC,iBAAiB,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;QACjE,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;IAC/D,CAAC;IAEM,KAAK,CAAC,QAAQ,CAAC,SAAkB;QACtC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,sCAAsC,CAAC,CAAC;QACvD,IAAI,CAAC,eAAe,EAAE,CAAC;QACvB,MAAM,IAAI,CAAC,mBAAmB,EAAE,CAAC;QACjC,MAAM,IAAI,CAAC,iBAAiB,CAAC,SAAS,CAAC,CAAC;QACxC,MAAM,IAAI,CAAC,+BAA+B,EAAE,CAAC;QAC7C,MAAM,IAAI,CAAC,qBAAqB,EAAE,CAAC;QACnC,MAAM,IAAI,CAAC,+BAA+B,EAAE,CAAC;QAC7C,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,oCAAoC,CAAC,CAAC;IACvD,CAAC;IAEO,eAAe;QACrB,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,aAAa,CAAC,EAAE,CAAC;YACvC,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QACnC,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,mBAAmB;QAC/B,MAAM,OAAO,GAAW,MAAM,IAAI,CAAC,sBAAsB,EAAE,CAAC;QAC5D,IAAI,CAAC,yBAAyB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YAC9D,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,OAAO,uCAAuC,yBAAyB,CAAC,IAAI,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;YAC7H,MAAM,KAAK,CAAC,MAAM,CAAC,CAAC;QACtB,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,iBAAiB,CAAC,SAAkB;QAChD,IAAI,SAAS,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,EAAE,CAAC;YACvC,MAAM,IAAI,CAAC,UAAU,EAAE,CAAC;QAC1B,CAAC;IACH,CAAC;IAEO,aAAa;QACnB,OAAO,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,iBAAiB,CAAC,IAAI,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,cAAc,CAAC,IAAI,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;IACjI,CAAC;IAEO,KAAK,CAAC,UAAU;QACtB,MAAM,CAAC,MAAM,CAAC,GAAG,MAAM,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,gBAAgB,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,QAAQ,EAAE,SAAS,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC;QAC9H,IAAI,MAAM,CAAC,QAAQ,CAAC,0BAA0B,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,EAAE,CAAC;YACzE,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,4CAA4C,CAAC,CAAC;YAC7D,MAAM,KAAK,CAAC,MAAM,CAAC,CAAC;QACtB,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,+BAA+B;QAC3C,MAAM,cAAc,GAAW,MAAM,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;QACnF,MAAM,UAAU,GAAW,MAAM,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;QAC3E,IAAI,cAAc,KAAK,UAAU,EAAE,CAAC;YAClC,MAAM,IAAI,CAAC,UAAU,EAAE,CAAC;QAC1B,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,aAAa,CAAC,UAAkB;QAC5C,MAAM,CAAC,cAAc,CAAC,GAAG,MAAM,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,UAAU,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,eAAe,CAAC,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC;QAC1H,OAAO,cAAc,CAAC,IAAI,EAAE,CAAC;IAC/B,CAAC;IAEO,KAAK,CAAC,qBAAqB;QACjC,MAAM,cAAc,GAAW,MAAM,IAAI,CAAC,iBAAiB,EAAE,CAAC;QAC9D,IAAI,cAAc,KAAK,MAAM,IAAI,CAAC,uBAAuB,EAAE,EAAE,CAAC;YAC5D,MAAM,IAAI,CAAC,SAAS,EAAE,CAAC;QACzB,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,SAAS;QACrB,MAAM,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,iBAAiB,EAAE,CAAC,SAAS,EAAE,WAAW,EAAE,KAAK,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC;IACvG,CAAC;IAEO,KAAK,CAAC,+BAA+B;QAC3C,IAAI,CAAC,MAAM,IAAI,CAAC,wBAAwB,EAAE,EAAE,CAAC;YAC3C,MAAM,IAAI,CAAC,mBAAmB,EAAE,CAAC;QACnC,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,wBAAwB;QACpC,MAAM,CAAC,YAAY,CAAC,GAAG,MAAM,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,iBAAiB,EAAE,CAAC,QAAQ,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC;QACvG,MAAM,MAAM,GAAG,IAAI,CAAC,oBAAoB,CAAC,YAAY,CAAC,CAAC;QACvD,MAAM,YAAY,GAAG,IAAI,CAAC,oBAAoB,CAAC,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;QAClG,OAAO,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC;IACnF,CAAC;IAEO,oBAAoB,CAAC,KAAa;QACxC,OAAO,KAAK,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAyB,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE;YAC3E,MAAM,CAAC,GAAG,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YACxC,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,GAAG,OAAO,CAAC;YACxC,OAAO,GAAG,CAAC;QACb,CAAC,EAAE,EAAE,CAAC,CAAC;IACT,CAAC;IAEO,KAAK,CAAC,mBAAmB;QAC/B,MAAM,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,iBAAiB,EAAE,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,CAAC,gBAAgB,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC;IAChH,CAAC;IAEO,KAAK,CAAC,sBAAsB;QAClC,MAAM,CAAC,OAAO,CAAC,GAAG,MAAM,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,gBAAgB,EAAE,CAAC,WAAW,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC;QACpG,OAAO,OAAO,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;IAC/C,CAAC;IAEO,KAAK,CAAC,iBAAiB;QAC7B,MAAM,CAAC,OAAO,CAAC,GAAG,MAAM,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,iBAAiB,EAAE,CAAC,WAAW,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC;QACrG,OAAO,OAAO,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IACtC,CAAC;IAEO,KAAK,CAAC,uBAAuB;QACnC,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,CAAgC,gCAAgC,CAAC,CAAC;YAClG,OAAO,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC;QACpC,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,2CAA2C,CAAC,EAAE,CAAC,CAAC;YAC/D,OAAO,OAAO,CAAC;QACjB,CAAC;IACH,CAAC;CACF;AAED,eAAe,aAAa,CAAC"}
|
package/dist/utils.d.ts
CHANGED
|
@@ -1,15 +1,9 @@
|
|
|
1
|
-
import type { Characteristic, Logger, Logging
|
|
1
|
+
import type { Characteristic, Logger, Logging } from 'homebridge';
|
|
2
2
|
import { ChildProcessWithoutNullStreams, SpawnOptionsWithoutStdio } from 'node:child_process';
|
|
3
3
|
export declare function deferAndCombine<T, U>(fn: (requestCount: number) => Promise<T>, timeout: number, runNowFn?: (arg: U) => void): (arg?: U) => Promise<T>;
|
|
4
4
|
export declare function delay(ms: number): Promise<void>;
|
|
5
|
-
export declare function getOrAddCharacteristic(service: Service, characteristic: WithUUID<new () => Characteristic>): Characteristic;
|
|
6
|
-
export declare function hasCharacteristic(characteristics: Array<Characteristic>, characteristic: WithUUID<{
|
|
7
|
-
new (): Characteristic;
|
|
8
|
-
}>): boolean;
|
|
9
5
|
export declare function isObjectLike(candidate: unknown): candidate is Record<string, unknown>;
|
|
10
|
-
export declare function kelvinToMired(kelvin: number): number;
|
|
11
6
|
export declare function lookup<T>(object: unknown, compareFn: undefined | ((objectProp: unknown, search: T) => boolean), value: T): string | undefined;
|
|
12
7
|
export declare function lookupCharacteristicNameByUUID(characteristic: typeof Characteristic, uuid: string): string | undefined;
|
|
13
|
-
export declare function miredToKelvin(mired: number): number;
|
|
14
8
|
export declare function prefixLogger(logger: Logger, prefix: string | (() => string)): Logging;
|
|
15
|
-
export declare function runCommand(logger: Logger, command: string, args?: readonly string[], options?: SpawnOptionsWithoutStdio, hideStdout?: boolean, hideStderr?: boolean, returnProcess?: boolean
|
|
9
|
+
export declare function runCommand(logger: Logger, command: string, args?: readonly string[], options?: SpawnOptionsWithoutStdio, hideStdout?: boolean, hideStderr?: boolean, returnProcess?: boolean): Promise<[string, string, number | null, (ChildProcessWithoutNullStreams | null)?]>;
|