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,54 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LightAccessory = void 0;
4
+ const Device_1 = require("../interface/Device");
5
+ const Observer_1 = require("../Observer");
6
+ const Services_1 = require("../Services");
7
+ class LightAccessory {
8
+ constructor(platform, accessory, bond) {
9
+ this.platform = platform;
10
+ this.accessory = accessory;
11
+ this.lightService = new Services_1.LightbulbService(platform, accessory, `${accessory.displayName} Light`);
12
+ if (platform.config.include_toggle_state) {
13
+ this.toggleLightService = new Services_1.ButtonService(platform, accessory, 'Toggle Light State', 'ToggleState');
14
+ }
15
+ else {
16
+ this.removeService('Toggle Light State');
17
+ }
18
+ this.observe(bond);
19
+ }
20
+ updateState(state) {
21
+ this.lightService.updateState(state);
22
+ }
23
+ observe(bond) {
24
+ const device = this.accessory.context.device;
25
+ if (Device_1.Device.LThasLightbulb(device)) {
26
+ this.lightService.observe(this.platform, bond, this.accessory);
27
+ }
28
+ else {
29
+ this.platform.error(this.accessory, 'LightAccessory does not have required ToggleLight action.');
30
+ }
31
+ this.observeLightToggle(bond, device);
32
+ }
33
+ observeLightToggle(bond, device) {
34
+ if (!this.toggleLightService) {
35
+ return;
36
+ }
37
+ Observer_1.Observer.set(this.toggleLightService.on, (_, callback) => {
38
+ bond.api.toggleState(device, 'light', callback)
39
+ .then(() => {
40
+ this.platform.debug(this.accessory, `${device.name} light state toggled`);
41
+ })
42
+ .catch((error) => {
43
+ this.platform.error(this.accessory, `Error toggling light state: ${error}`);
44
+ });
45
+ });
46
+ }
47
+ removeService(serviceName) {
48
+ const service = this.accessory.getService(serviceName);
49
+ if (service) {
50
+ this.accessory.removeService(service);
51
+ }
52
+ }
53
+ }
54
+ exports.LightAccessory = LightAccessory;
@@ -0,0 +1,98 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ShadesAccessory = void 0;
4
+ const Device_1 = require("../interface/Device");
5
+ const Observer_1 = require("../Observer");
6
+ const Services_1 = require("../Services");
7
+ class ShadesAccessory {
8
+ constructor(platform, accessory, bond) {
9
+ this.platform = platform;
10
+ this.accessory = accessory;
11
+ const device = accessory.context.device;
12
+ this.windowCoveringService = new Services_1.WindowCoveringService(platform, accessory);
13
+ if (platform.config.include_toggle_state) {
14
+ this.toggleStateService = new Services_1.ButtonService(platform, accessory, 'Toggle State', 'ToggleState');
15
+ }
16
+ else {
17
+ this.removeService('Toggle State');
18
+ }
19
+ if (Device_1.Device.MShasPreset(device)) {
20
+ this.presetService = new Services_1.ButtonService(platform, accessory, 'Preset', 'Preset');
21
+ }
22
+ this.observe(bond);
23
+ }
24
+ updateState(state) {
25
+ if (this.windowCoveringService) {
26
+ // Always return either 0 or 100
27
+ this.windowCoveringService.currentPosition.updateValue(state.open === 1 ? 100 : 0);
28
+ this.windowCoveringService.targetPosition.updateValue(state.open === 1 ? 100 : 0);
29
+ }
30
+ }
31
+ observe(bond) {
32
+ const device = this.accessory.context.device;
33
+ this.observeWindowCovering(bond, device);
34
+ this.observePreset(bond, device);
35
+ this.observeToggleState(bond, device);
36
+ }
37
+ observeWindowCovering(bond, device) {
38
+ if (!Device_1.Device.MShasToggle(device)) {
39
+ this.platform.error(this.accessory, 'ShadesAccessory does not have required ToggleOpen action.');
40
+ return;
41
+ }
42
+ // Set initial state
43
+ bond.api.getState(device.id).then(state => {
44
+ this.updateState(state);
45
+ });
46
+ const props = {
47
+ minValue: 0,
48
+ maxValue: 100,
49
+ minStep: 100,
50
+ };
51
+ this.windowCoveringService.targetPosition.setProps(props);
52
+ Observer_1.Observer.set(this.windowCoveringService.targetPosition, (value, callback) => {
53
+ // Since we can't really track state, just toggle open / closed
54
+ bond.api.toggleOpen(device, callback)
55
+ .then(() => {
56
+ this.platform.debug(this.accessory, `Toggled open: ${value}`);
57
+ })
58
+ .catch((error) => {
59
+ this.platform.error(this.accessory, `Error toggling open: ${error}`);
60
+ });
61
+ });
62
+ }
63
+ observePreset(bond, device) {
64
+ if (!this.presetService) {
65
+ return;
66
+ }
67
+ Observer_1.Observer.set(this.presetService.on, (_, callback) => {
68
+ bond.api.preset(device, callback)
69
+ .then(() => {
70
+ this.platform.debug(this.accessory, 'Executed shade preset');
71
+ })
72
+ .catch((error) => {
73
+ this.platform.error(this.accessory, `Error executing preset: ${error}`);
74
+ });
75
+ });
76
+ }
77
+ observeToggleState(bond, device) {
78
+ if (!this.toggleStateService) {
79
+ return;
80
+ }
81
+ Observer_1.Observer.set(this.toggleStateService.on, (_, callback) => {
82
+ bond.api.toggleState(device, 'open', callback)
83
+ .then(() => {
84
+ this.platform.debug(this.accessory, `${device.name} open state toggled`);
85
+ })
86
+ .catch((error) => {
87
+ this.platform.error(this.accessory, `Error toggling open state: ${error}`);
88
+ });
89
+ });
90
+ }
91
+ removeService(serviceName) {
92
+ const service = this.accessory.getService(serviceName);
93
+ if (service) {
94
+ this.accessory.removeService(service);
95
+ }
96
+ }
97
+ }
98
+ exports.ShadesAccessory = ShadesAccessory;
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Action = void 0;
4
+ var Action;
5
+ (function (Action) {
6
+ Action["ToggleLight"] = "ToggleLight";
7
+ Action["ToggleUpLight"] = "ToggleUpLight";
8
+ Action["ToggleDownLight"] = "ToggleDownLight";
9
+ Action["TurnOff"] = "TurnOff";
10
+ Action["TurnOn"] = "TurnOn";
11
+ Action["StartDimmer"] = "StartDimmer";
12
+ Action["StartUpLightDimmer"] = "StartUpLightDimmer";
13
+ Action["StartDownLightDimmer"] = "StartDownLightDimmer";
14
+ Action["StartIncreasingBrightness"] = "StartIncreasingBrightness";
15
+ Action["StartDecreasingBrightness"] = "StartDecreasingBrightness";
16
+ Action["Stop"] = "Stop";
17
+ Action["SetBrightness"] = "SetBrightness";
18
+ Action["SetSpeed"] = "SetSpeed";
19
+ Action["IncreaseSpeed"] = "IncreaseSpeed";
20
+ Action["DecreaseSpeed"] = "DecreaseSpeed";
21
+ Action["ToggleDirection"] = "ToggleDirection";
22
+ Action["TogglePower"] = "TogglePower";
23
+ Action["ToggleOpen"] = "ToggleOpen";
24
+ Action["TurnLightOff"] = "TurnLightOff";
25
+ Action["Open"] = "Open";
26
+ Action["Close"] = "Close";
27
+ Action["Preset"] = "Preset";
28
+ Action["SetFlame"] = "SetFlame";
29
+ })(Action = exports.Action || (exports.Action = {}));
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DeviceType = void 0;
4
+ var DeviceType;
5
+ (function (DeviceType) {
6
+ DeviceType["CeilingFan"] = "CF";
7
+ DeviceType["Shades"] = "MS";
8
+ DeviceType["Generic"] = "GX";
9
+ DeviceType["Fireplace"] = "FP";
10
+ DeviceType["Light"] = "LT";
11
+ })(DeviceType = exports.DeviceType || (exports.DeviceType = {}));
package/dist/index.js ADDED
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const settings_1 = require("./settings");
4
+ const platform_1 = require("./platform");
5
+ /**
6
+ * This method registers the platform with Homebridge
7
+ */
8
+ exports.default = (api) => {
9
+ api.registerPlatform(settings_1.PLUGIN_NAME, settings_1.PLATFORM_NAME, platform_1.BondPlatform);
10
+ };
@@ -0,0 +1,124 @@
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.BPUPMethod = exports.Bond = void 0;
7
+ const BondApi_1 = require("../BondApi");
8
+ const axios_1 = __importDefault(require("axios"));
9
+ class Bond {
10
+ constructor(platform, config) {
11
+ this.platform = platform;
12
+ this.deviceIds = [];
13
+ this.accessories = [];
14
+ this.config = config;
15
+ this.api = new BondApi_1.BondApi(platform, config.token, config.ip_address);
16
+ }
17
+ // Helper to sanitze the config object into bond objects
18
+ static objects(platform) {
19
+ const config = platform.config;
20
+ const bondData = config.bonds;
21
+ const bondObjs = bondData.map(config => {
22
+ return new Bond(platform, config);
23
+ });
24
+ return bondObjs;
25
+ }
26
+ // Helper to update the device ids of a group of bonds
27
+ static validate(bonds) {
28
+ const ps = [];
29
+ bonds.forEach(bond => {
30
+ ps.push(bond.validate());
31
+ });
32
+ return Promise.all(ps);
33
+ }
34
+ validate() {
35
+ const bond = this;
36
+ return this.api
37
+ .ping()
38
+ .then(() => {
39
+ return bond;
40
+ })
41
+ .catch((error) => {
42
+ var _a;
43
+ if (axios_1.default.isAxiosError(error) && error.response) {
44
+ const response = error.response;
45
+ switch (response.status) {
46
+ case 401:
47
+ this.platform.log.error('Unauthorized. Please check the `token` in your config to see if it is correct.');
48
+ return;
49
+ default:
50
+ this.platform.log.error(`A request error occurred: [status] ${response.status} [statusText] ${response.statusText}`);
51
+ }
52
+ }
53
+ else if (error.code === 'ECONNABORTED') {
54
+ this.platform.log.error(`Unable to find Bond for IP Address: ${bond.config.ip_address}. Skipping this Bond.`);
55
+ }
56
+ else {
57
+ this.platform.log.error(`A request error occurred: ${JSON.stringify(error)} [code] ${(_a = error.code) !== null && _a !== void 0 ? _a : ''}`);
58
+ }
59
+ });
60
+ }
61
+ // Helper to update the device ids of a group of bonds
62
+ static updateDeviceIds(bonds) {
63
+ const ps = [];
64
+ bonds.forEach(bond => {
65
+ ps.push(bond.updateDeviceIds());
66
+ ps.push(bond.updateBondId());
67
+ });
68
+ return Promise.all(ps);
69
+ }
70
+ updateDeviceIds() {
71
+ return this.api
72
+ .getDeviceIds()
73
+ .then(ids => {
74
+ this.deviceIds = ids;
75
+ })
76
+ .catch(error => {
77
+ this.platform.log.error(`Error getting device ids: ${error}`);
78
+ });
79
+ }
80
+ updateBondId() {
81
+ return this.api.getVersion()
82
+ .then(version => {
83
+ var _a, _b;
84
+ this.version = version;
85
+ this.platform.log.debug(`
86
+ ****** Bond Info *******
87
+ bondId: ${version.bondid}
88
+ FW: ${version.fw_ver}
89
+ API: v${version.api}
90
+ Make: ${(_a = version.make) !== null && _a !== void 0 ? _a : 'N/A'}
91
+ Model: ${(_b = version.model) !== null && _b !== void 0 ? _b : 'N/A'}\n************************`);
92
+ })
93
+ .catch(error => {
94
+ this.platform.log.error(`Error getting version: ${error}`);
95
+ });
96
+ }
97
+ // ID should be unique across multiple bonds in case device's have the same id across bonds.
98
+ uniqueDeviceId(deviceId) {
99
+ return `${this.version.bondid}${deviceId}`;
100
+ }
101
+ receivedBPUPPacket(packet) {
102
+ this.accessories.forEach(accessory => {
103
+ const device = accessory.accessory.context.device;
104
+ // Topic structure is 'devices/[device_id]/state'
105
+ if (packet.t
106
+ && packet.t.includes(device.id)
107
+ && packet.t.includes('state')
108
+ && packet.b) {
109
+ const state = packet.b;
110
+ this.platform.debug(accessory.accessory, 'Received new state: ' + JSON.stringify(state));
111
+ accessory.updateState(state);
112
+ }
113
+ });
114
+ }
115
+ }
116
+ exports.Bond = Bond;
117
+ var BPUPMethod;
118
+ (function (BPUPMethod) {
119
+ BPUPMethod[BPUPMethod["GET"] = 0] = "GET";
120
+ BPUPMethod[BPUPMethod["POST"] = 1] = "POST";
121
+ BPUPMethod[BPUPMethod["PUT"] = 2] = "PUT";
122
+ BPUPMethod[BPUPMethod["DELETE"] = 3] = "DELETE";
123
+ BPUPMethod[BPUPMethod["PATCH"] = 4] = "PATCH";
124
+ })(BPUPMethod = exports.BPUPMethod || (exports.BPUPMethod = {}));
@@ -0,0 +1,125 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Device = void 0;
4
+ const Action_1 = require("../enum/Action");
5
+ const DeviceType_1 = require("../enum/DeviceType");
6
+ // eslint-disable-next-line @typescript-eslint/no-namespace
7
+ var Device;
8
+ (function (Device) {
9
+ function displayName(device) {
10
+ return `${device.location} ${device.name}`;
11
+ }
12
+ Device.displayName = displayName;
13
+ function isSupported(device) {
14
+ const supported = [DeviceType_1.DeviceType.CeilingFan, DeviceType_1.DeviceType.Generic, DeviceType_1.DeviceType.Fireplace, DeviceType_1.DeviceType.Shades, DeviceType_1.DeviceType.Light];
15
+ return supported.includes(device.type);
16
+ }
17
+ Device.isSupported = isSupported;
18
+ function HasDimmer(device) {
19
+ const dimmer = [Action_1.Action.StartDimmer];
20
+ return device.actions.some(r => dimmer.includes(r));
21
+ }
22
+ Device.HasDimmer = HasDimmer;
23
+ function HasSeparateDimmers(device) {
24
+ const required = [Action_1.Action.StartIncreasingBrightness, Action_1.Action.StartDecreasingBrightness];
25
+ return required.every(r => device.actions.includes(r));
26
+ }
27
+ Device.HasSeparateDimmers = HasSeparateDimmers;
28
+ function CFhasLightbulb(device) {
29
+ const lightbulb = [Action_1.Action.ToggleLight];
30
+ return device.actions.some(r => lightbulb.includes(r));
31
+ }
32
+ Device.CFhasLightbulb = CFhasLightbulb;
33
+ function CFhasUpDownLight(device) {
34
+ const required = [Action_1.Action.ToggleUpLight, Action_1.Action.ToggleDownLight];
35
+ return required.every(r => device.actions.includes(r));
36
+ }
37
+ Device.CFhasUpDownLight = CFhasUpDownLight;
38
+ function canSetSpeed(device) {
39
+ const required = [Action_1.Action.SetSpeed];
40
+ const hasSetSpeed = required.every(r => device.actions.includes(r));
41
+ const hasMaxSpeed = device.properties.max_speed !== undefined;
42
+ return hasSetSpeed && hasMaxSpeed;
43
+ }
44
+ Device.canSetSpeed = canSetSpeed;
45
+ function canIncreaseDecreaseSpeed(device) {
46
+ const required = [Action_1.Action.IncreaseSpeed, Action_1.Action.DecreaseSpeed];
47
+ return required.every(r => device.actions.includes(r));
48
+ }
49
+ Device.canIncreaseDecreaseSpeed = canIncreaseDecreaseSpeed;
50
+ function hasOffOn(device) {
51
+ const required = [Action_1.Action.TurnOff, Action_1.Action.TurnOn];
52
+ return required.every(r => device.actions.includes(r));
53
+ }
54
+ Device.hasOffOn = hasOffOn;
55
+ function hasReverseSwitch(device) {
56
+ const required = [Action_1.Action.ToggleDirection];
57
+ return required.every(r => device.actions.includes(r));
58
+ }
59
+ Device.hasReverseSwitch = hasReverseSwitch;
60
+ function GXhasToggle(device) {
61
+ const fan = [Action_1.Action.TogglePower];
62
+ return device.actions.some(r => fan.includes(r));
63
+ }
64
+ Device.GXhasToggle = GXhasToggle;
65
+ function FPhasToggle(device) {
66
+ const fan = [Action_1.Action.TogglePower];
67
+ return device.actions.some(r => fan.includes(r));
68
+ }
69
+ Device.FPhasToggle = FPhasToggle;
70
+ function FPhasFlame(device) {
71
+ const required = [Action_1.Action.SetFlame, Action_1.Action.TogglePower];
72
+ return required.every(r => device.actions.includes(r));
73
+ }
74
+ Device.FPhasFlame = FPhasFlame;
75
+ function MShasToggle(device) {
76
+ const fan = [Action_1.Action.ToggleOpen];
77
+ return device.actions.some(r => fan.includes(r));
78
+ }
79
+ Device.MShasToggle = MShasToggle;
80
+ function MShasPreset(device) {
81
+ const required = [Action_1.Action.Preset];
82
+ return required.every(r => device.actions.includes(r));
83
+ }
84
+ Device.MShasPreset = MShasPreset;
85
+ function LThasLightbulb(device) {
86
+ const lightbulb = [Action_1.Action.ToggleLight];
87
+ return device.actions.some(r => lightbulb.includes(r));
88
+ }
89
+ Device.LThasLightbulb = LThasLightbulb;
90
+ function LThasBrightness(device) {
91
+ const required = [Action_1.Action.SetBrightness, Action_1.Action.TurnLightOff];
92
+ return required.every(r => device.actions.includes(r));
93
+ }
94
+ Device.LThasBrightness = LThasBrightness;
95
+ function fanSpeeds(device) {
96
+ if (device.commands) {
97
+ const values = device.commands
98
+ .filter(cmd => {
99
+ // Find all of the commands associated with speed
100
+ return cmd.action === Action_1.Action.SetSpeed;
101
+ })
102
+ .sort((a, b) => {
103
+ // sort them
104
+ return a.argument < b.argument ? 0 : 1;
105
+ })
106
+ .map(cmd => {
107
+ // map down to the raw argument values from that command
108
+ return cmd.argument || 0;
109
+ });
110
+ return values.sort();
111
+ }
112
+ else if (device.properties.max_speed === undefined || device.properties.max_speed === null) {
113
+ return [];
114
+ }
115
+ else {
116
+ // Assume speeds 1 - max_speed
117
+ const max_speed = device.properties.max_speed;
118
+ const vals = Array(max_speed)
119
+ .fill(1)
120
+ .map((x, y) => x + y);
121
+ return vals.sort();
122
+ }
123
+ }
124
+ Device.fanSpeeds = fanSpeeds;
125
+ })(Device = exports.Device || (exports.Device = {}));
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.BondConfig = exports.BondPlatformConfig = void 0;
4
+ // eslint-disable-next-line @typescript-eslint/no-namespace
5
+ var BondPlatformConfig;
6
+ (function (BondPlatformConfig) {
7
+ function isValid(platform) {
8
+ const cast = platform.config;
9
+ function evaluate(type, key) {
10
+ const value = cast[key];
11
+ if (value !== undefined && typeof (value) !== type) {
12
+ platform.log.error(`${key} has invalid value: ${value}. Expected ${type}, got ${typeof (value)}.`);
13
+ return false;
14
+ }
15
+ return true;
16
+ }
17
+ const validDimmer = evaluate('boolean', 'include_dimmer');
18
+ const validFanSpeed = evaluate('boolean', 'fan_speed_values');
19
+ const validToggleState = evaluate('boolean', 'include_toggle_state');
20
+ if (cast.bonds === undefined || cast.bonds.length === 0) {
21
+ platform.log.error('Missing bonds in config');
22
+ return false;
23
+ }
24
+ const bondsValid = cast.bonds.map(bond => {
25
+ return BondConfig.isValid(platform, bond);
26
+ }).every(v => v === true);
27
+ return validDimmer && validFanSpeed && validToggleState && bondsValid;
28
+ }
29
+ BondPlatformConfig.isValid = isValid;
30
+ })(BondPlatformConfig = exports.BondPlatformConfig || (exports.BondPlatformConfig = {}));
31
+ // eslint-disable-next-line @typescript-eslint/no-namespace
32
+ var BondConfig;
33
+ (function (BondConfig) {
34
+ function isValid(platform, config) {
35
+ function evaluate(type, key, value) {
36
+ if (value === undefined) {
37
+ platform.log.error(`Missing ${key} in BondConfig.`);
38
+ return false;
39
+ }
40
+ if (typeof (value) !== type) {
41
+ platform.log.error(`BondConfig ${key} has invalid value: ${value}. Expected ${type}, got ${typeof (value)}.`);
42
+ return false;
43
+ }
44
+ return true;
45
+ }
46
+ const validIP = evaluate('string', 'ip_address', config.ip_address);
47
+ const validToken = evaluate('string', 'token', config.token);
48
+ let validHideDeviceIds = true;
49
+ if (config.hide_device_ids !== undefined) {
50
+ validHideDeviceIds = config.hide_device_ids.map(id => {
51
+ if (typeof (id) !== 'string') {
52
+ platform.log.error(`hide_device_ids contains invalid value: ${id}. Expected string, got ${typeof (id)}.`);
53
+ return false;
54
+ }
55
+ return true;
56
+ }).every(v => v === true);
57
+ }
58
+ return validIP && validToken && validHideDeviceIds;
59
+ }
60
+ BondConfig.isValid = isValid;
61
+ })(BondConfig = exports.BondConfig || (exports.BondConfig = {}));