homebridge-smarthq-client 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.
Files changed (84) hide show
  1. package/LICENSE +21 -0
  2. package/Readme.md +138 -0
  3. package/config.schema.json +146 -0
  4. package/dist/index.d.ts +6 -0
  5. package/dist/index.js +9 -0
  6. package/dist/index.js.map +1 -0
  7. package/dist/platform.d.ts +40 -0
  8. package/dist/platform.js +243 -0
  9. package/dist/platform.js.map +1 -0
  10. package/dist/refrigerator/controlLock.d.ts +19 -0
  11. package/dist/refrigerator/controlLock.js +85 -0
  12. package/dist/refrigerator/controlLock.js.map +1 -0
  13. package/dist/refrigerator/convertibleDrawer.d.ts +27 -0
  14. package/dist/refrigerator/convertibleDrawer.js +317 -0
  15. package/dist/refrigerator/convertibleDrawer.js.map +1 -0
  16. package/dist/refrigerator/dispenserLight.d.ts +19 -0
  17. package/dist/refrigerator/dispenserLight.js +85 -0
  18. package/dist/refrigerator/dispenserLight.js.map +1 -0
  19. package/dist/refrigerator/energy.d.ts +19 -0
  20. package/dist/refrigerator/energy.js +93 -0
  21. package/dist/refrigerator/energy.js.map +1 -0
  22. package/dist/refrigerator/freezer.d.ts +41 -0
  23. package/dist/refrigerator/freezer.js +188 -0
  24. package/dist/refrigerator/freezer.js.map +1 -0
  25. package/dist/refrigerator/iceMaker.d.ts +19 -0
  26. package/dist/refrigerator/iceMaker.js +81 -0
  27. package/dist/refrigerator/iceMaker.js.map +1 -0
  28. package/dist/refrigerator/interiorLight.d.ts +21 -0
  29. package/dist/refrigerator/interiorLight.js +100 -0
  30. package/dist/refrigerator/interiorLight.js.map +1 -0
  31. package/dist/refrigerator/refrigerator.d.ts +41 -0
  32. package/dist/refrigerator/refrigerator.js +204 -0
  33. package/dist/refrigerator/refrigerator.js.map +1 -0
  34. package/dist/refrigerator/refrigeratorAlerts.d.ts +36 -0
  35. package/dist/refrigerator/refrigeratorAlerts.js +204 -0
  36. package/dist/refrigerator/refrigeratorAlerts.js.map +1 -0
  37. package/dist/refrigerator/sabbathMode.d.ts +20 -0
  38. package/dist/refrigerator/sabbathMode.js +91 -0
  39. package/dist/refrigerator/sabbathMode.js.map +1 -0
  40. package/dist/refrigerator/temperatureUnits.d.ts +21 -0
  41. package/dist/refrigerator/temperatureUnits.js +147 -0
  42. package/dist/refrigerator/temperatureUnits.js.map +1 -0
  43. package/dist/refrigerator/turboCoolMode.d.ts +23 -0
  44. package/dist/refrigerator/turboCoolMode.js +134 -0
  45. package/dist/refrigerator/turboCoolMode.js.map +1 -0
  46. package/dist/refrigerator/waterFilter.d.ts +19 -0
  47. package/dist/refrigerator/waterFilter.js +89 -0
  48. package/dist/refrigerator/waterFilter.js.map +1 -0
  49. package/dist/refrigeratorServices.d.ts +5 -0
  50. package/dist/refrigeratorServices.js +54 -0
  51. package/dist/refrigeratorServices.js.map +1 -0
  52. package/dist/settings.d.ts +12 -0
  53. package/dist/settings.js +13 -0
  54. package/dist/settings.js.map +1 -0
  55. package/dist/smartHqApi.d.ts +29 -0
  56. package/dist/smartHqApi.js +267 -0
  57. package/dist/smartHqApi.js.map +1 -0
  58. package/dist/smarthq-types.d.ts +29 -0
  59. package/dist/smarthq-types.js +2 -0
  60. package/dist/smarthq-types.js.map +1 -0
  61. package/eslint.config.js +12 -0
  62. package/images/homebridge.svg +1 -0
  63. package/package.json +61 -0
  64. package/src/@types/homebridge-lib.d.ts +14 -0
  65. package/src/index.ts +11 -0
  66. package/src/platform.ts +300 -0
  67. package/src/refrigerator/controlLock.ts +103 -0
  68. package/src/refrigerator/convertibleDrawer.ts +381 -0
  69. package/src/refrigerator/dispenserLight.ts +103 -0
  70. package/src/refrigerator/energy.ts +106 -0
  71. package/src/refrigerator/freezer.ts +227 -0
  72. package/src/refrigerator/iceMaker.ts +100 -0
  73. package/src/refrigerator/interiorLight.ts +118 -0
  74. package/src/refrigerator/refrigerator.ts +241 -0
  75. package/src/refrigerator/refrigeratorAlerts.ts +228 -0
  76. package/src/refrigerator/sabbathMode.ts +111 -0
  77. package/src/refrigerator/temperatureUnits.ts +178 -0
  78. package/src/refrigerator/turboCoolMode.ts +164 -0
  79. package/src/refrigerator/waterFilter.ts +107 -0
  80. package/src/refrigeratorServices.ts +60 -0
  81. package/src/settings.ts +14 -0
  82. package/src/smartHqApi.ts +305 -0
  83. package/src/smarthq-types.ts +31 -0
  84. package/tsconfig.json +24 -0
@@ -0,0 +1,267 @@
1
+ import axios, { isAxiosError } from 'axios';
2
+ import { writeFileSync, existsSync, readFileSync } from 'fs';
3
+ import { stringify } from 'querystring';
4
+ import chalk from 'chalk';
5
+ import { API_URL, AUTH_URL, ACCESSTOKEN_URL } from './settings.js';
6
+ /**
7
+ * SmartHq Api functions
8
+ * This class is the main constructor for your plugin, this is where you should
9
+ * parse the user config and discover/register accessories with Homebridge.
10
+ */
11
+ /* ---------- SmartHq Api ---------- */
12
+ export class SmartHqApi {
13
+ platform;
14
+ refresh_token;
15
+ expires;
16
+ access_token;
17
+ constructor(platform) {
18
+ this.platform = platform;
19
+ this.refresh_token = '';
20
+ this.access_token = '';
21
+ this.expires = 0;
22
+ this.loadAccessToken();
23
+ }
24
+ //-------------------------------------------------------------
25
+ // Create the url to be displayed in Homebridge log for first time
26
+ // user to visit the link and login successfully.
27
+ // Response will be sent to redirect uri
28
+ //-------------------------------------------------------------
29
+ authUrl() {
30
+ return AUTH_URL + stringify({
31
+ response_type: 'code',
32
+ client_id: this.platform.config.clientId,
33
+ redirect_uri: this.platform.config.redirectUri
34
+ });
35
+ }
36
+ async getOauthAccessToken(dataForBody) {
37
+ try {
38
+ const response = await axios.post(ACCESSTOKEN_URL, stringify(dataForBody), { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } });
39
+ this.saveToken(response.data);
40
+ }
41
+ catch (error) {
42
+ // Use isAxiosError type guard for safe property access
43
+ if (axios.isAxiosError(error)) {
44
+ if (error.response) {
45
+ switch (error.response.status) {
46
+ case 400:
47
+ this.platform.log.error('(400) Bad Request: The request is missing required parameters or includes invalid values.');
48
+ break;
49
+ case 401:
50
+ this.platform.log.error('(401) Unauthorized – The provided client credentials are invalid.: ');
51
+ break;
52
+ default:
53
+ this.platform.log.error('Error obtaining token: ', error.message);
54
+ break;
55
+ }
56
+ }
57
+ }
58
+ else {
59
+ // Not an Axios error (e.g., a general JavaScript error)
60
+ console.error('Unexpected error:', error);
61
+ }
62
+ }
63
+ }
64
+ async exchangeCodeForToken(code) {
65
+ return this.getOauthAccessToken({
66
+ grant_type: 'authorization_code',
67
+ client_id: this.platform.config.clientId,
68
+ client_secret: this.platform.config.clientSecret,
69
+ redirect_uri: this.platform.config.redirectUri,
70
+ code: code
71
+ });
72
+ }
73
+ async refreshAccessToken() {
74
+ return this.getOauthAccessToken({
75
+ grant_type: 'refresh_token',
76
+ client_id: this.platform.config.clientId,
77
+ client_secret: this.platform.config.clientSecret,
78
+ refresh_token: this.refresh_token
79
+ });
80
+ }
81
+ saveToken(data) {
82
+ Object.assign(this, data);
83
+ this.expires = Date.now() + data.expires_in * 1000;
84
+ try {
85
+ writeFileSync(this.platform.tokenPath, JSON.stringify(data, null, 2));
86
+ }
87
+ catch (error) {
88
+ this.platform.log.error('Error saving token: ', error);
89
+ }
90
+ }
91
+ loadAccessToken() {
92
+ if (!existsSync(this.platform.tokenPath))
93
+ return;
94
+ const data = readFileSync(this.platform.tokenPath).toString('utf8');
95
+ const tokenData = JSON.parse(data);
96
+ Object.assign(this, tokenData);
97
+ this.expires = Date.now() + tokenData.expires_in * 1000;
98
+ }
99
+ async httpHeaders() {
100
+ if (!this.access_token || Date.now() > this.expires - 60000) {
101
+ await this.refreshAccessToken();
102
+ }
103
+ return { Authorization: `Bearer ${this.access_token}` };
104
+ }
105
+ async getAppliances() {
106
+ //======================================================
107
+ // Get list of devices for your account
108
+ //======================================================
109
+ this.debug('green', 'Entering getAppliances()');
110
+ const url = new URL('/v2/device', API_URL);
111
+ try {
112
+ const res = await axios.get(url.toString(), { headers: await this.httpHeaders() });
113
+ return res.data.devices;
114
+ }
115
+ catch (error) {
116
+ if (isAxiosError(error)) {
117
+ if (error.response) {
118
+ switch (error.response.status) {
119
+ case 400:
120
+ this.platform.log.error('(400) Bad Request: ', error.message);
121
+ break;
122
+ case 401:
123
+ this.refreshAccessToken();
124
+ //this.platform.log.error('(401) Unauthorized: ', error.message); token expired - refresh token instead of error
125
+ break;
126
+ case 403:
127
+ this.platform.log.error('(403) Forbidden client does not have permission to view device: ', error.message);
128
+ break;
129
+ default:
130
+ this.platform.log.error('Error in getAppliances(): ', error.message);
131
+ break;
132
+ }
133
+ }
134
+ else {
135
+ this.debug('red', ('Still here too early.'));
136
+ }
137
+ }
138
+ }
139
+ }
140
+ async getServiceState(deviceId, serviceId) {
141
+ //======================================================
142
+ // Get the state of the service
143
+ //======================================================
144
+ const url = new URL(`/v2/device/${deviceId}/service/${serviceId}`, API_URL);
145
+ try {
146
+ const response = await axios.get(url.toString(), { headers: await this.httpHeaders() });
147
+ if (!response.data) {
148
+ this.platform.log.error(`Request ${url} failed with status ${response.status}`);
149
+ return;
150
+ }
151
+ return response.data.state;
152
+ }
153
+ catch (error) {
154
+ if (isAxiosError(error)) {
155
+ if (error.response && error.response.status === 401) {
156
+ await this.refreshAccessToken();
157
+ this.debug('red', 'Token refreshed in getServiceState.');
158
+ }
159
+ }
160
+ }
161
+ }
162
+ async getDeviceServices(deviceId) {
163
+ const url = new URL(`/v2/device/${deviceId}`, API_URL);
164
+ try {
165
+ const response = await axios.get(url.toString(), { headers: await this.httpHeaders() });
166
+ const services = response.data.services;
167
+ const sortedServices = services.sort((a, b) => {
168
+ if (a.serviceDeviceType < b.serviceDeviceType)
169
+ return -1;
170
+ if (a.serviceDeviceType > b.serviceDeviceType)
171
+ return 1;
172
+ return 0;
173
+ });
174
+ if (this.platform.config.debugServices) {
175
+ this.platform.log.info(chalk.red("(The 'state' of each service can be queried using getServiceState() in smartHQApi.js)"));
176
+ for (const service of sortedServices) {
177
+ this.platform.log.info(chalk.yellow("ServiceDeviceType = " + service.serviceDeviceType));
178
+ this.platform.log.info(chalk.yellow("ServiceType = " + service.serviceType));
179
+ this.platform.log.info(chalk.yellow("Domain = " + service.domainType));
180
+ this.platform.log.info(chalk.yellow("Valid Commands = " + chalk.green(JSON.stringify(service.supportedCommands))));
181
+ this.platform.log.info(chalk.yellow("Config = " + chalk.green(JSON.stringify(service.config))));
182
+ this.platform.log.info(chalk.yellow("State = " + chalk.red(JSON.stringify(service.state))));
183
+ this.platform.log.info("------------------------------------------------------------------------");
184
+ }
185
+ }
186
+ if (!response.data) {
187
+ this.platform.log.error(`Request ${url} failed with status ${response.status}`);
188
+ return;
189
+ }
190
+ return response.data.services;
191
+ }
192
+ catch (error) {
193
+ if (isAxiosError(error)) {
194
+ if (error.response && error.response.status === 401) {
195
+ await this.refreshAccessToken();
196
+ this.debug('red', 'Token refreshed in getDeviceServices.');
197
+ }
198
+ else {
199
+ this.platform.log.error('Error from getDeviceServices():', error.message);
200
+ }
201
+ }
202
+ }
203
+ }
204
+ async getRecentAlerts() {
205
+ // Check for alerts every minute
206
+ const urlAlert = new URL(`/v2/alert/recent?after=1m`, API_URL);
207
+ try {
208
+ const res = await axios.get(urlAlert.toString(), { headers: await this.httpHeaders() });
209
+ return res.data.alerts;
210
+ }
211
+ catch (error) {
212
+ if (isAxiosError(error)) {
213
+ if (error.response && error.response.status === 401) {
214
+ await this.refreshAccessToken();
215
+ this.debug('red', 'Token refreshed in getRecentAlerts.');
216
+ }
217
+ else {
218
+ this.platform.log.error('Error getting recent alerts:', +error.message);
219
+ }
220
+ }
221
+ }
222
+ }
223
+ async command(body) {
224
+ const url = new URL('/v2/command', API_URL);
225
+ try {
226
+ const response = await axios.post(url.toString(), body, { headers: await this.httpHeaders() });
227
+ return response.data;
228
+ }
229
+ catch (error) {
230
+ if (isAxiosError(error)) {
231
+ if (error.response && error.response.status === 401) {
232
+ await this.refreshAccessToken();
233
+ this.debug('red', 'Token refreshed in command.');
234
+ }
235
+ else {
236
+ this.platform.log.error('Error sending command:', body);
237
+ if (error.response) { // that falls out of the range of 2xx
238
+ this.platform.log(error.response.data);
239
+ }
240
+ }
241
+ }
242
+ }
243
+ }
244
+ // Use chalk to color debug messages (local to this plugin)
245
+ // only show debug messages if debugLogging is enabled in config
246
+ debug(color, message) {
247
+ if (this.platform.config.debugLogging) {
248
+ switch (color) {
249
+ case 'red':
250
+ this.platform.log.info(chalk.red('[SmartHQ] ' + message));
251
+ break;
252
+ case 'blue':
253
+ this.platform.log.info(chalk.blue('[SmartHQ] ' + message));
254
+ break;
255
+ case 'green':
256
+ this.platform.log.info(chalk.green('[SmartHQ] ' + message));
257
+ break;
258
+ case 'yellow':
259
+ this.platform.log.info(chalk.yellow('[SmartHQ] ' + message));
260
+ break;
261
+ default:
262
+ this.platform.log.info('[SmartHQ] ' + message);
263
+ }
264
+ }
265
+ }
266
+ }
267
+ //# sourceMappingURL=smartHqApi.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"smartHqApi.js","sourceRoot":"","sources":["../src/smartHqApi.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAiB,YAAY,EAAE,MAAM,OAAO,CAAC;AAC3D,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,IAAI,CAAC;AAC7D,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAC,MAAM,eAAe,CAAC;AAIlE;;;;GAIG;AACH,uCAAuC;AAEvC,MAAM,OAAO,UAAU;IAMF;IALnB,aAAa,CAAS;IACtB,OAAO,CAAS;IAChB,YAAY,CAAS;IAErB,YACmB,QAAyB;QAAzB,aAAQ,GAAR,QAAQ,CAAiB;QAE1C,IAAI,CAAC,aAAa,GAAG,EAAE,CAAC;QACxB,IAAI,CAAC,YAAY,GAAG,EAAE,CAAC;QACvB,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC;QACjB,IAAI,CAAC,eAAe,EAAE,CAAC;IACzB,CAAC;IAGD,+DAA+D;IAC/D,kEAAkE;IAClE,iDAAiD;IACjD,wCAAwC;IACxC,+DAA+D;IAC/D,OAAO;QACL,OAAO,QAAQ,GAAG,SAAS,CAAC;YAC1B,aAAa,EAAE,MAAM;YACrB,SAAS,EAAE,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ;YACxC,YAAY,EAAE,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,WAAW;SAC/C,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,mBAAmB,CAAC,WAAmC;QAC3D,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,IAAI,CAC/B,eAAe,EACf,SAAS,CAAC,WAAW,CAAC,EACtB,EAAE,OAAO,EAAE,EAAE,cAAc,EAAE,mCAAmC,EAAE,EAAE,CACrE,CAAC;YAEF,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QAChC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,uDAAuD;YACvD,IAAI,KAAK,CAAC,YAAY,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC9B,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;oBACnB,QAAQ,KAAK,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;wBAC9B,KAAK,GAAG;4BACN,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,2FAA2F,CAAC,CAAC;4BACrH,MAAM;wBACR,KAAK,GAAG;4BACN,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,qEAAqE,CAAC,CAAC;4BAC/F,MAAM;wBACR;4BACE,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,yBAAyB,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;4BAClE,MAAM;oBACV,CAAC;gBACH,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,wDAAwD;gBACxD,OAAO,CAAC,KAAK,CAAC,mBAAmB,EAAE,KAAK,CAAC,CAAC;YAC5C,CAAC;QACH,CAAC;IACH,CAAC;IAED,KAAK,CAAC,oBAAoB,CAAC,IAAY;QACrC,OAAO,IAAI,CAAC,mBAAmB,CAAC;YAC9B,UAAU,EAAE,oBAAoB;YAChC,SAAS,EAAE,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ;YACxC,aAAa,EAAE,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,YAAY;YAChD,YAAY,EAAE,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,WAAW;YAC9C,IAAI,EAAE,IAAI;SACX,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,kBAAkB;QACtB,OAAO,IAAI,CAAC,mBAAmB,CAAC;YAC9B,UAAU,EAAE,eAAe;YAC3B,SAAS,EAAE,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ;YACxC,aAAa,EAAE,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,YAAY;YAChD,aAAa,EAAE,IAAI,CAAC,aAAa;SAClC,CAAC,CAAC;IACL,CAAC;IAED,SAAS,CAAC,IAA2B;QACnC,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAE1B,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;QACnD,IAAI,CAAC;YACH,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QACxE,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,sBAAsB,EAAE,KAAK,CAAC,CAAC;QACzD,CAAC;IACH,CAAC;IAED,eAAe;QACb,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC;YAAE,OAAO;QACjD,MAAM,IAAI,GAAW,YAAY,CAAC,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QAC5E,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACnC,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;QAC/B,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC,UAAU,GAAG,IAAI,CAAC;IAC1D,CAAC;IAED,KAAK,CAAC,WAAW;QACf,IAAI,CAAC,IAAI,CAAC,YAAY,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,OAAO,GAAG,KAAK,EAAE,CAAC;YAC5D,MAAM,IAAI,CAAC,kBAAkB,EAAE,CAAC;QAClC,CAAC;QACD,OAAO,EAAE,aAAa,EAAE,UAAU,IAAI,CAAC,YAAY,EAAE,EAAE,CAAC;IAC1D,CAAC;IAED,KAAK,CAAC,aAAa;QACjB,wDAAwD;QACxD,uCAAuC;QACvC,wDAAwD;QACtD,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,0BAA0B,CAAC,CAAC;QAElD,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;QAC3C,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,EAAE,EACxC,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC,WAAW,EAAE,EAAE,CACtC,CAAC;YACF,OAAO,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC;QAC1B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,YAAY,CAAC,KAAK,CAAC,EAAE,CAAC;gBACxB,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;oBACnB,QAAQ,KAAK,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;wBAC9B,KAAK,GAAG;4BACN,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,qBAAqB,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;4BAC9D,MAAM;wBACR,KAAK,GAAG;4BACN,IAAI,CAAC,kBAAkB,EAAE,CAAC;4BAC1B,kHAAkH;4BAClH,MAAM;wBACR,KAAK,GAAG;4BACN,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,kEAAkE,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;4BAC3G,MAAM;wBACR;4BACE,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,4BAA4B,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;4BACrE,MAAM;oBACV,CAAC;gBACH,CAAC;qBAAO,CAAC;oBACP,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,uBAAuB,CAAC,CAAC,CAAC;gBAC/C,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,KAAK,CAAC,eAAe,CAAC,QAAgB,EAAE,SAAiB;QACvD,wDAAwD;QACxD,uCAAuC;QACvC,wDAAwD;QACxD,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,cAAc,QAAQ,YAAY,SAAS,EAAE,EAAE,OAAO,CAAC,CAAC;QAC5E,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,EAAE,EAC7C,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC,WAAW,EAAE,EAAE,CACtC,CAAC;YACF,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;gBACnB,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CACrB,WAAW,GAAG,uBAAuB,QAAQ,CAAC,MAAM,EAAE,CACvD,CAAC;gBACF,OAAO;YACT,CAAC;YACD,OAAO,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC;QAE7B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,YAAY,CAAC,KAAK,CAAC,EAAE,CAAC;gBACxB,IAAI,KAAK,CAAC,QAAQ,IAAI,KAAK,CAAC,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;oBACpD,MAAM,IAAI,CAAC,kBAAkB,EAAE,CAAC;oBAChC,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,qCAAqC,CAAC,CAAC;gBAC3D,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAMD,KAAK,CAAC,iBAAiB,CAAC,QAAgB;QACtC,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,cAAc,QAAQ,EAAE,EAAE,OAAO,CAAC,CAAC;QACvD,IAAI,CAAC;YACD,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,EAAE,EAC7C,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC,WAAW,EAAE,EAAE,CACtC,CAAC;YACF,MAAM,QAAQ,GAAiB,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC;YACtD,MAAM,cAAc,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;gBAC5C,IAAI,CAAC,CAAC,iBAAiB,GAAG,CAAC,CAAC,iBAAiB;oBAAE,OAAO,CAAC,CAAC,CAAC;gBACzD,IAAI,CAAC,CAAC,iBAAiB,GAAG,CAAC,CAAC,iBAAiB;oBAAE,OAAO,CAAC,CAAC;gBACxD,OAAO,CAAC,CAAC;YACX,CAAC,CAAC,CAAC;YAEH,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,aAAa,EAAE,CAAC;gBACvC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,uFAAuF,CAAC,CAAC,CAAC;gBAC3H,KAAK,MAAM,OAAO,IAAI,cAAc,EAAE,CAAC;oBACrC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,sBAAsB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAAC;oBACzF,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,sBAAsB,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC;oBACnF,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,sBAAsB,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC;oBAClF,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,sBAAsB,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAAC;oBACtH,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,sBAAsB,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;oBAC3G,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,sBAAsB,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;oBACxG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,0EAA0E,CAAC,CAAC;gBACrG,CAAC;YACH,CAAC;YACD,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;gBACnB,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CACrB,WAAW,GAAG,uBAAuB,QAAQ,CAAC,MAAM,EAAE,CACvD,CAAC;gBACF,OAAO;YACT,CAAC;YACD,OAAO,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC;QAClC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,YAAY,CAAC,KAAK,CAAC,EAAE,CAAC;gBACxB,IAAI,KAAK,CAAC,QAAQ,IAAI,KAAK,CAAC,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;oBACpD,MAAM,IAAI,CAAC,kBAAkB,EAAE,CAAC;oBAChC,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,uCAAuC,CAAC,CAAC;gBAC7D,CAAC;qBAAM,CAAC;oBACN,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,iCAAiC,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;gBAC5E,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IACF,KAAK,CAAC,eAAe;QAClB,gCAAgC;QAChC,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,2BAA2B,EAAE,OAAO,CAAC,CAAC;QAE/D,IAAI,CAAC;YACD,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,QAAQ,EAAE,EAC7C,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC,WAAW,EAAE,EAAE,CACtC,CAAC;YACF,OAAO,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC;QAE3B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,YAAY,CAAC,KAAK,CAAC,EAAE,CAAC;gBACxB,IAAI,KAAK,CAAC,QAAQ,IAAI,KAAK,CAAC,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;oBACpD,MAAM,IAAI,CAAC,kBAAkB,EAAE,CAAC;oBAChC,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,qCAAqC,CAAC,CAAC;gBAC3D,CAAC;qBAAM,CAAC;oBACN,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,8BAA8B,EAAE,CAAE,KAAK,CAAC,OAAO,CAAC,CAAC;gBAC3E,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,IAAY;QAExB,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;QAE5C,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,EAC9C,IAAI,EACJ,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC,WAAW,EAAE,EAAE,CACtC,CAAC;YACF,OAAO,QAAQ,CAAC,IAAI,CAAC;QAEvB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,YAAY,CAAC,KAAK,CAAC,EAAE,CAAC;gBACxB,IAAI,KAAK,CAAC,QAAQ,IAAI,KAAK,CAAC,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;oBACpD,MAAM,IAAI,CAAC,kBAAkB,EAAE,CAAC;oBAChC,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,6BAA6B,CAAC,CAAC;gBACnD,CAAC;qBAAM,CAAC;oBACN,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,wBAAwB,EAAE,IAAI,CAAC,CAAC;oBACxD,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAO,qCAAqC;wBAC/D,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;oBACzC,CAAC;gBACH,CAAC;YACH,CAAC;QACL,CAAC;IACH,CAAC;IAED,2DAA2D;IAC3D,gEAAgE;IAEhE,KAAK,CAAC,KAAa,EAAE,OAAe;QAChC,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,YAAY,EAAE,CAAC;YACtC,QAAO,KAAK,EAAE,CAAC;gBACb,KAAK,KAAK;oBACR,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,YAAY,GAAG,OAAO,CAAC,CAAC,CAAC;oBAC1D,MAAM;gBACR,KAAK,MAAM;oBACT,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,YAAY,GAAG,OAAO,CAAC,CAAC,CAAC;oBAC3D,MAAM;gBACR,KAAK,OAAO;oBACV,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,YAAY,GAAG,OAAO,CAAC,CAAC,CAAC;oBAC5D,MAAM;gBACR,KAAK,QAAQ;oBACX,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,YAAY,GAAG,OAAO,CAAC,CAAC,CAAC;oBAC7D,MAAM;gBACR;oBACE,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,YAAY,GAAG,OAAO,CAAC,CAAC;YACnD,CAAC;QACH,CAAC;IACH,CAAC;CAEF"}
@@ -0,0 +1,29 @@
1
+ export interface DevService {
2
+ serviceType: string;
3
+ lastSyncTime: string;
4
+ domainType: string;
5
+ supportedCommands: string[];
6
+ state: Record<string, unknown>;
7
+ serviceId: string;
8
+ serviceDeviceType: string;
9
+ config: Record<string, unknown>;
10
+ lastStateTime: string;
11
+ }
12
+ export interface DevDevice {
13
+ deviceType: string;
14
+ lastSyncTime: string;
15
+ roomNumber: string;
16
+ serial: string;
17
+ lastPresenceTime: string;
18
+ createdDateTime: string;
19
+ presence: string;
20
+ deviceId: string;
21
+ gatewayId: string;
22
+ room: string;
23
+ icon: string;
24
+ manufacturer: string;
25
+ nickname: string;
26
+ model: string;
27
+ floor: string;
28
+ macAddress: string;
29
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=smarthq-types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"smarthq-types.js","sourceRoot":"","sources":["../src/smarthq-types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,12 @@
1
+ import js from "@eslint/js";
2
+ import globals from "globals";
3
+ import tseslint from "typescript-eslint";
4
+ import { defineConfig } from "eslint/config";
5
+
6
+ export default defineConfig([
7
+ {
8
+ ignores: ['**/dist'],
9
+ },
10
+ { files: ["**/*.{js,mjs,cjs,ts,mts,cts}"], plugins: { js }, extends: ["js/recommended"], languageOptions: { globals: globals.browser } },
11
+ tseslint.configs.recommended,
12
+ ]);
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" viewBox="0 0 512 512"><linearGradient id="a" x1="256" x2="256" y1="280" y2="792" gradientTransform="translate(0 -280)" gradientUnits="userSpaceOnUse"><stop offset="0" style="stop-color:#57277c"/><stop offset="1" style="stop-color:#491f59"/></linearGradient><circle cx="256" cy="256" r="256" style="fill:url(#a)"/><radialGradient id="b" cx="256" cy="536" r="256" gradientTransform="translate(0 -280)" gradientUnits="userSpaceOnUse"><stop offset="0" style="stop-color:#000;stop-opacity:0"/><stop offset=".86" style="stop-color:#000;stop-opacity:6.000000e-02"/><stop offset="1" style="stop-color:#000;stop-opacity:.1"/></radialGradient><circle cx="256" cy="256" r="256" style="fill:url(#b)"/><path d="M434.3 229.9h-.3l-32.1-32.1c-1.2-1.2-1.8-2.7-1.8-4.4v-74.2c0-15.7-12.7-28.4-28.4-28.5h-20.1c-15.7 0-28.4 12.7-28.5 28.5v.4l-47.5-46c-11.2-10.7-28.9-10.6-39.9.3L74.9 234.7c-11.1 11.1-11.1 29.1 0 40.2l15.3 15.2c11.1 11 28.9 11.1 40.1.2l123.5-121.7c2.4-2.4 6.3-2.4 8.8 0l121 121c2.4 2.4 2.4 6.3 0 8.8l-14.9 14.9c-2.4 2.4-6.3 2.4-8.8 0l-85-82.3c-11.2-10.8-29-10.7-40 .3l-81.5 82c-11.1 11.1-11.1 29.1 0 40.2l15.1 15.1c11.1 11 29 11.1 40.1.1l44-43.4c2.4-2.4 6.3-2.4 8.8 0l43.7 43c2.4 2.4 2.5 6.3.1 8.7l-.1.1-43.3 43.4c-.2 0-.3-.1-.6-.1-9 0-16.2 7.3-16.2 16.3s7.3 16.2 16.3 16.2 16.2-7.3 16.2-16.3v-.3l43.5-43.5c11.1-11.1 11.1-29.1 0-40.2l-.2-.2-43.8-42.9c-11.1-10.9-28.9-10.9-40 0L192.9 353c-2.4 2.4-6.3 2.4-8.8 0L169 337.9c-2.4-2.4-2.4-6.3 0-8.8l81.7-82c2.4-2.4 6.3-2.5 8.8-.1l85 82.6c11.2 10.8 28.9 10.6 39.9-.3l14.9-14.9c11.1-11.1 11.1-29.1 0-40.2L278.3 153c-11.1-11-28.9-11.1-40.1-.2L114.7 274.5c-2.4 2.4-6.3 2.4-8.8 0l-15.3-15.3c-2.4-2.4-2.4-6.3 0-8.8L251.4 89.7c2.4-2.4 6.3-2.5 8.8-.1l85.2 82.4v-52.9c0-3.4 2.8-6.2 6.2-6.2h20.1c3.4 0 6.2 2.8 6.2 6.2v74.3c0 7.5 3 14.8 8.3 20.1l32 32c0 .2-.1.4-.1.6 0 9 7.3 16.2 16.2 16.2 9 0 16.2-7.3 16.2-16.2.1-9-7.2-16.2-16.2-16.2" style="fill:#fff"/></svg>
package/package.json ADDED
@@ -0,0 +1,61 @@
1
+ {
2
+ "name": "homebridge-smarthq-client",
3
+ "displayName": "SmartHQ",
4
+ "type": "module",
5
+ "version": "1.0.0",
6
+ "private": false,
7
+ "description": "Plugin for controlling GE refrigerator via SmartHQ API.",
8
+ "author": "C Baumann",
9
+ "license": "Apache-2.0",
10
+ "homepage": "https://github.com/ceb400/homebridge-smarthq-client#readme",
11
+ "repository": {
12
+ "type": "git",
13
+ "url": "https://github.com/ceb400/homebridge-smarthq-client.git"
14
+ },
15
+ "bugs": {
16
+ "url": "https://github.com/ceb400/homebridge-smarthq-client/issues"
17
+ },
18
+ "keywords": [
19
+ "homebridge-plugin",
20
+ "smarthq",
21
+ "GE Refrigerator",
22
+ "refrigerator",
23
+ "smart appliance",
24
+ "OAuth2"
25
+ ],
26
+ "main": "dist/index.js",
27
+ "engines": {
28
+ "node": "^20.18.0 || ^22.10.0 || ^24.0.0",
29
+ "homebridge": "^1.8.0 || ^2.0.0-beta.0"
30
+ },
31
+ "scripts": {
32
+ "build": "npm run lint && rimraf ./dist && tsc",
33
+ "lint": "eslint . --max-warnings=0",
34
+ "prepublishOnly": "npm run lint && npm run build",
35
+ "watch": "npm run build && npm link && nodemon"
36
+ },
37
+ "dependencies": {
38
+ "axios": "^1.13.2",
39
+ "chalk": "^5.6.2",
40
+ "express": "^5.2.1",
41
+ "homebridge-lib": "^7.1.12",
42
+ "node-fetch": "^3.3.2",
43
+ "node-persist": "^4.0.4",
44
+ "open": "^11.0.0",
45
+ "url-parse": "^1.5.10"
46
+ },
47
+ "devDependencies": {
48
+ "@eslint/js": "^9.39.2",
49
+ "@types/express": "^5.0.6",
50
+ "@types/node": "^24.10.4",
51
+ "@types/node-persist": "^3.1.8",
52
+ "eslint": "^9.39.2",
53
+ "globals": "^17.2.0",
54
+ "homebridge": "^2.0.0-beta.55",
55
+ "nodemon": "^3.1.11",
56
+ "rimraf": "^6.1.0",
57
+ "ts-node": "^10.9.2",
58
+ "typescript": "^5.9.3",
59
+ "typescript-eslint": "^8.54.0"
60
+ }
61
+ }
@@ -0,0 +1,14 @@
1
+ declare module 'homebridge-lib/EveHomeKitTypes' {
2
+ export class EveHomeKitTypes {
3
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
4
+ constructor(homebridge: any);
5
+
6
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
7
+ Characteristics: Record<string, any>;
8
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
9
+ Services: Record<string, any>;
10
+ }
11
+ }
12
+
13
+ declare module 'homebridge-lib' {
14
+ }
package/src/index.ts ADDED
@@ -0,0 +1,11 @@
1
+ import type { API } from 'homebridge';
2
+
3
+ import { SmartHqPlatform } from './platform.js';
4
+ import { PLATFORM_NAME } from './settings.js';
5
+
6
+ /**
7
+ * This method registers the platform with Homebridge
8
+ */
9
+ export default (api: API) => {
10
+ api.registerPlatform(PLATFORM_NAME, SmartHqPlatform);
11
+ };