homebridge-bond 3.2.9

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.
@@ -0,0 +1,51 @@
1
+ ---
2
+ name: Bug report
3
+ about: Create a report to help us improve
4
+ title: ''
5
+ labels: bug
6
+ assignees: ''
7
+
8
+ ---
9
+
10
+ **Describe the bug**
11
+ A clear and concise description of what the bug is.
12
+
13
+ **Information (please complete the following information):**
14
+ - Plugin version (run `npm list -g homebridge-bond` in terminal)
15
+ - Bond firmware version
16
+ - How homebridge is run: [command line | Homebridge UI | HOOBS | Other]
17
+
18
+ **Logs**
19
+ Logs are the _most_ helpful thing you can provide. Please exclude logs from other plugin. It's even better if you can provide logs while in debug mode (instructions [here](https://github.com/aarons22/homebridge-bond/wiki/Enabling-Debug-Mode)). For example:
20
+ ```
21
+ [9/4/2020, 8:11:11 PM] [Bond] Response (185d16e6920c0000) [get http://192.168.200.14/v2/sys/version] - {"target":"snowbird","fw_ver":"v2.14.5","fw_date":"Mon Aug 24 21:44:47 UTC 2020","uptime_s":37545,"bondid":"BD27788","upgrade_http":true,"api":2,"_":"e5b2a454"}
22
+ [9/4/2020, 8:11:11 PM] [Bond]
23
+ ****** Bond Info *******
24
+ bondId: BD27788
25
+ FW: v2.14.5
26
+ API: v2
27
+ Make: undefined
28
+ Model: undefined
29
+ ************************
30
+ [9/4/2020, 8:11:11 PM] [Bond] Response (185d16e6920b8000) [get http://192.168.200.14/v2/devices] - {"_":"01764b3d","30ba40e6":{"_":"89703ac5"},"00000003":{"_":"fe5ea57b"},"00000018":{"_":"1f6c6f4f"}}
31
+ [9/4/2020, 8:11:11 PM] [Bond] 3 cached accessories were loaded
32
+ [9/4/2020, 8:11:11 PM] [Bond] Updating device data with uniqueId BD2778830ba40e6
33
+ [9/4/2020, 8:11:11 PM] [Bond] Updating device data with uniqueId BD2778800000003
34
+ [9/4/2020, 8:11:11 PM] [Bond] Updating device data with uniqueId BD2778800000018
35
+ [9/4/2020, 8:11:11 PM] [Bond] Getting devices for this Bond (BD27788)...
36
+ [9/4/2020, 8:11:11 PM] [Bond] 3 devices were found on this Bond (BD27788).
37
+ [9/4/2020, 8:11:11 PM] [Bond] No new devices to add for this Bond (BD27788).
38
+ [9/4/2020, 8:11:12 PM] [Bond] Request (185d16e69289c000) [get http://192.168.200.14/v2/devices/30ba40e6/state]
39
+ [9/4/2020, 8:11:12 PM] [Bond] Configuring Accessory: Living Room LR Fan
40
+ [9/4/2020, 8:11:12 PM] [Bond] [LR Fan] min step: 33, max value: 99
41
+ [9/4/2020, 8:11:12 PM] [Bond] Request (185d16e6928a0000) [get http://192.168.200.14/v2/devices/00000003/state]
42
+ [9/4/2020, 8:11:12 PM] [Bond] Request (185d16e6928a0001) [get http://192.168.200.14/v2/devices/00000003/state]
43
+ [9/4/2020, 8:11:12 PM] [Bond] Request (185d16e6928a4000) [get http://192.168.200.14/v2/devices/00000003/state]
44
+ [9/4/2020, 8:11:12 PM] [Bond] Response (185d16e692898000) [get http://192.168.200.14/v2/devices/30ba40e6/state] - {"open":0,"_":"f7af4771"}
45
+ [9/4/2020, 8:11:12 PM] [Bond] Response (185d16e6928a0000) [get http://192.168.200.14/v2/devices/00000003/state] - {"power":1,"speed":1,"light":1,"_":"8358c6c1"}
46
+ [9/4/2020, 8:11:12 PM] [Bond] [LR Fan] speed value: 1
47
+ [9/4/2020, 8:11:12 PM] [Bond] [LR Fan] index value: 1
48
+ [9/4/2020, 8:11:12 PM] [Bond] [LR Fan] step value: 33
49
+ [9/4/2020, 8:11:12 PM] [Bond] Response (185d16e6928a0001) [get http://192.168.200.14/v2/devices/00000003/state] - {"power":1,"speed":1,"light":1,"_":"8358c6c1"}
50
+ [9/4/2020, 8:11:12 PM] [Bond] Response (185d16e6928a4000) [get http://192.168.200.14/v2/devices/00000003/state] - {"power":1,"speed":1,"light":1,"_":"8358c6c1"}
51
+ ```
@@ -0,0 +1,20 @@
1
+ ---
2
+ name: Feature request
3
+ about: Suggest an idea for this project
4
+ title: ''
5
+ labels: feature-request
6
+ assignees: ''
7
+
8
+ ---
9
+
10
+ **Is your feature request related to a problem? Please describe.**
11
+ A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
12
+
13
+ **Describe the solution you'd like**
14
+ A clear and concise description of what you want to happen.
15
+
16
+ **Describe alternatives you've considered**
17
+ A clear and concise description of any alternative solutions or features you've considered.
18
+
19
+ **Additional context**
20
+ Add any other context or screenshots about the feature request here.
@@ -0,0 +1,28 @@
1
+ name: Build and Lint
2
+
3
+ on: [push, pull_request]
4
+
5
+ jobs:
6
+ build:
7
+
8
+ strategy:
9
+ matrix:
10
+ node-version: [10.x, 12.x, 14.x]
11
+ os: [ubuntu-latest]
12
+
13
+ runs-on: ${{ matrix.os }}
14
+
15
+ steps:
16
+ - uses: actions/checkout@v2
17
+ - name: Use Node.js ${{ matrix.node-version }}
18
+ uses: actions/setup-node@v1
19
+ with:
20
+ node-version: ${{ matrix.node-version }}
21
+ - name: npm install, lint, build and test
22
+ run: |
23
+ npm install
24
+ npm run lint
25
+ npm run build
26
+ npm run test
27
+ env:
28
+ CI: true
package/.prettierrc ADDED
@@ -0,0 +1,5 @@
1
+ {
2
+ "printWidth": 120,
3
+ "trailingComma": "all",
4
+ "singleQuote": true
5
+ }
package/.travis.yml ADDED
@@ -0,0 +1,8 @@
1
+ language: node_js
2
+ node_js:
3
+ - 'lts/*'
4
+ cache:
5
+ directories:
6
+ - "node_modules"
7
+ script:
8
+ - npm run build
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2019 Aaron Sapp
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,109 @@
1
+ [![verified-by-homebridge](https://badgen.net/badge/homebridge/verified/purple)](https://github.com/homebridge/homebridge/wiki/Verified-Plugins)
2
+ [![npm](https://badgen.net/npm/v/homebridge-bond)](https://www.npmjs.com/package/homebridge-bond)
3
+ [![npm](https://badgen.net/npm/dt/homebridge-bond)](https://www.npmjs.com/package/homebridge-bond)
4
+
5
+ # homebridge-bond
6
+
7
+ Bond plug-in for [Homebridge](https://github.com/nfarina/homebridge) using the [Bond V2 API](http://docs-local.appbond.com).
8
+
9
+ ## Features
10
+
11
+ This plugin currently supports the following devices and features:
12
+
13
+ - Multiple Bonds
14
+ - Supported Devices
15
+ - Ceiling Fan
16
+ - Light on/off
17
+ - Up/Down light
18
+ - Fan Speeds 1-8 (dynamic based on bond configuration)
19
+ - Light Dimming
20
+ - Blinds
21
+ - Open / Close
22
+ - Generic Device
23
+ - On / Off (appears as switch in HomeKit)
24
+ - Fireplace
25
+ - Flame On / Off (appears as switch in HomeKit)
26
+
27
+
28
+ You can view the backlog of features [here](https://github.com/aarons22/homebridge-bond/). Feel free to add a feature request in the Issues tab!
29
+
30
+ ## Installation
31
+
32
+ ### Bond Parameters
33
+
34
+ | Option | Required | Explanation |
35
+ | ------------------ | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
36
+ | `ip_address` | true | To get your Bond IP Address, follow the instructions [here](https://github.com/aarons22/homebridge-bond/wiki/Get-Bond-IP-Address). |
37
+ | `token` | true | This can be found in the Bond app in your Bond Settings. Scroll down until you see `Local Token`. You can tap on the row to copy to your clipboard. |
38
+ | `hide_device_ids` | false | Array of device ids to ignore (i.e. `["1111", "2222"]`) |
39
+
40
+ ### Easiest Configuration
41
+
42
+ For the best experience setting up this plugin, please use [homebridge-config-ui-x](https://www.npmjs.com/package/homebridge-config-ui-x).
43
+
44
+ ### HOOBS Configuration
45
+
46
+ In HOOBS, you need to provide the bonds (optionally, turn on opt-in features):
47
+ ```json
48
+ [
49
+ {
50
+ "ip_address": "<IP_ADDRESS>",
51
+ "token": "<TOKEN>",
52
+ "hide_device_ids": ["123456"]
53
+ }
54
+ ]
55
+ ```
56
+
57
+ <ins>Example Config in HOOBS:</ins>
58
+
59
+ ![Config](./images/hoobs_configuration.png)
60
+
61
+ ### Basic Configuration
62
+
63
+ Assuming a global installation of `homebridge`, install the plugin:
64
+
65
+ `npm i -g homebridge-bond`
66
+
67
+ Add the `Bond` platform in your homebridge `config.json` file:
68
+
69
+ ```json
70
+ "platforms": [
71
+ {
72
+ "platform": "Bond",
73
+ "bonds": [
74
+ {
75
+ "ip_address": "<IP_ADDRESS>",
76
+ "token": "<TOKEN>"
77
+ }
78
+ ],
79
+ }
80
+ ],
81
+ ```
82
+
83
+ NOTE: If you have a "Smart by BOND" fan/device, you will need to add a Bond in the config for _each_ fan/device.
84
+
85
+ ### Optional Platform Parameters
86
+
87
+ | Option | Default | Explanation |
88
+ | ------------------ | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
89
+ | `include_dimmer` | false | If dimming is a valid action on a device, it will be included as additional switch on the accessory. When using this feature, turn the switch on to start dimming. When you reach the brightness level you would like, turn the switch off. |
90
+ | `fan_speed_values` | false | Use fan speed values instead of percentages (i.e. Hey Siri set the Office Fan to 2) |
91
+ | `include_toggle_state` | false | This will add a switch to single-action accessories to toggle the state (i.e. Shades, Fireplace, Generic, Lights). Fan speeds are not eligible for this option. |
92
+
93
+ ## Development
94
+
95
+ I'm more than happy to take PRs if you want to fix a bug you are having or take a shot at adding a new feature you're interested in. To compile the code in realtime, run:
96
+
97
+ ```
98
+ npm run dev
99
+ ```
100
+
101
+ To use the local version of the plugin in homebridge, I run `npm link` in the directory of the cloned repo.
102
+
103
+ ## Support
104
+
105
+ If you have general questions about usage, please use the [Discussions](https://github.com/aarons22/homebridge-bond/discussions) tab! If you are unsure if a problem you are having is actually a bug/issue with the plugin, that is a great place to start 😄.
106
+
107
+ ## Contact
108
+
109
+ You can find me on Twitter [@aaronsapp](https://twitter.com/aaronsapp)
@@ -0,0 +1,66 @@
1
+ {
2
+ "pluginAlias": "Bond",
3
+ "pluginType": "platform",
4
+ "singular": true,
5
+ "schema": {
6
+ "type": "object",
7
+ "properties": {
8
+ "bonds": {
9
+ "title": "Bonds",
10
+ "type": "array",
11
+ "required": true,
12
+ "uniqueItems": true,
13
+ "items": {
14
+ "title": "Bond",
15
+ "type": "object",
16
+ "properties": {
17
+ "ip_address": {
18
+ "title": "IP Address",
19
+ "type": "string",
20
+ "required": true,
21
+ "description": "IP Address of your Bond.",
22
+ "placeholder": "e.g. 192.168.1.1"
23
+ },
24
+ "token": {
25
+ "title": "Bond Token",
26
+ "type": "string",
27
+ "required": true,
28
+ "description": "Can be found in the bond app by tapping your Bond device and looking for 'Local Token'.",
29
+ "placeholder": "e.g. fd3904894ff98f"
30
+ },
31
+ "hide_device_ids": {
32
+ "title": "Hide Device IDs",
33
+ "description": "Hide individual devices by Device ID. Device ID can be found in the Bond app under Device Settings.",
34
+ "placeholder": "e.g. 0000018",
35
+ "type": "array",
36
+ "items": {
37
+ "type": "string"
38
+ }
39
+ }
40
+ }
41
+ }
42
+ },
43
+ "include_dimmer": {
44
+ "title": "Include dimmer",
45
+ "type": "boolean",
46
+ "default": false,
47
+ "required": false,
48
+ "description": "If dimming is a valid action on a device, it will be included as additional switch on the accessory. Since this is an odd solution to dimming, it's off by default."
49
+ },
50
+ "include_toggle_state": {
51
+ "title": "Include toggle switch for fixing device state.",
52
+ "type": "boolean",
53
+ "default": false,
54
+ "required": false,
55
+ "description": "This will add a switch to single-action accessories to toggle the state (i.e. Shades, Fireplace, Generic, Lights). Fan speeds are not eligible for this option."
56
+ },
57
+ "fan_speed_values": {
58
+ "title": "Use fan speed values",
59
+ "type": "boolean",
60
+ "default": false,
61
+ "required": false,
62
+ "description": "Use fan speed values instead of percentages (i.e. Hey Siri set the Office Fan to 2)."
63
+ }
64
+ }
65
+ }
66
+ }
@@ -0,0 +1,304 @@
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.BondApi = void 0;
7
+ const Action_1 = require("./enum/Action");
8
+ const BondUri_1 = require("./BondUri");
9
+ const axios_1 = __importDefault(require("axios"));
10
+ const axios_retry_1 = __importDefault(require("axios-retry"));
11
+ const flake_idgen_1 = __importDefault(require("flake-idgen"));
12
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
13
+ const intformat = require('biguint-format');
14
+ var HTTPMethod;
15
+ (function (HTTPMethod) {
16
+ HTTPMethod["GET"] = "get";
17
+ HTTPMethod["PUT"] = "put";
18
+ HTTPMethod["PATCH"] = "patch";
19
+ })(HTTPMethod || (HTTPMethod = {}));
20
+ const flakeIdGen = new flake_idgen_1.default();
21
+ class BondApi {
22
+ constructor(platform, bondToken, ipAddress) {
23
+ this.platform = platform;
24
+ this.bondToken = bondToken;
25
+ this.uri = new BondUri_1.BondUri(ipAddress);
26
+ axios_retry_1.default(axios_1.default, { retries: 10, retryDelay: axios_retry_1.default.exponentialDelay });
27
+ }
28
+ // Bond / Device Info
29
+ getVersion() {
30
+ return this.request(HTTPMethod.GET, this.uri.version());
31
+ }
32
+ getState(id) {
33
+ return this.request(HTTPMethod.GET, this.uri.state(id));
34
+ }
35
+ getDeviceIds() {
36
+ const req = this.request(HTTPMethod.GET, this.uri.deviceIds());
37
+ return req.then(json => Object.keys(json).filter(x => {
38
+ // Ignore anything that is an empty string or '_'
39
+ return x.length > 0 && x !== '_';
40
+ }));
41
+ }
42
+ getDevices(ids) {
43
+ const ps = [];
44
+ ids.forEach(id => {
45
+ ps.push(this.getDevice(id));
46
+ });
47
+ return Promise.all(ps);
48
+ }
49
+ getDevice(id) {
50
+ const req = this.request(HTTPMethod.GET, this.uri.device(id));
51
+ return req.then(json => {
52
+ // Set the id since it's not included in the response
53
+ json.id = id;
54
+ // get the properties of the device
55
+ return this.getProperties(id).then(properties => {
56
+ json.properties = properties;
57
+ if (json.commands) {
58
+ // commands are only present on Bridge devices.
59
+ return this.getCommands(id).then(commands => {
60
+ json.commands = commands;
61
+ return json;
62
+ });
63
+ }
64
+ else {
65
+ return json;
66
+ }
67
+ });
68
+ });
69
+ }
70
+ // Actions
71
+ action(device, action, callback) {
72
+ return this.request(HTTPMethod.PUT, this.uri.action(device.id, action))
73
+ .then(() => {
74
+ callback(null);
75
+ })
76
+ .catch((error) => {
77
+ callback(Error(error));
78
+ });
79
+ }
80
+ toggleLight(device, callback) {
81
+ return this.action(device, Action_1.Action.ToggleLight, callback);
82
+ }
83
+ toggleUpLight(device, callback) {
84
+ return this.action(device, Action_1.Action.ToggleUpLight, callback);
85
+ }
86
+ toggleDownLight(device, callback) {
87
+ return this.action(device, Action_1.Action.ToggleDownLight, callback);
88
+ }
89
+ startDimmer(device, callback) {
90
+ return this.action(device, Action_1.Action.StartDimmer, callback);
91
+ }
92
+ startUpLightDimmer(device, callback) {
93
+ return this.action(device, Action_1.Action.StartUpLightDimmer, callback);
94
+ }
95
+ startDownLightDimmer(device, callback) {
96
+ return this.action(device, Action_1.Action.StartDownLightDimmer, callback);
97
+ }
98
+ startIncreasingBrightness(device, callback) {
99
+ return this.action(device, Action_1.Action.StartIncreasingBrightness, callback);
100
+ }
101
+ startDecreasingBrightness(device, callback) {
102
+ return this.action(device, Action_1.Action.StartDecreasingBrightness, callback);
103
+ }
104
+ setBrightness(device, value, callback) {
105
+ const body = {
106
+ argument: value,
107
+ };
108
+ return this.request(HTTPMethod.PUT, this.uri.action(device.id, Action_1.Action.SetBrightness), body)
109
+ .then(() => {
110
+ callback(null);
111
+ })
112
+ .catch((error) => {
113
+ callback(Error(error));
114
+ });
115
+ }
116
+ setFlame(device, value, callback) {
117
+ const body = {
118
+ argument: value,
119
+ };
120
+ return this.request(HTTPMethod.PUT, this.uri.action(device.id, Action_1.Action.SetFlame), body)
121
+ .then(() => {
122
+ callback(null);
123
+ })
124
+ .catch((error) => {
125
+ callback(Error(error));
126
+ });
127
+ }
128
+ turnLightOff(device, callback) {
129
+ return this.action(device, Action_1.Action.TurnLightOff, callback);
130
+ }
131
+ toggleFan(device, on, callback) {
132
+ const action = on ? Action_1.Action.TurnOn : Action_1.Action.TurnOff;
133
+ return this.action(device, action, callback);
134
+ }
135
+ toggleDirection(device, callback) {
136
+ return this.action(device, Action_1.Action.ToggleDirection, callback);
137
+ }
138
+ togglePower(device, callback) {
139
+ return this.action(device, Action_1.Action.TogglePower, callback);
140
+ }
141
+ toggleOpen(device, callback) {
142
+ return this.action(device, Action_1.Action.ToggleOpen, callback);
143
+ }
144
+ preset(device, callback) {
145
+ return this.action(device, Action_1.Action.Preset, callback);
146
+ }
147
+ stop(device, callback) {
148
+ return this.request(HTTPMethod.PUT, this.uri.action(device.id, Action_1.Action.Stop))
149
+ .then(() => {
150
+ if (callback) {
151
+ callback(null);
152
+ }
153
+ })
154
+ .catch((error) => {
155
+ if (callback) {
156
+ callback(Error(error));
157
+ }
158
+ });
159
+ }
160
+ setFanSpeed(device, speed, callback) {
161
+ const body = {
162
+ argument: speed,
163
+ };
164
+ return this.request(HTTPMethod.PUT, this.uri.action(device.id, Action_1.Action.SetSpeed), body)
165
+ .then(() => {
166
+ callback(null);
167
+ })
168
+ .catch((error) => {
169
+ callback(Error(error));
170
+ });
171
+ }
172
+ increaseSpeed(device, callback) {
173
+ const body = {
174
+ argument: 1,
175
+ };
176
+ return this.request(HTTPMethod.PUT, this.uri.action(device.id, Action_1.Action.IncreaseSpeed), body)
177
+ .then(() => {
178
+ callback(null);
179
+ })
180
+ .catch((error) => {
181
+ callback(Error(error));
182
+ });
183
+ }
184
+ decreaseSpeed(device, callback) {
185
+ const body = {
186
+ argument: 1,
187
+ };
188
+ return this.request(HTTPMethod.PUT, this.uri.action(device.id, Action_1.Action.DecreaseSpeed), body)
189
+ .then(() => {
190
+ callback(null);
191
+ })
192
+ .catch((error) => {
193
+ callback(Error(error));
194
+ });
195
+ }
196
+ // State
197
+ updateState(device, state, callback) {
198
+ return this.request(HTTPMethod.PATCH, this.uri.state(device.id), state)
199
+ .then(() => {
200
+ callback(null);
201
+ })
202
+ .catch((error) => {
203
+ callback(Error(error));
204
+ });
205
+ }
206
+ // PATCH: Toggle state property for a device
207
+ toggleState(device, property, callback) {
208
+ return this.getState(device.id)
209
+ .then(state => {
210
+ if (property !== 'open' && property !== 'power' && property !== 'light') {
211
+ callback(null);
212
+ throw Error(`This device does not have ${property} in it's Bond state`);
213
+ }
214
+ if (state[property] !== undefined) {
215
+ const newState = {};
216
+ newState[property] = state[property] === 1 ? 0 : 1;
217
+ return this.updateState(device, newState, callback);
218
+ }
219
+ else {
220
+ callback(null);
221
+ throw Error(`This device does not have ${property} in it's Bond state`);
222
+ }
223
+ });
224
+ }
225
+ // Commands
226
+ getCommands(deviceId) {
227
+ return this.getCommandIds(deviceId).then(ids => {
228
+ const ps = [];
229
+ ids.forEach(id => {
230
+ ps.push(this.getCommand(deviceId, id));
231
+ });
232
+ return Promise.all(ps);
233
+ });
234
+ }
235
+ getCommandIds(id) {
236
+ const req = this.request(HTTPMethod.GET, this.uri.commands(id));
237
+ return req.then(json => Object.keys(json).filter(x => {
238
+ // Ignore anything that is an empty string or '_'
239
+ return x.length > 0 && x !== '_';
240
+ }));
241
+ }
242
+ getCommand(deviceId, commandId) {
243
+ return this.request(HTTPMethod.GET, this.uri.command(deviceId, commandId));
244
+ }
245
+ // Properties
246
+ getProperties(id) {
247
+ return this.request(HTTPMethod.GET, this.uri.properties(id));
248
+ }
249
+ // Helpers
250
+ ping() {
251
+ const uuid = intformat(flakeIdGen.next(), 'hex', { prefix: '18', padstr: '0', size: 16 }); // avoid duplicate action
252
+ const bondUuid = uuid.substring(0, 13) + uuid.substring(15); // remove '00' used for datacenter/worker in flakeIdGen
253
+ return axios_1.default({
254
+ method: HTTPMethod.GET,
255
+ url: this.uri.deviceIds(),
256
+ headers: {
257
+ 'BOND-Token': this.bondToken,
258
+ 'Bond-UUID': bondUuid,
259
+ },
260
+ timeout: 1000,
261
+ });
262
+ }
263
+ request(method, uri, body = {}) {
264
+ const bodyStr = JSON.stringify(body);
265
+ const uuid = intformat(flakeIdGen.next(), 'hex', { prefix: '18', padstr: '0', size: 16 }); // avoid duplicate action
266
+ const bondUuid = uuid.substring(0, 13) + uuid.substring(15); // remove '00' used for datacenter/worker in flakeIdGen
267
+ if (bodyStr !== '{}') {
268
+ this.platform.log.debug(`Request (${bondUuid}) [${method} ${uri}] - body: ${bodyStr}`);
269
+ }
270
+ else {
271
+ this.platform.log.debug(`Request (${bondUuid}) [${method} ${uri}]`);
272
+ }
273
+ return axios_1.default({
274
+ method,
275
+ url: uri,
276
+ headers: {
277
+ 'BOND-Token': this.bondToken,
278
+ 'Bond-UUID': bondUuid,
279
+ },
280
+ data: body,
281
+ timeout: 10000,
282
+ })
283
+ .then(response => {
284
+ this.platform.log.debug(`Response (${bondUuid}) [${method} ${uri}] - ${JSON.stringify(response.data)}`);
285
+ return response.data;
286
+ })
287
+ .catch((error) => {
288
+ if (axios_1.default.isAxiosError(error) && error.response) {
289
+ const response = error.response;
290
+ switch (response.status) {
291
+ case 401:
292
+ this.platform.log.error('Unauthorized. Please check the `token` in your config to see if it is correct.');
293
+ return;
294
+ default:
295
+ this.platform.log.error(`A request error occurred: [status] ${response.status} [statusText] ${response.statusText}`);
296
+ }
297
+ }
298
+ else {
299
+ this.platform.log.error(`A request error occurred: ${JSON.stringify(error)}`);
300
+ }
301
+ });
302
+ }
303
+ }
304
+ exports.BondApi = BondApi;
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.BondUri = void 0;
4
+ class BondUri {
5
+ constructor(bondIP) {
6
+ this.bondIP = bondIP;
7
+ }
8
+ version() {
9
+ return `http://${this.bondIP}/v2/sys/version`;
10
+ }
11
+ deviceIds() {
12
+ return `http://${this.bondIP}/v2/devices`;
13
+ }
14
+ device(id) {
15
+ return `http://${this.bondIP}/v2/devices/${id}`;
16
+ }
17
+ state(id) {
18
+ return `http://${this.bondIP}/v2/devices/${id}/state`;
19
+ }
20
+ action(id, action) {
21
+ return `http://${this.bondIP}/v2/devices/${id}/actions/${action}`;
22
+ }
23
+ commands(id) {
24
+ return `http://${this.bondIP}/v2/devices/${id}/commands`;
25
+ }
26
+ command(deviceId, commandId) {
27
+ return `http://${this.bondIP}/v2/devices/${deviceId}/commands/${commandId}`;
28
+ }
29
+ properties(id) {
30
+ return `http://${this.bondIP}/v2/devices/${id}/properties`;
31
+ }
32
+ }
33
+ exports.BondUri = BondUri;
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Observer = void 0;
4
+ class Observer {
5
+ static set(characteristic, set) {
6
+ characteristic
7
+ .on('set', (value, callback) => {
8
+ // Avoid doing anything when the device is in the requested state
9
+ if (value === characteristic.value) {
10
+ callback(null);
11
+ return;
12
+ }
13
+ set(value, callback);
14
+ });
15
+ }
16
+ }
17
+ exports.Observer = Observer;