@boozilla/homebridge-shome 1.0.1 → 1.0.3

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.
@@ -5,28 +5,32 @@
5
5
  "name": {
6
6
  "title": "Name",
7
7
  "type": "string",
8
- "default": "sHome",
9
- "required": true
8
+ "default": "sHome"
10
9
  },
11
10
  "username": {
12
11
  "title": "Username",
13
12
  "type": "string",
14
- "description": "Your Samsung sHome account username.",
15
- "required": true
13
+ "description": "Your Samsung sHome account username."
16
14
  },
17
15
  "password": {
18
16
  "title": "Password",
19
17
  "type": "string",
20
18
  "description": "Your Samsung sHome account password.",
21
- "required": true,
22
19
  "format": "password"
23
20
  },
24
21
  "deviceId": {
25
22
  "title": "Device ID",
26
23
  "type": "string",
27
- "description": "Your mobile device ID.",
28
- "required": true
24
+ "description": "Your mobile device ID."
29
25
  }
30
- }
31
- }
26
+ },
27
+ "required": [
28
+ "name",
29
+ "username",
30
+ "password",
31
+ "deviceId"
32
+ ]
33
+ },
34
+ "pluginAlias": "sHome",
35
+ "pluginType": "platform"
32
36
  }
@@ -18,8 +18,13 @@ export declare class ShomeClient {
18
18
  private cachedAccessToken;
19
19
  private ihdId;
20
20
  private tokenExpiry;
21
+ private requestQueue;
22
+ private isProcessing;
21
23
  constructor(log: Logger, username: string, password: string, deviceId: string);
24
+ private enqueue;
25
+ private processQueue;
22
26
  login(): Promise<string | null>;
27
+ private performLogin;
23
28
  getDeviceList(): Promise<MainDevice[]>;
24
29
  getDeviceInfo(thingId: string, type: string): Promise<SubDevice[] | null>;
25
30
  setDevice(thingId: string, deviceId: string, type: string, controlType: string, state: string, nickname?: string): Promise<boolean>;
@@ -4,6 +4,8 @@ const BASE_URL = 'https://shome-api.samsung-ihp.com';
4
4
  const APP_REGST_ID = '6110736314d9eef6baf393f3e43a5342f9ccde6ef300d878385acd9264cf14d5';
5
5
  const CHINA_APP_REGST_ID = 'SHOME==6110736314d9eef6baf393f3e43a5342f9ccde6ef300d878385acd9264cf14d5';
6
6
  const LANGUAGE = 'KOR';
7
+ const MAX_RETRIES = 3;
8
+ const INITIAL_BACKOFF_MS = 1000;
7
9
  export class ShomeClient {
8
10
  log;
9
11
  username;
@@ -12,13 +14,66 @@ export class ShomeClient {
12
14
  cachedAccessToken = null;
13
15
  ihdId = null;
14
16
  tokenExpiry = 0;
17
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
18
+ requestQueue = [];
19
+ isProcessing = false;
15
20
  constructor(log, username, password, deviceId) {
16
21
  this.log = log;
17
22
  this.username = username;
18
23
  this.password = password;
19
24
  this.deviceId = deviceId;
20
25
  }
26
+ async enqueue(request) {
27
+ return new Promise((resolve, reject) => {
28
+ this.requestQueue.push({ request, resolve, reject, authRetry: false });
29
+ if (!this.isProcessing) {
30
+ this.processQueue();
31
+ }
32
+ });
33
+ }
34
+ async processQueue() {
35
+ if (this.isProcessing || this.requestQueue.length === 0) {
36
+ return;
37
+ }
38
+ this.isProcessing = true;
39
+ const task = this.requestQueue.shift();
40
+ let retries = 0;
41
+ const execute = async () => {
42
+ try {
43
+ const result = await task.request();
44
+ task.resolve(result);
45
+ this.isProcessing = false;
46
+ this.processQueue();
47
+ }
48
+ catch (error) {
49
+ const isAuthError = axios.isAxiosError(error) && error.response?.status === 401;
50
+ if (isAuthError && !task.authRetry) {
51
+ this.log.warn('API authentication failed (401). Retrying after refreshing token.');
52
+ this.cachedAccessToken = null;
53
+ this.tokenExpiry = 0;
54
+ task.authRetry = true;
55
+ setTimeout(execute, 100);
56
+ }
57
+ else if (!isAuthError && retries < MAX_RETRIES) {
58
+ retries++;
59
+ const backoffTime = INITIAL_BACKOFF_MS * Math.pow(2, retries - 1);
60
+ this.log.warn(`Request failed. Retrying in ${backoffTime}ms... (Attempt ${retries}/${MAX_RETRIES})`);
61
+ setTimeout(execute, backoffTime);
62
+ }
63
+ else {
64
+ this.log.error(`Request failed after ${MAX_RETRIES} retries.`, error);
65
+ task.reject(error);
66
+ this.isProcessing = false;
67
+ this.processQueue();
68
+ }
69
+ }
70
+ };
71
+ await execute();
72
+ }
21
73
  async login() {
74
+ return this.enqueue(() => this.performLogin());
75
+ }
76
+ async performLogin() {
22
77
  if (!this.isTokenExpired()) {
23
78
  return this.cachedAccessToken;
24
79
  }
@@ -42,7 +97,6 @@ export class ShomeClient {
42
97
  if (response.data && response.data.accessToken) {
43
98
  this.cachedAccessToken = response.data.accessToken;
44
99
  this.ihdId = response.data.ihdId;
45
- // Decode token to find expiry
46
100
  const payload = JSON.parse(Buffer.from(this.cachedAccessToken.split('.')[1], 'base64').toString());
47
101
  this.tokenExpiry = payload.exp * 1000;
48
102
  this.log.info('Successfully logged in to sHome API.');
@@ -55,15 +109,15 @@ export class ShomeClient {
55
109
  }
56
110
  catch (error) {
57
111
  this.log.error(`Login error: ${error}`);
58
- return null;
112
+ throw error;
59
113
  }
60
114
  }
61
115
  async getDeviceList() {
62
- const token = await this.login();
63
- if (!token || !this.ihdId) {
64
- return [];
65
- }
66
- try {
116
+ return this.enqueue(async () => {
117
+ const token = await this.performLogin();
118
+ if (!token || !this.ihdId) {
119
+ return [];
120
+ }
67
121
  const createDate = this.getDateTime();
68
122
  const hashData = this.sha512(`IHRESTAPI${this.ihdId}${createDate}`);
69
123
  const response = await axios.get(`${BASE_URL}/v16/settings/${this.ihdId}/devices/`, {
@@ -71,18 +125,14 @@ export class ShomeClient {
71
125
  headers: { 'Authorization': `Bearer ${token}` },
72
126
  });
73
127
  return response.data.deviceList || [];
74
- }
75
- catch (error) {
76
- this.log.error(`Error getting device list: ${error}`);
77
- return [];
78
- }
128
+ });
79
129
  }
80
130
  async getDeviceInfo(thingId, type) {
81
- const token = await this.login();
82
- if (!token) {
83
- return null;
84
- }
85
- try {
131
+ return this.enqueue(async () => {
132
+ const token = await this.performLogin();
133
+ if (!token) {
134
+ return null;
135
+ }
86
136
  const createDate = this.getDateTime();
87
137
  const hashData = this.sha512(`IHRESTAPI${thingId}${createDate}`);
88
138
  const typePath = type.toLowerCase().replace(/_/g, '');
@@ -91,18 +141,14 @@ export class ShomeClient {
91
141
  headers: { 'Authorization': `Bearer ${token}` },
92
142
  });
93
143
  return response.data.deviceInfoList || null;
94
- }
95
- catch (error) {
96
- this.log.error(`Error getting device info for ${thingId}: ${error}`);
97
- return null;
98
- }
144
+ });
99
145
  }
100
146
  async setDevice(thingId, deviceId, type, controlType, state, nickname) {
101
- const token = await this.login();
102
- if (!token) {
103
- return false;
104
- }
105
- try {
147
+ return this.enqueue(async () => {
148
+ const token = await this.performLogin();
149
+ if (!token) {
150
+ return false;
151
+ }
106
152
  const createDate = this.getDateTime();
107
153
  const hashData = this.sha512(`IHRESTAPI${thingId}${deviceId}${state}${createDate}`);
108
154
  const typePath = type.toLowerCase().replace(/_/g, '');
@@ -118,19 +164,14 @@ export class ShomeClient {
118
164
  const displayName = nickname || `${thingId}/${deviceId}`;
119
165
  this.log.info(`[${displayName}] state set to ${state}.`);
120
166
  return true;
121
- }
122
- catch (error) {
123
- const displayName = nickname || `${thingId}/${deviceId}`;
124
- this.log.error(`Error setting device [${displayName}]: ${error}`);
125
- return false;
126
- }
167
+ });
127
168
  }
128
169
  async unlockDoorlock(thingId, nickname) {
129
- const token = await this.login();
130
- if (!token) {
131
- return false;
132
- }
133
- try {
170
+ return this.enqueue(async () => {
171
+ const token = await this.performLogin();
172
+ if (!token) {
173
+ return false;
174
+ }
134
175
  const createDate = this.getDateTime();
135
176
  const hashData = this.sha512(`IHRESTAPI${thingId}${createDate}`);
136
177
  await axios.put(`${BASE_URL}/v16/settings/doorlocks/${thingId}/open-mode`, null, {
@@ -144,12 +185,7 @@ export class ShomeClient {
144
185
  const displayName = nickname || thingId;
145
186
  this.log.info(`Unlocked [${displayName}].`);
146
187
  return true;
147
- }
148
- catch (error) {
149
- const displayName = nickname || thingId;
150
- this.log.error(`Error unlocking [${displayName}]: ${error}`);
151
- return false;
152
- }
188
+ });
153
189
  }
154
190
  sha512(input) {
155
191
  return CryptoJS.SHA512(input).toString();
@@ -1 +1 @@
1
- {"version":3,"file":"shomeClient.js","sourceRoot":"","sources":["../src/shomeClient.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,QAAQ,MAAM,WAAW,CAAC;AAGjC,MAAM,QAAQ,GAAG,mCAAmC,CAAC;AACrD,MAAM,YAAY,GAAG,kEAAkE,CAAC;AACxF,MAAM,kBAAkB,GAAG,yEAAyE,CAAC;AACrG,MAAM,QAAQ,GAAG,KAAK,CAAC;AAgBvB,MAAM,OAAO,WAAW;IAMC;IACA;IACA;IACA;IARf,iBAAiB,GAAkB,IAAI,CAAC;IACxC,KAAK,GAAkB,IAAI,CAAC;IAC5B,WAAW,GAAW,CAAC,CAAC;IAEhC,YACuB,GAAW,EACX,QAAgB,EAChB,QAAgB,EAChB,QAAgB;QAHhB,QAAG,GAAH,GAAG,CAAQ;QACX,aAAQ,GAAR,QAAQ,CAAQ;QAChB,aAAQ,GAAR,QAAQ,CAAQ;QAChB,aAAQ,GAAR,QAAQ,CAAQ;IAEvC,CAAC;IAED,KAAK,CAAC,KAAK;QACT,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,EAAE,CAAC;YAC3B,OAAO,IAAI,CAAC,iBAAiB,CAAC;QAChC,CAAC;QAED,IAAI,CAAC;YACH,MAAM,UAAU,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;YACtC,MAAM,cAAc,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YAClD,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,YAAY,IAAI,CAAC,QAAQ,GAAG,cAAc,GAAG,IAAI,CAAC,QAAQ,EAAE;gBAC/E,GAAG,YAAY,GAAG,kBAAkB,GAAG,QAAQ,GAAG,UAAU,EAAE,CAAC,CAAC;YAE1E,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,GAAG,QAAQ,kBAAkB,EAAE,IAAI,EAAE;gBACpE,MAAM,EAAE;oBACN,UAAU,EAAE,YAAY;oBACxB,eAAe,EAAE,kBAAkB;oBACnC,UAAU,EAAE,UAAU;oBACtB,QAAQ,EAAE,QAAQ;oBAClB,QAAQ,EAAE,QAAQ;oBAClB,gBAAgB,EAAE,IAAI,CAAC,QAAQ;oBAC/B,QAAQ,EAAE,cAAc;oBACxB,MAAM,EAAE,IAAI,CAAC,QAAQ;iBACtB;aACF,CAAC,CAAC;YAEH,IAAI,QAAQ,CAAC,IAAI,IAAI,QAAQ,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;gBAC/C,IAAI,CAAC,iBAAiB,GAAG,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC;gBACnD,IAAI,CAAC,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC;gBAEjC,8BAA8B;gBAC9B,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,iBAAkB,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;gBACpG,IAAI,CAAC,WAAW,GAAG,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC;gBAEtC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,sCAAsC,CAAC,CAAC;gBACtD,OAAO,IAAI,CAAC,iBAAiB,CAAC;YAChC,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,iDAAiD,CAAC,CAAC;gBAClE,OAAO,IAAI,CAAC;YACd,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,gBAAgB,KAAK,EAAE,CAAC,CAAC;YACxC,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED,KAAK,CAAC,aAAa;QACjB,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC;QACjC,IAAI,CAAC,KAAK,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;YAC1B,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,IAAI,CAAC;YACH,MAAM,UAAU,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;YACtC,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,YAAY,IAAI,CAAC,KAAK,GAAG,UAAU,EAAE,CAAC,CAAC;YAEpE,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,GAAG,QAAQ,iBAAiB,IAAI,CAAC,KAAK,WAAW,EAAE;gBAClF,MAAM,EAAE,EAAE,UAAU,EAAE,QAAQ,EAAE;gBAChC,OAAO,EAAE,EAAE,eAAe,EAAE,UAAU,KAAK,EAAE,EAAE;aAChD,CAAC,CAAC;YAEH,OAAO,QAAQ,CAAC,IAAI,CAAC,UAAU,IAAI,EAAE,CAAC;QACxC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,8BAA8B,KAAK,EAAE,CAAC,CAAC;YACtD,OAAO,EAAE,CAAC;QACZ,CAAC;IACH,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,OAAe,EAAE,IAAY;QAC/C,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC;QACjC,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,OAAO,IAAI,CAAC;QACd,CAAC;QAED,IAAI,CAAC;YACH,MAAM,UAAU,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;YACtC,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,YAAY,OAAO,GAAG,UAAU,EAAE,CAAC,CAAC;YACjE,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YAEtD,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,GAAG,QAAQ,iBAAiB,QAAQ,IAAI,OAAO,EAAE,EAAE;gBAClF,MAAM,EAAE,EAAE,UAAU,EAAE,QAAQ,EAAE;gBAChC,OAAO,EAAE,EAAE,eAAe,EAAE,UAAU,KAAK,EAAE,EAAE;aAChD,CAAC,CAAC;YAEH,OAAO,QAAQ,CAAC,IAAI,CAAC,cAAc,IAAI,IAAI,CAAC;QAC9C,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,iCAAiC,OAAO,KAAK,KAAK,EAAE,CAAC,CAAC;YACrE,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED,KAAK,CAAC,SAAS,CAAC,OAAe,EAAE,QAAgB,EAAE,IAAY,EAAE,WAAmB,EAAE,KAAa,EAAE,QAAiB;QACpH,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC;QACjC,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,OAAO,KAAK,CAAC;QACf,CAAC;QAED,IAAI,CAAC;YACH,MAAM,UAAU,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;YACtC,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,YAAY,OAAO,GAAG,QAAQ,GAAG,KAAK,GAAG,UAAU,EAAE,CAAC,CAAC;YACpF,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YACtD,MAAM,WAAW,GAAG,WAAW,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;YAEjE,MAAM,KAAK,CAAC,GAAG,CAAC,GAAG,QAAQ,iBAAiB,QAAQ,IAAI,OAAO,IAAI,QAAQ,IAAI,WAAW,EAAE,EAAE,IAAI,EAAE;gBAClG,MAAM,EAAE;oBACN,UAAU;oBACV,CAAC,WAAW,KAAK,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK;oBACvD,QAAQ;iBACT;gBACD,OAAO,EAAE,EAAE,eAAe,EAAE,UAAU,KAAK,EAAE,EAAE;aAChD,CAAC,CAAC;YAEH,MAAM,WAAW,GAAG,QAAQ,IAAI,GAAG,OAAO,IAAI,QAAQ,EAAE,CAAC;YACzD,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,WAAW,kBAAkB,KAAK,GAAG,CAAC,CAAC;YACzD,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,WAAW,GAAG,QAAQ,IAAI,GAAG,OAAO,IAAI,QAAQ,EAAE,CAAC;YACzD,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,yBAAyB,WAAW,MAAM,KAAK,EAAE,CAAC,CAAC;YAClE,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IAED,KAAK,CAAC,cAAc,CAAC,OAAe,EAAE,QAAiB;QACrD,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC;QACjC,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,OAAO,KAAK,CAAC;QACf,CAAC;QAED,IAAI,CAAC;YACH,MAAM,UAAU,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;YACtC,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,YAAY,OAAO,GAAG,UAAU,EAAE,CAAC,CAAC;YAEjE,MAAM,KAAK,CAAC,GAAG,CAAC,GAAG,QAAQ,2BAA2B,OAAO,YAAY,EAAE,IAAI,EAAE;gBAC/E,MAAM,EAAE;oBACN,UAAU;oBACV,GAAG,EAAE,EAAE;oBACP,QAAQ;iBACT;gBACD,OAAO,EAAE,EAAE,eAAe,EAAE,UAAU,KAAK,EAAE,EAAE;aAChD,CAAC,CAAC;YAEH,MAAM,WAAW,GAAG,QAAQ,IAAI,OAAO,CAAC;YACxC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,aAAa,WAAW,IAAI,CAAC,CAAC;YAC5C,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,WAAW,GAAG,QAAQ,IAAI,OAAO,CAAC;YACxC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,oBAAoB,WAAW,MAAM,KAAK,EAAE,CAAC,CAAC;YAC7D,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IAEO,MAAM,CAAC,KAAa;QAC1B,OAAO,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,QAAQ,EAAE,CAAC;IAC3C,CAAC;IAEO,cAAc;QACpB,OAAO,CAAC,IAAI,CAAC,iBAAiB,IAAI,IAAI,CAAC,GAAG,EAAE,IAAI,IAAI,CAAC,WAAW,CAAC;IACnE,CAAC;IAEO,WAAW;QACjB,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,MAAM,GAAG,GAAG,CAAC,GAAW,EAAE,EAAE,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;QAC7D,OAAO,GAAG,GAAG,CAAC,cAAc,EAAE,GAAG,GAAG,CAAC,GAAG,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,UAAU,EAAE,CAAC,EAAE;YAC7E,GAAG,GAAG,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,aAAa,EAAE,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,aAAa,EAAE,CAAC,EAAE,CAAC;IAC5F,CAAC;CACF"}
1
+ {"version":3,"file":"shomeClient.js","sourceRoot":"","sources":["../src/shomeClient.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@boozilla/homebridge-shome",
3
3
  "displayName": "sHome Plugin",
4
- "version": "1.0.1",
4
+ "version": "1.0.3",
5
5
  "private": false,
6
6
  "description": "A Homebridge plugin for Samsung Smart Home",
7
7
  "author": "boozilla",
@@ -6,6 +6,8 @@ const BASE_URL = 'https://shome-api.samsung-ihp.com';
6
6
  const APP_REGST_ID = '6110736314d9eef6baf393f3e43a5342f9ccde6ef300d878385acd9264cf14d5';
7
7
  const CHINA_APP_REGST_ID = 'SHOME==6110736314d9eef6baf393f3e43a5342f9ccde6ef300d878385acd9264cf14d5';
8
8
  const LANGUAGE = 'KOR';
9
+ const MAX_RETRIES = 3;
10
+ const INITIAL_BACKOFF_MS = 1000;
9
11
 
10
12
  // Define and export interfaces for device types
11
13
  export interface MainDevice {
@@ -21,10 +23,20 @@ export interface SubDevice {
21
23
  [key: string]: unknown;
22
24
  }
23
25
 
26
+ type QueueTask<T = unknown> = {
27
+ request: () => Promise<T>;
28
+ resolve: (value: T | PromiseLike<T>) => void;
29
+ reject: (reason?: unknown) => void;
30
+ authRetry: boolean;
31
+ };
32
+
24
33
  export class ShomeClient {
25
34
  private cachedAccessToken: string | null = null;
26
35
  private ihdId: string | null = null;
27
36
  private tokenExpiry: number = 0;
37
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
38
+ private requestQueue: QueueTask<any>[] = [];
39
+ private isProcessing = false;
28
40
 
29
41
  constructor(
30
42
  private readonly log: Logger,
@@ -34,7 +46,60 @@ export class ShomeClient {
34
46
  ) {
35
47
  }
36
48
 
49
+ private async enqueue<T>(request: () => Promise<T>): Promise<T> {
50
+ return new Promise<T>((resolve, reject) => {
51
+ this.requestQueue.push({ request, resolve, reject, authRetry: false });
52
+ if (!this.isProcessing) {
53
+ this.processQueue();
54
+ }
55
+ });
56
+ }
57
+
58
+ private async processQueue(): Promise<void> {
59
+ if (this.isProcessing || this.requestQueue.length === 0) {
60
+ return;
61
+ }
62
+ this.isProcessing = true;
63
+ const task = this.requestQueue.shift()!;
64
+ let retries = 0;
65
+
66
+ const execute = async () => {
67
+ try {
68
+ const result = await task.request();
69
+ task.resolve(result);
70
+ this.isProcessing = false;
71
+ this.processQueue();
72
+ } catch (error) {
73
+ const isAuthError = axios.isAxiosError(error) && error.response?.status === 401;
74
+
75
+ if (isAuthError && !task.authRetry) {
76
+ this.log.warn('API authentication failed (401). Retrying after refreshing token.');
77
+ this.cachedAccessToken = null;
78
+ this.tokenExpiry = 0;
79
+ task.authRetry = true;
80
+ setTimeout(execute, 100);
81
+ } else if (!isAuthError && retries < MAX_RETRIES) {
82
+ retries++;
83
+ const backoffTime = INITIAL_BACKOFF_MS * Math.pow(2, retries - 1);
84
+ this.log.warn(`Request failed. Retrying in ${backoffTime}ms... (Attempt ${retries}/${MAX_RETRIES})`);
85
+ setTimeout(execute, backoffTime);
86
+ } else {
87
+ this.log.error(`Request failed after ${MAX_RETRIES} retries.`, error);
88
+ task.reject(error);
89
+ this.isProcessing = false;
90
+ this.processQueue();
91
+ }
92
+ }
93
+ };
94
+
95
+ await execute();
96
+ }
97
+
37
98
  async login(): Promise<string | null> {
99
+ return this.enqueue(() => this.performLogin());
100
+ }
101
+
102
+ private async performLogin(): Promise<string | null> {
38
103
  if (!this.isTokenExpired()) {
39
104
  return this.cachedAccessToken;
40
105
  }
@@ -62,7 +127,6 @@ export class ShomeClient {
62
127
  this.cachedAccessToken = response.data.accessToken;
63
128
  this.ihdId = response.data.ihdId;
64
129
 
65
- // Decode token to find expiry
66
130
  const payload = JSON.parse(Buffer.from(this.cachedAccessToken!.split('.')[1], 'base64').toString());
67
131
  this.tokenExpiry = payload.exp * 1000;
68
132
 
@@ -74,17 +138,17 @@ export class ShomeClient {
74
138
  }
75
139
  } catch (error) {
76
140
  this.log.error(`Login error: ${error}`);
77
- return null;
141
+ throw error;
78
142
  }
79
143
  }
80
144
 
81
145
  async getDeviceList(): Promise<MainDevice[]> {
82
- const token = await this.login();
83
- if (!token || !this.ihdId) {
84
- return [];
85
- }
146
+ return this.enqueue(async () => {
147
+ const token = await this.performLogin();
148
+ if (!token || !this.ihdId) {
149
+ return [];
150
+ }
86
151
 
87
- try {
88
152
  const createDate = this.getDateTime();
89
153
  const hashData = this.sha512(`IHRESTAPI${this.ihdId}${createDate}`);
90
154
 
@@ -92,21 +156,17 @@ export class ShomeClient {
92
156
  params: { createDate, hashData },
93
157
  headers: { 'Authorization': `Bearer ${token}` },
94
158
  });
95
-
96
159
  return response.data.deviceList || [];
97
- } catch (error) {
98
- this.log.error(`Error getting device list: ${error}`);
99
- return [];
100
- }
160
+ });
101
161
  }
102
162
 
103
163
  async getDeviceInfo(thingId: string, type: string): Promise<SubDevice[] | null> {
104
- const token = await this.login();
105
- if (!token) {
106
- return null;
107
- }
164
+ return this.enqueue(async () => {
165
+ const token = await this.performLogin();
166
+ if (!token) {
167
+ return null;
168
+ }
108
169
 
109
- try {
110
170
  const createDate = this.getDateTime();
111
171
  const hashData = this.sha512(`IHRESTAPI${thingId}${createDate}`);
112
172
  const typePath = type.toLowerCase().replace(/_/g, '');
@@ -115,21 +175,17 @@ export class ShomeClient {
115
175
  params: { createDate, hashData },
116
176
  headers: { 'Authorization': `Bearer ${token}` },
117
177
  });
118
-
119
178
  return response.data.deviceInfoList || null;
120
- } catch (error) {
121
- this.log.error(`Error getting device info for ${thingId}: ${error}`);
122
- return null;
123
- }
179
+ });
124
180
  }
125
181
 
126
182
  async setDevice(thingId: string, deviceId: string, type: string, controlType: string, state: string, nickname?: string): Promise<boolean> {
127
- const token = await this.login();
128
- if (!token) {
129
- return false;
130
- }
183
+ return this.enqueue(async () => {
184
+ const token = await this.performLogin();
185
+ if (!token) {
186
+ return false;
187
+ }
131
188
 
132
- try {
133
189
  const createDate = this.getDateTime();
134
190
  const hashData = this.sha512(`IHRESTAPI${thingId}${deviceId}${state}${createDate}`);
135
191
  const typePath = type.toLowerCase().replace(/_/g, '');
@@ -147,20 +203,16 @@ export class ShomeClient {
147
203
  const displayName = nickname || `${thingId}/${deviceId}`;
148
204
  this.log.info(`[${displayName}] state set to ${state}.`);
149
205
  return true;
150
- } catch (error) {
151
- const displayName = nickname || `${thingId}/${deviceId}`;
152
- this.log.error(`Error setting device [${displayName}]: ${error}`);
153
- return false;
154
- }
206
+ });
155
207
  }
156
208
 
157
209
  async unlockDoorlock(thingId: string, nickname?: string): Promise<boolean> {
158
- const token = await this.login();
159
- if (!token) {
160
- return false;
161
- }
210
+ return this.enqueue(async () => {
211
+ const token = await this.performLogin();
212
+ if (!token) {
213
+ return false;
214
+ }
162
215
 
163
- try {
164
216
  const createDate = this.getDateTime();
165
217
  const hashData = this.sha512(`IHRESTAPI${thingId}${createDate}`);
166
218
 
@@ -176,11 +228,7 @@ export class ShomeClient {
176
228
  const displayName = nickname || thingId;
177
229
  this.log.info(`Unlocked [${displayName}].`);
178
230
  return true;
179
- } catch (error) {
180
- const displayName = nickname || thingId;
181
- this.log.error(`Error unlocking [${displayName}]: ${error}`);
182
- return false;
183
- }
231
+ });
184
232
  }
185
233
 
186
234
  private sha512(input: string): string {