homebridge-generac 0.1.0-beta.1

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.
Files changed (71) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/LICENSE +200 -0
  3. package/NOTICE +20 -0
  4. package/README.md +179 -0
  5. package/SECURITY.md +17 -0
  6. package/config.schema.json +133 -0
  7. package/dist/accessory.d.ts +54 -0
  8. package/dist/accessory.js +191 -0
  9. package/dist/accessory.js.map +1 -0
  10. package/dist/api.d.ts +43 -0
  11. package/dist/api.js +124 -0
  12. package/dist/api.js.map +1 -0
  13. package/dist/attention.d.ts +18 -0
  14. package/dist/attention.js +40 -0
  15. package/dist/attention.js.map +1 -0
  16. package/dist/auth.d.ts +56 -0
  17. package/dist/auth.js +412 -0
  18. package/dist/auth.js.map +1 -0
  19. package/dist/captures.d.ts +9 -0
  20. package/dist/captures.js +42 -0
  21. package/dist/captures.js.map +1 -0
  22. package/dist/cli.d.ts +2 -0
  23. package/dist/cli.js +116 -0
  24. package/dist/cli.js.map +1 -0
  25. package/dist/exercise.d.ts +42 -0
  26. package/dist/exercise.js +115 -0
  27. package/dist/exercise.js.map +1 -0
  28. package/dist/files.d.ts +5 -0
  29. package/dist/files.js +28 -0
  30. package/dist/files.js.map +1 -0
  31. package/dist/index.d.ts +3 -0
  32. package/dist/index.js +6 -0
  33. package/dist/index.js.map +1 -0
  34. package/dist/model.d.ts +74 -0
  35. package/dist/model.js +167 -0
  36. package/dist/model.js.map +1 -0
  37. package/dist/platform.d.ts +117 -0
  38. package/dist/platform.js +596 -0
  39. package/dist/platform.js.map +1 -0
  40. package/dist/settings.d.ts +75 -0
  41. package/dist/settings.js +115 -0
  42. package/dist/settings.js.map +1 -0
  43. package/dist/state.d.ts +28 -0
  44. package/dist/state.js +43 -0
  45. package/dist/state.js.map +1 -0
  46. package/dist/types.d.ts +98 -0
  47. package/dist/types.js +48 -0
  48. package/dist/types.js.map +1 -0
  49. package/dist/ui/server.d.ts +96 -0
  50. package/dist/ui/server.js +328 -0
  51. package/dist/ui/server.js.map +1 -0
  52. package/homebridge-ui/public/generac-banner.png +0 -0
  53. package/homebridge-ui/public/generac.css +255 -0
  54. package/homebridge-ui/public/index.css +510 -0
  55. package/homebridge-ui/public/index.html +14 -0
  56. package/homebridge-ui/public/js/api.js +31 -0
  57. package/homebridge-ui/public/js/app.js +1 -0
  58. package/homebridge-ui/public/js/card.js +27 -0
  59. package/homebridge-ui/public/js/copy.js +167 -0
  60. package/homebridge-ui/public/js/dom.js +247 -0
  61. package/homebridge-ui/public/js/footer.js +26 -0
  62. package/homebridge-ui/public/js/format.js +62 -0
  63. package/homebridge-ui/public/js/main.js +288 -0
  64. package/homebridge-ui/public/js/mark.js +34 -0
  65. package/homebridge-ui/public/js/model.js +120 -0
  66. package/homebridge-ui/public/js/sections/account.js +272 -0
  67. package/homebridge-ui/public/js/sections/generators.js +165 -0
  68. package/homebridge-ui/public/js/sections/settings.js +114 -0
  69. package/homebridge-ui/public/js/validate.js +45 -0
  70. package/homebridge-ui/server.js +8 -0
  71. package/package.json +70 -0
package/dist/auth.js ADDED
@@ -0,0 +1,412 @@
1
+ /**
2
+ * The Auth0 and DPoP login flow in this file is ported from binarydev/ha-generac
3
+ * (Auth0 flow by sslivins, MFA handling by pjordanandrsn, Apache-2.0; see NOTICE).
4
+ * It was validated end to end against a live Mobile Link account with SMS MFA
5
+ * on September 15, 2026.
6
+ */
7
+ /**
8
+ * Generac Mobile Link authentication: Auth0 universal login (PKCE) with
9
+ * DPoP-bound tokens, driven the way the iOS app does it.
10
+ *
11
+ * Only `login()` needs a password, and only `homebridge-generac login` calls
12
+ * it. The running plugin uses `refreshAccessToken()` with the persisted
13
+ * refresh token, which Auth0 does not rotate for this client.
14
+ */
15
+ import crypto from 'node:crypto';
16
+ export const AUTH0_DOMAIN = 'auth.ecobee.com';
17
+ const AUTHORIZE_URL = `https://${AUTH0_DOMAIN}/authorize`;
18
+ const TOKEN_URL = `https://${AUTH0_DOMAIN}/oauth/token`;
19
+ const RESUME_URL = `https://${AUTH0_DOMAIN}/authorize/resume`;
20
+ const IDENTIFIER_URL = `https://${AUTH0_DOMAIN}/u/login/identifier`;
21
+ const PASSWORD_URL = `https://${AUTH0_DOMAIN}/u/login/password`;
22
+ const CLIENT_ID = 'eyjSuHZLjX3JC1lNmougLa8rjUw666TN';
23
+ const REDIRECT_URI = 'com.generac.mobilelink.auth0://auth.ecobee.com/ios/com.generac.mobilelink/callback';
24
+ const APP_SCHEME = 'com.generac.mobilelink.auth0://';
25
+ const SCOPE = 'openid email offline_access invoke:api';
26
+ const AUDIENCE = 'https://prod.ecobee.com/api/v1';
27
+ export const USER_AGENT_API = 'mobilelink/86535 CFNetwork/3860.500.112 Darwin/25.4.0';
28
+ const USER_AGENT_WEB = 'Mozilla/5.0 (iPhone; CPU iPhone OS 26_4 like Mac OS X) ' +
29
+ 'AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148';
30
+ function b64url(buf) {
31
+ return Buffer.from(buf).toString('base64url');
32
+ }
33
+ const AUTH0_CLIENT_HEADER = b64url(Buffer.from(JSON.stringify({ env: { swift: '6.x', iOS: '26.4' }, version: '2.16.2', name: 'Auth0.swift' })));
34
+ const CODE_CHALLENGES = {
35
+ 'mfa-sms-challenge': 'sms',
36
+ 'mfa-otp-challenge': 'otp',
37
+ 'mfa-email-challenge': 'email',
38
+ };
39
+ export class AuthError extends Error {
40
+ step;
41
+ constructor(message, step) {
42
+ super(message);
43
+ this.step = step;
44
+ this.name = 'AuthError';
45
+ }
46
+ }
47
+ /** Refresh token has been revoked or expired server-side. Needs a new login. */
48
+ export class InvalidGrantError extends AuthError {
49
+ constructor(message) {
50
+ super(message, 'refresh');
51
+ this.name = 'InvalidGrantError';
52
+ }
53
+ }
54
+ function truncate(s, n = 160) {
55
+ if (!s) {
56
+ return '';
57
+ }
58
+ return s.length > n ? s.slice(0, n) + '…' : s;
59
+ }
60
+ // ---------------------------------------------------------------------------
61
+ // DPoP key
62
+ // ---------------------------------------------------------------------------
63
+ export class DPoPKey {
64
+ privateKey;
65
+ jwk;
66
+ thumbprint;
67
+ constructor(privateKey) {
68
+ this.privateKey = privateKey;
69
+ const pub = crypto.createPublicKey(privateKey).export({ format: 'jwk' });
70
+ // RFC 7638 thumbprint: required members in lexicographic order.
71
+ this.jwk = { crv: pub.crv, kty: pub.kty, x: pub.x, y: pub.y };
72
+ this.thumbprint = b64url(crypto.createHash('sha256').update(JSON.stringify(this.jwk)).digest());
73
+ }
74
+ static generate() {
75
+ const { privateKey } = crypto.generateKeyPairSync('ec', { namedCurve: 'prime256v1' });
76
+ return new DPoPKey(privateKey);
77
+ }
78
+ static fromPem(pem) {
79
+ return new DPoPKey(crypto.createPrivateKey(pem));
80
+ }
81
+ toPem() {
82
+ return this.privateKey.export({ type: 'pkcs8', format: 'pem' }).toString();
83
+ }
84
+ signProof(htm, htu, nonce) {
85
+ const header = { alg: 'ES256', typ: 'dpop+jwt', jwk: this.jwk };
86
+ const payload = {
87
+ jti: crypto.randomUUID(),
88
+ htm: htm.toUpperCase(),
89
+ htu,
90
+ iat: Math.floor(Date.now() / 1000),
91
+ };
92
+ if (nonce) {
93
+ payload.nonce = nonce;
94
+ }
95
+ const input = b64url(Buffer.from(JSON.stringify(header))) + '.' + b64url(Buffer.from(JSON.stringify(payload)));
96
+ const sig = crypto.sign('sha256', Buffer.from(input), { key: this.privateKey, dsaEncoding: 'ieee-p1363' });
97
+ return `${input}.${b64url(sig)}`;
98
+ }
99
+ }
100
+ function makePkce() {
101
+ const verifier = b64url(crypto.randomBytes(32));
102
+ const challenge = b64url(crypto.createHash('sha256').update(verifier).digest());
103
+ return { verifier, challenge };
104
+ }
105
+ // ---------------------------------------------------------------------------
106
+ // Cookie jar + manual-redirect fetch (the last hop is an app-scheme URL)
107
+ // ---------------------------------------------------------------------------
108
+ class CookieJar {
109
+ cookies = new Map();
110
+ absorb(res) {
111
+ for (const sc of res.headers.getSetCookie()) {
112
+ const [pair] = sc.split(';');
113
+ const eq = pair.indexOf('=');
114
+ if (eq < 0) {
115
+ continue;
116
+ }
117
+ this.cookies.set(pair.slice(0, eq).trim(), pair.slice(eq + 1).trim());
118
+ }
119
+ }
120
+ header() {
121
+ return [...this.cookies].map(([k, v]) => `${k}=${v}`).join('; ');
122
+ }
123
+ }
124
+ async function fetchWithJar(jar, url, init = {}) {
125
+ const headers = { ...(init.headers ?? {}) };
126
+ const cookie = jar.header();
127
+ if (cookie) {
128
+ headers.Cookie = cookie;
129
+ }
130
+ const res = await fetch(url, { ...init, headers, redirect: 'manual' });
131
+ jar.absorb(res);
132
+ return res;
133
+ }
134
+ function isRedirect(res) {
135
+ return res.status === 302 || res.status === 303;
136
+ }
137
+ export function extractAuth0ErrorCode(html) {
138
+ const m = /data-error-code="([^"]+)"/.exec(html);
139
+ return m ? m[1] : null;
140
+ }
141
+ function absolute(loc) {
142
+ return new URL(loc, `https://${AUTH0_DOMAIN}`);
143
+ }
144
+ function log(ctx, step, msg) {
145
+ ctx.opts.log?.(step, msg);
146
+ }
147
+ async function fail(ctx, step, res, detail) {
148
+ const body = await res.text();
149
+ ctx.opts.onFailureBody?.(step, res.status, body);
150
+ const code = extractAuth0ErrorCode(body);
151
+ throw new AuthError(`${step}: HTTP ${res.status}${code ? ` (auth0: ${code})` : ''}${detail ? ` ${detail}` : ''}`, step);
152
+ }
153
+ async function stepAuthorize(ctx, key, state, challenge) {
154
+ const params = new URLSearchParams({
155
+ response_type: 'code',
156
+ code_challenge: challenge,
157
+ code_challenge_method: 'S256',
158
+ redirect_uri: REDIRECT_URI,
159
+ scope: SCOPE,
160
+ audience: AUDIENCE,
161
+ state,
162
+ dpop_jkt: key.thumbprint,
163
+ client_id: CLIENT_ID,
164
+ prompt: 'login',
165
+ login_hint: '',
166
+ auth0Client: AUTH0_CLIENT_HEADER,
167
+ });
168
+ const res = await fetchWithJar(ctx.jar, `${AUTHORIZE_URL}?${params}`, {
169
+ headers: { 'User-Agent': USER_AGENT_WEB, Accept: 'text/html,*/*' },
170
+ });
171
+ if (!isRedirect(res)) {
172
+ return fail(ctx, 'authorize', res);
173
+ }
174
+ const loc = res.headers.get('location') ?? '';
175
+ log(ctx, 'authorize', `302 -> ${truncate(loc)}`);
176
+ const next = absolute(loc).searchParams.get('state');
177
+ if (!next) {
178
+ throw new AuthError('authorize: no state in redirect', 'authorize');
179
+ }
180
+ return next;
181
+ }
182
+ async function postForm(ctx, step, url, state, form) {
183
+ const res = await fetchWithJar(ctx.jar, `${url}?state=${encodeURIComponent(state)}`, {
184
+ method: 'POST',
185
+ headers: {
186
+ 'User-Agent': USER_AGENT_WEB,
187
+ 'Content-Type': 'application/x-www-form-urlencoded',
188
+ Accept: 'text/html,*/*',
189
+ Origin: `https://${AUTH0_DOMAIN}`,
190
+ Referer: `${url}?state=${state}`,
191
+ },
192
+ body: new URLSearchParams(form).toString(),
193
+ });
194
+ if (!isRedirect(res)) {
195
+ return fail(ctx, step, res);
196
+ }
197
+ const loc = res.headers.get('location') ?? '';
198
+ log(ctx, step, `302 -> ${truncate(loc)}`);
199
+ return loc;
200
+ }
201
+ async function stepIdentifier(ctx, state, email) {
202
+ const loc = await postForm(ctx, 'identifier', IDENTIFIER_URL, state, {
203
+ state,
204
+ username: email,
205
+ 'js-available': 'true',
206
+ 'webauthn-available': 'true',
207
+ 'is-brave': 'false',
208
+ 'webauthn-platform-available': 'true',
209
+ action: 'default',
210
+ });
211
+ const u = absolute(loc);
212
+ if (!u.pathname.endsWith('/u/login/password')) {
213
+ throw new AuthError('identifier: email not recognized', 'identifier');
214
+ }
215
+ return u.searchParams.get('state');
216
+ }
217
+ async function stepPassword(ctx, state, email, password) {
218
+ const loc = await postForm(ctx, 'password', PASSWORD_URL, state, { state, username: email, password, action: 'default' });
219
+ const u = absolute(loc);
220
+ if (!u.pathname.endsWith('/authorize/resume')) {
221
+ throw new AuthError('password: rejected', 'password');
222
+ }
223
+ return u.searchParams.get('state');
224
+ }
225
+ async function handleCustomPrompt(ctx, loc) {
226
+ const u = absolute(loc);
227
+ const state = u.searchParams.get('state');
228
+ if (!state) {
229
+ throw new AuthError('custom-prompt: no state', 'custom-prompt');
230
+ }
231
+ // Auth0 convention: POST state + action=default hits the primary button.
232
+ const res = await fetchWithJar(ctx.jar, u.toString(), {
233
+ method: 'POST',
234
+ headers: {
235
+ 'User-Agent': USER_AGENT_WEB,
236
+ 'Content-Type': 'application/x-www-form-urlencoded',
237
+ Accept: 'text/html,*/*',
238
+ Origin: `https://${AUTH0_DOMAIN}`,
239
+ Referer: u.toString(),
240
+ },
241
+ body: new URLSearchParams({ state, action: 'default' }).toString(),
242
+ });
243
+ if (!isRedirect(res)) {
244
+ return fail(ctx, 'custom-prompt', res, 'This prompt needs a real browser (T&C, email verification or profile step). Sign in to the Mobile Link app, clear it, then retry.');
245
+ }
246
+ const next = res.headers.get('location') ?? '';
247
+ log(ctx, 'custom-prompt', `302 -> ${truncate(next)}`);
248
+ const nextState = absolute(next).searchParams.get('state');
249
+ if (!nextState) {
250
+ throw new AuthError('custom-prompt: no state after continue', 'custom-prompt');
251
+ }
252
+ return nextState;
253
+ }
254
+ export function challengeType(pathname) {
255
+ for (const [frag, type] of Object.entries(CODE_CHALLENGES)) {
256
+ if (pathname.includes(frag)) {
257
+ return type;
258
+ }
259
+ }
260
+ return null;
261
+ }
262
+ async function postMfaCode(ctx, url, state, code) {
263
+ const res = await fetchWithJar(ctx.jar, `${url}?state=${encodeURIComponent(state)}`, {
264
+ method: 'POST',
265
+ headers: {
266
+ 'User-Agent': USER_AGENT_WEB,
267
+ 'Content-Type': 'application/x-www-form-urlencoded',
268
+ Accept: 'text/html,*/*',
269
+ Origin: `https://${AUTH0_DOMAIN}`,
270
+ Referer: `${url}?state=${state}`,
271
+ },
272
+ body: new URLSearchParams({ state, code, action: 'default' }).toString(),
273
+ });
274
+ if (!isRedirect(res)) {
275
+ const body = await res.text();
276
+ ctx.opts.onFailureBody?.('mfa-submit', res.status, body);
277
+ return { ok: false, error: extractAuth0ErrorCode(body) ?? `HTTP ${res.status}` };
278
+ }
279
+ return { ok: true, loc: res.headers.get('location') ?? '' };
280
+ }
281
+ /** Follow /authorize/resume until Auth0 hands back the app-scheme redirect with the code. */
282
+ async function driveResume(ctx, resumeState, depth = 0) {
283
+ if (depth > 4) {
284
+ throw new AuthError('resume: too many redirects', 'resume');
285
+ }
286
+ for (let attempt = 0; attempt < 3; attempt++) {
287
+ const res = await fetchWithJar(ctx.jar, `${RESUME_URL}?state=${encodeURIComponent(resumeState)}`, {
288
+ headers: { 'User-Agent': USER_AGENT_WEB, Accept: 'text/html,*/*' },
289
+ });
290
+ if (!isRedirect(res)) {
291
+ return fail(ctx, 'resume', res);
292
+ }
293
+ const loc = res.headers.get('location') ?? '';
294
+ log(ctx, 'resume', `302 -> ${truncate(loc)}`);
295
+ if (loc.startsWith(APP_SCHEME)) {
296
+ const code = new URL(loc).searchParams.get('code');
297
+ if (!code) {
298
+ throw new AuthError('resume: no code in callback', 'resume');
299
+ }
300
+ return code;
301
+ }
302
+ const u = absolute(loc);
303
+ const mfaType = challengeType(u.pathname);
304
+ if (mfaType) {
305
+ const challengeUrl = `https://${AUTH0_DOMAIN}${u.pathname}`;
306
+ let mfaState = u.searchParams.get('state');
307
+ log(ctx, 'mfa', `Auth0 wants a ${mfaType.toUpperCase()} code`);
308
+ for (let tries = 0; tries < 3; tries++) {
309
+ const code = await ctx.opts.mfaPrompt(mfaType, tries + 1);
310
+ const r = await postMfaCode(ctx, challengeUrl, mfaState, code);
311
+ if (!r.ok) {
312
+ log(ctx, 'mfa', `code rejected (${r.error})`);
313
+ continue;
314
+ }
315
+ log(ctx, 'mfa-submit', `302 -> ${truncate(r.loc)}`);
316
+ if (r.loc.startsWith(APP_SCHEME)) {
317
+ const c = new URL(r.loc).searchParams.get('code');
318
+ if (!c) {
319
+ throw new AuthError('mfa: no code in callback', 'mfa');
320
+ }
321
+ return c;
322
+ }
323
+ const nu = absolute(r.loc);
324
+ if (challengeType(nu.pathname)) {
325
+ mfaState = nu.searchParams.get('state');
326
+ log(ctx, 'mfa', 'challenge re-presented; code wrong or expired');
327
+ continue;
328
+ }
329
+ if (nu.pathname.includes('/u/mfa-')) {
330
+ throw new AuthError(`mfa: unsupported follow-on factor ${nu.pathname}`, 'mfa');
331
+ }
332
+ if (nu.pathname.endsWith('/authorize/resume')) {
333
+ return driveResume(ctx, nu.searchParams.get('state'), depth + 1);
334
+ }
335
+ throw new AuthError(`mfa: unexpected redirect ${truncate(r.loc)}`, 'mfa');
336
+ }
337
+ throw new AuthError('mfa: three rejected codes', 'mfa');
338
+ }
339
+ if (u.pathname.includes('/u/mfa-')) {
340
+ throw new AuthError(`resume: MFA factor at ${u.pathname} cannot be driven from a terminal (push, security key or voice). ` +
341
+ 'Switch the account to SMS or an authenticator app.', 'mfa');
342
+ }
343
+ if (loc.includes('/u/custom-prompt/')) {
344
+ resumeState = await handleCustomPrompt(ctx, loc);
345
+ continue;
346
+ }
347
+ throw new AuthError(`resume: unexpected redirect ${truncate(loc)}`, 'resume');
348
+ }
349
+ throw new AuthError('resume: three consecutive custom prompts. Clear pending prompts in the Mobile Link app and retry.', 'resume');
350
+ }
351
+ async function tokenRequest(key, body, log) {
352
+ const post = async (nonce) => {
353
+ const res = await fetch(TOKEN_URL, {
354
+ method: 'POST',
355
+ headers: {
356
+ 'Content-Type': 'application/json',
357
+ Accept: 'application/json',
358
+ DPoP: key.signProof('POST', TOKEN_URL, nonce),
359
+ 'User-Agent': USER_AGENT_API,
360
+ },
361
+ body: JSON.stringify(body),
362
+ });
363
+ const text = await res.text();
364
+ let payload;
365
+ try {
366
+ payload = JSON.parse(text);
367
+ }
368
+ catch {
369
+ payload = { raw: text };
370
+ }
371
+ return { status: res.status, payload, nonce: res.headers.get('dpop-nonce') };
372
+ };
373
+ let r = await post();
374
+ if (r.status === 400 && r.payload.error === 'use_dpop_nonce' && r.nonce) {
375
+ log?.('token', 'server demanded a DPoP nonce; retrying');
376
+ r = await post(r.nonce);
377
+ }
378
+ return r;
379
+ }
380
+ export async function login(email, password, opts) {
381
+ const key = DPoPKey.generate();
382
+ const { verifier, challenge } = makePkce();
383
+ const ctx = { jar: new CookieJar(), opts };
384
+ const state = b64url(crypto.randomBytes(32));
385
+ const loginState = await stepAuthorize(ctx, key, state, challenge);
386
+ const pwState = await stepIdentifier(ctx, loginState, email);
387
+ const resumeState = await stepPassword(ctx, pwState, email, password);
388
+ const code = await driveResume(ctx, resumeState);
389
+ const r = await tokenRequest(key, { grant_type: 'authorization_code', client_id: CLIENT_ID, code, code_verifier: verifier, redirect_uri: REDIRECT_URI }, opts.log);
390
+ if (r.status !== 200) {
391
+ throw new AuthError(`token: code exchange failed HTTP ${r.status} ${JSON.stringify(r.payload)}`, 'token');
392
+ }
393
+ const tokens = r.payload;
394
+ if (!tokens.refresh_token) {
395
+ throw new AuthError('token: no refresh_token in response', 'token');
396
+ }
397
+ log(ctx, 'token', `login OK, expires_in=${tokens.expires_in}s`);
398
+ return { key, refreshToken: tokens.refresh_token, tokens };
399
+ }
400
+ export async function refreshAccessToken(key, refreshToken, log) {
401
+ const r = await tokenRequest(key, { grant_type: 'refresh_token', client_id: CLIENT_ID, refresh_token: refreshToken }, log);
402
+ if (r.status === 200) {
403
+ return r.payload;
404
+ }
405
+ const err = String(r.payload.error ?? '');
406
+ const desc = String(r.payload.error_description ?? '');
407
+ if (err === 'invalid_grant' || (r.status === 403 && /invalid|revoked|expired/i.test(desc))) {
408
+ throw new InvalidGrantError(`refresh token rejected (${err || r.status}): ${desc}`);
409
+ }
410
+ throw new AuthError(`refresh failed HTTP ${r.status} ${JSON.stringify(r.payload)}`, 'refresh');
411
+ }
412
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import type { RawApparatusDetail } from './types.js';
2
+ export declare const CAPTURES_KEEP = 10;
3
+ export declare function capturesDir(storagePath: string): string;
4
+ /** `{ISO timestamp with colons replaced by dashes}-status{n}.json`, which also sorts chronologically by name. */
5
+ export declare function captureFileName(now: Date, status: number): string;
6
+ /** Removes every capture beyond the newest `keep`. Returns the file names removed. */
7
+ export declare function pruneCaptures(dir: string, keep?: number): string[];
8
+ /** Writes one capture and prunes. Returns the file written. */
9
+ export declare function writeCapture(dir: string, detail: RawApparatusDetail, status: number, now: Date, keep?: number): string;
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Debug captures (SPEC section 12): the raw details payload on every status change or new lastExerciseAt,
3
+ * so a real Exercising payload can become the second fixture. Written atomically; the newest ten are kept.
4
+ * The payload is the API's own JSON and never carries a token (tokens live in headers, never in bodies).
5
+ */
6
+ import fs from 'node:fs';
7
+ import path from 'node:path';
8
+ import { writeFileAtomic } from './files.js';
9
+ import { dataDir } from './settings.js';
10
+ export const CAPTURES_KEEP = 10;
11
+ export function capturesDir(storagePath) {
12
+ return path.join(dataDir(storagePath), 'captures');
13
+ }
14
+ /** `{ISO timestamp with colons replaced by dashes}-status{n}.json`, which also sorts chronologically by name. */
15
+ export function captureFileName(now, status) {
16
+ return `${now.toISOString().replace(/:/g, '-')}-status${status}.json`;
17
+ }
18
+ const CAPTURE_PATTERN = /^\d{4}-\d{2}-\d{2}T\d{2}-\d{2}-\d{2}\.\d{3}Z-status\d+\.json$/;
19
+ /** Removes every capture beyond the newest `keep`. Returns the file names removed. */
20
+ export function pruneCaptures(dir, keep = CAPTURES_KEEP) {
21
+ let names;
22
+ try {
23
+ names = fs.readdirSync(dir).filter((n) => CAPTURE_PATTERN.test(n));
24
+ }
25
+ catch {
26
+ return [];
27
+ }
28
+ names.sort();
29
+ const stale = names.slice(0, Math.max(0, names.length - keep));
30
+ for (const name of stale) {
31
+ fs.rmSync(path.join(dir, name), { force: true });
32
+ }
33
+ return stale;
34
+ }
35
+ /** Writes one capture and prunes. Returns the file written. */
36
+ export function writeCapture(dir, detail, status, now, keep = CAPTURES_KEEP) {
37
+ const file = path.join(dir, captureFileName(now, status));
38
+ writeFileAtomic(file, JSON.stringify(detail, null, 2) + '\n', 0o600);
39
+ pruneCaptures(dir, keep);
40
+ return file;
41
+ }
42
+ //# sourceMappingURL=captures.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"captures.js","sourceRoot":"","sources":["../src/captures.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAGxC,MAAM,CAAC,MAAM,aAAa,GAAG,EAAE,CAAC;AAEhC,MAAM,UAAU,WAAW,CAAC,WAAmB;IAC7C,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,UAAU,CAAC,CAAC;AACrD,CAAC;AAED,iHAAiH;AACjH,MAAM,UAAU,eAAe,CAAC,GAAS,EAAE,MAAc;IACvD,OAAO,GAAG,GAAG,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,UAAU,MAAM,OAAO,CAAC;AACxE,CAAC;AAED,MAAM,eAAe,GAAG,+DAA+D,CAAC;AAExF,sFAAsF;AACtF,MAAM,UAAU,aAAa,CAAC,GAAW,EAAE,IAAI,GAAG,aAAa;IAC7D,IAAI,KAAe,CAAC;IACpB,IAAI,CAAC;QACH,KAAK,GAAG,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IACrE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,KAAK,CAAC,IAAI,EAAE,CAAC;IACb,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC;IAC/D,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACnD,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,+DAA+D;AAC/D,MAAM,UAAU,YAAY,CAAC,GAAW,EAAE,MAA0B,EAAE,MAAc,EAAE,GAAS,EAAE,IAAI,GAAG,aAAa;IACnH,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,eAAe,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC;IAC1D,eAAe,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,KAAK,CAAC,CAAC;IACrE,aAAa,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IACzB,OAAO,IAAI,CAAC;AACd,CAAC"}
package/dist/cli.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/cli.js ADDED
@@ -0,0 +1,116 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * homebridge-generac CLI
4
+ *
5
+ * homebridge-generac login [--out <file>] sign in once, save refresh token
6
+ * homebridge-generac status [--creds <file>] print what the account exposes
7
+ *
8
+ * Run `login` as the same user Homebridge runs as so the credentials land where
9
+ * the platform looks for them.
10
+ */
11
+ import fs from 'node:fs';
12
+ import path from 'node:path';
13
+ import readline from 'node:readline';
14
+ import { login } from './auth.js';
15
+ import { MobileLinkClient, readCredentials, writeCredentials } from './api.js';
16
+ import { toGeneratorState } from './model.js';
17
+ import { credentialCandidates, defaultStoragePath, primaryCredentialsPath } from './settings.js';
18
+ import { DEVICE_TYPE, DEVICE_TYPE_LABEL } from './types.js';
19
+ function arg(name) {
20
+ const i = process.argv.indexOf(name);
21
+ return i >= 0 ? process.argv[i + 1] : undefined;
22
+ }
23
+ function log(step, msg) {
24
+ console.error(` ${step.padEnd(14)} ${msg}`);
25
+ }
26
+ async function prompt(question, hidden = false) {
27
+ if (hidden && !process.stdin.isTTY) {
28
+ console.error('Refusing to read a password without a terminal (it would echo in the clear). Use `ssh -t`.');
29
+ process.exit(2);
30
+ }
31
+ const rl = readline.createInterface({ input: process.stdin, output: process.stderr, terminal: true });
32
+ if (hidden) {
33
+ const anyRl = rl;
34
+ const orig = anyRl._writeToOutput;
35
+ anyRl._writeToOutput = function (s) {
36
+ if (s.includes(question)) {
37
+ orig.call(rl, s);
38
+ }
39
+ else {
40
+ orig.call(rl, '*');
41
+ }
42
+ };
43
+ }
44
+ const answer = await new Promise((res) => rl.question(question, res));
45
+ rl.close();
46
+ if (hidden) {
47
+ process.stderr.write('\n');
48
+ }
49
+ return answer.trim();
50
+ }
51
+ async function cmdLogin() {
52
+ const out = arg('--out') ?? primaryCredentialsPath(defaultStoragePath());
53
+ const email = process.env.GENERAC_EMAIL || (await prompt('Mobile Link email: '));
54
+ const password = process.env.GENERAC_PASSWORD || (await prompt('Mobile Link password: ', true));
55
+ console.error(`\nSigning in to Mobile Link as ${email}…`);
56
+ const result = await login(email, password, {
57
+ log,
58
+ mfaPrompt: async (type) => prompt(`Enter the ${type.toUpperCase()} code you just received: `),
59
+ onFailureBody: (step, status, body) => {
60
+ const f = path.join(process.cwd(), `homebridge-generac-debug-${step}-${status}.html`);
61
+ fs.writeFileSync(f, body);
62
+ log('debug', `saved server response to ${f}`);
63
+ },
64
+ });
65
+ writeCredentials(out, {
66
+ email,
67
+ refresh_token: result.refreshToken,
68
+ dpop_private_key_pem: result.key.toPem(),
69
+ created_at: new Date().toISOString(),
70
+ });
71
+ console.error(`\nSaved credentials to ${out} (mode 600).`);
72
+ console.error('The password was not stored. Homebridge will use the refresh token from now on.\n');
73
+ console.error('Add this platform to your Homebridge config if you have not already:\n');
74
+ console.error(JSON.stringify({ platform: 'Generac', name: 'Generac' }, null, 2));
75
+ console.error('');
76
+ }
77
+ async function cmdStatus() {
78
+ const explicit = arg('--creds');
79
+ const candidates = credentialCandidates(defaultStoragePath(), explicit);
80
+ const file = candidates.find((f) => fs.existsSync(f));
81
+ if (!file) {
82
+ console.error(`No credentials found. Looked in:\n ${candidates.join('\n ')}\nRun \`homebridge-generac login\` first.`);
83
+ process.exit(1);
84
+ }
85
+ const creds = readCredentials(file);
86
+ console.error(`Using ${file} (${creds.email})`);
87
+ const client = MobileLinkClient.fromCredentials(creds, { log });
88
+ const list = await client.listApparatus();
89
+ const out = [];
90
+ for (const raw of list) {
91
+ const label = DEVICE_TYPE_LABEL[raw.type] ?? `type ${raw.type}`;
92
+ if (raw.type !== DEVICE_TYPE.GENERATOR) {
93
+ out.push({ apparatusId: raw.apparatusId, name: raw.name, type: `${raw.type} (${label})`, exposed: false });
94
+ continue;
95
+ }
96
+ try {
97
+ const d = await client.apparatusDetails(raw.apparatusId);
98
+ out.push(d ? toGeneratorState(d, raw, { faultOnStopped: true, faultOnDisconnected: false }) : { apparatusId: raw.apparatusId, error: 'no details' });
99
+ }
100
+ catch (err) {
101
+ out.push({ apparatusId: raw.apparatusId, name: raw.name, error: err.message });
102
+ }
103
+ }
104
+ console.log(JSON.stringify(out, null, 2));
105
+ }
106
+ const cmd = process.argv[2];
107
+ const run = cmd === 'login' ? cmdLogin : cmd === 'status' ? cmdStatus : null;
108
+ if (!run) {
109
+ console.error('Usage: homebridge-generac <login [--out file] | status [--creds file]>');
110
+ process.exit(2);
111
+ }
112
+ run().catch((err) => {
113
+ console.error(`\nFAILED: ${err.message}`);
114
+ process.exit(1);
115
+ });
116
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA;;;;;;;;GAQG;AACH,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,QAAQ,MAAM,eAAe,CAAC;AACrC,OAAO,EAAE,KAAK,EAAgB,MAAM,WAAW,CAAC;AAChD,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAC/E,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAC;AACjG,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAE5D,SAAS,GAAG,CAAC,IAAY;IACvB,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACrC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AAClD,CAAC;AAED,SAAS,GAAG,CAAC,IAAY,EAAE,GAAW;IACpC,OAAO,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,GAAG,EAAE,CAAC,CAAC;AAC/C,CAAC;AAED,KAAK,UAAU,MAAM,CAAC,QAAgB,EAAE,MAAM,GAAG,KAAK;IACpD,IAAI,MAAM,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QACnC,OAAO,CAAC,KAAK,CAAC,4FAA4F,CAAC,CAAC;QAC5G,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,MAAM,EAAE,GAAG,QAAQ,CAAC,eAAe,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;IACtG,IAAI,MAAM,EAAE,CAAC;QACX,MAAM,KAAK,GAAG,EAAwD,CAAC;QACvE,MAAM,IAAI,GAAG,KAAK,CAAC,cAAc,CAAC;QAClC,KAAK,CAAC,cAAc,GAAG,UAAU,CAAS;YACxC,IAAI,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;gBACzB,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;YACnB,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;YACrB,CAAC;QACH,CAAC,CAAC;IACJ,CAAC;IACD,MAAM,MAAM,GAAG,MAAM,IAAI,OAAO,CAAS,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE,CAAC,QAAQ,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,CAAC;IAC9E,EAAE,CAAC,KAAK,EAAE,CAAC;IACX,IAAI,MAAM,EAAE,CAAC;QACX,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC7B,CAAC;IACD,OAAO,MAAM,CAAC,IAAI,EAAE,CAAC;AACvB,CAAC;AAED,KAAK,UAAU,QAAQ;IACrB,MAAM,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,IAAI,sBAAsB,CAAC,kBAAkB,EAAE,CAAC,CAAC;IACzE,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,CAAC,MAAM,MAAM,CAAC,qBAAqB,CAAC,CAAC,CAAC;IACjF,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,gBAAgB,IAAI,CAAC,MAAM,MAAM,CAAC,wBAAwB,EAAE,IAAI,CAAC,CAAC,CAAC;IAEhG,OAAO,CAAC,KAAK,CAAC,kCAAkC,KAAK,GAAG,CAAC,CAAC;IAC1D,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,KAAK,EAAE,QAAQ,EAAE;QAC1C,GAAG;QACH,SAAS,EAAE,KAAK,EAAE,IAAa,EAAE,EAAE,CAAC,MAAM,CAAC,aAAa,IAAI,CAAC,WAAW,EAAE,2BAA2B,CAAC;QACtG,aAAa,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE;YACpC,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,4BAA4B,IAAI,IAAI,MAAM,OAAO,CAAC,CAAC;YACtF,EAAE,CAAC,aAAa,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;YAC1B,GAAG,CAAC,OAAO,EAAE,4BAA4B,CAAC,EAAE,CAAC,CAAC;QAChD,CAAC;KACF,CAAC,CAAC;IAEH,gBAAgB,CAAC,GAAG,EAAE;QACpB,KAAK;QACL,aAAa,EAAE,MAAM,CAAC,YAAY;QAClC,oBAAoB,EAAE,MAAM,CAAC,GAAG,CAAC,KAAK,EAAE;QACxC,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACrC,CAAC,CAAC;IAEH,OAAO,CAAC,KAAK,CAAC,0BAA0B,GAAG,cAAc,CAAC,CAAC;IAC3D,OAAO,CAAC,KAAK,CAAC,mFAAmF,CAAC,CAAC;IACnG,OAAO,CAAC,KAAK,CAAC,wEAAwE,CAAC,CAAC;IACxF,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IACjF,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;AACpB,CAAC;AAED,KAAK,UAAU,SAAS;IACtB,MAAM,QAAQ,GAAG,GAAG,CAAC,SAAS,CAAC,CAAC;IAChC,MAAM,UAAU,GAAG,oBAAoB,CAAC,kBAAkB,EAAE,EAAE,QAAQ,CAAC,CAAC;IACxE,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;IACtD,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,OAAO,CAAC,KAAK,CAAC,uCAAuC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,2CAA2C,CAAC,CAAC;QACzH,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,MAAM,KAAK,GAAG,eAAe,CAAC,IAAI,CAAE,CAAC;IACrC,OAAO,CAAC,KAAK,CAAC,SAAS,IAAI,KAAK,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC;IAChD,MAAM,MAAM,GAAG,gBAAgB,CAAC,eAAe,CAAC,KAAK,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC;IAEhE,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,aAAa,EAAE,CAAC;IAC1C,MAAM,GAAG,GAAc,EAAE,CAAC;IAC1B,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,MAAM,KAAK,GAAG,iBAAiB,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,QAAQ,GAAG,CAAC,IAAI,EAAE,CAAC;QAChE,IAAI,GAAG,CAAC,IAAI,KAAK,WAAW,CAAC,SAAS,EAAE,CAAC;YACvC,GAAG,CAAC,IAAI,CAAC,EAAE,WAAW,EAAE,GAAG,CAAC,WAAW,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,GAAG,CAAC,IAAI,KAAK,KAAK,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;YAC3G,SAAS;QACX,CAAC;QACD,IAAI,CAAC;YACH,MAAM,CAAC,GAAG,MAAM,MAAM,CAAC,gBAAgB,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;YACzD,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE,cAAc,EAAE,IAAI,EAAE,mBAAmB,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,GAAG,CAAC,WAAW,EAAE,KAAK,EAAE,YAAY,EAAE,CAAC,CAAC;QACvJ,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,GAAG,CAAC,IAAI,CAAC,EAAE,WAAW,EAAE,GAAG,CAAC,WAAW,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,KAAK,EAAG,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;QAC5F,CAAC;IACH,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;AAC5C,CAAC;AAED,MAAM,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAC5B,MAAM,GAAG,GAAG,GAAG,KAAK,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC;AAC7E,IAAI,CAAC,GAAG,EAAE,CAAC;IACT,OAAO,CAAC,KAAK,CAAC,wEAAwE,CAAC,CAAC;IACxF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AACD,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IAClB,OAAO,CAAC,KAAK,CAAC,aAAc,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;IACrD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}