homebridge-soundtouchspeaker 0.2.4-beta.2 → 0.2.4
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/.commitlintrc.json +3 -0
- package/.husky/commit-msg +1 -0
- package/.releaserc.json +9 -0
- package/CONTRIBUTING.md +80 -0
- package/README.md +28 -12
- package/__mocks__/homebridge.js +8 -0
- package/config.schema.json +8 -2
- package/dist/PlatformConfiguration.js +16 -12
- package/dist/PlatformConfiguration.js.map +1 -1
- package/dist/accessories/SoundTouchSpeakerPlatformAccessory.js +54 -71
- package/dist/accessories/SoundTouchSpeakerPlatformAccessory.js.map +1 -1
- package/dist/accessories/services/SoundTouchSpeakerCharacteristic.js +4 -0
- package/dist/accessories/services/SoundTouchSpeakerCharacteristic.js.map +1 -1
- package/dist/accessories/services/SoundTouchSpeakerInformationCharacteristic.js +17 -30
- package/dist/accessories/services/SoundTouchSpeakerInformationCharacteristic.js.map +1 -1
- package/dist/accessories/services/SoundTouchSpeakerOnCharacteristic.js +33 -62
- package/dist/accessories/services/SoundTouchSpeakerOnCharacteristic.js.map +1 -1
- package/dist/devices/SoundTouch/SoundTouchDevice.js +81 -89
- package/dist/devices/SoundTouch/SoundTouchDevice.js.map +1 -1
- package/dist/devices/SoundTouch/SoundTouchDeviceConfiguration.js +15 -10
- package/dist/devices/SoundTouch/SoundTouchDeviceConfiguration.js.map +1 -1
- package/dist/devices/SoundTouch/api/api-discovery.js +29 -42
- package/dist/devices/SoundTouch/api/api-discovery.js.map +1 -1
- package/dist/devices/SoundTouch/api/api.js +159 -210
- package/dist/devices/SoundTouch/api/api.js.map +1 -1
- package/dist/devices/SoundTouch/api/error.js +2 -0
- package/dist/devices/SoundTouch/api/error.js.map +1 -1
- package/dist/devices/SoundTouch/api/utils/xml-element.js +1 -0
- package/dist/devices/SoundTouch/api/utils/xml-element.js.map +1 -1
- package/dist/platform.js +69 -77
- package/dist/platform.js.map +1 -1
- package/dist/utils/FormattedLogger.js +3 -0
- package/dist/utils/FormattedLogger.js.map +1 -1
- package/jest.config.ts +11 -3
- package/package.json +22 -14
- package/dist/__tests__/ExternalPlatformConfig.test.d.ts +0 -1
- package/dist/__tests__/ExternalPlatformConfig.test.js +0 -72
- package/dist/__tests__/ExternalPlatformConfig.test.js.map +0 -1
- package/dist/__tests__/PlatformConfiguration.test.d.ts +0 -1
- package/dist/__tests__/PlatformConfiguration.test.js +0 -97
- package/dist/__tests__/PlatformConfiguration.test.js.map +0 -1
- package/dist/devices/SoundTouch/__tests__/SoundTouchDeviceConfiguration.test.d.ts +0 -1
- package/dist/devices/SoundTouch/__tests__/SoundTouchDeviceConfiguration.test.js +0 -120
- package/dist/devices/SoundTouch/__tests__/SoundTouchDeviceConfiguration.test.js.map +0 -1
- package/dist/utils/__tests__/FormattedLogger.test.d.ts +0 -1
- package/dist/utils/__tests__/FormattedLogger.test.js +0 -121
- package/dist/utils/__tests__/FormattedLogger.test.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
npx --no-install commitlint --edit "$1"
|
package/.releaserc.json
ADDED
package/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
Thanks for helping improve this plugin. This document covers the branching
|
|
4
|
+
model, commit/PR naming rules, and how releases are produced.
|
|
5
|
+
|
|
6
|
+
## Local setup
|
|
7
|
+
|
|
8
|
+
Requires Node.js 22 or 24.
|
|
9
|
+
|
|
10
|
+
```sh
|
|
11
|
+
npm install # installs deps and Git hooks (husky)
|
|
12
|
+
npm run build # type-check and compile to dist/
|
|
13
|
+
npm test # run the test suite
|
|
14
|
+
npm run lint # eslint (use npm run format for prettier)
|
|
15
|
+
npm run watch # build, npm link, and reload on change for live testing
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Branching model
|
|
19
|
+
|
|
20
|
+
The release pipeline flows **`latest` → `dev` → `beta` → `latest`**.
|
|
21
|
+
|
|
22
|
+
| Branch | Purpose | On push |
|
|
23
|
+
| ---------------- | ------------------------------------ | ---------------------------------------- |
|
|
24
|
+
| `latest` | stable release channel | publishes `x.y.z` to npm `@latest` |
|
|
25
|
+
| `beta` | pre-release channel | publishes `x.y.z-beta.n` to npm `@beta` |
|
|
26
|
+
| `dev` | integration / active development | CI only (no publish) |
|
|
27
|
+
| feature branches | individual changes (`fix/…`, `feat/…`) | CI runs on the pull request |
|
|
28
|
+
|
|
29
|
+
Typical cycle:
|
|
30
|
+
|
|
31
|
+
1. `dev` is cut from `latest` and tracks the next release.
|
|
32
|
+
2. Branch feature work off `dev` and open a pull request **into `dev`**. CI
|
|
33
|
+
lints, builds, and tests it.
|
|
34
|
+
3. Promote `dev` → `beta`. Merging publishes a pre-release to npm `@beta`.
|
|
35
|
+
4. Once the pre-release is proven, promote `beta` → `latest`. Merging
|
|
36
|
+
publishes the stable release to npm `@latest`.
|
|
37
|
+
|
|
38
|
+
> Use a regular merge (not squash) for the `dev → beta` and `beta → latest`
|
|
39
|
+
> promotions so release tags stay reachable. Feature PRs into `dev` are
|
|
40
|
+
> squash-merged.
|
|
41
|
+
|
|
42
|
+
You never edit the `version` in `package.json`, write a changelog, or create
|
|
43
|
+
GitHub Releases by hand — all of that is automated (see **Releases** below).
|
|
44
|
+
|
|
45
|
+
## Commit and PR naming
|
|
46
|
+
|
|
47
|
+
Commit messages **and pull request titles** must follow
|
|
48
|
+
[Conventional Commits](https://www.conventionalcommits.org/). This is what
|
|
49
|
+
decides the next version, so it is enforced:
|
|
50
|
+
|
|
51
|
+
- a local `commit-msg` hook (commitlint) rejects invalid commit messages, and
|
|
52
|
+
- a required **PR Title** check rejects invalid pull request titles.
|
|
53
|
+
|
|
54
|
+
> Feature PRs are squash-merged, so the **PR title becomes the released commit
|
|
55
|
+
> message**. Get the title right even if the individual commits were messy.
|
|
56
|
+
|
|
57
|
+
| Prefix | Release | Example |
|
|
58
|
+
| ----------------------------------- | -------- | ---------------------------------------- |
|
|
59
|
+
| `fix:` | patch | `fix: correct speaker discovery timeout` |
|
|
60
|
+
| `feat:` | minor | `feat: add volume control` |
|
|
61
|
+
| `feat!:` or a `BREAKING CHANGE:` footer | major | `feat!: drop Homebridge v1 support` |
|
|
62
|
+
| `chore:` / `docs:` / `ci:` / `test:` / `refactor:` | none | `chore: bump dev dependencies` |
|
|
63
|
+
|
|
64
|
+
If a change should not trigger a release (tooling, docs, CI), use one of the
|
|
65
|
+
no-release types.
|
|
66
|
+
|
|
67
|
+
## Releases
|
|
68
|
+
|
|
69
|
+
Releases are fully automated with
|
|
70
|
+
[semantic-release](https://semantic-release.gitbook.io/) when commits land on
|
|
71
|
+
`beta` or `latest`. On a release-worthy commit it:
|
|
72
|
+
|
|
73
|
+
- determines the next version from the commit messages,
|
|
74
|
+
- publishes to npm (with provenance) on the matching dist-tag,
|
|
75
|
+
- creates the git tag, and
|
|
76
|
+
- creates a GitHub Release with notes generated from the commits.
|
|
77
|
+
|
|
78
|
+
Because release branches are protected, semantic-release does **not** commit a
|
|
79
|
+
version bump back to the repo — git tags are the source of truth, and the
|
|
80
|
+
changelog lives in the GitHub Releases, not a committed file.
|
package/README.md
CHANGED
|
@@ -1,30 +1,38 @@
|
|
|
1
|
-
# homebridge-soundtouch-
|
|
1
|
+
# homebridge-soundtouch-speaker
|
|
2
2
|
|
|
3
3
|
[](https://badge.fury.io/js/homebridge-soundtouchspeaker)
|
|
4
4
|
[](https://badgen.net/npm/dt/homebridge-soundtouchspeaker)
|
|
5
5
|
|
|
6
|
-
[Bose SoundTouch](https://www.bose.com/soundtouch-systems.html) plugin for [Homebridge](https://github.com/
|
|
6
|
+
[Bose SoundTouch](https://www.bose.com/soundtouch-systems.html) plugin for [Homebridge](https://github.com/homebridge/homebridge).
|
|
7
7
|
|
|
8
8
|
This allows you to control your SoundTouch devices with HomeKit and Siri.
|
|
9
9
|
|
|
10
|
-
Attempts to repair the [plugin](https://github.com/bbriatte/homebridge-soundtouch-platform/blob/master/README.md) originally
|
|
11
|
-
made by [@bbriatte](http://github.com/bbriatte) to work on Homebridge v1.8.
|
|
10
|
+
Attempts to repair the [plugin](https://github.com/bbriatte/homebridge-soundtouch-platform/blob/master/README.md) originally
|
|
11
|
+
made by [@bbriatte](http://github.com/bbriatte) to work on current Homebridge (v1.8 and v2).
|
|
12
12
|
|
|
13
13
|
Initial version only supports a switch accessory type, to power a speaker on and off. Future versions hope to reinstate support
|
|
14
14
|
for other features like volume control, sources, presets, lightbulb mode if there is demand.
|
|
15
15
|
|
|
16
16
|
## Prerequisites
|
|
17
|
-
1. [Homebridge](https://github.com/homebridge/homebridge) v1.8.0 or later
|
|
18
|
-
2. Node
|
|
17
|
+
1. [Homebridge](https://github.com/homebridge/homebridge) v1.8.0 or later (Homebridge v2 is supported)
|
|
18
|
+
2. Node.js 22 or 24
|
|
19
19
|
|
|
20
20
|
## Installation
|
|
21
|
-
|
|
21
|
+
Install through the [Homebridge UI](https://github.com/homebridge/homebridge-config-ui-x) (search for **SoundTouch Speaker**), or from the command line:
|
|
22
|
+
|
|
23
|
+
```sh
|
|
24
|
+
# stable
|
|
25
|
+
hb-service add homebridge-soundtouchspeaker
|
|
26
|
+
|
|
27
|
+
# latest pre-release
|
|
28
|
+
hb-service add homebridge-soundtouchspeaker@beta
|
|
29
|
+
```
|
|
22
30
|
## Configuration
|
|
23
31
|
Example `config.json` to discover all SoundTouch accessories
|
|
24
32
|
|
|
25
33
|
```json
|
|
26
34
|
{
|
|
27
|
-
|
|
35
|
+
"platform": "SoundTouchHomebridgePlugin",
|
|
28
36
|
"discoverAllAccessories": true
|
|
29
37
|
}
|
|
30
38
|
```
|
|
@@ -33,6 +41,7 @@ Example `config.json` to register a SoundTouch accessory using the speaker name
|
|
|
33
41
|
|
|
34
42
|
```json
|
|
35
43
|
{
|
|
44
|
+
"platform": "SoundTouchHomebridgePlugin",
|
|
36
45
|
"discoverAllAccessories": false,
|
|
37
46
|
"accessories": [
|
|
38
47
|
{
|
|
@@ -47,6 +56,7 @@ Example `config.json` to register a SoundTouch accessory using the ip address of
|
|
|
47
56
|
|
|
48
57
|
```json
|
|
49
58
|
{
|
|
59
|
+
"platform": "SoundTouchHomebridgePlugin",
|
|
50
60
|
"discoverAllAccessories": false,
|
|
51
61
|
"accessories": [
|
|
52
62
|
{
|
|
@@ -86,13 +96,19 @@ Example `config.json` for multiple speakers:
|
|
|
86
96
|
* `global`: Default configuration for all accessories. see **Global element**
|
|
87
97
|
|
|
88
98
|
### Accessory element
|
|
99
|
+
Each accessory must be matched to a device using either `ip` or `room`. If both are set, `ip` takes precedence.
|
|
100
|
+
|
|
89
101
|
*Optional fields*
|
|
90
|
-
* `name`: The name
|
|
102
|
+
* `name`: The name used for the accessory in HomeKit. Defaults to the device's own name as reported by the speaker.
|
|
91
103
|
* `ip`: The ip address of your device on your network.
|
|
92
|
-
* `
|
|
104
|
+
* `port`: The port used to reach the device. Only used with `ip`. __default__: **8090**
|
|
105
|
+
* `room`: Must match exactly the name of the SoundTouch device (as set in the Bose app). Ignored if `ip` is set.
|
|
106
|
+
* `pollingInterval`: Poll this device every interval in milliseconds. Overrides the global value.
|
|
93
107
|
|
|
94
108
|
|
|
95
109
|
### Global element
|
|
110
|
+
Default configuration applied to all accessories. Any value here can be overridden per accessory.
|
|
111
|
+
|
|
96
112
|
*Optional fields*
|
|
97
|
-
* `verbose`: Log all device information
|
|
98
|
-
* `pollingInterval`:
|
|
113
|
+
* `verbose`: Log all device information __default__: **false**
|
|
114
|
+
* `pollingInterval`: Poll each device every interval in milliseconds __default__: **2000**
|
package/config.schema.json
CHANGED
|
@@ -32,8 +32,8 @@
|
|
|
32
32
|
"properties": {
|
|
33
33
|
"name": {
|
|
34
34
|
"type": "string",
|
|
35
|
-
"required":
|
|
36
|
-
"description": "Name
|
|
35
|
+
"required": false,
|
|
36
|
+
"description": "Name shown in HomeKit. Defaults to the device's own name."
|
|
37
37
|
},
|
|
38
38
|
"ip": {
|
|
39
39
|
"type": "string",
|
|
@@ -42,6 +42,12 @@
|
|
|
42
42
|
"pattern": "^[^{}/ :\\\\]+(?::\\d+)?$",
|
|
43
43
|
"placeholder": "eg. 0.0.0.0"
|
|
44
44
|
},
|
|
45
|
+
"port": {
|
|
46
|
+
"type": "integer",
|
|
47
|
+
"required": false,
|
|
48
|
+
"description": "Port to use with ip",
|
|
49
|
+
"placeholder": "8090"
|
|
50
|
+
},
|
|
45
51
|
"room": {
|
|
46
52
|
"type": "string",
|
|
47
53
|
"required": false,
|
|
@@ -5,11 +5,15 @@ const DEFAULT_POLLING_INTERVAL = 2 * 1000; // 2 seconds
|
|
|
5
5
|
const DEFAULT_DISCOVER_ALL_ACCESSORIES = false;
|
|
6
6
|
const DEFAULT_VERBOSE = false;
|
|
7
7
|
export class PlatformConfiguration {
|
|
8
|
+
name;
|
|
9
|
+
discoverAllAccessories;
|
|
10
|
+
accessories;
|
|
11
|
+
pollingInterval;
|
|
12
|
+
verbose;
|
|
8
13
|
constructor(props) {
|
|
9
|
-
var _a;
|
|
10
14
|
this.name = props.name;
|
|
11
15
|
this.discoverAllAccessories = props.discoverAllAccessories;
|
|
12
|
-
this.accessories =
|
|
16
|
+
this.accessories = props?.accessories ?? [];
|
|
13
17
|
this.pollingInterval = props.pollingInterval;
|
|
14
18
|
this.verbose = props.verbose;
|
|
15
19
|
}
|
|
@@ -17,13 +21,12 @@ export class PlatformConfiguration {
|
|
|
17
21
|
return JSON.stringify(this, null, 2);
|
|
18
22
|
}
|
|
19
23
|
static fromExternalConfiguration(props) {
|
|
20
|
-
var _a, _b, _c, _d, _e;
|
|
21
24
|
return new PlatformConfiguration({
|
|
22
|
-
discoverAllAccessories:
|
|
25
|
+
discoverAllAccessories: props.discoverAllAccessories ?? DEFAULT_DISCOVER_ALL_ACCESSORIES,
|
|
23
26
|
verbose: DEFAULT_VERBOSE,
|
|
24
27
|
pollingInterval: DEFAULT_POLLING_INTERVAL,
|
|
25
|
-
accessories:
|
|
26
|
-
|
|
28
|
+
accessories: props.accessories
|
|
29
|
+
?.map((accessory) => {
|
|
27
30
|
const resultingConfig = flattenAccessoryConfiguration({
|
|
28
31
|
accessory,
|
|
29
32
|
globalConfig: props.global,
|
|
@@ -31,15 +34,16 @@ export class PlatformConfiguration {
|
|
|
31
34
|
return resultingConfig
|
|
32
35
|
? DeviceConfiguration.fromAccessoryConfiguration({
|
|
33
36
|
accessoryConfig: resultingConfig,
|
|
34
|
-
name: accessory
|
|
37
|
+
name: accessory?.name,
|
|
35
38
|
})
|
|
36
39
|
: DeviceConfiguration.create({
|
|
37
|
-
name: accessory
|
|
38
|
-
verboseLogging:
|
|
39
|
-
pollingInterval:
|
|
40
|
+
name: accessory?.name,
|
|
41
|
+
verboseLogging: props.global?.verbose,
|
|
42
|
+
pollingInterval: props.global?.pollingInterval,
|
|
40
43
|
});
|
|
41
|
-
})
|
|
42
|
-
|
|
44
|
+
})
|
|
45
|
+
?.filter((d) => !!d) ?? [],
|
|
46
|
+
name: props.name ?? PLATFORM_NAME,
|
|
43
47
|
});
|
|
44
48
|
}
|
|
45
49
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PlatformConfiguration.js","sourceRoot":"","sources":["../src/PlatformConfiguration.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,6BAA6B,GAE9B,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,mBAAmB,EAAE,MAAM,uDAAuD,CAAC;AAC5F,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAE9C,MAAM,wBAAwB,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC,YAAY;AACvD,MAAM,gCAAgC,GAAG,KAAK,CAAC;AAC/C,MAAM,eAAe,GAAG,KAAK,CAAC;AAE9B,MAAM,OAAO,qBAAqB;
|
|
1
|
+
{"version":3,"file":"PlatformConfiguration.js","sourceRoot":"","sources":["../src/PlatformConfiguration.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,6BAA6B,GAE9B,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,mBAAmB,EAAE,MAAM,uDAAuD,CAAC;AAC5F,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAE9C,MAAM,wBAAwB,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC,YAAY;AACvD,MAAM,gCAAgC,GAAG,KAAK,CAAC;AAC/C,MAAM,eAAe,GAAG,KAAK,CAAC;AAE9B,MAAM,OAAO,qBAAqB;IAChC,IAAI,CAAS;IACb,sBAAsB,CAAU;IAChC,WAAW,CAAwB;IACnC,eAAe,CAAS;IACxB,OAAO,CAAU;IAEjB,YAAY,KAMX;QACC,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC;QACvB,IAAI,CAAC,sBAAsB,GAAG,KAAK,CAAC,sBAAsB,CAAC;QAC3D,IAAI,CAAC,WAAW,GAAG,KAAK,EAAE,WAAW,IAAI,EAAE,CAAC;QAC5C,IAAI,CAAC,eAAe,GAAG,KAAK,CAAC,eAAe,CAAC;QAC7C,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC;IAC/B,CAAC;IAED,MAAM;QACJ,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IACvC,CAAC;IAED,MAAM,CAAC,yBAAyB,CAAC,KAA6B;QAC5D,OAAO,IAAI,qBAAqB,CAAC;YAC/B,sBAAsB,EACpB,KAAK,CAAC,sBAAsB,IAAI,gCAAgC;YAClE,OAAO,EAAE,eAAe;YACxB,eAAe,EAAE,wBAAwB;YACzC,WAAW,EACT,KAAK,CAAC,WAAW;gBACf,EAAE,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE;gBAClB,MAAM,eAAe,GAAG,6BAA6B,CAAC;oBACpD,SAAS;oBACT,YAAY,EAAE,KAAK,CAAC,MAAM;iBAC3B,CAAC,CAAC;gBACH,OAAO,eAAe;oBACpB,CAAC,CAAC,mBAAmB,CAAC,0BAA0B,CAAC;wBAC7C,eAAe,EAAE,eAAe;wBAChC,IAAI,EAAE,SAAS,EAAE,IAAI;qBACtB,CAAC;oBACJ,CAAC,CAAC,mBAAmB,CAAC,MAAM,CAAC;wBACzB,IAAI,EAAE,SAAS,EAAE,IAAI;wBACrB,cAAc,EAAE,KAAK,CAAC,MAAM,EAAE,OAAO;wBACrC,eAAe,EAAE,KAAK,CAAC,MAAM,EAAE,eAAe;qBAC/C,CAAC,CAAC;YACT,CAAC,CAAC;gBACF,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE;YAC9B,IAAI,EAAE,KAAK,CAAC,IAAI,IAAI,aAAa;SAClC,CAAC,CAAC;IACL,CAAC;CACF"}
|
|
@@ -1,93 +1,76 @@
|
|
|
1
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
-
});
|
|
9
|
-
};
|
|
10
|
-
var __rest = (this && this.__rest) || function (s, e) {
|
|
11
|
-
var t = {};
|
|
12
|
-
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
13
|
-
t[p] = s[p];
|
|
14
|
-
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
15
|
-
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
16
|
-
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
17
|
-
t[p[i]] = s[p[i]];
|
|
18
|
-
}
|
|
19
|
-
return t;
|
|
20
|
-
};
|
|
21
1
|
import { getServiceName, ServiceType, SoundTouchSpeakerCharacteristic, } from './services/SoundTouchSpeakerCharacteristic.js';
|
|
22
2
|
import { SoundTouchSpeakerInformationCharacteristic } from './services/SoundTouchSpeakerInformationCharacteristic.js';
|
|
23
3
|
import { SoundTouchSpeakerOnCharacteristic } from './services/SoundTouchSpeakerOnCharacteristic.js';
|
|
24
4
|
export class SoundTouchSpeakerPlatformAccessory extends SoundTouchSpeakerCharacteristic {
|
|
25
|
-
|
|
26
|
-
|
|
5
|
+
speakerCharacteristics;
|
|
6
|
+
_isPolling = false;
|
|
7
|
+
constructor({ speakerCharacteristics, ...props }) {
|
|
27
8
|
super(props);
|
|
28
|
-
this._isPolling = false;
|
|
29
9
|
this.speakerCharacteristics = speakerCharacteristics;
|
|
30
10
|
}
|
|
31
|
-
init() {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
yield speakerCharacteristic.init();
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
if (this.device.configuration.pollingInterval !== undefined) {
|
|
39
|
-
this._isPolling = true;
|
|
40
|
-
this._refreshDeviceServices().then(() => {
|
|
41
|
-
//no-op
|
|
42
|
-
});
|
|
11
|
+
async init() {
|
|
12
|
+
for (const speakerCharacteristic of this.speakerCharacteristics) {
|
|
13
|
+
if (speakerCharacteristic.init) {
|
|
14
|
+
await speakerCharacteristic.init();
|
|
43
15
|
}
|
|
44
|
-
|
|
45
|
-
|
|
16
|
+
}
|
|
17
|
+
if (this.device.configuration.pollingInterval !== undefined) {
|
|
18
|
+
this._isPolling = true;
|
|
19
|
+
this._refreshDeviceServices().then(() => {
|
|
20
|
+
//no-op
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
this.log.info(`Device ready`);
|
|
46
24
|
}
|
|
47
|
-
refresh() {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
yield speakerCharacteristic.refresh();
|
|
52
|
-
}
|
|
25
|
+
async refresh() {
|
|
26
|
+
for (const speakerCharacteristic of this.speakerCharacteristics) {
|
|
27
|
+
if (speakerCharacteristic.refresh) {
|
|
28
|
+
await speakerCharacteristic.refresh();
|
|
53
29
|
}
|
|
54
|
-
}
|
|
30
|
+
}
|
|
55
31
|
}
|
|
56
32
|
stopPolling() {
|
|
57
33
|
this._isPolling = false;
|
|
58
34
|
}
|
|
59
|
-
_refreshDeviceServices() {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
yield this.refresh();
|
|
65
|
-
}
|
|
66
|
-
catch (e) {
|
|
67
|
-
this.log.error('Polling refresh failed', e);
|
|
68
|
-
}
|
|
35
|
+
async _refreshDeviceServices() {
|
|
36
|
+
while (this._isPolling) {
|
|
37
|
+
await new Promise((resolve) => setTimeout(resolve, this.device.configuration.pollingInterval));
|
|
38
|
+
try {
|
|
39
|
+
await this.refresh();
|
|
69
40
|
}
|
|
70
|
-
|
|
41
|
+
catch (e) {
|
|
42
|
+
this.log.error('Polling refresh failed', e);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
71
45
|
}
|
|
72
|
-
static createAccessory(props) {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
46
|
+
static async createAccessory(props) {
|
|
47
|
+
const service = SoundTouchSpeakerPlatformAccessory.ensureAccessoryService({
|
|
48
|
+
serviceType: ServiceType.ON_OFF,
|
|
49
|
+
service: props.platform.service.Switch,
|
|
50
|
+
...props,
|
|
51
|
+
});
|
|
52
|
+
const characteristics = [
|
|
53
|
+
await SoundTouchSpeakerOnCharacteristic.create({
|
|
54
|
+
service,
|
|
55
|
+
...props,
|
|
56
|
+
}),
|
|
57
|
+
...props.defaultCharacteristics,
|
|
58
|
+
];
|
|
59
|
+
return new SoundTouchSpeakerPlatformAccessory({
|
|
60
|
+
speakerCharacteristics: [...characteristics],
|
|
61
|
+
...props,
|
|
80
62
|
});
|
|
81
63
|
}
|
|
82
|
-
static create(props) {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
return accessory;
|
|
64
|
+
static async create(props) {
|
|
65
|
+
const defaultCharacteristics = [
|
|
66
|
+
await SoundTouchSpeakerInformationCharacteristic.create(props),
|
|
67
|
+
];
|
|
68
|
+
const accessory = await SoundTouchSpeakerPlatformAccessory.createAccessory({
|
|
69
|
+
defaultCharacteristics,
|
|
70
|
+
...props,
|
|
90
71
|
});
|
|
72
|
+
await accessory.init();
|
|
73
|
+
return accessory;
|
|
91
74
|
}
|
|
92
75
|
static ensureAccessoryService({ device, accessory, serviceType, service, }) {
|
|
93
76
|
const serviceName = getServiceName({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SoundTouchSpeakerPlatformAccessory.js","sourceRoot":"","sources":["../../src/accessories/SoundTouchSpeakerPlatformAccessory.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"SoundTouchSpeakerPlatformAccessory.js","sourceRoot":"","sources":["../../src/accessories/SoundTouchSpeakerPlatformAccessory.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,6 +4,10 @@ export var ServiceType;
|
|
|
4
4
|
ServiceType["ON_OFF"] = "ON";
|
|
5
5
|
})(ServiceType || (ServiceType = {}));
|
|
6
6
|
export class SoundTouchSpeakerCharacteristic {
|
|
7
|
+
platform;
|
|
8
|
+
accessory;
|
|
9
|
+
device;
|
|
10
|
+
log;
|
|
7
11
|
constructor({ accessory, platform, device, }) {
|
|
8
12
|
this.accessory = accessory;
|
|
9
13
|
this.platform = platform;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SoundTouchSpeakerCharacteristic.js","sourceRoot":"","sources":["../../../src/accessories/services/SoundTouchSpeakerCharacteristic.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,YAAY,EAAU,MAAM,gCAAgC,CAAC;AAEtE,MAAM,CAAN,IAAY,WAEX;AAFD,WAAY,WAAW;IACrB,4BAAe,CAAA;AACjB,CAAC,EAFW,WAAW,KAAX,WAAW,QAEtB;AAED,MAAM,OAAgB,+BAA+B;
|
|
1
|
+
{"version":3,"file":"SoundTouchSpeakerCharacteristic.js","sourceRoot":"","sources":["../../../src/accessories/services/SoundTouchSpeakerCharacteristic.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,YAAY,EAAU,MAAM,gCAAgC,CAAC;AAEtE,MAAM,CAAN,IAAY,WAEX;AAFD,WAAY,WAAW;IACrB,4BAAe,CAAA;AACjB,CAAC,EAFW,WAAW,KAAX,WAAW,QAEtB;AAED,MAAM,OAAgB,+BAA+B;IACzC,QAAQ,CAA+B;IACvC,SAAS,CAAoB;IAC7B,MAAM,CAAmB;IACzB,GAAG,CAAS;IAEtB,YAAsB,EACpB,SAAS,EACT,QAAQ,EACR,MAAM,GAKP;QACC,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAC3B,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,GAAG,GAAG,YAAY,CAAC,UAAU,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IAC1E,CAAC;IAED,IAAI;QACF,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;IAC3B,CAAC;IACD,OAAO;QACL,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;IAC3B,CAAC;CACF;AAED,MAAM,UAAU,cAAc,CAAC,EAC7B,WAAW,EACX,MAAM,GAIP;IACC,OAAO,GAAG,MAAM,CAAC,IAAI,IAAI,WAAW,UAAU,CAAC;AACjD,CAAC"}
|
|
@@ -1,45 +1,32 @@
|
|
|
1
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
-
});
|
|
9
|
-
};
|
|
10
1
|
import { SoundTouchSpeakerCharacteristic } from './SoundTouchSpeakerCharacteristic.js';
|
|
11
2
|
const SOUNDTOUCH_MANUFACTURER = 'Bose';
|
|
12
3
|
export class SoundTouchSpeakerInformationCharacteristic extends SoundTouchSpeakerCharacteristic {
|
|
13
4
|
constructor(props) {
|
|
14
5
|
super(props);
|
|
15
6
|
}
|
|
16
|
-
init() {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
}
|
|
32
|
-
});
|
|
7
|
+
async init() {
|
|
8
|
+
this.log.debug('initialising info');
|
|
9
|
+
const deviceName = this.calculateDeviceName();
|
|
10
|
+
const informationService = this.accessory.getService(this.platform.service.AccessoryInformation);
|
|
11
|
+
if (!informationService) {
|
|
12
|
+
throw new Error('No information service found');
|
|
13
|
+
}
|
|
14
|
+
informationService
|
|
15
|
+
.setCharacteristic(this.platform.characteristic.Name, deviceName)
|
|
16
|
+
.setCharacteristic(this.platform.characteristic.Manufacturer, SOUNDTOUCH_MANUFACTURER)
|
|
17
|
+
.setCharacteristic(this.platform.characteristic.Model, this.device.model)
|
|
18
|
+
.setCharacteristic(this.platform.characteristic.SerialNumber, this.device.id);
|
|
19
|
+
if (this.device.version) {
|
|
20
|
+
informationService.setCharacteristic(this.platform.characteristic.FirmwareRevision, this.device.version);
|
|
21
|
+
}
|
|
33
22
|
}
|
|
34
23
|
calculateDeviceName() {
|
|
35
24
|
return this.device.name.toLowerCase().endsWith('speaker')
|
|
36
25
|
? this.device.name
|
|
37
26
|
: `${this.device.name} Speaker`;
|
|
38
27
|
}
|
|
39
|
-
static create(props) {
|
|
40
|
-
return
|
|
41
|
-
return new SoundTouchSpeakerInformationCharacteristic(props);
|
|
42
|
-
});
|
|
28
|
+
static async create(props) {
|
|
29
|
+
return new SoundTouchSpeakerInformationCharacteristic(props);
|
|
43
30
|
}
|
|
44
31
|
}
|
|
45
32
|
//# sourceMappingURL=SoundTouchSpeakerInformationCharacteristic.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SoundTouchSpeakerInformationCharacteristic.js","sourceRoot":"","sources":["../../../src/accessories/services/SoundTouchSpeakerInformationCharacteristic.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"SoundTouchSpeakerInformationCharacteristic.js","sourceRoot":"","sources":["../../../src/accessories/services/SoundTouchSpeakerInformationCharacteristic.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,+BAA+B,EAAE,MAAM,sCAAsC,CAAC;AAKvF,MAAM,uBAAuB,GAAG,MAAM,CAAC;AAEvC,MAAM,OAAO,0CAA2C,SAAQ,+BAA+B;IAE7F,YAAY,KAIX;QACC,KAAK,CAAC,KAAK,CAAC,CAAC;IACf,CAAC;IAED,KAAK,CAAC,IAAI;QACR,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC;QAEpC,MAAM,UAAU,GAAG,IAAI,CAAC,mBAAmB,EAAE,CAAC;QAE9C,MAAM,kBAAkB,GAAG,IAAI,CAAC,SAAS,CAAC,UAAU,CAClD,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,oBAAoB,CAC3C,CAAC;QACF,IAAI,CAAC,kBAAkB,EAAE,CAAC;YACxB,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;QAClD,CAAC;QACD,kBAAkB;aACf,iBAAiB,CAAC,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,IAAI,EAAE,UAAU,CAAC;aAChE,iBAAiB,CAChB,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,YAAY,EACzC,uBAAuB,CACxB;aACA,iBAAiB,CAAC,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC;aACxE,iBAAiB,CAChB,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,YAAY,EACzC,IAAI,CAAC,MAAM,CAAC,EAAE,CACf,CAAC;QACJ,IAAI,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACxB,kBAAkB,CAAC,iBAAiB,CAClC,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,gBAAgB,EAC7C,IAAI,CAAC,MAAM,CAAC,OAAO,CACpB,CAAC;QACJ,CAAC;IACH,CAAC;IAED,mBAAmB;QACjB,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC;YACvD,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI;YAClB,CAAC,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,UAAU,CAAC;IACpC,CAAC;IAED,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,KAInB;QACC,OAAO,IAAI,0CAA0C,CAAC,KAAK,CAAC,CAAC;IAC/D,CAAC;CACF"}
|