@boozilla/homebridge-shome 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 (44) hide show
  1. package/.idea/aws.xml +11 -0
  2. package/.idea/codeStyles/codeStyleConfig.xml +5 -0
  3. package/.idea/homebridge-shome.iml +9 -0
  4. package/.idea/misc.xml +6 -0
  5. package/.idea/modules.xml +8 -0
  6. package/.idea/vcs.xml +6 -0
  7. package/README.md +66 -0
  8. package/config.schema.json +32 -0
  9. package/dist/accessories/doorlockAccessory.d.ts +10 -0
  10. package/dist/accessories/doorlockAccessory.js +55 -0
  11. package/dist/accessories/doorlockAccessory.js.map +1 -0
  12. package/dist/accessories/heaterAccessory.d.ts +16 -0
  13. package/dist/accessories/heaterAccessory.js +75 -0
  14. package/dist/accessories/heaterAccessory.js.map +1 -0
  15. package/dist/accessories/lightAccessory.d.ts +10 -0
  16. package/dist/accessories/lightAccessory.js +32 -0
  17. package/dist/accessories/lightAccessory.js.map +1 -0
  18. package/dist/accessories/ventilatorAccessory.d.ts +12 -0
  19. package/dist/accessories/ventilatorAccessory.js +65 -0
  20. package/dist/accessories/ventilatorAccessory.js.map +1 -0
  21. package/dist/index.d.ts +3 -0
  22. package/dist/index.js +6 -0
  23. package/dist/index.js.map +1 -0
  24. package/dist/platform.d.ts +16 -0
  25. package/dist/platform.js +98 -0
  26. package/dist/platform.js.map +1 -0
  27. package/dist/settings.d.ts +8 -0
  28. package/dist/settings.js +9 -0
  29. package/dist/settings.js.map +1 -0
  30. package/dist/shomeClient.d.ts +30 -0
  31. package/dist/shomeClient.js +163 -0
  32. package/dist/shomeClient.js.map +1 -0
  33. package/eslint.config.js +35 -0
  34. package/nodemon.json +12 -0
  35. package/package.json +50 -0
  36. package/src/accessories/doorlockAccessory.ts +62 -0
  37. package/src/accessories/heaterAccessory.ts +94 -0
  38. package/src/accessories/lightAccessory.ts +41 -0
  39. package/src/accessories/ventilatorAccessory.ts +78 -0
  40. package/src/index.ts +7 -0
  41. package/src/platform.ts +113 -0
  42. package/src/settings.ts +9 -0
  43. package/src/shomeClient.ts +196 -0
  44. package/tsconfig.json +23 -0
package/.idea/aws.xml ADDED
@@ -0,0 +1,11 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="accountSettings">
4
+ <option name="activeRegion" value="us-east-1" />
5
+ <option name="recentlyUsedRegions">
6
+ <list>
7
+ <option value="us-east-1" />
8
+ </list>
9
+ </option>
10
+ </component>
11
+ </project>
@@ -0,0 +1,5 @@
1
+ <component name="ProjectCodeStyleConfiguration">
2
+ <state>
3
+ <option name="PREFERRED_PROJECT_CODE_STYLE" value="eslint-config-based" />
4
+ </state>
5
+ </component>
@@ -0,0 +1,9 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <module type="JAVA_MODULE" version="4">
3
+ <component name="NewModuleRootManager" inherit-compiler-output="true">
4
+ <exclude-output />
5
+ <content url="file://$MODULE_DIR$" />
6
+ <orderEntry type="inheritedJdk" />
7
+ <orderEntry type="sourceFolder" forTests="false" />
8
+ </component>
9
+ </module>
package/.idea/misc.xml ADDED
@@ -0,0 +1,6 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="ProjectRootManager" version="2" languageLevel="JDK_24" default="true" project-jdk-name="zulu-24" project-jdk-type="JavaSDK">
4
+ <output url="file://$PROJECT_DIR$/out" />
5
+ </component>
6
+ </project>
@@ -0,0 +1,8 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="ProjectModuleManager">
4
+ <modules>
5
+ <module fileurl="file://$PROJECT_DIR$/.idea/homebridge-shome.iml" filepath="$PROJECT_DIR$/.idea/homebridge-shome.iml" />
6
+ </modules>
7
+ </component>
8
+ </project>
package/.idea/vcs.xml ADDED
@@ -0,0 +1,6 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="VcsDirectoryMappings">
4
+ <mapping directory="" vcs="Git" />
5
+ </component>
6
+ </project>
package/README.md ADDED
@@ -0,0 +1,66 @@
1
+ # Homebridge sHome
2
+
3
+ `homebridge-shome` is a [Homebridge](https://homebridge.io/) plugin that allows you to integrate devices from the
4
+ Samsung Smart Home (sHome) platform into Apple HomeKit.
5
+
6
+ With this plugin, you can control devices connected to Samsung sHome, such as lights, heating, ventilation systems, and
7
+ door locks, using the Home app and Siri on your Apple devices.
8
+
9
+ ## Key Features
10
+
11
+ * **Light Control**: Turn individual lights in each room on or off.
12
+ * **Heating Control**: Control thermostats in each room individually. Monitor the current temperature and set your
13
+ desired target temperature.
14
+ * **Ventilation System Control**: Turn the ventilation system on or off and adjust its fan speed.
15
+ * **Digital Door Lock**: Check the current state of your door lock (locked/unlocked) and unlock it remotely.
16
+ * **Individual Accessory Support**: Each sub-device registered in your system, such as 'Living Room Light' or 'Master
17
+ Bedroom Thermostat', is added as an independent HomeKit accessory for granular control.
18
+
19
+ ## Installation
20
+
21
+ If you have a running Homebridge setup, install the plugin using the following command:
22
+
23
+ ```sh
24
+ npm install -g homebridge-shome
25
+ ```
26
+
27
+ ## Configuration
28
+
29
+ Add a new platform to the `platforms` array in your Homebridge `config.json` file.
30
+
31
+ ```json
32
+ {
33
+ "platforms": [
34
+ {
35
+ "platform": "sHome",
36
+ "name": "sHome",
37
+ "username": "YOUR_SHOME_USERNAME",
38
+ "password": "YOUR_SHOME_PASSWORD",
39
+ "deviceId": "YOUR_MOBILE_DEVICE_ID"
40
+ }
41
+ ]
42
+ }
43
+ ```
44
+
45
+ ### Configuration Fields
46
+
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 |
54
+
55
+ **Note:** The `deviceId` can often be found by inspecting the sHome app's internal storage or by using specific tools to
56
+ retrieve it. A correct value is essential for the API login to succeed.
57
+
58
+ ## Disclaimer
59
+
60
+ This plugin is not officially developed, endorsed, or supported by Samsung. It is a personal project that relies on an
61
+ unofficial API. The API may change at any time without notice, which could cause this plugin to stop working. Use at
62
+ your own risk.
63
+
64
+ ## License
65
+
66
+ This project is licensed under the MIT License.
@@ -0,0 +1,32 @@
1
+ {
2
+ "schema": {
3
+ "type": "object",
4
+ "properties": {
5
+ "name": {
6
+ "title": "Name",
7
+ "type": "string",
8
+ "default": "sHome",
9
+ "required": true
10
+ },
11
+ "username": {
12
+ "title": "Username",
13
+ "type": "string",
14
+ "description": "Your Samsung sHome account username.",
15
+ "required": true
16
+ },
17
+ "password": {
18
+ "title": "Password",
19
+ "type": "string",
20
+ "description": "Your Samsung sHome account password.",
21
+ "required": true,
22
+ "format": "password"
23
+ },
24
+ "deviceId": {
25
+ "title": "Device ID",
26
+ "type": "string",
27
+ "description": "Your mobile device ID.",
28
+ "required": true
29
+ }
30
+ }
31
+ }
32
+ }
@@ -0,0 +1,10 @@
1
+ import { CharacteristicValue, PlatformAccessory } from 'homebridge';
2
+ import { ShomePlatform } from '../platform.js';
3
+ export declare class DoorlockAccessory {
4
+ private readonly platform;
5
+ private readonly accessory;
6
+ private service;
7
+ constructor(platform: ShomePlatform, accessory: PlatformAccessory);
8
+ getCurrentState(): Promise<CharacteristicValue>;
9
+ setTargetState(value: CharacteristicValue): Promise<void>;
10
+ }
@@ -0,0 +1,55 @@
1
+ export class DoorlockAccessory {
2
+ platform;
3
+ accessory;
4
+ service;
5
+ constructor(platform, accessory) {
6
+ this.platform = platform;
7
+ this.accessory = accessory;
8
+ const device = this.accessory.context.device;
9
+ this.accessory.getService(this.platform.Service.AccessoryInformation)
10
+ .setCharacteristic(this.platform.Characteristic.Manufacturer, 'Samsung')
11
+ .setCharacteristic(this.platform.Characteristic.Model, 'Doorlock')
12
+ .setCharacteristic(this.platform.Characteristic.SerialNumber, device.thngId);
13
+ this.service = this.accessory.getService(this.platform.Service.LockMechanism) ||
14
+ this.accessory.addService(this.platform.Service.LockMechanism);
15
+ this.service.setCharacteristic(this.platform.Characteristic.Name, device.nickname);
16
+ this.service.getCharacteristic(this.platform.Characteristic.LockCurrentState)
17
+ .onGet(this.getCurrentState.bind(this));
18
+ this.service.getCharacteristic(this.platform.Characteristic.LockTargetState)
19
+ .onGet(this.getCurrentState.bind(this))
20
+ .onSet(this.setTargetState.bind(this));
21
+ }
22
+ async getCurrentState() {
23
+ const device = this.accessory.context.device;
24
+ if (device.status === 0 || device.status === false) {
25
+ return this.platform.Characteristic.LockCurrentState.UNSECURED;
26
+ }
27
+ else {
28
+ return this.platform.Characteristic.LockCurrentState.SECURED;
29
+ }
30
+ }
31
+ async setTargetState(value) {
32
+ const device = this.accessory.context.device;
33
+ if (value === this.platform.Characteristic.LockTargetState.UNSECURED) {
34
+ this.platform.log.info(`Unlocking ${device.nickname}...`);
35
+ const success = await this.platform.shomeClient.unlockDoorlock(device.thngId);
36
+ if (success) {
37
+ this.platform.log.info(`${device.nickname} unlocked successfully.`);
38
+ this.service.updateCharacteristic(this.platform.Characteristic.LockCurrentState, this.platform.Characteristic.LockCurrentState.UNSECURED);
39
+ }
40
+ else {
41
+ this.platform.log.error(`Failed to unlock ${device.nickname}.`);
42
+ setTimeout(() => {
43
+ this.service.updateCharacteristic(this.platform.Characteristic.LockTargetState, this.platform.Characteristic.LockTargetState.SECURED);
44
+ }, 1000);
45
+ }
46
+ }
47
+ else {
48
+ this.platform.log.info(`Locking ${device.nickname} via the app is not supported.`);
49
+ setTimeout(() => {
50
+ this.service.updateCharacteristic(this.platform.Characteristic.LockTargetState, this.platform.Characteristic.LockTargetState.SECURED);
51
+ }, 1000);
52
+ }
53
+ }
54
+ }
55
+ //# sourceMappingURL=doorlockAccessory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doorlockAccessory.js","sourceRoot":"","sources":["../../src/accessories/doorlockAccessory.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import { CharacteristicValue, PlatformAccessory } from 'homebridge';
2
+ import { ShomePlatform } from '../platform.js';
3
+ export declare class HeaterAccessory {
4
+ private readonly platform;
5
+ private readonly accessory;
6
+ private service;
7
+ constructor(platform: ShomePlatform, accessory: PlatformAccessory);
8
+ getActive(): Promise<CharacteristicValue>;
9
+ getCurrentState(): Promise<CharacteristicValue>;
10
+ getTargetState(): Promise<CharacteristicValue>;
11
+ getCurrentTemperature(): Promise<CharacteristicValue>;
12
+ getTargetTemperature(): Promise<CharacteristicValue>;
13
+ setActive(value: CharacteristicValue): Promise<void>;
14
+ setTargetState(): Promise<void>;
15
+ setTargetTemperature(value: CharacteristicValue): Promise<void>;
16
+ }
@@ -0,0 +1,75 @@
1
+ export class HeaterAccessory {
2
+ platform;
3
+ accessory;
4
+ service;
5
+ constructor(platform, accessory) {
6
+ this.platform = platform;
7
+ this.accessory = accessory;
8
+ const device = this.accessory.context.device;
9
+ const subDevice = this.accessory.context.subDevice;
10
+ this.accessory.getService(this.platform.Service.AccessoryInformation)
11
+ .setCharacteristic(this.platform.Characteristic.Manufacturer, 'Samsung')
12
+ .setCharacteristic(this.platform.Characteristic.Model, 'Heater')
13
+ .setCharacteristic(this.platform.Characteristic.SerialNumber, `${device.thngId}-${subDevice.deviceId}`);
14
+ this.service = this.accessory.getService(this.platform.Service.HeaterCooler) ||
15
+ this.accessory.addService(this.platform.Service.HeaterCooler);
16
+ this.service.setCharacteristic(this.platform.Characteristic.Name, subDevice.nickname);
17
+ this.service.getCharacteristic(this.platform.Characteristic.Active)
18
+ .onGet(this.getActive.bind(this))
19
+ .onSet(this.setActive.bind(this));
20
+ this.service.getCharacteristic(this.platform.Characteristic.CurrentHeaterCoolerState)
21
+ .onGet(this.getCurrentState.bind(this));
22
+ this.service.getCharacteristic(this.platform.Characteristic.TargetHeaterCoolerState)
23
+ // 버그 수정: validValues를 HEAT로만 설정하여 다른 모드(냉방, 자동)를 UI에서 제거
24
+ .setProps({
25
+ validValues: [this.platform.Characteristic.TargetHeaterCoolerState.HEAT],
26
+ })
27
+ .onSet(this.setTargetState.bind(this))
28
+ .onGet(this.getTargetState.bind(this));
29
+ this.service.getCharacteristic(this.platform.Characteristic.CurrentTemperature)
30
+ .onGet(this.getCurrentTemperature.bind(this));
31
+ this.service.getCharacteristic(this.platform.Characteristic.HeatingThresholdTemperature)
32
+ .setProps({ minValue: 5, maxValue: 40, minStep: 1 })
33
+ .onGet(this.getTargetTemperature.bind(this))
34
+ .onSet(this.setTargetTemperature.bind(this));
35
+ }
36
+ // ... (이하 다른 함수들은 이전과 동일)
37
+ async getActive() {
38
+ const subDevice = this.accessory.context.subDevice;
39
+ return subDevice.deviceStatus === 1
40
+ ? this.platform.Characteristic.Active.ACTIVE
41
+ : this.platform.Characteristic.Active.INACTIVE;
42
+ }
43
+ async getCurrentState() {
44
+ const subDevice = this.accessory.context.subDevice;
45
+ return subDevice.deviceStatus === 1
46
+ ? this.platform.Characteristic.CurrentHeaterCoolerState.HEATING
47
+ : this.platform.Characteristic.CurrentHeaterCoolerState.INACTIVE;
48
+ }
49
+ async getTargetState() {
50
+ return this.platform.Characteristic.TargetHeaterCoolerState.HEAT;
51
+ }
52
+ async getCurrentTemperature() {
53
+ const subDevice = this.accessory.context.subDevice;
54
+ return subDevice.currentTemp;
55
+ }
56
+ async getTargetTemperature() {
57
+ const subDevice = this.accessory.context.subDevice;
58
+ return subDevice.setTemp;
59
+ }
60
+ async setActive(value) {
61
+ const device = this.accessory.context.device;
62
+ const subDevice = this.accessory.context.subDevice;
63
+ const state = value === this.platform.Characteristic.Active.ACTIVE ? 'ON' : 'OFF';
64
+ await this.platform.shomeClient.setDevice(device.thngId, subDevice.deviceId.toString(), 'HEATER', 'ON_OFF', state);
65
+ }
66
+ async setTargetState() {
67
+ // 이 함수는 setProps로 인해 HEAT 값만 받게 되므로 별도 처리가 불필요합니다.
68
+ }
69
+ async setTargetTemperature(value) {
70
+ const device = this.accessory.context.device;
71
+ const subDevice = this.accessory.context.subDevice;
72
+ await this.platform.shomeClient.setDevice(device.thngId, subDevice.deviceId.toString(), 'HEATER', 'TEMPERATURE', value.toString());
73
+ }
74
+ }
75
+ //# sourceMappingURL=heaterAccessory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"heaterAccessory.js","sourceRoot":"","sources":["../../src/accessories/heaterAccessory.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import { CharacteristicValue, PlatformAccessory } from 'homebridge';
2
+ import { ShomePlatform } from '../platform.js';
3
+ export declare class LightAccessory {
4
+ private readonly platform;
5
+ private readonly accessory;
6
+ private service;
7
+ constructor(platform: ShomePlatform, accessory: PlatformAccessory);
8
+ getOn(): Promise<CharacteristicValue>;
9
+ setOn(value: CharacteristicValue): Promise<void>;
10
+ }
@@ -0,0 +1,32 @@
1
+ export class LightAccessory {
2
+ platform;
3
+ accessory;
4
+ service;
5
+ constructor(platform, accessory) {
6
+ this.platform = platform;
7
+ this.accessory = accessory;
8
+ const device = this.accessory.context.device;
9
+ const subDevice = this.accessory.context.subDevice;
10
+ this.accessory.getService(this.platform.Service.AccessoryInformation)
11
+ .setCharacteristic(this.platform.Characteristic.Manufacturer, 'Samsung')
12
+ .setCharacteristic(this.platform.Characteristic.Model, 'Smart Light')
13
+ .setCharacteristic(this.platform.Characteristic.SerialNumber, `${device.thngId}-${subDevice.deviceId}`);
14
+ this.service = this.accessory.getService(this.platform.Service.Lightbulb) ||
15
+ this.accessory.addService(this.platform.Service.Lightbulb);
16
+ this.service.setCharacteristic(this.platform.Characteristic.Name, subDevice.nickname);
17
+ this.service.getCharacteristic(this.platform.Characteristic.On)
18
+ .onGet(this.getOn.bind(this))
19
+ .onSet(this.setOn.bind(this));
20
+ }
21
+ async getOn() {
22
+ const subDevice = this.accessory.context.subDevice;
23
+ return subDevice.deviceStatus === 1;
24
+ }
25
+ async setOn(value) {
26
+ const device = this.accessory.context.device;
27
+ const subDevice = this.accessory.context.subDevice;
28
+ const state = value ? 'ON' : 'OFF';
29
+ await this.platform.shomeClient.setDevice(device.thngId, subDevice.deviceId.toString(), 'LIGHT', 'ON_OFF', state);
30
+ }
31
+ }
32
+ //# sourceMappingURL=lightAccessory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lightAccessory.js","sourceRoot":"","sources":["../../src/accessories/lightAccessory.ts"],"names":[],"mappings":"AAGA,MAAM,OAAO,cAAc;IAIN;IACA;IAJX,OAAO,CAAU;IAEzB,YACmB,QAAuB,EACvB,SAA4B;QAD5B,aAAQ,GAAR,QAAQ,CAAe;QACvB,cAAS,GAAT,SAAS,CAAmB;QAE7C,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,MAAM,CAAC;QAC7C,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,SAAS,CAAC;QAEnD,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,oBAAoB,CAAE;aACnE,iBAAiB,CAAC,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,YAAY,EAAE,SAAS,CAAC;aACvE,iBAAiB,CAAC,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,KAAK,EAAE,aAAa,CAAC;aACpE,iBAAiB,CAAC,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,YAAY,EAAE,GAAG,MAAM,CAAC,MAAM,IAAI,SAAS,CAAC,QAAQ,EAAE,CAAC,CAAC;QAE1G,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,SAAS,CAAC;YACvE,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QAE7D,IAAI,CAAC,OAAO,CAAC,iBAAiB,CAAC,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,IAAI,EAAE,SAAS,CAAC,QAAQ,CAAC,CAAC;QAEtF,IAAI,CAAC,OAAO,CAAC,iBAAiB,CAAC,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC;aAC5D,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;aAC5B,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IAClC,CAAC;IAED,KAAK,CAAC,KAAK;QACT,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,SAAS,CAAC;QACnD,OAAO,SAAS,CAAC,YAAY,KAAK,CAAC,CAAC;IACtC,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,KAA0B;QACpC,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,MAAM,CAAC;QAC7C,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,SAAS,CAAC;QAEnD,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC;QACnC,MAAM,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,QAAQ,CAAC,QAAQ,EAAE,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;IACpH,CAAC;CACF"}
@@ -0,0 +1,12 @@
1
+ import { CharacteristicValue, PlatformAccessory } from 'homebridge';
2
+ import { ShomePlatform } from '../platform.js';
3
+ export declare class VentilatorAccessory {
4
+ private readonly platform;
5
+ private readonly accessory;
6
+ private fanService;
7
+ constructor(platform: ShomePlatform, accessory: PlatformAccessory);
8
+ getActive(): Promise<CharacteristicValue>;
9
+ getRotationSpeed(): Promise<CharacteristicValue>;
10
+ setActive(value: CharacteristicValue): Promise<void>;
11
+ setRotationSpeed(value: CharacteristicValue): Promise<void>;
12
+ }
@@ -0,0 +1,65 @@
1
+ export class VentilatorAccessory {
2
+ platform;
3
+ accessory;
4
+ fanService;
5
+ constructor(platform, accessory) {
6
+ this.platform = platform;
7
+ this.accessory = accessory;
8
+ const device = this.accessory.context.device;
9
+ const subDevice = this.accessory.context.subDevice;
10
+ this.accessory.getService(this.platform.Service.AccessoryInformation)
11
+ .setCharacteristic(this.platform.Characteristic.Manufacturer, 'Samsung')
12
+ .setCharacteristic(this.platform.Characteristic.Model, 'Ventilator')
13
+ .setCharacteristic(this.platform.Characteristic.SerialNumber, `${device.thngId}-${subDevice.deviceId}`);
14
+ this.fanService = this.accessory.getService(this.platform.Service.Fanv2) ||
15
+ this.accessory.addService(this.platform.Service.Fanv2);
16
+ this.fanService.setCharacteristic(this.platform.Characteristic.Name, subDevice.nickname);
17
+ this.fanService.getCharacteristic(this.platform.Characteristic.Active)
18
+ .onGet(this.getActive.bind(this))
19
+ .onSet(this.setActive.bind(this));
20
+ this.fanService.getCharacteristic(this.platform.Characteristic.RotationSpeed)
21
+ .onGet(this.getRotationSpeed.bind(this))
22
+ .onSet(this.setRotationSpeed.bind(this));
23
+ }
24
+ async getActive() {
25
+ const subDevice = this.accessory.context.subDevice;
26
+ return subDevice.deviceStatus === 1
27
+ ? this.platform.Characteristic.Active.ACTIVE
28
+ : this.platform.Characteristic.Active.INACTIVE;
29
+ }
30
+ async getRotationSpeed() {
31
+ const subDevice = this.accessory.context.subDevice;
32
+ const apiSpeed = subDevice.windSpeedMode; // 1, 2, 3
33
+ // sHome API (1:강, 2:중, 3:약) -> HomeKit % (100:강, 66:중, 33:약)
34
+ if (apiSpeed === 1) {
35
+ return 100;
36
+ }
37
+ else if (apiSpeed === 2) {
38
+ return 66;
39
+ }
40
+ else {
41
+ return 33;
42
+ }
43
+ }
44
+ async setActive(value) {
45
+ const device = this.accessory.context.device;
46
+ const subDevice = this.accessory.context.subDevice;
47
+ const state = value === this.platform.Characteristic.Active.ACTIVE ? 'ON' : 'OFF';
48
+ await this.platform.shomeClient.setDevice(device.thngId, subDevice.deviceId.toString(), 'VENTILATOR', 'ON_OFF', state);
49
+ }
50
+ async setRotationSpeed(value) {
51
+ const device = this.accessory.context.device;
52
+ const subDevice = this.accessory.context.subDevice;
53
+ const numericValue = Number(value);
54
+ // HomeKit % -> sHome API (1:강, 2:중, 3:약)
55
+ let apiSpeed = 3;
56
+ if (numericValue > 33) {
57
+ apiSpeed = 2;
58
+ }
59
+ if (numericValue > 66) {
60
+ apiSpeed = 1;
61
+ }
62
+ await this.platform.shomeClient.setDevice(device.thngId, subDevice.deviceId.toString(), 'VENTILATOR', 'WINDSPEED', apiSpeed.toString());
63
+ }
64
+ }
65
+ //# sourceMappingURL=ventilatorAccessory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ventilatorAccessory.js","sourceRoot":"","sources":["../../src/accessories/ventilatorAccessory.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { API } from 'homebridge';
2
+ declare const _default: (api: API) => void;
3
+ export default _default;
package/dist/index.js ADDED
@@ -0,0 +1,6 @@
1
+ import { PLATFORM_NAME } from './settings.js';
2
+ import { ShomePlatform } from './platform.js';
3
+ export default (api) => {
4
+ api.registerPlatform(PLATFORM_NAME, ShomePlatform);
5
+ };
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAE9C,eAAe,CAAC,GAAQ,EAAE,EAAE;IAC1B,GAAG,CAAC,gBAAgB,CAAC,aAAa,EAAE,aAAa,CAAC,CAAC;AACrD,CAAC,CAAC"}
@@ -0,0 +1,16 @@
1
+ import { API, Characteristic, DynamicPlatformPlugin, Logger, PlatformAccessory, PlatformConfig, Service } from 'homebridge';
2
+ import { ShomeClient, MainDevice, SubDevice } from './shomeClient.js';
3
+ export declare class ShomePlatform implements DynamicPlatformPlugin {
4
+ readonly log: Logger;
5
+ readonly config: PlatformConfig;
6
+ readonly api: API;
7
+ readonly Service: typeof Service;
8
+ readonly Characteristic: typeof Characteristic;
9
+ readonly accessories: PlatformAccessory[];
10
+ readonly shomeClient: ShomeClient;
11
+ constructor(log: Logger, config: PlatformConfig, api: API);
12
+ configureAccessory(accessory: PlatformAccessory): void;
13
+ discoverDevices(): Promise<void>;
14
+ setupAccessory(mainDevice: MainDevice, subDevice: SubDevice | null, uuid: string): PlatformAccessory;
15
+ createAccessory(accessory: PlatformAccessory): void;
16
+ }
@@ -0,0 +1,98 @@
1
+ import { PLATFORM_NAME, PLUGIN_NAME } from './settings.js';
2
+ import { ShomeClient } from './shomeClient.js';
3
+ import { LightAccessory } from './accessories/lightAccessory.js';
4
+ import { VentilatorAccessory } from './accessories/ventilatorAccessory.js';
5
+ import { HeaterAccessory } from './accessories/heaterAccessory.js';
6
+ import { DoorlockAccessory } from './accessories/doorlockAccessory.js';
7
+ const CONTROLLABLE_MULTI_DEVICE_TYPES = ['LIGHT', 'HEATER', 'VENTILATOR'];
8
+ const SPECIAL_CONTROLLABLE_TYPES = ['DOORLOCK'];
9
+ export class ShomePlatform {
10
+ log;
11
+ config;
12
+ api;
13
+ Service;
14
+ Characteristic;
15
+ accessories = [];
16
+ shomeClient;
17
+ constructor(log, config, api) {
18
+ this.log = log;
19
+ this.config = config;
20
+ this.api = api;
21
+ this.Service = this.api.hap.Service;
22
+ this.Characteristic = this.api.hap.Characteristic;
23
+ this.shomeClient = new ShomeClient(this.log, this.config.username, this.config.password, this.config.deviceId);
24
+ this.api.on('didFinishLaunching', () => {
25
+ this.discoverDevices();
26
+ });
27
+ }
28
+ configureAccessory(accessory) {
29
+ this.accessories.push(accessory);
30
+ }
31
+ async discoverDevices() {
32
+ const devices = await this.shomeClient.getDeviceList();
33
+ const foundAccessories = [];
34
+ for (const device of devices) {
35
+ if (CONTROLLABLE_MULTI_DEVICE_TYPES.includes(device.thngModelTypeName)) {
36
+ const deviceInfoList = await this.shomeClient.getDeviceInfo(device.thngId, device.thngModelTypeName);
37
+ if (deviceInfoList) {
38
+ for (const subDevice of deviceInfoList) {
39
+ const uuid = this.api.hap.uuid.generate(`${device.thngId}-${subDevice.deviceId}`);
40
+ const accessory = this.setupAccessory(device, subDevice, uuid);
41
+ foundAccessories.push(accessory);
42
+ }
43
+ }
44
+ }
45
+ else if (SPECIAL_CONTROLLABLE_TYPES.includes(device.thngModelTypeName)) {
46
+ const uuid = this.api.hap.uuid.generate(device.thngId);
47
+ const accessory = this.setupAccessory(device, null, uuid);
48
+ foundAccessories.push(accessory);
49
+ }
50
+ else {
51
+ this.log.info(`Ignoring device: ${device.nickname} (Type: ${device.thngModelTypeName})`);
52
+ }
53
+ }
54
+ const accessoriesToRemove = this.accessories.filter(cachedAccessory => !foundAccessories.some(foundAccessory => foundAccessory.UUID === cachedAccessory.UUID));
55
+ if (accessoriesToRemove.length > 0) {
56
+ this.log.info('Removing stale accessories:', accessoriesToRemove.map(a => a.displayName));
57
+ this.api.unregisterPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, accessoriesToRemove);
58
+ }
59
+ }
60
+ setupAccessory(mainDevice, subDevice, uuid) {
61
+ const displayName = subDevice ? subDevice.nickname : mainDevice.nickname;
62
+ const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
63
+ if (existingAccessory) {
64
+ this.log.info('Restoring existing accessory from cache:', displayName);
65
+ existingAccessory.context.device = mainDevice;
66
+ existingAccessory.context.subDevice = subDevice;
67
+ this.createAccessory(existingAccessory);
68
+ return existingAccessory;
69
+ }
70
+ else {
71
+ this.log.info('Adding new accessory:', displayName);
72
+ const accessory = new this.api.platformAccessory(displayName, uuid);
73
+ accessory.context.device = mainDevice;
74
+ accessory.context.subDevice = subDevice;
75
+ this.createAccessory(accessory);
76
+ this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]);
77
+ return accessory;
78
+ }
79
+ }
80
+ createAccessory(accessory) {
81
+ const device = accessory.context.device;
82
+ switch (device.thngModelTypeName) {
83
+ case 'LIGHT':
84
+ new LightAccessory(this, accessory);
85
+ break;
86
+ case 'VENTILATOR':
87
+ new VentilatorAccessory(this, accessory);
88
+ break;
89
+ case 'HEATER':
90
+ new HeaterAccessory(this, accessory);
91
+ break;
92
+ case 'DOORLOCK':
93
+ new DoorlockAccessory(this, accessory);
94
+ break;
95
+ }
96
+ }
97
+ }
98
+ //# sourceMappingURL=platform.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"platform.js","sourceRoot":"","sources":["../src/platform.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * This is the name of the platform that users will use to register the plugin in the Homebridge config.json
3
+ */
4
+ export declare const PLATFORM_NAME = "sHome";
5
+ /**
6
+ * This must match the name of your plugin as defined the package.json
7
+ */
8
+ export declare const PLUGIN_NAME = "homebridge-shome";
@@ -0,0 +1,9 @@
1
+ /**
2
+ * This is the name of the platform that users will use to register the plugin in the Homebridge config.json
3
+ */
4
+ export const PLATFORM_NAME = 'sHome';
5
+ /**
6
+ * This must match the name of your plugin as defined the package.json
7
+ */
8
+ export const PLUGIN_NAME = 'homebridge-shome';
9
+ //# sourceMappingURL=settings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"settings.js","sourceRoot":"","sources":["../src/settings.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,OAAO,CAAC;AAErC;;GAEG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,kBAAkB,CAAC"}