homebridge-frontier-silicon-plugin 1.0.2 → 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/index.js +28 -22
  3. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -4,6 +4,18 @@ All notable changes to this project are documented in this file.
4
4
 
5
5
  The format is based on Keep a Changelog, and this project follows Semantic Versioning.
6
6
 
7
+ ## [1.1.0] – 2025-12-28
8
+
9
+ ### Changed
10
+ - Replaced the Lightbulb Brightness based volume control with a native HomeKit **Speaker** service.
11
+ - Volume is now exposed using the official `Volume` characteristic.
12
+ - Power and volume are logically separated, matching HomeKit audio device expectations.
13
+
14
+ ### Improved
15
+ - More natural HomeKit UI for audio devices.
16
+ - Better compatibility with HomeKit audio controls and third-party Home apps.
17
+ - Non-linear volume mapping retained for precise low-volume control.
18
+
7
19
  ## [1.0.2] – 2025-12-28
8
20
 
9
21
  ### Changed
package/index.js CHANGED
@@ -21,11 +21,13 @@ function FrontierSiliconAccessory(log, config) {
21
21
  this.ip = config.ip;
22
22
  this.pin = String(config.pin ?? "1234");
23
23
  this.pollIntervalSeconds = Number(config.pollIntervalSeconds ?? 5);
24
+
25
+ // Keep volume enabled by default. This now uses a Speaker service.
24
26
  this.enableVolume = config.enableVolume !== false;
25
27
 
26
28
  this.lastKnownPower = null;
27
29
 
28
- // This stores the last known radio volume (0..100, device scale)
30
+ // Store last known RADIO volume in device scale 0..100
29
31
  this.lastKnownRadioVolume = null;
30
32
 
31
33
  if (!this.ip) {
@@ -38,39 +40,45 @@ function FrontierSiliconAccessory(log, config) {
38
40
  log: this.log
39
41
  });
40
42
 
41
- this.switchService = new Service.Switch(this.name);
43
+ this.informationService = new Service.AccessoryInformation()
44
+ .setCharacteristic(Characteristic.Manufacturer, "Frontier Silicon")
45
+ .setCharacteristic(Characteristic.Model, "FSAPI Radio")
46
+ .setCharacteristic(Characteristic.SerialNumber, this.ip || "unknown");
42
47
 
48
+ // Power as Switch (kept as-is for maximum Home app compatibility)
49
+ this.switchService = new Service.Switch(this.name);
43
50
  this.switchService
44
51
  .getCharacteristic(Characteristic.On)
45
52
  .on("get", this.handleGetPower.bind(this))
46
53
  .on("set", this.handleSetPower.bind(this));
47
54
 
55
+ // Speaker service for volume (and optional mute)
48
56
  if (this.enableVolume) {
49
- // Volume is exposed as a separate slider using Lightbulb Brightness
50
- this.volumeService = new Service.Lightbulb(this.name + " Volume");
51
-
52
- this.volumeService
53
- .getCharacteristic(Characteristic.On)
54
- .on("get", (cb) => cb(null, true))
55
- .on("set", (_val, cb) => cb(null));
57
+ this.speakerService = new Service.Speaker(this.name + " Speaker");
56
58
 
57
- this.volumeService
58
- .getCharacteristic(Characteristic.Brightness)
59
+ // Volume characteristic uses HomeKit scale 0..100
60
+ this.speakerService
61
+ .getCharacteristic(Characteristic.Volume)
59
62
  .on("get", this.handleGetVolume.bind(this))
60
63
  .on("set", this.handleSetVolume.bind(this));
61
- }
62
64
 
63
- this.informationService = new Service.AccessoryInformation()
64
- .setCharacteristic(Characteristic.Manufacturer, "Frontier Silicon")
65
- .setCharacteristic(Characteristic.Model, "FSAPI Radio")
66
- .setCharacteristic(Characteristic.SerialNumber, this.ip || "unknown");
65
+ // Optional mute support placeholder:
66
+ // If you want real mute later, we can map this to an FSAPI endpoint if available.
67
+ // For now, we expose mute but keep it non-functional (always false) to avoid confusion.
68
+ if (Characteristic.Mute) {
69
+ this.speakerService
70
+ .getCharacteristic(Characteristic.Mute)
71
+ .on("get", (cb) => cb(null, false))
72
+ .on("set", (_val, cb) => cb(null));
73
+ }
74
+ }
67
75
 
68
76
  this.startPolling();
69
77
  }
70
78
 
71
79
  FrontierSiliconAccessory.prototype.getServices = function () {
72
80
  const services = [this.informationService, this.switchService];
73
- if (this.enableVolume && this.volumeService) services.push(this.volumeService);
81
+ if (this.enableVolume && this.speakerService) services.push(this.speakerService);
74
82
  return services;
75
83
  };
76
84
 
@@ -142,14 +150,14 @@ FrontierSiliconAccessory.prototype.startPolling = function () {
142
150
  if (this.log.debug) this.log.debug("Polling power failed.", toMsg(err));
143
151
  }
144
152
 
145
- if (this.enableVolume && this.volumeService) {
153
+ if (this.enableVolume && this.speakerService) {
146
154
  try {
147
155
  const radioVol = await this.client.getVolume();
148
156
  if (this.lastKnownRadioVolume !== radioVol) {
149
157
  this.lastKnownRadioVolume = radioVol;
150
158
  const homekitVol = radioToHomekitVolume(radioVol);
151
- this.volumeService
152
- .getCharacteristic(Characteristic.Brightness)
159
+ this.speakerService
160
+ .getCharacteristic(Characteristic.Volume)
153
161
  .updateValue(homekitVol);
154
162
  }
155
163
  } catch (err) {
@@ -179,7 +187,6 @@ FsApiClient.prototype.getPower = async function () {
179
187
 
180
188
  FsApiClient.prototype.setPower = async function (on) {
181
189
  const v = on ? 1 : 0;
182
- // Important: SET must start query with ?value= so pin can be appended with &
183
190
  await this.fetchText("/fsapi/SET/netRemote.sys.power?value=" + v);
184
191
  };
185
192
 
@@ -191,7 +198,6 @@ FsApiClient.prototype.getVolume = async function () {
191
198
 
192
199
  FsApiClient.prototype.setVolume = async function (volume) {
193
200
  const v = clampInt(Number(volume), 0, 100);
194
- // Important: SET must start query with ?value= so pin can be appended with &
195
201
  await this.fetchText("/fsapi/SET/netRemote.sys.audio.volume?value=" + v);
196
202
  };
197
203
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "homebridge-frontier-silicon-plugin",
3
- "version": "1.0.2",
3
+ "version": "1.0.3",
4
4
  "description": "Homebridge plugin for Frontier Silicon FSAPI devices, power and volume with safe polling",
5
5
  "license": "ISC",
6
6
  "main": "index.js",