iobroker.homewizard 0.1.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 +190 -0
- package/admin/homewizard.svg +6 -0
- package/admin/i18n/de/translations.json +16 -0
- package/admin/i18n/en/translations.json +16 -0
- package/admin/i18n/es/translations.json +16 -0
- package/admin/i18n/fr/translations.json +16 -0
- package/admin/i18n/it/translations.json +16 -0
- package/admin/i18n/nl/translations.json +16 -0
- package/admin/i18n/pl/translations.json +16 -0
- package/admin/i18n/pt/translations.json +16 -0
- package/admin/i18n/ru/translations.json +16 -0
- package/admin/i18n/uk/translations.json +16 -0
- package/admin/i18n/zh-cn/translations.json +16 -0
- package/admin/jsonConfig.json +99 -0
- package/build/lib/discovery.js +103 -0
- package/build/lib/discovery.js.map +7 -0
- package/build/lib/homewizard-client.js +193 -0
- package/build/lib/homewizard-client.js.map +7 -0
- package/build/lib/state-manager.js +749 -0
- package/build/lib/state-manager.js.map +7 -0
- package/build/lib/types.js +17 -0
- package/build/lib/types.js.map +7 -0
- package/build/lib/websocket-client.js +151 -0
- package/build/lib/websocket-client.js.map +7 -0
- package/build/main.js +441 -0
- package/build/main.js.map +7 -0
- package/io-package.json +136 -0
- package/package.json +77 -0
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
var homewizard_client_exports = {};
|
|
30
|
+
__export(homewizard_client_exports, {
|
|
31
|
+
HomeWizardApiError: () => HomeWizardApiError,
|
|
32
|
+
HomeWizardClient: () => HomeWizardClient
|
|
33
|
+
});
|
|
34
|
+
module.exports = __toCommonJS(homewizard_client_exports);
|
|
35
|
+
var https = __toESM(require("node:https"));
|
|
36
|
+
class HomeWizardClient {
|
|
37
|
+
ip;
|
|
38
|
+
token;
|
|
39
|
+
/**
|
|
40
|
+
* @param ip Device IP address
|
|
41
|
+
* @param token Bearer token (empty string for pairing requests)
|
|
42
|
+
*/
|
|
43
|
+
constructor(ip, token = "") {
|
|
44
|
+
this.ip = ip;
|
|
45
|
+
this.token = token;
|
|
46
|
+
}
|
|
47
|
+
/** Get device info (GET /api) */
|
|
48
|
+
async getDeviceInfo() {
|
|
49
|
+
return this.request("GET", "/api");
|
|
50
|
+
}
|
|
51
|
+
/** Request pairing token (POST /api/user) — 403 until button pressed */
|
|
52
|
+
async requestPairing() {
|
|
53
|
+
return this.request("POST", "/api/user", {
|
|
54
|
+
name: "local/iobroker"
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
/** Get current measurement (REST fallback) */
|
|
58
|
+
async getMeasurement() {
|
|
59
|
+
return this.request("GET", "/api/measurement");
|
|
60
|
+
}
|
|
61
|
+
/** Get system info */
|
|
62
|
+
async getSystem() {
|
|
63
|
+
return this.request("GET", "/api/system");
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Update system settings
|
|
67
|
+
*
|
|
68
|
+
* @param settings System settings to update
|
|
69
|
+
*/
|
|
70
|
+
async setSystem(settings) {
|
|
71
|
+
return this.request("PUT", "/api/system", settings);
|
|
72
|
+
}
|
|
73
|
+
/** Reboot device */
|
|
74
|
+
async reboot() {
|
|
75
|
+
await this.request("PUT", "/api/system/reboot");
|
|
76
|
+
}
|
|
77
|
+
/** Identify device (blink LED) */
|
|
78
|
+
async identify() {
|
|
79
|
+
await this.request("PUT", "/api/system/identify");
|
|
80
|
+
}
|
|
81
|
+
/** Get battery control status */
|
|
82
|
+
async getBatteries() {
|
|
83
|
+
return this.request("GET", "/api/batteries");
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Set battery control
|
|
87
|
+
*
|
|
88
|
+
* @param settings Battery control settings to update
|
|
89
|
+
*/
|
|
90
|
+
async setBatteries(settings) {
|
|
91
|
+
return this.request("PUT", "/api/batteries", settings);
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* @param method HTTP method
|
|
95
|
+
* @param path API path
|
|
96
|
+
* @param body Optional request body
|
|
97
|
+
*/
|
|
98
|
+
request(method, path, body) {
|
|
99
|
+
return new Promise((resolve, reject) => {
|
|
100
|
+
const bodyStr = body ? JSON.stringify(body) : void 0;
|
|
101
|
+
const headers = {
|
|
102
|
+
"X-Api-Version": "2"
|
|
103
|
+
};
|
|
104
|
+
if (this.token) {
|
|
105
|
+
headers.Authorization = `Bearer ${this.token}`;
|
|
106
|
+
}
|
|
107
|
+
if (bodyStr) {
|
|
108
|
+
headers["Content-Type"] = "application/json";
|
|
109
|
+
headers["Content-Length"] = Buffer.byteLength(bodyStr).toString();
|
|
110
|
+
}
|
|
111
|
+
const req = https.request(
|
|
112
|
+
{
|
|
113
|
+
hostname: this.ip,
|
|
114
|
+
port: 443,
|
|
115
|
+
path,
|
|
116
|
+
method,
|
|
117
|
+
headers,
|
|
118
|
+
rejectUnauthorized: false,
|
|
119
|
+
// HomeWizard uses self-signed certs
|
|
120
|
+
timeout: 1e4
|
|
121
|
+
},
|
|
122
|
+
(res) => {
|
|
123
|
+
const chunks = [];
|
|
124
|
+
res.on("data", (chunk) => chunks.push(chunk));
|
|
125
|
+
res.on("end", () => {
|
|
126
|
+
var _a;
|
|
127
|
+
const data = Buffer.concat(chunks).toString();
|
|
128
|
+
if (!res.statusCode || res.statusCode >= 400) {
|
|
129
|
+
const error = new HomeWizardApiError(
|
|
130
|
+
(_a = res.statusCode) != null ? _a : 0,
|
|
131
|
+
data,
|
|
132
|
+
`${method} ${path}`
|
|
133
|
+
);
|
|
134
|
+
reject(error);
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
if (!data) {
|
|
138
|
+
resolve(void 0);
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
try {
|
|
142
|
+
resolve(JSON.parse(data));
|
|
143
|
+
} catch {
|
|
144
|
+
reject(
|
|
145
|
+
new Error(
|
|
146
|
+
`Invalid JSON from ${method} ${path}: ${data.substring(0, 200)}`
|
|
147
|
+
)
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
);
|
|
153
|
+
req.on("error", reject);
|
|
154
|
+
req.on("timeout", () => {
|
|
155
|
+
req.destroy(new Error(`Timeout: ${method} ${path}`));
|
|
156
|
+
});
|
|
157
|
+
if (bodyStr) {
|
|
158
|
+
req.write(bodyStr);
|
|
159
|
+
}
|
|
160
|
+
req.end();
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
class HomeWizardApiError extends Error {
|
|
165
|
+
statusCode;
|
|
166
|
+
errorCode;
|
|
167
|
+
/**
|
|
168
|
+
* @param statusCode HTTP status code
|
|
169
|
+
* @param body Response body
|
|
170
|
+
* @param context Request context for error message
|
|
171
|
+
*/
|
|
172
|
+
constructor(statusCode, body, context) {
|
|
173
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
174
|
+
let errorCode = "unknown";
|
|
175
|
+
let description = body;
|
|
176
|
+
try {
|
|
177
|
+
const parsed = JSON.parse(body);
|
|
178
|
+
errorCode = (_c = (_b = (_a = parsed.error) == null ? void 0 : _a.code) != null ? _b : parsed.error) != null ? _c : "unknown";
|
|
179
|
+
description = (_g = (_f = (_d = parsed.error) == null ? void 0 : _d.description) != null ? _f : (_e = parsed.error) == null ? void 0 : _e.code) != null ? _g : body;
|
|
180
|
+
} catch {
|
|
181
|
+
}
|
|
182
|
+
super(`${context}: HTTP ${statusCode} \u2014 ${description}`);
|
|
183
|
+
this.name = "HomeWizardApiError";
|
|
184
|
+
this.statusCode = statusCode;
|
|
185
|
+
this.errorCode = errorCode;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
189
|
+
0 && (module.exports = {
|
|
190
|
+
HomeWizardApiError,
|
|
191
|
+
HomeWizardClient
|
|
192
|
+
});
|
|
193
|
+
//# sourceMappingURL=homewizard-client.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/lib/homewizard-client.ts"],
|
|
4
|
+
"sourcesContent": ["import * as https from \"node:https\";\nimport type {\n BatteryControl,\n DeviceInfo,\n Measurement,\n PairingResponse,\n SystemInfo,\n} from \"./types\";\n\n/** HTTPS client for HomeWizard API v2 */\nexport class HomeWizardClient {\n private readonly ip: string;\n private readonly token: string;\n\n /**\n * @param ip Device IP address\n * @param token Bearer token (empty string for pairing requests)\n */\n constructor(ip: string, token: string = \"\") {\n this.ip = ip;\n this.token = token;\n }\n\n /** Get device info (GET /api) */\n async getDeviceInfo(): Promise<DeviceInfo> {\n return this.request<DeviceInfo>(\"GET\", \"/api\");\n }\n\n /** Request pairing token (POST /api/user) \u2014 403 until button pressed */\n async requestPairing(): Promise<PairingResponse> {\n return this.request<PairingResponse>(\"POST\", \"/api/user\", {\n name: \"local/iobroker\",\n });\n }\n\n /** Get current measurement (REST fallback) */\n async getMeasurement(): Promise<Measurement> {\n return this.request<Measurement>(\"GET\", \"/api/measurement\");\n }\n\n /** Get system info */\n async getSystem(): Promise<SystemInfo> {\n return this.request<SystemInfo>(\"GET\", \"/api/system\");\n }\n\n /**\n * Update system settings\n *\n * @param settings System settings to update\n */\n async setSystem(settings: Partial<SystemInfo>): Promise<SystemInfo> {\n return this.request<SystemInfo>(\"PUT\", \"/api/system\", settings);\n }\n\n /** Reboot device */\n async reboot(): Promise<void> {\n await this.request(\"PUT\", \"/api/system/reboot\");\n }\n\n /** Identify device (blink LED) */\n async identify(): Promise<void> {\n await this.request(\"PUT\", \"/api/system/identify\");\n }\n\n /** Get battery control status */\n async getBatteries(): Promise<BatteryControl> {\n return this.request<BatteryControl>(\"GET\", \"/api/batteries\");\n }\n\n /**\n * Set battery control\n *\n * @param settings Battery control settings to update\n */\n async setBatteries(\n settings: Partial<BatteryControl>,\n ): Promise<BatteryControl> {\n return this.request<BatteryControl>(\"PUT\", \"/api/batteries\", settings);\n }\n\n /**\n * @param method HTTP method\n * @param path API path\n * @param body Optional request body\n */\n private request<T>(method: string, path: string, body?: unknown): Promise<T> {\n return new Promise((resolve, reject) => {\n const bodyStr = body ? JSON.stringify(body) : undefined;\n const headers: Record<string, string> = {\n \"X-Api-Version\": \"2\",\n };\n\n if (this.token) {\n headers.Authorization = `Bearer ${this.token}`;\n }\n if (bodyStr) {\n headers[\"Content-Type\"] = \"application/json\";\n headers[\"Content-Length\"] = Buffer.byteLength(bodyStr).toString();\n }\n\n const req = https.request(\n {\n hostname: this.ip,\n port: 443,\n path,\n method,\n headers,\n rejectUnauthorized: false, // HomeWizard uses self-signed certs\n timeout: 10_000,\n },\n (res) => {\n const chunks: Buffer[] = [];\n res.on(\"data\", (chunk: Buffer) => chunks.push(chunk));\n res.on(\"end\", () => {\n const data = Buffer.concat(chunks).toString();\n if (!res.statusCode || res.statusCode >= 400) {\n const error = new HomeWizardApiError(\n res.statusCode ?? 0,\n data,\n `${method} ${path}`,\n );\n reject(error);\n return;\n }\n if (!data) {\n resolve(undefined as T);\n return;\n }\n try {\n resolve(JSON.parse(data) as T);\n } catch {\n reject(\n new Error(\n `Invalid JSON from ${method} ${path}: ${data.substring(0, 200)}`,\n ),\n );\n }\n });\n },\n );\n\n req.on(\"error\", reject);\n req.on(\"timeout\", () => {\n req.destroy(new Error(`Timeout: ${method} ${path}`));\n });\n\n if (bodyStr) {\n req.write(bodyStr);\n }\n req.end();\n });\n }\n}\n\n/** API error with status code and parsed error body */\nexport class HomeWizardApiError extends Error {\n readonly statusCode: number;\n readonly errorCode: string;\n\n /**\n * @param statusCode HTTP status code\n * @param body Response body\n * @param context Request context for error message\n */\n constructor(statusCode: number, body: string, context: string) {\n let errorCode = \"unknown\";\n let description = body;\n try {\n const parsed = JSON.parse(body);\n errorCode = parsed.error?.code ?? parsed.error ?? \"unknown\";\n description = parsed.error?.description ?? parsed.error?.code ?? body;\n } catch {\n // body is not JSON\n }\n super(`${context}: HTTP ${statusCode} \u2014 ${description}`);\n this.name = \"HomeWizardApiError\";\n this.statusCode = statusCode;\n this.errorCode = errorCode;\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|