homebridge-selve-home-server-2 1.1.2

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 (40) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +124 -0
  3. package/config.schema.json +79 -0
  4. package/dist/configs/selve-accessory-config.d.ts +10 -0
  5. package/dist/configs/selve-accessory-config.d.ts.map +1 -0
  6. package/dist/configs/selve-accessory-config.js +3 -0
  7. package/dist/configs/selve-accessory-config.js.map +1 -0
  8. package/dist/configs/selve-platform-config.d.ts +10 -0
  9. package/dist/configs/selve-platform-config.d.ts.map +1 -0
  10. package/dist/configs/selve-platform-config.js +3 -0
  11. package/dist/configs/selve-platform-config.js.map +1 -0
  12. package/dist/helpers.d.ts +2 -0
  13. package/dist/helpers.d.ts.map +1 -0
  14. package/dist/helpers.js +9 -0
  15. package/dist/helpers.js.map +1 -0
  16. package/dist/index.d.ts +7 -0
  17. package/dist/index.d.ts.map +1 -0
  18. package/dist/index.js +11 -0
  19. package/dist/index.js.map +1 -0
  20. package/dist/platform.d.ts +12 -0
  21. package/dist/platform.d.ts.map +1 -0
  22. package/dist/platform.js +45 -0
  23. package/dist/platform.js.map +1 -0
  24. package/dist/selve-shutter-accessory.d.ts +26 -0
  25. package/dist/selve-shutter-accessory.d.ts.map +1 -0
  26. package/dist/selve-shutter-accessory.js +164 -0
  27. package/dist/selve-shutter-accessory.js.map +1 -0
  28. package/dist/services/home-server-2.service.d.ts +23 -0
  29. package/dist/services/home-server-2.service.d.ts.map +1 -0
  30. package/dist/services/home-server-2.service.js +169 -0
  31. package/dist/services/home-server-2.service.js.map +1 -0
  32. package/dist/settings.d.ts +9 -0
  33. package/dist/settings.d.ts.map +1 -0
  34. package/dist/settings.js +12 -0
  35. package/dist/settings.js.map +1 -0
  36. package/dist/states/selve-states.d.ts +56 -0
  37. package/dist/states/selve-states.d.ts.map +1 -0
  38. package/dist/states/selve-states.js +37 -0
  39. package/dist/states/selve-states.js.map +1 -0
  40. package/package.json +60 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 benlns
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,124 @@
1
+ # homebridge-selve-home-server-2
2
+
3
+ Homebridge plugin for controlling shutters and similar Selve devices through the **Selve Home Server 2**.
4
+
5
+ It connects to the local Selve API and exposes configured devices to Apple Home through Homebridge.
6
+
7
+ ## Features
8
+
9
+ - control Selve shutters from Apple Home
10
+ - current position and movement state updates
11
+ - optional buttons for intermediate position 1 and 2
12
+ - support for multiple configured shutters
13
+ - compatible with Homebridge 2
14
+
15
+ ## Requirements
16
+
17
+ - Homebridge `^2.0.1`
18
+ - Node.js `22.x` or `24.x`
19
+ - a reachable **Selve Home Server 2** in your local network
20
+ - device IDs (`sid`) for the shutters you want to expose
21
+
22
+ ## Installation
23
+
24
+ Install from npm:
25
+
26
+ ```bash
27
+ npm install -g homebridge-selve-home-server-2
28
+ ```
29
+
30
+ ## Configuration
31
+
32
+ Add the platform to your Homebridge config:
33
+
34
+ ```json
35
+ {
36
+ "platform": "SelveHomeServer2",
37
+ "name": "Selve Home Server 2",
38
+ "url": "http://192.168.2.1",
39
+ "password": "your-password",
40
+ "pollInterval": 15,
41
+ "shutters": [
42
+ {
43
+ "name": "Living Room",
44
+ "device": 1,
45
+ "showIntermediate1": true,
46
+ "showIntermediate2": true
47
+ }
48
+ ]
49
+ }
50
+ ```
51
+
52
+ ## Configuration Options
53
+
54
+ ### Platform
55
+
56
+ - `platform`: must be `SelveHomeServer2`
57
+ - `name`: display name of the platform in Homebridge
58
+ - `url`: local URL or IP address of the Selve Home Server 2
59
+ - `password`: optional password of the Selve Home Server 2
60
+ - `pollInterval`: optional refresh interval in seconds, minimum `5`, default `15`
61
+
62
+ ### Shutters
63
+
64
+ - `name`: display name in Apple Home
65
+ - `device`: Selve device number (`sid`) from the Home Server
66
+ - `showIntermediate1`: optional switch for intermediate position 1
67
+ - `showIntermediate2`: optional switch for intermediate position 2
68
+
69
+ ## Finding the Device Number
70
+
71
+ The plugin uses the Selve device number (`sid`) for each shutter.
72
+
73
+ If you are working with the Selve API directly, the official Postman collection may help:
74
+
75
+ [Selve Home Server 2 Postman Collection](https://www.selve.de/media/03/32/2d/1627308855/Selve_Home_Server_2.postman_collection.json.zip)
76
+
77
+ ## Notes
78
+
79
+ - the plugin communicates with the local Selve endpoint `/cmd`
80
+ - state handling is aligned with the Selve Home Server 2 API documentation
81
+ - intermediate position commands use `movetoP1` and `movetoP2`
82
+
83
+ ## Raspberry Pi Zero 2
84
+
85
+ If you run Homebridge on a Raspberry Pi Zero 2, this repository also includes helper scripts for creating a customized Homebridge image with the plugin preinstalled on first boot.
86
+
87
+ Relevant files:
88
+
89
+ - [build-custom-pi-image.sh](/Users/ben/Documents/GitHub/homebridge-selve-home-server-2/scripts/build-custom-pi-image.sh)
90
+ - [build-pi-zero2-bundle.sh](/Users/ben/Documents/GitHub/homebridge-selve-home-server-2/scripts/build-pi-zero2-bundle.sh)
91
+
92
+ Short workflow:
93
+
94
+ 1. Download an official Homebridge Raspberry Pi image.
95
+ 2. Run:
96
+
97
+ ```bash
98
+ sudo ./scripts/build-custom-pi-image.sh /path/to/homebridge-image.img.xz /path/to/homebridge-selve-zero2.img
99
+ ```
100
+
101
+ 3. Flash the generated image to the SD card.
102
+ 4. Boot the Raspberry Pi with network access.
103
+
104
+ ## Troubleshooting
105
+
106
+ - verify that the Selve Home Server 2 is reachable from the Homebridge machine
107
+ - verify that the configured `device` numbers match the Selve `sid` values
108
+ - if states update too slowly, reduce `pollInterval`
109
+ - if the server is password protected, make sure `password` is set correctly
110
+
111
+ ## Compatibility
112
+
113
+ Tested target:
114
+
115
+ - Homebridge `2.0.2`
116
+
117
+ Supported runtime:
118
+
119
+ - Node.js `22.x`
120
+ - Node.js `24.x`
121
+
122
+ ## License
123
+
124
+ [MIT](LICENSE)
@@ -0,0 +1,79 @@
1
+ {
2
+ "pluginAlias": "SelveHomeServer2",
3
+ "pluginType": "platform",
4
+ "singular": false,
5
+ "headerDisplay": "",
6
+ "schema": {
7
+ "type": "object",
8
+ "properties": {
9
+ "name": {
10
+ "title": "Platform Name",
11
+ "type": "string",
12
+ "default": "Selve Home Server 2",
13
+ "required": true
14
+ },
15
+ "url": {
16
+ "title": "Home Server URL",
17
+ "description": "Address of your home server in your local network, example: http://192.168.2.1.",
18
+ "type": "string",
19
+ "required": false
20
+ },
21
+ "password": {
22
+ "title": "Home Server Password",
23
+ "description": "Password for the Home Server.",
24
+ "type": "string",
25
+ "required": false,
26
+ "format": "password",
27
+ "x-display": "password"
28
+ },
29
+ "pollInterval": {
30
+ "title": "Polling Interval (seconds)",
31
+ "description": "How often device states should be refreshed from the Home Server. Minimum 5 seconds.",
32
+ "type": "integer",
33
+ "required": false,
34
+ "default": 15,
35
+ "minimum": 5
36
+ },
37
+ "shutters": {
38
+ "type": "array",
39
+ "items": {
40
+ "title": "Shutter Config",
41
+ "type": "object",
42
+ "properties": {
43
+ "name": {
44
+ "title": "Name",
45
+ "description": "Name of the shutter or room (e.g. Livingroom)",
46
+ "type": "string",
47
+ "required": true
48
+ },
49
+ "device": {
50
+ "title": "Number",
51
+ "description": "Device number set during pairing",
52
+ "type": "integer",
53
+ "required": true,
54
+ "default": 0,
55
+ "minimum": 0,
56
+ "maximum": 63
57
+ },
58
+ "showIntermediate1": {
59
+ "title": "Show position 1 button",
60
+ "description": "Show a toggle button to allow moving to intermediate position 1",
61
+ "type": "boolean",
62
+ "required": false,
63
+ "default": false
64
+ },
65
+ "showIntermediate2": {
66
+ "title": "Show position 2 button",
67
+ "description": "Show a toggle button to allow moving to intermediate position 2",
68
+ "type": "boolean",
69
+ "required": false,
70
+ "default": false
71
+ }
72
+ }
73
+ }
74
+ }
75
+ }
76
+ },
77
+ "form": null,
78
+ "display": null
79
+ }
@@ -0,0 +1,10 @@
1
+ import { AccessoryConfig } from "homebridge";
2
+ export interface SelveAcessoryConfig extends AccessoryConfig {
3
+ name: string;
4
+ device: number;
5
+ showIntermediate1?: boolean;
6
+ showIntermediate2?: boolean;
7
+ button_pos_1?: boolean;
8
+ button_pos_2?: boolean;
9
+ }
10
+ //# sourceMappingURL=selve-accessory-config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"selve-accessory-config.d.ts","sourceRoot":"","sources":["../../src/configs/selve-accessory-config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAE7C,MAAM,WAAW,mBAAoB,SAAQ,eAAe;IAC1D,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB"}
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=selve-accessory-config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"selve-accessory-config.js","sourceRoot":"","sources":["../../src/configs/selve-accessory-config.ts"],"names":[],"mappings":""}
@@ -0,0 +1,10 @@
1
+ import { PlatformConfig } from "homebridge";
2
+ import { SelveAcessoryConfig } from "./selve-accessory-config";
3
+ export interface SelvePlatformConfig extends PlatformConfig {
4
+ name?: string;
5
+ url?: string;
6
+ password?: string;
7
+ pollInterval?: number;
8
+ shutters?: Array<SelveAcessoryConfig>;
9
+ }
10
+ //# sourceMappingURL=selve-platform-config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"selve-platform-config.d.ts","sourceRoot":"","sources":["../../src/configs/selve-platform-config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAE/D,MAAM,WAAW,mBAAoB,SAAQ,cAAc;IACzD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,KAAK,CAAC,mBAAmB,CAAC,CAAC;CACvC"}
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=selve-platform-config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"selve-platform-config.js","sourceRoot":"","sources":["../../src/configs/selve-platform-config.ts"],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
1
+ export declare function buildApiUrl(url: string, password: string | undefined): string;
2
+ //# sourceMappingURL=helpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../src/helpers.ts"],"names":[],"mappings":"AAAA,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAI7E"}
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.buildApiUrl = buildApiUrl;
4
+ function buildApiUrl(url, password) {
5
+ url = url.replace(/^https?:\/\//i, '');
6
+ url = url.replace(/\/+$/, '');
7
+ return `http://${url}/cmd${password ? `?auth=${password}` : ''}`;
8
+ }
9
+ //# sourceMappingURL=helpers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"helpers.js","sourceRoot":"","sources":["../src/helpers.ts"],"names":[],"mappings":";;AAAA,kCAIC;AAJD,SAAgB,WAAW,CAAC,GAAW,EAAE,QAA4B;IACnE,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,eAAe,EAAE,EAAE,CAAC,CAAC;IACvC,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAC9B,OAAO,UAAU,GAAG,OAAO,QAAQ,CAAC,CAAC,CAAC,SAAS,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;AACnE,CAAC"}
@@ -0,0 +1,7 @@
1
+ import type { API } from 'homebridge';
2
+ /**
3
+ * This method registers the platform with Homebridge
4
+ */
5
+ declare const _default: (api: API) => void;
6
+ export default _default;
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,YAAY,CAAC;AAKtC;;GAEG;yBACa,KAAK,GAAG;AAAxB,wBAEE"}
package/dist/index.js ADDED
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const platform_js_1 = require("./platform.js");
4
+ const settings_js_1 = require("./settings.js");
5
+ /**
6
+ * This method registers the platform with Homebridge
7
+ */
8
+ exports.default = (api) => {
9
+ api.registerPlatform(settings_js_1.PLATFORM_NAME, platform_js_1.Platform);
10
+ };
11
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;AAEA,+CAAyC;AACzC,+CAA8C;AAE9C;;GAEG;AACH,kBAAe,CAAC,GAAQ,EAAE,EAAE;IAC1B,GAAG,CAAC,gBAAgB,CAAC,2BAAa,EAAE,sBAAQ,CAAC,CAAC;AAChD,CAAC,CAAC"}
@@ -0,0 +1,12 @@
1
+ import { AccessoryPlugin, API, Logging, StaticPlatformPlugin } from 'homebridge';
2
+ import { SelvePlatformConfig } from './configs/selve-platform-config';
3
+ export declare class Platform implements StaticPlatformPlugin {
4
+ private static readonly DEFAULT_POLL_INTERVAL_SECONDS;
5
+ private readonly log;
6
+ private readonly service;
7
+ private readonly shutters;
8
+ private readonly hap;
9
+ constructor(log: Logging, config: SelvePlatformConfig, api: API);
10
+ accessories(callback: (foundAccessories: AccessoryPlugin[]) => void): void;
11
+ }
12
+ //# sourceMappingURL=platform.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"platform.d.ts","sourceRoot":"","sources":["../src/platform.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,eAAe,EACf,GAAG,EAEH,OAAO,EACP,oBAAoB,EACrB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AAItE,qBAAa,QAAS,YAAW,oBAAoB;IACnD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,6BAA6B,CAAM;IAC3D,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAU;IAC9B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAa;IACrC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAsB;IAC/C,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAM;gBAEd,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,mBAAmB,EAAE,GAAG,EAAE,GAAG;IA+B/D,WAAW,CAAC,QAAQ,EAAE,CAAC,gBAAgB,EAAE,eAAe,EAAE,KAAK,IAAI,GAAG,IAAI;CAG3E"}
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Platform = void 0;
4
+ const selve_shutter_accessory_1 = require("./selve-shutter-accessory");
5
+ const home_server_2_service_1 = require("./services/home-server-2.service");
6
+ class Platform {
7
+ static DEFAULT_POLL_INTERVAL_SECONDS = 15;
8
+ log;
9
+ service;
10
+ shutters;
11
+ hap;
12
+ constructor(log, config, api) {
13
+ this.log = log;
14
+ this.hap = api.hap;
15
+ if (config.url) {
16
+ this.service = new home_server_2_service_1.HS2Service(log, config.url, config.password);
17
+ }
18
+ else {
19
+ throw Error('\'url\' is not defined in the configuration. Please provide a valid URL.');
20
+ }
21
+ const shutterConfigs = config.shutters || [];
22
+ const pollIntervalSeconds = Math.max(5, Number(config.pollInterval) || Platform.DEFAULT_POLL_INTERVAL_SECONDS);
23
+ if (shutterConfigs.length === 0) {
24
+ this.log.warn('No shutter configs defined!');
25
+ }
26
+ this.shutters = shutterConfigs.reduce((acc, shutterConfig) => {
27
+ if (!shutterConfig.name) {
28
+ this.log.error('Shutter name not set!');
29
+ return acc;
30
+ }
31
+ else if (typeof shutterConfig.device !== 'number') {
32
+ this.log.error('Shutter device undefined or not a number!');
33
+ return acc;
34
+ }
35
+ acc.push(new selve_shutter_accessory_1.SelveShutter(this.hap, this.log, shutterConfig, this.service, pollIntervalSeconds * 1000));
36
+ return acc;
37
+ }, []);
38
+ this.log.debug(`Initialized ${this.shutters.length} shutter(s).`);
39
+ }
40
+ accessories(callback) {
41
+ callback(this.shutters);
42
+ }
43
+ }
44
+ exports.Platform = Platform;
45
+ //# sourceMappingURL=platform.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"platform.js","sourceRoot":"","sources":["../src/platform.ts"],"names":[],"mappings":";;;AAQA,uEAAyD;AACzD,4EAA8D;AAE9D,MAAa,QAAQ;IACX,MAAM,CAAU,6BAA6B,GAAG,EAAE,CAAC;IAC1C,GAAG,CAAU;IACb,OAAO,CAAa;IACpB,QAAQ,CAAsB;IAC9B,GAAG,CAAM;IAE1B,YAAY,GAAY,EAAE,MAA2B,EAAE,GAAQ;QAC7D,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;QACf,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC;QAEnB,IAAI,MAAM,CAAC,GAAG,EAAE,CAAC;YACf,IAAI,CAAC,OAAO,GAAG,IAAI,kCAAU,CAAC,GAAG,EAAE,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;QAClE,CAAC;aAAM,CAAC;YACN,MAAM,KAAK,CAAC,0EAA0E,CAAC,CAAC;QAC1F,CAAC;QAED,MAAM,cAAc,GAAG,MAAM,CAAC,QAAQ,IAAI,EAAE,CAAC;QAC7C,MAAM,mBAAmB,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,IAAI,QAAQ,CAAC,6BAA6B,CAAC,CAAC;QAC/G,IAAI,cAAc,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAChC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,6BAA6B,CAAC,CAAC;QAC/C,CAAC;QAED,IAAI,CAAC,QAAQ,GAAG,cAAc,CAAC,MAAM,CAAsB,CAAC,GAAmB,EAAE,aAAa,EAAE,EAAE;YAChG,IAAI,CAAC,aAAa,CAAC,IAAI,EAAE,CAAC;gBAC1B,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAC;gBACxC,OAAO,GAAG,CAAC;YACX,CAAC;iBAAM,IAAI,OAAO,aAAa,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;gBACtD,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,2CAA2C,CAAC,CAAC;gBAC5D,OAAO,GAAG,CAAC;YACX,CAAC;YACD,GAAG,CAAC,IAAI,CAAC,IAAI,sCAAY,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,aAAa,EAAE,IAAI,CAAC,OAAO,EAAE,mBAAmB,GAAG,IAAI,CAAC,CAAC,CAAC;YACxG,OAAO,GAAG,CAAC;QACb,CAAC,EAAE,EAAE,CAAC,CAAC;QAEP,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,eAAe,IAAI,CAAC,QAAQ,CAAC,MAAM,cAAc,CAAC,CAAC;IACpE,CAAC;IAED,WAAW,CAAC,QAAuD;QACjE,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC1B,CAAC;;AAxCH,4BAyCC"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Selve Shutter Accessory Plugin for Homebridge
3
+ * This plugin allows control of Selve shutters via Homebridge using the Home Server 2 API
4
+ * Adapted code from http://github.com/tfohlmeister/homebridge-selve
5
+ */
6
+ import { AccessoryPlugin, HAP, Logging, Service } from "homebridge";
7
+ import { SelveAcessoryConfig } from "./configs/selve-accessory-config";
8
+ import { HS2Service } from "./services/home-server-2.service";
9
+ export declare class SelveShutter implements AccessoryPlugin {
10
+ private readonly log;
11
+ name: string;
12
+ private readonly service;
13
+ private readonly informationService;
14
+ private readonly shutterService;
15
+ private readonly intermediate1SwitchService;
16
+ private readonly intermediate2SwitchService;
17
+ private readonly device;
18
+ private state;
19
+ private services;
20
+ private targetPosition;
21
+ private readonly pollIntervalMs;
22
+ constructor(hap: HAP, log: Logging, config: SelveAcessoryConfig, service: HS2Service, pollIntervalMs: number);
23
+ getServices(): Array<Service>;
24
+ private scheduleRefresh;
25
+ }
26
+ //# sourceMappingURL=selve-shutter-accessory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"selve-shutter-accessory.d.ts","sourceRoot":"","sources":["../src/selve-shutter-accessory.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EACL,eAAe,EAKf,GAAG,EACH,OAAO,EACP,OAAO,EACR,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AACvE,OAAO,EAAE,UAAU,EAAE,MAAM,kCAAkC,CAAC;AAE9D,qBAAa,YAAa,YAAW,eAAe;IAClD,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAU;IAC9B,IAAI,EAAE,MAAM,CAAC;IAEb,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAa;IACrC,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAU;IAC7C,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAU;IACzC,OAAO,CAAC,QAAQ,CAAC,0BAA0B,CAAU;IACrD,OAAO,CAAC,QAAQ,CAAC,0BAA0B,CAAU;IACrD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,KAAK,CAAc;IAC3B,OAAO,CAAC,QAAQ,CAAiB;IACjC,OAAO,CAAC,cAAc,CAAO;IAC7B,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;gBAE5B,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,mBAAmB,EAAE,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM;IAuJrG,WAAW,IAAI,KAAK,CAAC,OAAO,CAAC;IAIpC,OAAO,CAAC,eAAe;CAOxB"}
@@ -0,0 +1,164 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SelveShutter = void 0;
4
+ const selve_states_1 = require("./states/selve-states");
5
+ class SelveShutter {
6
+ log;
7
+ name;
8
+ service;
9
+ informationService;
10
+ shutterService;
11
+ intermediate1SwitchService;
12
+ intermediate2SwitchService;
13
+ device;
14
+ state;
15
+ services;
16
+ targetPosition = 100;
17
+ pollIntervalMs;
18
+ constructor(hap, log, config, service, pollIntervalMs) {
19
+ this.log = log;
20
+ this.name = config.name;
21
+ this.device = config.device;
22
+ this.service = service;
23
+ this.pollIntervalMs = pollIntervalMs;
24
+ this.state = new selve_states_1.CommeoState();
25
+ // initialize services
26
+ this.shutterService = new hap.Service.WindowCovering(this.name);
27
+ this.informationService = new hap.Service.AccessoryInformation();
28
+ this.intermediate1SwitchService = new hap.Service.Switch(`${this.name} Position 1`, "1");
29
+ this.intermediate2SwitchService = new hap.Service.Switch(`${this.name} Position 2`, "2");
30
+ // setup shutter services
31
+ this.shutterService
32
+ .getCharacteristic(hap.Characteristic.CurrentPosition)
33
+ .on("get" /* CharacteristicEventTypes.GET */, (cb) => cb(null, this.state.CurrentPosition));
34
+ this.shutterService
35
+ .getCharacteristic(hap.Characteristic.TargetPosition)
36
+ .on("get" /* CharacteristicEventTypes.GET */, (cb) => cb(null, this.targetPosition))
37
+ .on("set" /* CharacteristicEventTypes.SET */, (newPosition, cb) => {
38
+ this.log.debug(`[${this.name}] Set new target position to ${newPosition}`);
39
+ this.targetPosition = Number(newPosition);
40
+ this.service.sendMovePosition(this.device, this.targetPosition, (error) => {
41
+ if (!error) {
42
+ this.scheduleRefresh();
43
+ }
44
+ cb(error);
45
+ });
46
+ });
47
+ this.shutterService
48
+ .getCharacteristic(hap.Characteristic.PositionState)
49
+ .on("get" /* CharacteristicEventTypes.GET */, (cb) => cb(null, this.state.PositionState));
50
+ this.shutterService
51
+ .getCharacteristic(hap.Characteristic.ObstructionDetected)
52
+ .on("get" /* CharacteristicEventTypes.GET */, (cb) => cb(null, this.state.ObstructionDetected));
53
+ // setup optional intermediate button services
54
+ this.intermediate1SwitchService
55
+ .getCharacteristic(hap.Characteristic.On)
56
+ .on("set" /* CharacteristicEventTypes.SET */, (value, cb) => {
57
+ if (!value) {
58
+ return cb();
59
+ }
60
+ this.log.debug(`[${this.name}] Set to move to intermediate position 1`);
61
+ this.service.sendMoveIntermediatePosition(this.device, 1, (error) => {
62
+ if (!error) {
63
+ this.scheduleRefresh();
64
+ }
65
+ cb(error);
66
+ });
67
+ // toggle off button after some cooldown
68
+ setTimeout(() => {
69
+ this.intermediate1SwitchService.getCharacteristic(hap.Characteristic.On).updateValue(false);
70
+ }, 500);
71
+ });
72
+ this.intermediate2SwitchService
73
+ .getCharacteristic(hap.Characteristic.On)
74
+ .on("set" /* CharacteristicEventTypes.SET */, (value, cb) => {
75
+ if (!value) {
76
+ return cb();
77
+ }
78
+ this.log.debug(`[${this.name}] Set to move to intermediate position 2`);
79
+ this.service.sendMoveIntermediatePosition(this.device, 2, (error) => {
80
+ if (!error) {
81
+ this.scheduleRefresh();
82
+ }
83
+ cb(error);
84
+ });
85
+ // toggle off button after some cooldown
86
+ setTimeout(() => {
87
+ this.intermediate2SwitchService.getCharacteristic(hap.Characteristic.On).updateValue(false);
88
+ }, 500);
89
+ });
90
+ // setup info service
91
+ this.informationService = new hap.Service.AccessoryInformation()
92
+ .setCharacteristic(hap.Characteristic.Manufacturer, "Selve")
93
+ .setCharacteristic(hap.Characteristic.Model, "Selve")
94
+ .setCharacteristic(hap.Characteristic.SerialNumber, this.name)
95
+ .setCharacteristic(hap.Characteristic.Identifier, this.device.toString());
96
+ // handle status updates
97
+ this.service.eventEmitter.on(String(this.device), (newState) => {
98
+ this.log.debug(`[${this.name}] New state`, newState);
99
+ this.state = newState;
100
+ this.shutterService.getCharacteristic(hap.Characteristic.PositionState).updateValue(this.state.PositionState);
101
+ this.shutterService
102
+ .getCharacteristic(hap.Characteristic.ObstructionDetected)
103
+ .updateValue(this.state.ObstructionDetected);
104
+ const wasMovedFromExternal = // whether the device was operated from an external source (e.g. switch, other remote)
105
+ (this.state.PositionState === selve_states_1.HomebridgeStatusState.INCREASING &&
106
+ this.targetPosition <= this.state.CurrentPosition) ||
107
+ (this.state.PositionState === selve_states_1.HomebridgeStatusState.DECREASING &&
108
+ this.targetPosition >= this.state.CurrentPosition);
109
+ if (wasMovedFromExternal) {
110
+ // little hack to correctly show "opening" and "closing" status in Home app
111
+ if (this.state.PositionState === selve_states_1.HomebridgeStatusState.INCREASING) {
112
+ this.shutterService
113
+ .getCharacteristic(hap.Characteristic.CurrentPosition)
114
+ .updateValue(Math.max(0, this.state.CurrentPosition - 1));
115
+ }
116
+ else {
117
+ this.shutterService
118
+ .getCharacteristic(hap.Characteristic.CurrentPosition)
119
+ .updateValue(Math.min(100, this.state.CurrentPosition + 1));
120
+ }
121
+ this.shutterService
122
+ .getCharacteristic(hap.Characteristic.TargetPosition)
123
+ .updateValue(this.state.CurrentPosition);
124
+ }
125
+ else {
126
+ this.shutterService
127
+ .getCharacteristic(hap.Characteristic.CurrentPosition)
128
+ .updateValue(this.state.CurrentPosition);
129
+ }
130
+ if (this.state.PositionState === selve_states_1.HomebridgeStatusState.STOPPED) {
131
+ this.targetPosition = this.state.CurrentPosition;
132
+ this.shutterService
133
+ .getCharacteristic(hap.Characteristic.TargetPosition)
134
+ .updateValue(this.state.CurrentPosition);
135
+ }
136
+ });
137
+ // request current position on startup
138
+ setTimeout(() => {
139
+ this.service.requestUpdate(this.device, (error) => !!error && log.error(error.message));
140
+ }, 500);
141
+ setInterval(() => {
142
+ this.service.requestUpdate(this.device, (error) => !!error && log.error(error.message));
143
+ }, this.pollIntervalMs);
144
+ this.services = [
145
+ this.informationService,
146
+ this.shutterService,
147
+ (config.showIntermediate1 ?? config.button_pos_1) ? this.intermediate1SwitchService : null,
148
+ (config.showIntermediate2 ?? config.button_pos_2) ? this.intermediate2SwitchService : null,
149
+ ].filter((s) => !!s);
150
+ log.debug(`Selve shutter ${this.name} created.`);
151
+ }
152
+ getServices() {
153
+ return this.services;
154
+ }
155
+ scheduleRefresh() {
156
+ for (const delay of [1000, 4000, 8000]) {
157
+ setTimeout(() => {
158
+ this.service.requestUpdate(this.device, (error) => !!error && this.log.error(error.message));
159
+ }, delay);
160
+ }
161
+ }
162
+ }
163
+ exports.SelveShutter = SelveShutter;
164
+ //# sourceMappingURL=selve-shutter-accessory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"selve-shutter-accessory.js","sourceRoot":"","sources":["../src/selve-shutter-accessory.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ import { EventEmitter } from "events";
2
+ import { Logging } from "homebridge";
3
+ export type ServiceCallback = (error?: Error | undefined, value?: string | boolean | number | undefined) => void;
4
+ /**
5
+ * HS2Service is responsible for communicating with the Selve Home Server 2 API.
6
+ * It provides methods to send commands and request updates for shutters.
7
+ */
8
+ export declare class HS2Service {
9
+ private apiUrl;
10
+ private log;
11
+ eventEmitter: EventEmitter<any>;
12
+ constructor(log: Logging, url: string, password?: string);
13
+ private convertPosition;
14
+ private sendPostRequest;
15
+ private sendGetRequest;
16
+ private mapRunState;
17
+ private parseNumber;
18
+ sendMovePosition(device: number, targetPos: number, cb?: ServiceCallback): Promise<void>;
19
+ sendStop(device: number, cb?: ServiceCallback): Promise<void>;
20
+ sendMoveIntermediatePosition(device: number, pos: 1 | 2, cb?: ServiceCallback): Promise<void>;
21
+ requestUpdate(device: number, cb?: ServiceCallback): Promise<void>;
22
+ }
23
+ //# sourceMappingURL=home-server-2.service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"home-server-2.service.d.ts","sourceRoot":"","sources":["../../src/services/home-server-2.service.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AASrC,MAAM,MAAM,eAAe,GAAG,CAAC,KAAK,CAAC,EAAE,KAAK,GAAG,SAAS,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,SAAS,KAAK,IAAI,CAAC;AAEjH;;;GAGG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,GAAG,CAAU;IACd,YAAY,oBAAsB;gBAE7B,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM;IAKxD,OAAO,CAAC,eAAe;IAIvB,OAAO,CAAC,eAAe;IAevB,OAAO,CAAC,cAAc;IAoBtB,OAAO,CAAC,WAAW;IAWnB,OAAO,CAAC,WAAW;IAWN,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IAqBxF,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IAkB7D,4BAA4B,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IAoB7F,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC;CAiChF"}
@@ -0,0 +1,169 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.HS2Service = void 0;
7
+ const axios_1 = __importDefault(require("axios"));
8
+ const events_1 = require("events");
9
+ const selve_states_1 = require("../states/selve-states");
10
+ const helpers_1 = require("../helpers");
11
+ /**
12
+ * HS2Service is responsible for communicating with the Selve Home Server 2 API.
13
+ * It provides methods to send commands and request updates for shutters.
14
+ */
15
+ class HS2Service {
16
+ apiUrl;
17
+ log;
18
+ eventEmitter = new events_1.EventEmitter();
19
+ constructor(log, url, password) {
20
+ this.log = log;
21
+ this.apiUrl = (0, helpers_1.buildApiUrl)(url, password);
22
+ }
23
+ convertPosition(pos) {
24
+ return 100 - pos; // HomeKit uses 0 as fully open, Selve uses 100 as fully open
25
+ }
26
+ sendPostRequest(device, data) {
27
+ return axios_1.default.post(this.apiUrl, {
28
+ XC_FNC: "SendGenericCmd",
29
+ id: device < 10 ? `0${device}` : String(device),
30
+ data: data
31
+ })
32
+ .then((response) => {
33
+ this.log.debug(`Successfully sent post request.`, JSON.stringify(response.data, null, 2));
34
+ })
35
+ .catch((error) => {
36
+ this.log.error(`Error sending post request:`, error);
37
+ throw error instanceof Error ? error : new Error(String(error));
38
+ });
39
+ }
40
+ sendGetRequest(fnc, type, adr) {
41
+ return axios_1.default.get(this.apiUrl, { params: {
42
+ XC_FNC: fnc,
43
+ type: type || undefined,
44
+ adr: adr || undefined
45
+ } })
46
+ .then((response) => {
47
+ this.log.debug(`Successfully sent get request.`, JSON.stringify(response.data, null, 2));
48
+ if (response.data?.XC_ERR) {
49
+ const message = response.data.XC_ERR.message || `API error ${response.data.XC_ERR.code ?? "unknown"}`;
50
+ throw new Error(message);
51
+ }
52
+ return response.data?.XC_SUC;
53
+ })
54
+ .catch((error) => {
55
+ this.log.error(`Error sending get request:`, error);
56
+ throw error instanceof Error ? error : new Error(String(error));
57
+ });
58
+ }
59
+ mapRunState(runState) {
60
+ switch (runState) {
61
+ case selve_states_1.DeviceRunState.UP:
62
+ return selve_states_1.HomebridgeStatusState.INCREASING;
63
+ case selve_states_1.DeviceRunState.DOWN:
64
+ return selve_states_1.HomebridgeStatusState.DECREASING;
65
+ default:
66
+ return selve_states_1.HomebridgeStatusState.STOPPED;
67
+ }
68
+ }
69
+ parseNumber(value, fallback = 0) {
70
+ if (typeof value === "number") {
71
+ return value;
72
+ }
73
+ if (typeof value === "string" && value.length > 0) {
74
+ const parsed = Number(value);
75
+ return Number.isFinite(parsed) ? parsed : fallback;
76
+ }
77
+ return fallback;
78
+ }
79
+ async sendMovePosition(device, targetPos, cb) {
80
+ try {
81
+ await this.sendPostRequest(device, {
82
+ cmd: "moveTo",
83
+ value: this.convertPosition(targetPos)
84
+ });
85
+ await this.requestUpdate(device);
86
+ if (cb) {
87
+ cb();
88
+ return;
89
+ }
90
+ }
91
+ catch (error) {
92
+ this.log.error("Error while moving:", error);
93
+ if (cb) {
94
+ cb(error instanceof Error ? error : new Error(String(error)));
95
+ return;
96
+ }
97
+ throw error;
98
+ }
99
+ }
100
+ async sendStop(device, cb) {
101
+ try {
102
+ await this.sendPostRequest(device, { cmd: "stop" });
103
+ await this.requestUpdate(device);
104
+ if (cb) {
105
+ cb();
106
+ return;
107
+ }
108
+ }
109
+ catch (error) {
110
+ this.log.error("Error while stopping:", error);
111
+ if (cb) {
112
+ cb(error instanceof Error ? error : new Error(String(error)));
113
+ return;
114
+ }
115
+ throw error;
116
+ }
117
+ }
118
+ async sendMoveIntermediatePosition(device, pos, cb) {
119
+ try {
120
+ await this.sendPostRequest(device, {
121
+ cmd: pos === 1 ? "movetoP1" : "movetoP2",
122
+ });
123
+ await this.requestUpdate(device);
124
+ if (cb) {
125
+ cb();
126
+ return;
127
+ }
128
+ }
129
+ catch (error) {
130
+ this.log.error("Error while moving to intermediate position:", error);
131
+ if (cb) {
132
+ cb(error instanceof Error ? error : new Error(String(error)));
133
+ return;
134
+ }
135
+ throw error;
136
+ }
137
+ }
138
+ async requestUpdate(device, cb) {
139
+ try {
140
+ const commeoStates = await this.sendGetRequest("GetStates") ?? [];
141
+ const deviceState = commeoStates.find((state) => "sid" in state && Number(state.sid) === device);
142
+ if (deviceState && "sid" in deviceState) {
143
+ const runtimeState = deviceState.states ?? deviceState.state;
144
+ const PositionState = this.mapRunState(this.parseNumber(runtimeState?.run_state, selve_states_1.DeviceRunState.STOP));
145
+ const CurrentPosition = this.convertPosition(this.parseNumber(runtimeState?.position, 0));
146
+ const ObstructionDetected = (parseInt(runtimeState?.flags ?? "0000", 16) & 0b00000100) !== 0;
147
+ this.eventEmitter.emit(String(device), {
148
+ CurrentPosition,
149
+ PositionState,
150
+ ObstructionDetected,
151
+ });
152
+ }
153
+ if (cb) {
154
+ cb();
155
+ return;
156
+ }
157
+ }
158
+ catch (error) {
159
+ this.log.error("Error while requesting status:", error);
160
+ if (cb) {
161
+ cb(error instanceof Error ? error : new Error(String(error)));
162
+ return;
163
+ }
164
+ throw error;
165
+ }
166
+ }
167
+ }
168
+ exports.HS2Service = HS2Service;
169
+ //# sourceMappingURL=home-server-2.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"home-server-2.service.js","sourceRoot":"","sources":["../../src/services/home-server-2.service.ts"],"names":[],"mappings":"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"}
@@ -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 declare const PLATFORM_NAME = "SelveHomeServer2";
5
+ /**
6
+ * This must match the name of your plugin as defined the package.json `name` property
7
+ */
8
+ export declare const PLUGIN_NAME = "homebridge-selve-home-server-2";
9
+ //# sourceMappingURL=settings.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"settings.d.ts","sourceRoot":"","sources":["../src/settings.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,eAAO,MAAM,aAAa,qBAAqB,CAAC;AAEhD;;GAEG;AACH,eAAO,MAAM,WAAW,mCAAmC,CAAC"}
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PLUGIN_NAME = exports.PLATFORM_NAME = void 0;
4
+ /**
5
+ * This is the name of the platform that users will use to register the plugin in the Homebridge config.json
6
+ */
7
+ exports.PLATFORM_NAME = 'SelveHomeServer2';
8
+ /**
9
+ * This must match the name of your plugin as defined the package.json `name` property
10
+ */
11
+ exports.PLUGIN_NAME = 'homebridge-selve-home-server-2';
12
+ //# sourceMappingURL=settings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"settings.js","sourceRoot":"","sources":["../src/settings.ts"],"names":[],"mappings":";;;AAAA;;GAEG;AACU,QAAA,aAAa,GAAG,kBAAkB,CAAC;AAEhD;;GAEG;AACU,QAAA,WAAW,GAAG,gCAAgC,CAAC"}
@@ -0,0 +1,56 @@
1
+ export declare class CommeoState {
2
+ CurrentPosition: number;
3
+ PositionState: HomebridgeStatusState;
4
+ ObstructionDetected: boolean;
5
+ constructor();
6
+ }
7
+ export declare enum DeviceRunState {
8
+ STOP = 0,
9
+ UP = 1,
10
+ DOWN = 2
11
+ }
12
+ export declare enum DeviceStatus {
13
+ ON = 0,
14
+ OFF = 1
15
+ }
16
+ export declare enum TimeoutState {
17
+ NO_TIMEOUT = 0,
18
+ TIMEOUT = 1
19
+ }
20
+ export type DeviceState = {
21
+ position?: number | string;
22
+ run_state?: DeviceRunState | `${DeviceRunState}`;
23
+ current?: number | string;
24
+ target?: number | string;
25
+ flags: string;
26
+ timeout?: TimeoutState | `${TimeoutState}`;
27
+ };
28
+ export type CommeoAPIDeviceState = {
29
+ type: "EVENT";
30
+ adr: string;
31
+ state: string;
32
+ } | {
33
+ type: "CM" | "EV";
34
+ sid: string;
35
+ adr: string;
36
+ cid: string;
37
+ deviceType: string;
38
+ eType: string;
39
+ state?: DeviceState;
40
+ states?: DeviceState;
41
+ };
42
+ export type APISuccessResponse = {
43
+ XC_SUC: CommeoAPIDeviceState[];
44
+ };
45
+ export type APIErrorResponse = {
46
+ XC_ERR: {
47
+ code: number;
48
+ message: string;
49
+ };
50
+ };
51
+ export declare enum HomebridgeStatusState {
52
+ DECREASING = 0,
53
+ INCREASING = 1,
54
+ STOPPED = 2
55
+ }
56
+ //# sourceMappingURL=selve-states.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"selve-states.d.ts","sourceRoot":"","sources":["../../src/states/selve-states.ts"],"names":[],"mappings":"AAAA,qBAAa,WAAW;IACtB,eAAe,EAAE,MAAM,CAAC;IACxB,aAAa,EAAE,qBAAqB,CAAC;IACrC,mBAAmB,EAAE,OAAO,CAAC;;CAO9B;AAED,oBAAY,cAAc;IACxB,IAAI,IAAI;IACR,EAAE,IAAI;IACN,IAAI,IAAI;CACT;AAED,oBAAY,YAAY;IACtB,EAAE,IAAI;IACN,GAAG,IAAI;CACR;AAED,oBAAY,YAAY;IACtB,UAAU,IAAI;IACd,OAAO,IAAI;CACZ;AAED,MAAM,MAAM,WAAW,GAAG;IACxB,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC3B,SAAS,CAAC,EAAE,cAAc,GAAG,GAAG,cAAc,EAAE,CAAC;IACjD,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC1B,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,YAAY,GAAG,GAAG,YAAY,EAAE,CAAC;CAC5C,CAAA;AAED,MAAM,MAAM,oBAAoB,GAAK;IACjC,IAAI,EAAE,OAAO,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;CACf,GAAG;IACF,IAAI,EAAE,IAAI,GAAG,IAAI,CAAC;IAClB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,MAAM,CAAC,EAAE,WAAW,CAAC;CACxB,CAAA;AAED,MAAM,MAAM,kBAAkB,GAAG;IAC/B,MAAM,EAAE,oBAAoB,EAAE,CAAC;CAChC,CAAA;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC7B,MAAM,EAAE;QACN,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAA;KAChB,CAAA;CACF,CAAA;AAED,oBAAY,qBAAqB;IAC/B,UAAU,IAAI;IACd,UAAU,IAAI;IACd,OAAO,IAAI;CACZ"}
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.HomebridgeStatusState = exports.TimeoutState = exports.DeviceStatus = exports.DeviceRunState = exports.CommeoState = void 0;
4
+ class CommeoState {
5
+ CurrentPosition;
6
+ PositionState;
7
+ ObstructionDetected;
8
+ constructor() {
9
+ this.CurrentPosition = 100;
10
+ this.PositionState = HomebridgeStatusState.STOPPED;
11
+ this.ObstructionDetected = false;
12
+ }
13
+ }
14
+ exports.CommeoState = CommeoState;
15
+ var DeviceRunState;
16
+ (function (DeviceRunState) {
17
+ DeviceRunState[DeviceRunState["STOP"] = 0] = "STOP";
18
+ DeviceRunState[DeviceRunState["UP"] = 1] = "UP";
19
+ DeviceRunState[DeviceRunState["DOWN"] = 2] = "DOWN";
20
+ })(DeviceRunState || (exports.DeviceRunState = DeviceRunState = {}));
21
+ var DeviceStatus;
22
+ (function (DeviceStatus) {
23
+ DeviceStatus[DeviceStatus["ON"] = 0] = "ON";
24
+ DeviceStatus[DeviceStatus["OFF"] = 1] = "OFF";
25
+ })(DeviceStatus || (exports.DeviceStatus = DeviceStatus = {}));
26
+ var TimeoutState;
27
+ (function (TimeoutState) {
28
+ TimeoutState[TimeoutState["NO_TIMEOUT"] = 0] = "NO_TIMEOUT";
29
+ TimeoutState[TimeoutState["TIMEOUT"] = 1] = "TIMEOUT";
30
+ })(TimeoutState || (exports.TimeoutState = TimeoutState = {}));
31
+ var HomebridgeStatusState;
32
+ (function (HomebridgeStatusState) {
33
+ HomebridgeStatusState[HomebridgeStatusState["DECREASING"] = 0] = "DECREASING";
34
+ HomebridgeStatusState[HomebridgeStatusState["INCREASING"] = 1] = "INCREASING";
35
+ HomebridgeStatusState[HomebridgeStatusState["STOPPED"] = 2] = "STOPPED";
36
+ })(HomebridgeStatusState || (exports.HomebridgeStatusState = HomebridgeStatusState = {}));
37
+ //# sourceMappingURL=selve-states.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"selve-states.js","sourceRoot":"","sources":["../../src/states/selve-states.ts"],"names":[],"mappings":";;;AAAA,MAAa,WAAW;IACtB,eAAe,CAAS;IACxB,aAAa,CAAwB;IACrC,mBAAmB,CAAU;IAE7B;QACE,IAAI,CAAC,eAAe,GAAG,GAAG,CAAC;QAC3B,IAAI,CAAC,aAAa,GAAG,qBAAqB,CAAC,OAAO,CAAC;QACnD,IAAI,CAAC,mBAAmB,GAAG,KAAK,CAAC;IACnC,CAAC;CACF;AAVD,kCAUC;AAED,IAAY,cAIX;AAJD,WAAY,cAAc;IACxB,mDAAQ,CAAA;IACR,+CAAM,CAAA;IACN,mDAAQ,CAAA;AACV,CAAC,EAJW,cAAc,8BAAd,cAAc,QAIzB;AAED,IAAY,YAGX;AAHD,WAAY,YAAY;IACtB,2CAAM,CAAA;IACN,6CAAO,CAAA;AACT,CAAC,EAHW,YAAY,4BAAZ,YAAY,QAGvB;AAED,IAAY,YAGX;AAHD,WAAY,YAAY;IACtB,2DAAc,CAAA;IACd,qDAAW,CAAA;AACb,CAAC,EAHW,YAAY,4BAAZ,YAAY,QAGvB;AAqCD,IAAY,qBAIX;AAJD,WAAY,qBAAqB;IAC/B,6EAAc,CAAA;IACd,6EAAc,CAAA;IACd,uEAAW,CAAA;AACb,CAAC,EAJW,qBAAqB,qCAArB,qBAAqB,QAIhC"}
package/package.json ADDED
@@ -0,0 +1,60 @@
1
+ {
2
+ "name": "homebridge-selve-home-server-2",
3
+ "version": "1.1.2",
4
+ "description": "Selve Home Server 2 Support for Homebridge: https://github.com/homebridge/homebridge",
5
+ "keywords": [
6
+ "homebridge-plugin",
7
+ "selve",
8
+ "home",
9
+ "server",
10
+ "2"
11
+ ],
12
+ "homebridge-plugin": true,
13
+ "homepage": "https://github.com/benlns/homebridge-selve-home-server-2#readme",
14
+ "bugs": {
15
+ "url": "https://github.com/benlns/homebridge-selve-home-server-2/issues"
16
+ },
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "git+https://github.com/benlns/homebridge-selve-home-server-2.git"
20
+ },
21
+ "license": "MIT",
22
+ "author": "benlns",
23
+ "type": "commonjs",
24
+ "main": "dist/index.js",
25
+ "files": [
26
+ "dist",
27
+ "config.schema.json",
28
+ "README.md",
29
+ "LICENSE"
30
+ ],
31
+ "scripts": {
32
+ "build": "rimraf dist && tsc",
33
+ "clean": "rimraf dist",
34
+ "lint": "eslint .",
35
+ "lint:fix": "eslint . --fix",
36
+ "test": "npm run build && node --test test/**/*.test.js",
37
+ "prepack": "npm run clean && npm run build",
38
+ "prepublishOnly": "npm test",
39
+ "pack:check": "npm pack --dry-run --cache ./.tmp/npm-cache",
40
+ "release:check": "npm test && npm run pack:check"
41
+ },
42
+ "dependencies": {
43
+ "axios": "^1.16.1",
44
+ "homebridge-lib": "^8.1.0"
45
+ },
46
+ "devDependencies": {
47
+ "@eslint/js": "^10.0.1",
48
+ "@types/node": "^25.9.1",
49
+ "eslint": "^10.4.1",
50
+ "globals": "^17.6.0",
51
+ "homebridge": "^2.0.2",
52
+ "rimraf": "^6.1.3",
53
+ "typescript": "^6.0.3",
54
+ "typescript-eslint": "^8.60.0"
55
+ },
56
+ "engines": {
57
+ "node": "^22 || ^24",
58
+ "homebridge": "^2.0.1"
59
+ }
60
+ }