@boozilla/homebridge-shome 1.0.10 → 1.0.12

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/README.md CHANGED
@@ -36,7 +36,8 @@ Add a new platform to the `platforms` array in your Homebridge `config.json` fil
36
36
  "name": "sHome",
37
37
  "username": "YOUR_SHOME_USERNAME",
38
38
  "password": "YOUR_SHOME_PASSWORD",
39
- "deviceId": "YOUR_MOBILE_DEVICE_ID"
39
+ "deviceId": "YOUR_MOBILE_DEVICE_ID",
40
+ "pollingInterval": 3000
40
41
  }
41
42
  ]
42
43
  }
@@ -44,13 +45,14 @@ Add a new platform to the `platforms` array in your Homebridge `config.json` fil
44
45
 
45
46
  ### Configuration Fields
46
47
 
47
- | Key | Description | Required |
48
- |:-----------|:--------------------------------------------------------------------------------------------------------------|:---------|
49
- | `platform` | Must be set to **"sHome"**. | Yes |
50
- | `name` | The name of the platform that will appear in the Homebridge logs (e.g., "sHome"). | Yes |
51
- | `username` | Your Samsung sHome account username. | Yes |
52
- | `password` | Your Samsung sHome account password. | Yes |
53
- | `deviceId` | The unique ID of the mobile device where the sHome app is installed. This is required for API authentication. | Yes |
48
+ | Key | Description | Required |
49
+ |:------------------|:--------------------------------------------------------------------------------------------------------------|:---------|
50
+ | `platform` | Must be set to **"sHome"**. | Yes |
51
+ | `name` | The name of the platform that will appear in the Homebridge logs (e.g., "sHome"). | Yes |
52
+ | `username` | Your Samsung sHome account username. | Yes |
53
+ | `password` | Your Samsung sHome account password. | Yes |
54
+ | `deviceId` | The unique ID of the mobile device where the sHome app is installed. This is required for API authentication. | Yes |
55
+ | `pollingInterval` | The interval in milliseconds to poll for device status updates. Set to 0 to disable. | No |
54
56
 
55
57
  **Note:** The `deviceId` can often be found by inspecting the sHome app's internal storage or by using specific tools to
56
58
  retrieve it. A correct value is essential for the API login to succeed.
@@ -5,36 +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
- "format": "password",
22
- "required": true
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
26
  "pollingInterval": {
31
27
  "title": "Polling Interval (ms)",
32
28
  "type": "integer",
33
29
  "default": 3000,
34
- "description": "The interval in milliseconds to poll for device status updates. Set to 0 to disable.",
35
- "required": false
30
+ "description": "The interval in milliseconds to poll for device status updates. Set to 0 to disable."
36
31
  }
37
- }
32
+ },
33
+ "required": ["name", "username", "password", "deviceId"]
38
34
  },
39
35
  "pluginAlias": "sHome",
40
36
  "pluginType": "platform"
@@ -18,14 +18,15 @@ export declare class ShomeClient {
18
18
  private cachedAccessToken;
19
19
  private ihdId;
20
20
  private tokenExpiry;
21
- private requestQueue;
22
- private isProcessing;
21
+ private putQueue;
22
+ private isProcessingPut;
23
+ private loginPromise;
23
24
  constructor(log: Logger, username: string, password: string, deviceId: string);
24
- private enqueue;
25
- private processQueue;
26
- private executeTaskWithRetries;
27
- login(): Promise<string | null>;
25
+ private login;
28
26
  private performLogin;
27
+ private enqueuePut;
28
+ private processPutQueue;
29
+ private executeWithRetries;
29
30
  getDeviceList(): Promise<MainDevice[]>;
30
31
  getDeviceInfo(thingId: string, type: string): Promise<SubDevice[] | null>;
31
32
  setDevice(thingId: string, deviceId: string, type: string, controlType: string, state: string, nickname?: string): Promise<boolean>;
@@ -16,69 +16,35 @@ export class ShomeClient {
16
16
  ihdId = null;
17
17
  tokenExpiry = 0;
18
18
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
19
- requestQueue = [];
20
- isProcessing = false;
19
+ putQueue = [];
20
+ isProcessingPut = false;
21
+ loginPromise = null;
21
22
  constructor(log, username, password, deviceId) {
22
23
  this.log = log;
23
24
  this.username = username;
24
25
  this.password = password;
25
26
  this.deviceId = deviceId;
26
27
  }
27
- enqueue(request) {
28
- return new Promise((resolve, reject) => {
29
- this.requestQueue.push({ request, resolve, reject, authRetry: false });
30
- this.processQueue();
31
- });
32
- }
33
- async processQueue() {
34
- if (this.isProcessing) {
35
- return; // A processing loop is already running
36
- }
37
- this.isProcessing = true;
38
- while (this.requestQueue.length > 0) {
39
- const task = this.requestQueue.shift();
40
- try {
41
- const result = await this.executeTaskWithRetries(task);
42
- task.resolve(result);
43
- }
44
- catch (error) {
45
- task.reject(error);
46
- }
47
- // Add a delay between requests to avoid overwhelming the server
48
- await new Promise(resolve => setTimeout(resolve, REQUEST_DELAY_MS));
28
+ login() {
29
+ if (!this.isTokenExpired()) {
30
+ return Promise.resolve(this.cachedAccessToken);
49
31
  }
50
- this.isProcessing = false;
51
- }
52
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
53
- async executeTaskWithRetries(task) {
54
- let retries = 0;
55
- while (true) {
56
- try {
57
- const result = await task.request();
58
- return result;
59
- }
60
- catch (error) {
61
- const isAuthError = axios.isAxiosError(error) && error.response?.status === 401;
62
- if (isAuthError && !task.authRetry) {
63
- this.log.warn('API authentication failed (401). Retrying after refreshing token.');
64
- this.cachedAccessToken = null;
65
- this.tokenExpiry = 0;
66
- task.authRetry = true;
67
- continue; // Immediately retry the request
68
- }
69
- if (retries >= MAX_RETRIES) {
70
- this.log.error(`Request failed after ${MAX_RETRIES} retries. Giving up.`, error);
71
- throw error; // Throw final error
72
- }
73
- retries++;
74
- const backoffTime = INITIAL_BACKOFF_MS * Math.pow(2, retries - 1);
75
- this.log.warn(`Request failed. Retrying in ${backoffTime}ms... (Attempt ${retries}/${MAX_RETRIES})`);
76
- await new Promise(resolve => setTimeout(resolve, backoffTime));
77
- }
32
+ if (this.loginPromise) {
33
+ return this.loginPromise;
78
34
  }
79
- }
80
- async login() {
81
- return this.enqueue(() => this.performLogin());
35
+ this.loginPromise = new Promise((resolve, reject) => {
36
+ this.putQueue.unshift({
37
+ request: () => this.performLogin(),
38
+ resolve,
39
+ reject,
40
+ });
41
+ this.processPutQueue();
42
+ });
43
+ // Clean up the promise once it's settled
44
+ this.loginPromise.finally(() => {
45
+ this.loginPromise = null;
46
+ });
47
+ return this.loginPromise;
82
48
  }
83
49
  async performLogin() {
84
50
  if (!this.isTokenExpired()) {
@@ -119,9 +85,66 @@ export class ShomeClient {
119
85
  throw error;
120
86
  }
121
87
  }
88
+ enqueuePut(request) {
89
+ return new Promise((resolve, reject) => {
90
+ this.putQueue.push({ request, resolve, reject });
91
+ this.processPutQueue();
92
+ });
93
+ }
94
+ async processPutQueue() {
95
+ if (this.isProcessingPut) {
96
+ return;
97
+ }
98
+ this.isProcessingPut = true;
99
+ while (this.putQueue.length > 0) {
100
+ const task = this.putQueue.shift();
101
+ try {
102
+ const result = await this.executeWithRetries(task.request, true);
103
+ task.resolve(result);
104
+ }
105
+ catch (error) {
106
+ task.reject(error);
107
+ }
108
+ await new Promise(resolve => setTimeout(resolve, REQUEST_DELAY_MS));
109
+ }
110
+ this.isProcessingPut = false;
111
+ }
112
+ async executeWithRetries(request, isQueued = false) {
113
+ let retries = 0;
114
+ while (true) {
115
+ try {
116
+ // For non-queued (concurrent) requests, we need to ensure login happens before the request.
117
+ // For queued requests, the login is handled as part of the queue, so we can just await it.
118
+ if (!isQueued) {
119
+ await this.login();
120
+ }
121
+ return await request();
122
+ }
123
+ catch (error) {
124
+ const isAuthError = axios.isAxiosError(error) && error.response?.status === 401;
125
+ if (isAuthError) {
126
+ this.log.warn('API authentication failed (401). Invalidating token.');
127
+ this.cachedAccessToken = null;
128
+ this.tokenExpiry = 0;
129
+ }
130
+ if (retries >= MAX_RETRIES) {
131
+ this.log.error(`Request failed after ${MAX_RETRIES} retries. Giving up.`, error);
132
+ throw error;
133
+ }
134
+ retries++;
135
+ const backoffTime = INITIAL_BACKOFF_MS * Math.pow(2, retries - 1);
136
+ if (!isAuthError) {
137
+ this.log.warn(`Request failed. Retrying in ${backoffTime}ms... (Attempt ${retries}/${MAX_RETRIES})`);
138
+ }
139
+ await new Promise(resolve => setTimeout(resolve, backoffTime));
140
+ // After a failure, always ensure we are logged in before the next attempt.
141
+ await this.login();
142
+ }
143
+ }
144
+ }
122
145
  async getDeviceList() {
123
- return this.enqueue(async () => {
124
- const token = await this.performLogin();
146
+ return this.executeWithRetries(async () => {
147
+ const token = this.cachedAccessToken;
125
148
  if (!token || !this.ihdId) {
126
149
  return [];
127
150
  }
@@ -135,8 +158,8 @@ export class ShomeClient {
135
158
  });
136
159
  }
137
160
  async getDeviceInfo(thingId, type) {
138
- return this.enqueue(async () => {
139
- const token = await this.performLogin();
161
+ return this.executeWithRetries(async () => {
162
+ const token = this.cachedAccessToken;
140
163
  if (!token) {
141
164
  return null;
142
165
  }
@@ -151,8 +174,8 @@ export class ShomeClient {
151
174
  });
152
175
  }
153
176
  async setDevice(thingId, deviceId, type, controlType, state, nickname) {
154
- return this.enqueue(async () => {
155
- const token = await this.performLogin();
177
+ return this.enqueuePut(async () => {
178
+ const token = this.cachedAccessToken;
156
179
  if (!token) {
157
180
  return false;
158
181
  }
@@ -174,8 +197,8 @@ export class ShomeClient {
174
197
  });
175
198
  }
176
199
  async unlockDoorlock(thingId, nickname) {
177
- return this.enqueue(async () => {
178
- const token = await this.performLogin();
200
+ return this.enqueuePut(async () => {
201
+ const token = this.cachedAccessToken;
179
202
  if (!token) {
180
203
  return false;
181
204
  }
@@ -1 +1 @@
1
- {"version":3,"file":"shomeClient.js","sourceRoot":"","sources":["../src/shomeClient.ts"],"names":[],"mappings":"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"}
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.10",
4
+ "version": "1.0.12",
5
5
  "private": false,
6
6
  "description": "A Homebridge plugin for Samsung Smart Home",
7
7
  "author": "boozilla",
@@ -28,7 +28,6 @@ type QueueTask<T = unknown> = {
28
28
  request: () => Promise<T>;
29
29
  resolve: (value: T | PromiseLike<T>) => void;
30
30
  reject: (reason?: unknown) => void;
31
- authRetry: boolean;
32
31
  };
33
32
 
34
33
  export class ShomeClient {
@@ -36,8 +35,9 @@ export class ShomeClient {
36
35
  private ihdId: string | null = null;
37
36
  private tokenExpiry: number = 0;
38
37
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
39
- private requestQueue: QueueTask<any>[] = [];
40
- private isProcessing = false;
38
+ private putQueue: QueueTask<any>[] = [];
39
+ private isProcessingPut = false;
40
+ private loginPromise: Promise<string | null> | null = null;
41
41
 
42
42
  constructor(
43
43
  private readonly log: Logger,
@@ -47,67 +47,30 @@ export class ShomeClient {
47
47
  ) {
48
48
  }
49
49
 
50
- private enqueue<T>(request: () => Promise<T>): Promise<T> {
51
- return new Promise<T>((resolve, reject) => {
52
- this.requestQueue.push({ request, resolve, reject, authRetry: false });
53
- this.processQueue();
54
- });
55
- }
56
-
57
- private async processQueue(): Promise<void> {
58
- if (this.isProcessing) {
59
- return; // A processing loop is already running
50
+ private login(): Promise<string | null> {
51
+ if (!this.isTokenExpired()) {
52
+ return Promise.resolve(this.cachedAccessToken);
60
53
  }
61
- this.isProcessing = true;
62
54
 
63
- while (this.requestQueue.length > 0) {
64
- const task = this.requestQueue.shift()!;
65
- try {
66
- const result = await this.executeTaskWithRetries(task);
67
- task.resolve(result);
68
- } catch (error) {
69
- task.reject(error);
70
- }
71
- // Add a delay between requests to avoid overwhelming the server
72
- await new Promise(resolve => setTimeout(resolve, REQUEST_DELAY_MS));
55
+ if (this.loginPromise) {
56
+ return this.loginPromise;
73
57
  }
74
58
 
75
- this.isProcessing = false;
76
- }
77
-
78
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
79
- private async executeTaskWithRetries(task: QueueTask<any>): Promise<any> {
80
- let retries = 0;
81
- while (true) {
82
- try {
83
- const result = await task.request();
84
- return result;
85
- } catch (error) {
86
- const isAuthError = axios.isAxiosError(error) && error.response?.status === 401;
87
-
88
- if (isAuthError && !task.authRetry) {
89
- this.log.warn('API authentication failed (401). Retrying after refreshing token.');
90
- this.cachedAccessToken = null;
91
- this.tokenExpiry = 0;
92
- task.authRetry = true;
93
- continue; // Immediately retry the request
94
- }
95
-
96
- if (retries >= MAX_RETRIES) {
97
- this.log.error(`Request failed after ${MAX_RETRIES} retries. Giving up.`, error);
98
- throw error; // Throw final error
99
- }
59
+ this.loginPromise = new Promise((resolve, reject) => {
60
+ this.putQueue.unshift({ // Prioritize login by adding to the front of the queue
61
+ request: () => this.performLogin(),
62
+ resolve,
63
+ reject,
64
+ });
65
+ this.processPutQueue();
66
+ });
100
67
 
101
- retries++;
102
- const backoffTime = INITIAL_BACKOFF_MS * Math.pow(2, retries - 1);
103
- this.log.warn(`Request failed. Retrying in ${backoffTime}ms... (Attempt ${retries}/${MAX_RETRIES})`);
104
- await new Promise(resolve => setTimeout(resolve, backoffTime));
105
- }
106
- }
107
- }
68
+ // Clean up the promise once it's settled
69
+ this.loginPromise.finally(() => {
70
+ this.loginPromise = null;
71
+ });
108
72
 
109
- async login(): Promise<string | null> {
110
- return this.enqueue(() => this.performLogin());
73
+ return this.loginPromise;
111
74
  }
112
75
 
113
76
  private async performLogin(): Promise<string | null> {
@@ -153,9 +116,73 @@ export class ShomeClient {
153
116
  }
154
117
  }
155
118
 
119
+ private enqueuePut<T>(request: () => Promise<T>): Promise<T> {
120
+ return new Promise<T>((resolve, reject) => {
121
+ this.putQueue.push({ request, resolve, reject });
122
+ this.processPutQueue();
123
+ });
124
+ }
125
+
126
+ private async processPutQueue(): Promise<void> {
127
+ if (this.isProcessingPut) {
128
+ return;
129
+ }
130
+ this.isProcessingPut = true;
131
+
132
+ while (this.putQueue.length > 0) {
133
+ const task = this.putQueue.shift()!;
134
+ try {
135
+ const result = await this.executeWithRetries(task.request, true);
136
+ task.resolve(result);
137
+ } catch (error) {
138
+ task.reject(error);
139
+ }
140
+ await new Promise(resolve => setTimeout(resolve, REQUEST_DELAY_MS));
141
+ }
142
+
143
+ this.isProcessingPut = false;
144
+ }
145
+
146
+ private async executeWithRetries<T>(request: () => Promise<T>, isQueued = false): Promise<T> {
147
+ let retries = 0;
148
+ while (true) {
149
+ try {
150
+ // For non-queued (concurrent) requests, we need to ensure login happens before the request.
151
+ // For queued requests, the login is handled as part of the queue, so we can just await it.
152
+ if (!isQueued) {
153
+ await this.login();
154
+ }
155
+ return await request();
156
+ } catch (error) {
157
+ const isAuthError = axios.isAxiosError(error) && error.response?.status === 401;
158
+
159
+ if (isAuthError) {
160
+ this.log.warn('API authentication failed (401). Invalidating token.');
161
+ this.cachedAccessToken = null;
162
+ this.tokenExpiry = 0;
163
+ }
164
+
165
+ if (retries >= MAX_RETRIES) {
166
+ this.log.error(`Request failed after ${MAX_RETRIES} retries. Giving up.`, error);
167
+ throw error;
168
+ }
169
+
170
+ retries++;
171
+ const backoffTime = INITIAL_BACKOFF_MS * Math.pow(2, retries - 1);
172
+ if (!isAuthError) {
173
+ this.log.warn(`Request failed. Retrying in ${backoffTime}ms... (Attempt ${retries}/${MAX_RETRIES})`);
174
+ }
175
+ await new Promise(resolve => setTimeout(resolve, backoffTime));
176
+
177
+ // After a failure, always ensure we are logged in before the next attempt.
178
+ await this.login();
179
+ }
180
+ }
181
+ }
182
+
156
183
  async getDeviceList(): Promise<MainDevice[]> {
157
- return this.enqueue(async () => {
158
- const token = await this.performLogin();
184
+ return this.executeWithRetries(async () => {
185
+ const token = this.cachedAccessToken;
159
186
  if (!token || !this.ihdId) {
160
187
  return [];
161
188
  }
@@ -173,8 +200,8 @@ export class ShomeClient {
173
200
  }
174
201
 
175
202
  async getDeviceInfo(thingId: string, type: string): Promise<SubDevice[] | null> {
176
- return this.enqueue(async () => {
177
- const token = await this.performLogin();
203
+ return this.executeWithRetries(async () => {
204
+ const token = this.cachedAccessToken;
178
205
  if (!token) {
179
206
  return null;
180
207
  }
@@ -193,8 +220,8 @@ export class ShomeClient {
193
220
  }
194
221
 
195
222
  async setDevice(thingId: string, deviceId: string, type: string, controlType: string, state: string, nickname?: string): Promise<boolean> {
196
- return this.enqueue(async () => {
197
- const token = await this.performLogin();
223
+ return this.enqueuePut(async () => {
224
+ const token = this.cachedAccessToken;
198
225
  if (!token) {
199
226
  return false;
200
227
  }
@@ -220,8 +247,8 @@ export class ShomeClient {
220
247
  }
221
248
 
222
249
  async unlockDoorlock(thingId: string, nickname?: string): Promise<boolean> {
223
- return this.enqueue(async () => {
224
- const token = await this.performLogin();
250
+ return this.enqueuePut(async () => {
251
+ const token = this.cachedAccessToken;
225
252
  if (!token) {
226
253
  return false;
227
254
  }