homebridge-smartika 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +367 -0
- package/config.schema.json +71 -0
- package/package.json +57 -0
- package/src/SmartikaCrypto.js +134 -0
- package/src/SmartikaDiscovery.js +177 -0
- package/src/SmartikaHubConnection.js +528 -0
- package/src/SmartikaPlatform.js +379 -0
- package/src/SmartikaProtocol.js +977 -0
- package/src/accessories/SmartikaFanAccessory.js +162 -0
- package/src/accessories/SmartikaLightAccessory.js +203 -0
- package/src/accessories/SmartikaPlugAccessory.js +112 -0
- package/src/index.js +12 -0
- package/src/settings.js +16 -0
- package/tools/smartika-cli.js +1443 -0
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Smartika Fan Accessory
|
|
5
|
+
*
|
|
6
|
+
* Exposes Smartika ceiling fan devices to HomeKit with support for:
|
|
7
|
+
* - On/Off control
|
|
8
|
+
* - Rotation Speed
|
|
9
|
+
*/
|
|
10
|
+
class SmartikaFanAccessory {
|
|
11
|
+
/**
|
|
12
|
+
* @param {import('../SmartikaPlatform')} platform
|
|
13
|
+
* @param {import('homebridge').PlatformAccessory} accessory
|
|
14
|
+
* @param {Object} device - Device info from hub
|
|
15
|
+
*/
|
|
16
|
+
constructor(platform, accessory, device) {
|
|
17
|
+
this.platform = platform;
|
|
18
|
+
this.accessory = accessory;
|
|
19
|
+
this.device = device;
|
|
20
|
+
this.log = platform.log;
|
|
21
|
+
|
|
22
|
+
// HAP references
|
|
23
|
+
this.Service = platform.api.hap.Service;
|
|
24
|
+
this.Characteristic = platform.api.hap.Characteristic;
|
|
25
|
+
|
|
26
|
+
// Current state
|
|
27
|
+
this.state = {
|
|
28
|
+
active: false,
|
|
29
|
+
rotationSpeed: 0,
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
// Configure the fan service
|
|
33
|
+
this.configureService();
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Configure the Fanv2 service
|
|
38
|
+
*/
|
|
39
|
+
configureService() {
|
|
40
|
+
// Use Fanv2 for better HomeKit support
|
|
41
|
+
this.service = this.accessory.getService(this.Service.Fanv2) ||
|
|
42
|
+
this.accessory.addService(this.Service.Fanv2, this.device.typeName);
|
|
43
|
+
|
|
44
|
+
// Set the service name
|
|
45
|
+
this.service.setCharacteristic(this.Characteristic.Name, this.device.typeName);
|
|
46
|
+
|
|
47
|
+
// Configure Active characteristic (on/off)
|
|
48
|
+
this.service.getCharacteristic(this.Characteristic.Active)
|
|
49
|
+
.onGet(this.getActive.bind(this))
|
|
50
|
+
.onSet(this.setActive.bind(this));
|
|
51
|
+
|
|
52
|
+
// Configure RotationSpeed characteristic
|
|
53
|
+
this.service.getCharacteristic(this.Characteristic.RotationSpeed)
|
|
54
|
+
.onGet(this.getRotationSpeed.bind(this))
|
|
55
|
+
.onSet(this.setRotationSpeed.bind(this))
|
|
56
|
+
.setProps({
|
|
57
|
+
minValue: 0,
|
|
58
|
+
maxValue: 100,
|
|
59
|
+
minStep: 1,
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
this.log.debug(`Configured fan accessory: ${this.device.typeName} (0x${this.device.shortAddress.toString(16)})`);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Handle GET Active
|
|
67
|
+
* @returns {number} - 0 (INACTIVE) or 1 (ACTIVE)
|
|
68
|
+
*/
|
|
69
|
+
getActive() {
|
|
70
|
+
this.log.debug(`GET Active for ${this.device.typeName}: ${this.state.active}`);
|
|
71
|
+
return this.state.active ? 1 : 0;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Handle SET Active
|
|
76
|
+
* @param {number} value - 0 (INACTIVE) or 1 (ACTIVE)
|
|
77
|
+
*/
|
|
78
|
+
async setActive(value) {
|
|
79
|
+
const active = value === 1;
|
|
80
|
+
this.log.info(`SET Active for ${this.device.typeName}: ${active}`);
|
|
81
|
+
|
|
82
|
+
try {
|
|
83
|
+
await this.platform.hub.setDevicePower(active, [this.device.shortAddress]);
|
|
84
|
+
this.state.active = active;
|
|
85
|
+
|
|
86
|
+
// If turning on and speed is 0, set a default speed
|
|
87
|
+
if (active && this.state.rotationSpeed === 0) {
|
|
88
|
+
this.state.rotationSpeed = 50;
|
|
89
|
+
this.service.updateCharacteristic(this.Characteristic.RotationSpeed, 50);
|
|
90
|
+
}
|
|
91
|
+
} catch (error) {
|
|
92
|
+
this.log.error(`Failed to set power for ${this.device.typeName}:`, error.message);
|
|
93
|
+
throw new this.platform.api.hap.HapStatusError(
|
|
94
|
+
this.platform.api.hap.HAPStatus.SERVICE_COMMUNICATION_FAILURE,
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Handle GET RotationSpeed
|
|
101
|
+
* @returns {number} - Speed percentage (0-100)
|
|
102
|
+
*/
|
|
103
|
+
getRotationSpeed() {
|
|
104
|
+
this.log.debug(`GET RotationSpeed for ${this.device.typeName}: ${this.state.rotationSpeed}%`);
|
|
105
|
+
return this.state.rotationSpeed;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Handle SET RotationSpeed
|
|
110
|
+
* @param {number} value - Speed percentage (0-100)
|
|
111
|
+
*/
|
|
112
|
+
async setRotationSpeed(value) {
|
|
113
|
+
this.log.info(`SET RotationSpeed for ${this.device.typeName}: ${value}%`);
|
|
114
|
+
|
|
115
|
+
try {
|
|
116
|
+
// Convert 0-100% to 0-255
|
|
117
|
+
const speed255 = Math.round(value / 100 * 255);
|
|
118
|
+
await this.platform.hub.setFanSpeed(speed255, [this.device.shortAddress]);
|
|
119
|
+
this.state.rotationSpeed = value;
|
|
120
|
+
|
|
121
|
+
// Update active state based on speed
|
|
122
|
+
if (value > 0 && !this.state.active) {
|
|
123
|
+
this.state.active = true;
|
|
124
|
+
this.service.updateCharacteristic(this.Characteristic.Active, 1);
|
|
125
|
+
} else if (value === 0 && this.state.active) {
|
|
126
|
+
this.state.active = false;
|
|
127
|
+
this.service.updateCharacteristic(this.Characteristic.Active, 0);
|
|
128
|
+
}
|
|
129
|
+
} catch (error) {
|
|
130
|
+
this.log.error(`Failed to set fan speed for ${this.device.typeName}:`, error.message);
|
|
131
|
+
throw new this.platform.api.hap.HapStatusError(
|
|
132
|
+
this.platform.api.hap.HAPStatus.SERVICE_COMMUNICATION_FAILURE,
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Update state from hub status
|
|
139
|
+
* @param {Object} status - Status from hub
|
|
140
|
+
*/
|
|
141
|
+
updateStatus(status) {
|
|
142
|
+
// Update Active state
|
|
143
|
+
if (status.on !== undefined && status.on !== this.state.active) {
|
|
144
|
+
this.state.active = status.on;
|
|
145
|
+
this.service.updateCharacteristic(this.Characteristic.Active, status.on ? 1 : 0);
|
|
146
|
+
this.log.debug(`Updated ${this.device.typeName} Active: ${status.on}`);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Update RotationSpeed
|
|
150
|
+
if (status.speed !== undefined) {
|
|
151
|
+
// Convert 0-255 to 0-100%
|
|
152
|
+
const speed = Math.round(status.speed / 255 * 100);
|
|
153
|
+
if (speed !== this.state.rotationSpeed) {
|
|
154
|
+
this.state.rotationSpeed = speed;
|
|
155
|
+
this.service.updateCharacteristic(this.Characteristic.RotationSpeed, speed);
|
|
156
|
+
this.log.debug(`Updated ${this.device.typeName} RotationSpeed: ${speed}%`);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
module.exports = SmartikaFanAccessory;
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Smartika Light Accessory
|
|
5
|
+
*
|
|
6
|
+
* Exposes Smartika light devices to HomeKit with support for:
|
|
7
|
+
* - On/Off control
|
|
8
|
+
* - Brightness (dimming)
|
|
9
|
+
* - Color Temperature
|
|
10
|
+
*/
|
|
11
|
+
class SmartikaLightAccessory {
|
|
12
|
+
/**
|
|
13
|
+
* @param {import('../SmartikaPlatform')} platform
|
|
14
|
+
* @param {import('homebridge').PlatformAccessory} accessory
|
|
15
|
+
* @param {Object} device - Device info from hub
|
|
16
|
+
*/
|
|
17
|
+
constructor(platform, accessory, device) {
|
|
18
|
+
this.platform = platform;
|
|
19
|
+
this.accessory = accessory;
|
|
20
|
+
this.device = device;
|
|
21
|
+
this.log = platform.log;
|
|
22
|
+
|
|
23
|
+
// HAP references
|
|
24
|
+
this.Service = platform.api.hap.Service;
|
|
25
|
+
this.Characteristic = platform.api.hap.Characteristic;
|
|
26
|
+
|
|
27
|
+
// Current state
|
|
28
|
+
this.state = {
|
|
29
|
+
on: false,
|
|
30
|
+
brightness: 100,
|
|
31
|
+
colorTemperature: 200, // HomeKit: 140-500 mireds
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
// Configure the lightbulb service
|
|
35
|
+
this.configureService();
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Configure the Lightbulb service
|
|
40
|
+
*/
|
|
41
|
+
configureService() {
|
|
42
|
+
// Get or create the Lightbulb service
|
|
43
|
+
this.service = this.accessory.getService(this.Service.Lightbulb) ||
|
|
44
|
+
this.accessory.addService(this.Service.Lightbulb, this.device.typeName);
|
|
45
|
+
|
|
46
|
+
// Set the service name
|
|
47
|
+
this.service.setCharacteristic(this.Characteristic.Name, this.device.typeName);
|
|
48
|
+
|
|
49
|
+
// Configure On characteristic
|
|
50
|
+
this.service.getCharacteristic(this.Characteristic.On)
|
|
51
|
+
.onGet(this.getOn.bind(this))
|
|
52
|
+
.onSet(this.setOn.bind(this));
|
|
53
|
+
|
|
54
|
+
// Configure Brightness characteristic
|
|
55
|
+
this.service.getCharacteristic(this.Characteristic.Brightness)
|
|
56
|
+
.onGet(this.getBrightness.bind(this))
|
|
57
|
+
.onSet(this.setBrightness.bind(this));
|
|
58
|
+
|
|
59
|
+
// Configure Color Temperature characteristic (if device supports it)
|
|
60
|
+
// Most Smartika lights support color temperature
|
|
61
|
+
this.service.getCharacteristic(this.Characteristic.ColorTemperature)
|
|
62
|
+
.onGet(this.getColorTemperature.bind(this))
|
|
63
|
+
.onSet(this.setColorTemperature.bind(this))
|
|
64
|
+
.setProps({
|
|
65
|
+
minValue: 140, // ~7142K (cool white)
|
|
66
|
+
maxValue: 500, // ~2000K (warm white)
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
this.log.debug(`Configured light accessory: ${this.device.typeName} (0x${this.device.shortAddress.toString(16)})`);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Handle GET On
|
|
74
|
+
* @returns {boolean}
|
|
75
|
+
*/
|
|
76
|
+
getOn() {
|
|
77
|
+
this.log.debug(`GET On for ${this.device.typeName}: ${this.state.on}`);
|
|
78
|
+
return this.state.on;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Handle SET On
|
|
83
|
+
* @param {boolean} value
|
|
84
|
+
*/
|
|
85
|
+
async setOn(value) {
|
|
86
|
+
this.log.info(`SET On for ${this.device.typeName}: ${value}`);
|
|
87
|
+
|
|
88
|
+
try {
|
|
89
|
+
await this.platform.hub.setDevicePower(value, [this.device.shortAddress]);
|
|
90
|
+
this.state.on = value;
|
|
91
|
+
} catch (error) {
|
|
92
|
+
this.log.error(`Failed to set power for ${this.device.typeName}:`, error.message);
|
|
93
|
+
throw new this.platform.api.hap.HapStatusError(
|
|
94
|
+
this.platform.api.hap.HAPStatus.SERVICE_COMMUNICATION_FAILURE,
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Handle GET Brightness
|
|
101
|
+
* @returns {number} - Brightness percentage (0-100)
|
|
102
|
+
*/
|
|
103
|
+
getBrightness() {
|
|
104
|
+
this.log.debug(`GET Brightness for ${this.device.typeName}: ${this.state.brightness}%`);
|
|
105
|
+
return this.state.brightness;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Handle SET Brightness
|
|
110
|
+
* @param {number} value - Brightness percentage (0-100)
|
|
111
|
+
*/
|
|
112
|
+
async setBrightness(value) {
|
|
113
|
+
this.log.info(`SET Brightness for ${this.device.typeName}: ${value}%`);
|
|
114
|
+
|
|
115
|
+
try {
|
|
116
|
+
// Convert 0-100% to 0-255
|
|
117
|
+
const brightness255 = Math.round(value / 100 * 255);
|
|
118
|
+
await this.platform.hub.setLightBrightness(brightness255, [this.device.shortAddress]);
|
|
119
|
+
this.state.brightness = value;
|
|
120
|
+
|
|
121
|
+
// If brightness is set to > 0, ensure light is on
|
|
122
|
+
if (value > 0 && !this.state.on) {
|
|
123
|
+
this.state.on = true;
|
|
124
|
+
this.service.updateCharacteristic(this.Characteristic.On, true);
|
|
125
|
+
}
|
|
126
|
+
} catch (error) {
|
|
127
|
+
this.log.error(`Failed to set brightness for ${this.device.typeName}:`, error.message);
|
|
128
|
+
throw new this.platform.api.hap.HapStatusError(
|
|
129
|
+
this.platform.api.hap.HAPStatus.SERVICE_COMMUNICATION_FAILURE,
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Handle GET ColorTemperature
|
|
136
|
+
* @returns {number} - Color temperature in mireds (140-500)
|
|
137
|
+
*/
|
|
138
|
+
getColorTemperature() {
|
|
139
|
+
this.log.debug(`GET ColorTemperature for ${this.device.typeName}: ${this.state.colorTemperature} mireds`);
|
|
140
|
+
return this.state.colorTemperature;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Handle SET ColorTemperature
|
|
145
|
+
* @param {number} value - Color temperature in mireds (140-500)
|
|
146
|
+
*/
|
|
147
|
+
async setColorTemperature(value) {
|
|
148
|
+
this.log.info(`SET ColorTemperature for ${this.device.typeName}: ${value} mireds`);
|
|
149
|
+
|
|
150
|
+
try {
|
|
151
|
+
// Convert mireds to Smartika temperature (0=warm, 255=cool)
|
|
152
|
+
// HomeKit: 140 (cool/7142K) to 500 (warm/2000K)
|
|
153
|
+
// Smartika: 0 (warm) to 255 (cool)
|
|
154
|
+
// So we need to invert: higher mireds = warmer = lower Smartika value
|
|
155
|
+
const temp255 = Math.round((500 - value) / (500 - 140) * 255);
|
|
156
|
+
await this.platform.hub.setLightTemperature(temp255, [this.device.shortAddress]);
|
|
157
|
+
this.state.colorTemperature = value;
|
|
158
|
+
} catch (error) {
|
|
159
|
+
this.log.error(`Failed to set color temperature for ${this.device.typeName}:`, error.message);
|
|
160
|
+
throw new this.platform.api.hap.HapStatusError(
|
|
161
|
+
this.platform.api.hap.HAPStatus.SERVICE_COMMUNICATION_FAILURE,
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Update state from hub status
|
|
168
|
+
* @param {Object} status - Status from hub
|
|
169
|
+
*/
|
|
170
|
+
updateStatus(status) {
|
|
171
|
+
// Update On state
|
|
172
|
+
if (status.on !== undefined && status.on !== this.state.on) {
|
|
173
|
+
this.state.on = status.on;
|
|
174
|
+
this.service.updateCharacteristic(this.Characteristic.On, status.on);
|
|
175
|
+
this.log.debug(`Updated ${this.device.typeName} On: ${status.on}`);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Update Brightness
|
|
179
|
+
if (status.brightness !== undefined) {
|
|
180
|
+
// Convert 0-255 to 0-100%
|
|
181
|
+
const brightness = Math.round(status.brightness / 255 * 100);
|
|
182
|
+
if (brightness !== this.state.brightness) {
|
|
183
|
+
this.state.brightness = brightness;
|
|
184
|
+
this.service.updateCharacteristic(this.Characteristic.Brightness, brightness);
|
|
185
|
+
this.log.debug(`Updated ${this.device.typeName} Brightness: ${brightness}%`);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// Update Color Temperature
|
|
190
|
+
if (status.temperature !== undefined) {
|
|
191
|
+
// Convert Smartika temperature (0=warm, 255=cool) to mireds (140-500)
|
|
192
|
+
// Invert: lower Smartika = warmer = higher mireds
|
|
193
|
+
const mireds = Math.round(500 - (status.temperature / 255 * (500 - 140)));
|
|
194
|
+
if (mireds !== this.state.colorTemperature) {
|
|
195
|
+
this.state.colorTemperature = mireds;
|
|
196
|
+
this.service.updateCharacteristic(this.Characteristic.ColorTemperature, mireds);
|
|
197
|
+
this.log.debug(`Updated ${this.device.typeName} ColorTemperature: ${mireds} mireds`);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
module.exports = SmartikaLightAccessory;
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Smartika Plug Accessory
|
|
5
|
+
*
|
|
6
|
+
* Exposes Smartika smart plug devices to HomeKit with support for:
|
|
7
|
+
* - On/Off control
|
|
8
|
+
*/
|
|
9
|
+
class SmartikaPlugAccessory {
|
|
10
|
+
/**
|
|
11
|
+
* @param {import('../SmartikaPlatform')} platform
|
|
12
|
+
* @param {import('homebridge').PlatformAccessory} accessory
|
|
13
|
+
* @param {Object} device - Device info from hub
|
|
14
|
+
*/
|
|
15
|
+
constructor(platform, accessory, device) {
|
|
16
|
+
this.platform = platform;
|
|
17
|
+
this.accessory = accessory;
|
|
18
|
+
this.device = device;
|
|
19
|
+
this.log = platform.log;
|
|
20
|
+
|
|
21
|
+
// HAP references
|
|
22
|
+
this.Service = platform.api.hap.Service;
|
|
23
|
+
this.Characteristic = platform.api.hap.Characteristic;
|
|
24
|
+
|
|
25
|
+
// Current state
|
|
26
|
+
this.state = {
|
|
27
|
+
on: false,
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
// Configure the outlet service
|
|
31
|
+
this.configureService();
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Configure the Outlet service
|
|
36
|
+
*/
|
|
37
|
+
configureService() {
|
|
38
|
+
// Get or create the Outlet service
|
|
39
|
+
this.service = this.accessory.getService(this.Service.Outlet) ||
|
|
40
|
+
this.accessory.addService(this.Service.Outlet, this.device.typeName);
|
|
41
|
+
|
|
42
|
+
// Set the service name
|
|
43
|
+
this.service.setCharacteristic(this.Characteristic.Name, this.device.typeName);
|
|
44
|
+
|
|
45
|
+
// Configure On characteristic
|
|
46
|
+
this.service.getCharacteristic(this.Characteristic.On)
|
|
47
|
+
.onGet(this.getOn.bind(this))
|
|
48
|
+
.onSet(this.setOn.bind(this));
|
|
49
|
+
|
|
50
|
+
// Configure OutletInUse characteristic (we'll assume it's in use if it's on)
|
|
51
|
+
this.service.getCharacteristic(this.Characteristic.OutletInUse)
|
|
52
|
+
.onGet(this.getOutletInUse.bind(this));
|
|
53
|
+
|
|
54
|
+
this.log.debug(`Configured plug accessory: ${this.device.typeName} (0x${this.device.shortAddress.toString(16)})`);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Handle GET On
|
|
59
|
+
* @returns {boolean}
|
|
60
|
+
*/
|
|
61
|
+
getOn() {
|
|
62
|
+
this.log.debug(`GET On for ${this.device.typeName}: ${this.state.on}`);
|
|
63
|
+
return this.state.on;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Handle SET On
|
|
68
|
+
* @param {boolean} value
|
|
69
|
+
*/
|
|
70
|
+
async setOn(value) {
|
|
71
|
+
this.log.info(`SET On for ${this.device.typeName}: ${value}`);
|
|
72
|
+
|
|
73
|
+
try {
|
|
74
|
+
await this.platform.hub.setDevicePower(value, [this.device.shortAddress]);
|
|
75
|
+
this.state.on = value;
|
|
76
|
+
|
|
77
|
+
// Update OutletInUse when power state changes
|
|
78
|
+
this.service.updateCharacteristic(this.Characteristic.OutletInUse, value);
|
|
79
|
+
} catch (error) {
|
|
80
|
+
this.log.error(`Failed to set power for ${this.device.typeName}:`, error.message);
|
|
81
|
+
throw new this.platform.api.hap.HapStatusError(
|
|
82
|
+
this.platform.api.hap.HAPStatus.SERVICE_COMMUNICATION_FAILURE,
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Handle GET OutletInUse
|
|
89
|
+
* @returns {boolean}
|
|
90
|
+
*/
|
|
91
|
+
getOutletInUse() {
|
|
92
|
+
// We'll assume the outlet is in use if it's on
|
|
93
|
+
// (Smartika plugs don't report power consumption)
|
|
94
|
+
return this.state.on;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Update state from hub status
|
|
99
|
+
* @param {Object} status - Status from hub
|
|
100
|
+
*/
|
|
101
|
+
updateStatus(status) {
|
|
102
|
+
// Update On state
|
|
103
|
+
if (status.on !== undefined && status.on !== this.state.on) {
|
|
104
|
+
this.state.on = status.on;
|
|
105
|
+
this.service.updateCharacteristic(this.Characteristic.On, status.on);
|
|
106
|
+
this.service.updateCharacteristic(this.Characteristic.OutletInUse, status.on);
|
|
107
|
+
this.log.debug(`Updated ${this.device.typeName} On: ${status.on}`);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
module.exports = SmartikaPlugAccessory;
|
package/src/index.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { PLATFORM_NAME, PLUGIN_NAME } = require('./settings');
|
|
4
|
+
const SmartikaPlatform = require('./SmartikaPlatform');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Homebridge plugin entry point
|
|
8
|
+
* @param {API} api - Homebridge API
|
|
9
|
+
*/
|
|
10
|
+
module.exports = (api) => {
|
|
11
|
+
api.registerPlatform(PLUGIN_NAME, PLATFORM_NAME, SmartikaPlatform);
|
|
12
|
+
};
|
package/src/settings.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Platform name - must match the "pluginAlias" in config.schema.json
|
|
5
|
+
*/
|
|
6
|
+
const PLATFORM_NAME = 'Smartika';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Plugin name - must match the "name" in package.json
|
|
10
|
+
*/
|
|
11
|
+
const PLUGIN_NAME = 'homebridge-smartika';
|
|
12
|
+
|
|
13
|
+
module.exports = {
|
|
14
|
+
PLATFORM_NAME,
|
|
15
|
+
PLUGIN_NAME,
|
|
16
|
+
};
|