Skip to content

Commit 2eca5bf

Browse files
committed
feat: Send a device setting event to SinricPro
1 parent fa44a0c commit 2eca5bf

8 files changed

Lines changed: 115 additions & 8 deletions

File tree

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,4 +40,5 @@ yarn-error.log*
4040

4141

4242
.claude.md
43-
claude.md
43+
claude.md
44+
notes-to-aruna.txt

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## [5.2.0]
2+
3+
feat: Send a device setting event to SinricPro
4+
15
## [5.1.0]
26

37
feat: Implemented example applications for various device types including Camera, PowerSensor, Device Settings, Module Settings, and Temperature Sensor.

examples/settings/device/index.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,14 @@ async function main() {
5050
return false;
5151
});
5252

53+
// Example: Send a device setting event to SinricPro
54+
// This can be used to report setting changes made locally (e.g., via physical button)
55+
// setTimeout(async () => {
56+
// console.log('\n[Example] Sending device setting event...');
57+
// const sent = await myBlinds.sendSettingEvent('id_tilt', 75);
58+
// console.log(` Setting event sent: ${sent}`);
59+
// }, 5000);
60+
5361
// Add device to SinricPro
5462
SinricPro.add(myBlinds);
5563

@@ -67,12 +75,14 @@ async function main() {
6775
console.log('Device Settings vs Module Settings:');
6876
console.log('='.repeat(60));
6977
console.log(' Device Settings: Configuration for THIS specific device');
70-
console.log(' - Registered via: device.onSetting(callback)');
78+
console.log(' - Receive via: device.onSetting(callback)');
79+
console.log(' - Send via: device.sendSettingEvent(settingId, value)');
7180
console.log(' - Examples: Tilt angle');
7281
console.log(' - Callback receives: (deviceId, settingId, value)');
7382
console.log('');
7483
console.log(' Module Settings: Configuration for the module/board');
75-
console.log(' - Registered via: SinricPro.onSetSetting(callback)');
84+
console.log(' - Receive via: SinricPro.onSetSetting(callback)');
85+
console.log(' - Send via: SinricPro.sendSettingEvent(settingId, value)');
7686
console.log(' - Examples: WiFi retry count, log level');
7787

7888
console.log('\n' + '='.repeat(60));

examples/settings/module/index.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,14 @@ async function main() {
6161

6262
SinricPro.onConnected(() => {
6363
console.log('\nConnected to SinricPro!');
64+
65+
// Example: Send a module setting event to SinricPro
66+
// This can be used to report module-level settings changes
67+
// setTimeout(async () => {
68+
// console.log('\n[Example] Sending module setting event...');
69+
// const sent = await SinricPro.sendSettingEvent('if_wifiretrycount', 5);
70+
// console.log(` Module setting event sent: ${sent}`);
71+
// }, 5000);
6472
});
6573

6674
// Initialize SinricPro
@@ -73,9 +81,14 @@ async function main() {
7381
console.log('Module Settings vs Device Settings:');
7482
console.log('='.repeat(60));
7583
console.log(' Module Settings: Configuration for the module/board itself');
76-
console.log(' - Registered via: SinricPro.onSetSetting(callback)');
84+
console.log(' - Receive via: SinricPro.onSetSetting(callback)');
85+
console.log(' - Send via: SinricPro.sendSettingEvent(settingId, value)');
7786
console.log(' - Examples: WiFi retry count');
7887
console.log('');
88+
console.log(' Device Settings: Configuration for individual devices');
89+
console.log(' - Receive via: device.onSetting(callback)');
90+
console.log(' - Send via: device.sendSettingEvent(settingId, value)');
91+
console.log('');
7992

8093
console.log('\n' + '='.repeat(60));
8194
console.log('Current Module Configuration:');

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "sinricpro",
3-
"version": "5.1.0",
3+
"version": "5.2.0",
44
"description": "Official SinricPro SDK for Node.js and TypeScript - Control IoT devices with Alexa and Google Home",
55
"main": "dist/index.js",
66
"exports": {

src/capabilities/SettingController.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
*/
44

55
import { SinricProDevice } from '../core/SinricProDevice';
6+
import { EventLimiter } from '../core/EventLimiter';
67
import type { SinricProRequest } from '../core/types';
8+
import { EVENT_LIMIT_STATE, PHYSICAL_INTERACTION } from '../core/types';
79

810
// eslint-disable-next-line @typescript-eslint/no-explicit-any
911
type Constructor<T = object> = new (...args: any[]) => T;
@@ -16,11 +18,13 @@ export type SettingCallback = (
1618

1719
export interface ISettingController {
1820
onSetting(callback: SettingCallback): void;
21+
sendSettingEvent(settingId: string, value: unknown, cause?: string): Promise<boolean>;
1922
}
2023

2124
export function SettingController<T extends Constructor<SinricProDevice>>(Base: T) {
2225
return class extends Base implements ISettingController {
2326
private settingCallback: SettingCallback | null = null;
27+
private settingEventLimiter: EventLimiter = new EventLimiter(EVENT_LIMIT_STATE);
2428

2529
// eslint-disable-next-line @typescript-eslint/no-explicit-any
2630
constructor(...args: any[]) {
@@ -32,6 +36,18 @@ export function SettingController<T extends Constructor<SinricProDevice>>(Base:
3236
this.settingCallback = callback;
3337
}
3438

39+
async sendSettingEvent(
40+
settingId: string,
41+
value: unknown,
42+
cause: string = PHYSICAL_INTERACTION
43+
): Promise<boolean> {
44+
if (this.settingEventLimiter.isLimited()) {
45+
return false;
46+
}
47+
48+
return this.sendEvent('setSetting', { id: settingId, value }, cause);
49+
}
50+
3551
private async handleSettingRequest(request: SinricProRequest): Promise<boolean> {
3652
if (request.action !== 'setSetting' || !this.settingCallback) {
3753
return false;

src/core/SinricPro.ts

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ import type {
1818
PongCallback,
1919
ModuleSettingCallback,
2020
} from './types';
21-
import { SINRICPRO_SERVER_URL } from './types';
21+
import { SINRICPRO_SERVER_URL, EVENT_LIMIT_STATE, PHYSICAL_INTERACTION } from './types';
22+
import { EventLimiter } from './EventLimiter';
2223

2324
// Internal config type with serverUrl
2425
interface InternalConfig extends Required<SinricProConfig> {
@@ -37,6 +38,7 @@ export class SinricPro extends EventEmitter implements ISinricPro {
3738
private isInitialized: boolean = false;
3839
private processingInterval: NodeJS.Timeout | null = null;
3940
private moduleSettingCallback: ModuleSettingCallback | null = null;
41+
private settingEventLimiter: EventLimiter = new EventLimiter(EVENT_LIMIT_STATE);
4042

4143
private constructor() {
4244
super();
@@ -216,6 +218,67 @@ export class SinricPro extends EventEmitter implements ISinricPro {
216218
this.moduleSettingCallback = callback;
217219
}
218220

221+
/**
222+
* Send a module-level setting event to SinricPro server
223+
*
224+
* Module settings are configuration values for the module (dev board) itself.
225+
* Use this to report setting changes like WiFi configuration, logging level,
226+
* or other module-wide settings.
227+
*
228+
* @param settingId - The setting identifier
229+
* @param value - The setting value (can be any JSON-serializable type)
230+
* @param cause - (optional) Reason for the event (default: 'PHYSICAL_INTERACTION')
231+
* @returns Promise<boolean> - true if event was sent, false if rate limited
232+
* @example
233+
* ```typescript
234+
* await SinricPro.sendSettingEvent('wifi_retry_count', 5);
235+
* await SinricPro.sendSettingEvent('debug_mode', true);
236+
* ```
237+
*/
238+
async sendSettingEvent(
239+
settingId: string,
240+
value: unknown,
241+
cause: string = PHYSICAL_INTERACTION
242+
): Promise<boolean> {
243+
if (this.settingEventLimiter.isLimited()) {
244+
return false;
245+
}
246+
247+
if (!this.isConnected()) {
248+
SinricProSdkLogger.error('Cannot send setting event: Not connected to SinricPro');
249+
return false;
250+
}
251+
252+
const eventMessage: SinricProMessage = {
253+
header: {
254+
payloadVersion: 2,
255+
signatureVersion: 1,
256+
},
257+
payload: {
258+
action: 'setSetting',
259+
replyToken: this.generateMessageId(),
260+
type: 'event' as MessageType,
261+
createdAt: this.getTimestamp(),
262+
cause: { type: cause },
263+
scope: 'module',
264+
value: { id: settingId, value },
265+
},
266+
};
267+
268+
try {
269+
await this.sendMessage(eventMessage);
270+
SinricProSdkLogger.debug(`Module setting event sent: ${settingId}`, value);
271+
return true;
272+
} catch (error) {
273+
SinricProSdkLogger.error(`Failed to send module setting event ${settingId}:`, error);
274+
return false;
275+
}
276+
}
277+
278+
private generateMessageId(): string {
279+
return `${Date.now()}-${Math.random().toString(36).substring(2, 11)}`;
280+
}
281+
219282
/**
220283
* Stop the SinricPro SDK and disconnect from the server
221284
* @example

0 commit comments

Comments
 (0)