@rnsc/homebridge-komfovent-ping2 0.2.3 → 0.3.0-beta.1

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/README.md CHANGED
@@ -2,11 +2,77 @@
2
2
 
3
3
  ![homebridge-logo](https://github.com/homebridge/branding/raw/master/logos/homebridge-wordmark-logo-vertical.png)
4
4
 
5
- Due to the lack of capabilities of the PING2 module provided by Komfovent (no API, simple HTML forms), this plugin aims at exposing the Komfovent Domekt unit as a simple fan.
5
+ Homebridge plugin that exposes a Komfovent Domekt ventilation unit (C4 controller) as a Fan accessory in HomeKit. Communicates directly with the PING2 module over **Modbus TCP** (port 502) no middleware required.
6
6
 
7
- The plugin relies on a middleware server written in Python to abstract the rather awful HTML forms from the PING2 module for the Homebridge code. [link](https://github.com/rnsc/komfovent-ping2-json-server)
7
+ ## Features
8
8
 
9
- Ideally the functions covered will be:
9
+ * **ON/OFF** start/stop the ventilation unit
10
+ * **Fan speed** — set Mode 2 intake and exhaust intensity from 5% to 95% in 5% increments
11
+ * **Supply air temperature** — exposed as a TemperatureSensor accessory in HomeKit
10
12
 
11
- * ON/OFF
12
- * Set the fan speed by 5% increment through the fan accessory in Homekit
13
+ ## Requirements
14
+
15
+ * A Komfovent Domekt unit with a **C4 controller** and **PING2 network module**
16
+ * The PING2 module must be reachable over TCP on port 502 (Modbus TCP)
17
+ * Homebridge >= 1.8.0
18
+ * Node.js >= 20.18
19
+
20
+ ## Configuration
21
+
22
+ Add the platform to your Homebridge `config.json`:
23
+
24
+ ```json
25
+ {
26
+ "platforms": [
27
+ {
28
+ "platform": "KomfoventPing2",
29
+ "devices": [
30
+ {
31
+ "name": "Ventilation",
32
+ "host": "192.168.1.100",
33
+ "deviceId": "abcdef1234567890"
34
+ }
35
+ ]
36
+ }
37
+ ]
38
+ }
39
+ ```
40
+
41
+ | Field | Required | Default | Description |
42
+ |-------|----------|---------|-------------|
43
+ | `name` | Yes | — | Display name in HomeKit |
44
+ | `host` | Yes | — | IP address or hostname of the PING2 module |
45
+ | `deviceId` | Yes | — | 16-character ID (A-Z, a-z, 0-9, _) for HomeKit UUID generation |
46
+ | `port` | No | `502` | Modbus TCP port |
47
+ | `slaveId` | No | `1` | Modbus slave ID (1-254) |
48
+
49
+ ### Verifying Modbus connectivity
50
+
51
+ You can verify that your PING2 module is reachable over Modbus TCP using `mbpoll`:
52
+
53
+ ```bash
54
+ brew install mbpoll # or apt-get install mbpoll
55
+ mbpoll -m tcp -a 1 -r 1000 -c 10 -t 4 -1 <PING2_IP>
56
+ ```
57
+
58
+ ## Migration from v0.2.x
59
+
60
+ Version 0.3.0 replaces the Python middleware ([komfovent-ping2-json-server](https://github.com/rnsc/komfovent-ping2-json-server)) with direct Modbus TCP communication. The middleware server is no longer needed.
61
+
62
+ Update your config — replace `url` with `host`:
63
+
64
+ ```diff
65
+ {
66
+ "platform": "KomfoventPing2",
67
+ "devices": [
68
+ {
69
+ "name": "Ventilation",
70
+ - "url": "http://192.168.1.100:5000",
71
+ + "host": "192.168.1.100",
72
+ "deviceId": "abcdef1234567890"
73
+ }
74
+ ]
75
+ }
76
+ ```
77
+
78
+ Your existing HomeKit accessory will be preserved as long as the `deviceId` stays the same.
@@ -16,16 +16,32 @@
16
16
  "type": "string",
17
17
  "required": true
18
18
  },
19
- "url": {
20
- "title": "URL",
19
+ "host": {
20
+ "title": "Host",
21
21
  "type": "string",
22
- "required": true
22
+ "required": true,
23
+ "description": "IP address or hostname of the PING2 module"
24
+ },
25
+ "port": {
26
+ "title": "Modbus TCP Port",
27
+ "type": "integer",
28
+ "default": 502,
29
+ "description": "Modbus TCP port (default: 502)"
30
+ },
31
+ "slaveId": {
32
+ "title": "Modbus Slave ID",
33
+ "type": "integer",
34
+ "default": 1,
35
+ "minimum": 1,
36
+ "maximum": 254,
37
+ "description": "Modbus slave ID (default: 1)"
23
38
  },
24
39
  "deviceId": {
25
40
  "title": "Device ID",
26
41
  "type": "string",
27
42
  "required": true,
28
- "pattern": "^[\\w\\d]{16}$"
43
+ "pattern": "^[A-Za-z0-9_]{16}$",
44
+ "description": "Unique 16-character ID (letters, digits, underscore) for HomeKit UUID generation"
29
45
  }
30
46
  }
31
47
  }
package/dist/client.d.ts CHANGED
@@ -1,17 +1,54 @@
1
- import { KomfoventPing2Platform } from './platform';
2
- import { PlatformConfig } from 'homebridge';
3
- import { Device } from './types';
4
- export declare class Ping2JsonClient {
5
- private readonly platform;
1
+ import type { Logging } from 'homebridge';
2
+ import type { Device } from './types';
3
+ export declare const C4_REGISTERS: {
4
+ readonly START_STOP: 1000;
5
+ readonly SEASON: 1001;
6
+ readonly VENTILATION_LEVEL: 1100;
7
+ readonly VENTILATION_LEVEL_CURRENT: 1101;
8
+ readonly MODE: 1102;
9
+ readonly INTAKE_LEVEL_1: 1103;
10
+ readonly INTAKE_LEVEL_2: 1104;
11
+ readonly INTAKE_LEVEL_3: 1105;
12
+ readonly INTAKE_LEVEL_4: 1106;
13
+ readonly EXHAUST_LEVEL_1: 1107;
14
+ readonly EXHAUST_LEVEL_2: 1108;
15
+ readonly EXHAUST_LEVEL_3: 1109;
16
+ readonly EXHAUST_LEVEL_4: 1110;
17
+ readonly FAN_STATUS: 1114;
18
+ readonly SUPPLY_FAN_SPEED: 1115;
19
+ readonly EXHAUST_FAN_SPEED: 1116;
20
+ readonly TIME: 1002;
21
+ readonly DAY_OF_WEEK: 1003;
22
+ readonly MONTH_DAY: 1004;
23
+ readonly YEAR: 1005;
24
+ readonly SUPPLY_AIR_TEMP: 1200;
25
+ readonly SETPOINT_TEMP: 1201;
26
+ };
27
+ export interface UnitStatus {
28
+ active: boolean;
29
+ mode2Speed: number;
30
+ supplyFanSpeed: number;
31
+ exhaustFanSpeed: number;
32
+ supplyAirTemp: number;
33
+ setpointTemp: number;
34
+ }
35
+ export declare class ModbusClient {
36
+ private readonly log;
6
37
  private readonly device;
7
- private readonly config;
8
- constructor(platform: KomfoventPing2Platform, device: Device, config: PlatformConfig);
9
- getStatus(): Promise<{
10
- active: string;
11
- speed: number;
12
- }>;
13
- setPower(value: string): Promise<boolean>;
14
- setSpeed(value: number): Promise<boolean>;
15
- private putRequest;
38
+ private client;
39
+ private connected;
40
+ private operationQueue;
41
+ private statusPromise;
42
+ private statusPromiseTime;
43
+ private static readonly STATUS_CACHE_TTL_MS;
44
+ constructor(log: Logging, device: Device);
45
+ private serialize;
46
+ private invalidateCache;
47
+ private closeExistingConnection;
48
+ private ensureConnection;
49
+ getStatus(): Promise<UnitStatus>;
50
+ setPower(on: boolean): Promise<void>;
51
+ setMode2Speed(speed: number): Promise<void>;
52
+ syncClock(): Promise<void>;
53
+ disconnect(): void;
16
54
  }
17
- //# sourceMappingURL=client.d.ts.map
package/dist/client.js CHANGED
@@ -3,54 +3,183 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.Ping2JsonClient = void 0;
7
- const axios_1 = __importDefault(require("axios"));
8
- class Ping2JsonClient {
9
- constructor(platform, device, config) {
10
- this.platform = platform;
6
+ exports.ModbusClient = exports.C4_REGISTERS = void 0;
7
+ const modbus_serial_1 = __importDefault(require("modbus-serial"));
8
+ // C4 controller Modbus holding register addresses
9
+ exports.C4_REGISTERS = {
10
+ START_STOP: 1000,
11
+ SEASON: 1001,
12
+ VENTILATION_LEVEL: 1100,
13
+ VENTILATION_LEVEL_CURRENT: 1101,
14
+ MODE: 1102,
15
+ INTAKE_LEVEL_1: 1103,
16
+ INTAKE_LEVEL_2: 1104,
17
+ INTAKE_LEVEL_3: 1105,
18
+ INTAKE_LEVEL_4: 1106,
19
+ EXHAUST_LEVEL_1: 1107,
20
+ EXHAUST_LEVEL_2: 1108,
21
+ EXHAUST_LEVEL_3: 1109,
22
+ EXHAUST_LEVEL_4: 1110,
23
+ FAN_STATUS: 1114,
24
+ SUPPLY_FAN_SPEED: 1115,
25
+ EXHAUST_FAN_SPEED: 1116,
26
+ TIME: 1002,
27
+ DAY_OF_WEEK: 1003,
28
+ MONTH_DAY: 1004,
29
+ YEAR: 1005,
30
+ SUPPLY_AIR_TEMP: 1200,
31
+ SETPOINT_TEMP: 1201,
32
+ };
33
+ class ModbusClient {
34
+ log;
35
+ device;
36
+ client;
37
+ connected = false;
38
+ operationQueue = Promise.resolve();
39
+ statusPromise = null;
40
+ statusPromiseTime = 0;
41
+ static STATUS_CACHE_TTL_MS = 2000;
42
+ constructor(log, device) {
43
+ this.log = log;
11
44
  this.device = device;
12
- this.config = config;
45
+ this.client = new modbus_serial_1.default();
46
+ }
47
+ // Serializes all Modbus operations to prevent concurrent socket access
48
+ serialize(operation) {
49
+ const result = this.operationQueue.then(operation, operation);
50
+ this.operationQueue = result.catch(() => { });
51
+ return result;
52
+ }
53
+ invalidateCache() {
54
+ this.statusPromise = null;
55
+ this.statusPromiseTime = 0;
56
+ }
57
+ closeExistingConnection() {
58
+ try {
59
+ if (this.client.isOpen) {
60
+ this.client.close(() => { });
61
+ }
62
+ }
63
+ catch {
64
+ // ignore close errors on stale connections
65
+ }
66
+ }
67
+ async ensureConnection() {
68
+ if (this.connected && this.client.isOpen) {
69
+ return;
70
+ }
71
+ this.connected = false;
72
+ this.closeExistingConnection();
73
+ try {
74
+ this.client = new modbus_serial_1.default();
75
+ await this.client.connectTCP(this.device.host, { port: this.device.port });
76
+ this.client.setID(this.device.slaveId);
77
+ this.client.setTimeout(5000);
78
+ this.connected = true;
79
+ this.log.info(`Connected to ${this.device.host}:${this.device.port} (slave ${this.device.slaveId})`);
80
+ }
81
+ catch (error) {
82
+ this.log.error(`Failed to connect to ${this.device.host}:${this.device.port}:`, error);
83
+ throw error;
84
+ }
13
85
  }
14
86
  async getStatus() {
15
- this.platform.log.info('Get status');
16
- return axios_1.default.get(this.device.url, {
17
- headers: {
18
- 'Accept': 'application/json',
19
- },
20
- }).then((response) => {
21
- this.platform.log.info(`Reply from Python JSON API: ${JSON.stringify(response.data)}`);
22
- return response.data;
23
- })
24
- .catch((error) => {
25
- this.platform.log.error('Error with getRequest:', error);
26
- return Promise.resolve();
87
+ const now = Date.now();
88
+ if (this.statusPromise && (now - this.statusPromiseTime) < ModbusClient.STATUS_CACHE_TTL_MS) {
89
+ return this.statusPromise;
90
+ }
91
+ this.statusPromiseTime = now;
92
+ this.statusPromise = this.serialize(async () => {
93
+ try {
94
+ await this.ensureConnection();
95
+ const general = await this.client.readHoldingRegisters(exports.C4_REGISTERS.START_STOP, 1);
96
+ const ventilation = await this.client.readHoldingRegisters(exports.C4_REGISTERS.VENTILATION_LEVEL, 17);
97
+ const temps = await this.client.readHoldingRegisters(exports.C4_REGISTERS.SUPPLY_AIR_TEMP, 2);
98
+ return {
99
+ active: general.data[0] === 1,
100
+ mode2Speed: ventilation.data[4], // reg 1104 — Mode 2 intake intensity
101
+ supplyFanSpeed: ventilation.data[15], // reg 1115
102
+ exhaustFanSpeed: ventilation.data[16], // reg 1116
103
+ supplyAirTemp: temps.data[0] / 10, // reg 1200, value is 10x
104
+ setpointTemp: temps.data[1] / 10, // reg 1201, value is 10x
105
+ };
106
+ }
107
+ catch (error) {
108
+ this.connected = false;
109
+ this.closeExistingConnection();
110
+ this.invalidateCache();
111
+ this.log.error('Failed to read status:', error);
112
+ throw error;
113
+ }
27
114
  });
115
+ return this.statusPromise;
28
116
  }
29
- async setPower(value) {
30
- this.platform.log.info('Turn on/off ->', value.toString());
31
- return this.putRequest(this.device.deviceId, { 'active': value }, 'setPower', 'Error updating power:');
32
- }
33
- async setSpeed(value) {
34
- this.platform.log.info('Change speed ->', value);
35
- return this.putRequest(this.device.deviceId, { 'speed': value }, 'setSpeed', 'Error updating speed:');
36
- }
37
- putRequest(deviceId, requestData, caller, errorHeader) {
38
- this.platform.log.info(`${caller}-> requestData: ${JSON.stringify(requestData)}`);
39
- return axios_1.default.put(this.device.url, requestData, {
40
- headers: {
41
- 'Accept': 'application/json',
42
- 'Content-Type': 'application/json',
43
- },
44
- })
45
- .then(res => {
46
- this.platform.log.info(`${caller}-> device: ${deviceId}; response:${JSON.stringify(res.data)}`);
47
- return true;
48
- })
49
- .catch((error) => {
50
- this.platform.log.error(errorHeader, error);
51
- return false;
117
+ async setPower(on) {
118
+ return this.serialize(async () => {
119
+ try {
120
+ await this.ensureConnection();
121
+ await this.client.writeRegister(exports.C4_REGISTERS.START_STOP, on ? 1 : 0);
122
+ this.invalidateCache();
123
+ this.log.info(`Power set to ${on ? 'ON' : 'OFF'}`);
124
+ }
125
+ catch (error) {
126
+ this.connected = false;
127
+ this.closeExistingConnection();
128
+ this.invalidateCache();
129
+ this.log.error('Failed to set power:', error);
130
+ throw error;
131
+ }
52
132
  });
53
133
  }
134
+ async setMode2Speed(speed) {
135
+ speed = Math.round(speed / 5) * 5;
136
+ speed = Math.min(95, Math.max(5, speed));
137
+ return this.serialize(async () => {
138
+ try {
139
+ await this.ensureConnection();
140
+ await this.client.writeRegister(exports.C4_REGISTERS.INTAKE_LEVEL_2, speed);
141
+ await this.client.writeRegister(exports.C4_REGISTERS.EXHAUST_LEVEL_2, speed);
142
+ this.invalidateCache();
143
+ this.log.info(`Mode 2 speed set to ${speed}% (intake + exhaust)`);
144
+ }
145
+ catch (error) {
146
+ this.connected = false;
147
+ this.closeExistingConnection();
148
+ this.invalidateCache();
149
+ this.log.error('Failed to set Mode 2 speed:', error);
150
+ throw error;
151
+ }
152
+ });
153
+ }
154
+ async syncClock() {
155
+ return this.serialize(async () => {
156
+ try {
157
+ await this.ensureConnection();
158
+ const now = new Date();
159
+ const time = (now.getHours() << 8) | now.getMinutes();
160
+ const dayOfWeek = now.getDay() === 0 ? 7 : now.getDay();
161
+ const monthDay = ((now.getMonth() + 1) << 8) | now.getDate();
162
+ const year = now.getFullYear();
163
+ await this.client.writeRegister(exports.C4_REGISTERS.TIME, time);
164
+ await this.client.writeRegister(exports.C4_REGISTERS.DAY_OF_WEEK, dayOfWeek);
165
+ await this.client.writeRegister(exports.C4_REGISTERS.MONTH_DAY, monthDay);
166
+ await this.client.writeRegister(exports.C4_REGISTERS.YEAR, year);
167
+ this.log.info(`Clock synced to ${now.toLocaleString()}`);
168
+ }
169
+ catch (error) {
170
+ this.connected = false;
171
+ this.closeExistingConnection();
172
+ this.invalidateCache();
173
+ this.log.error('Failed to sync clock:', error);
174
+ throw error;
175
+ }
176
+ });
177
+ }
178
+ disconnect() {
179
+ this.connected = false;
180
+ this.closeExistingConnection();
181
+ this.invalidateCache();
182
+ }
54
183
  }
55
- exports.Ping2JsonClient = Ping2JsonClient;
184
+ exports.ModbusClient = ModbusClient;
56
185
  //# sourceMappingURL=client.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":";;;;;;AAEA,kDAA0B;AAI1B,MAAa,eAAe;IAE1B,YAA6B,QAAgC,EAChC,MAAc,EACd,MAAsB;QAFtB,aAAQ,GAAR,QAAQ,CAAwB;QAChC,WAAM,GAAN,MAAM,CAAQ;QACd,WAAM,GAAN,MAAM,CAAgB;IACnD,CAAC;IAED,KAAK,CAAC,SAAS;QACb,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QACrC,OAAO,eAAK,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE;YAChC,OAAO,EAAC;gBACN,QAAQ,EAAE,kBAAkB;aAC7B;SACF,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAC,EAAE;YAClB,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,+BAA+B,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACvF,OAAO,QAAQ,CAAC,IAAI,CAAC;QACvB,CAAC,CAAC;aACC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;YACf,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,wBAAwB,EAAE,KAAK,CAAC,CAAC;YACzD,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;QAC3B,CAAC,CAAC,CAAC;IACP,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,KAAa;QAC1B,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,gBAAgB,EAAE,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC;QAC3D,OAAO,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,UAAU,EAAE,uBAAuB,CAAC,CAAC;IACzG,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,KAAa;QAC1B,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,iBAAiB,EAAE,KAAK,CAAC,CAAC;QACjD,OAAO,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,UAAU,EAAE,uBAAuB,CAAC,CAAC;IACxG,CAAC;IAEO,UAAU,CAAC,QAAgB,EAAE,WAAgB,EAAE,MAAc,EAAE,WAAmB;QACxF,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,MAAM,mBAAmB,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;QAClF,OAAO,eAAK,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,EAC9B,WAAW,EAAE;YACX,OAAO,EAAE;gBACP,QAAQ,EAAE,kBAAkB;gBAC5B,cAAc,EAAE,kBAAkB;aACnC;SACF,CAAC;aACD,IAAI,CAAC,GAAG,CAAC,EAAE;YACV,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,MAAM,cAAc,QAAQ,cAAc,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YAChG,OAAO,IAAI,CAAC;QACd,CAAC,CAAC;aACD,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;YACf,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC;YAC5C,OAAO,KAAK,CAAC;QACf,CAAC,CACA,CAAC;IACN,CAAC;CACF;AApDD,0CAoDC"}
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,7 +1,3 @@
1
- import { API } from 'homebridge';
1
+ import type { API } from 'homebridge';
2
2
  declare const _default: (api: API) => void;
3
- /**
4
- * This method registers the platform with Homebridge
5
- */
6
3
  export = _default;
7
- //# sourceMappingURL=index.d.ts.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,yCAA2C;AAC3C,yCAAoD;AAKpD,iBAAS,CAAC,GAAQ,EAAE,EAAE;IACpB,GAAG,CAAC,gBAAgB,CAAC,wBAAa,EAAE,iCAAsB,CAAC,CAAC;AAC9D,CAAC,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,yCAA2C;AAC3C,yCAAoD;AAEpD,iBAAS,CAAC,GAAQ,EAAE,EAAE;IACpB,GAAG,CAAC,gBAAgB,CAAC,wBAAa,EAAE,iCAAsB,CAAC,CAAC;AAC9D,CAAC,CAAC"}
@@ -1,13 +1,13 @@
1
- import { API, DynamicPlatformPlugin, Logger, PlatformAccessory, PlatformConfig, Service, Characteristic } from 'homebridge';
1
+ import type { API, Characteristic, DynamicPlatformPlugin, Logging, PlatformAccessory, PlatformConfig, Service } from 'homebridge';
2
2
  export declare class KomfoventPing2Platform implements DynamicPlatformPlugin {
3
- readonly log: Logger;
3
+ readonly log: Logging;
4
4
  readonly config: PlatformConfig;
5
5
  readonly api: API;
6
6
  readonly Service: typeof Service;
7
7
  readonly Characteristic: typeof Characteristic;
8
- readonly accessories: PlatformAccessory[];
9
- constructor(log: Logger, config: PlatformConfig, api: API);
8
+ readonly accessories: Map<string, PlatformAccessory>;
9
+ private readonly activeAccessories;
10
+ constructor(log: Logging, config: PlatformConfig, api: API);
10
11
  configureAccessory(accessory: PlatformAccessory): void;
11
12
  discoverDevices(): void;
12
13
  }
13
- //# sourceMappingURL=platform.d.ts.map
package/dist/platform.js CHANGED
@@ -1,41 +1,72 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.KomfoventPing2Platform = void 0;
4
- const settings_1 = require("./settings");
5
4
  const platformAccessory_1 = require("./platformAccessory");
5
+ const settings_1 = require("./settings");
6
6
  class KomfoventPing2Platform {
7
+ log;
8
+ config;
9
+ api;
10
+ Service;
11
+ Characteristic;
12
+ accessories = new Map();
13
+ activeAccessories = [];
7
14
  constructor(log, config, api) {
8
15
  this.log = log;
9
16
  this.config = config;
10
17
  this.api = api;
11
- this.Service = this.api.hap.Service;
12
- this.Characteristic = this.api.hap.Characteristic;
13
- this.accessories = [];
18
+ this.Service = api.hap.Service;
19
+ this.Characteristic = api.hap.Characteristic;
14
20
  this.log.debug('Finished initializing platform:', this.config.name);
15
21
  this.api.on('didFinishLaunching', () => {
16
22
  log.debug('Executed didFinishLaunching callback');
17
23
  this.discoverDevices();
18
24
  });
25
+ this.api.on('shutdown', () => {
26
+ log.debug('Shutting down — cleaning up accessories');
27
+ for (const acc of this.activeAccessories) {
28
+ acc.shutdown();
29
+ }
30
+ });
19
31
  }
20
32
  configureAccessory(accessory) {
21
33
  this.log.info('Loading accessory from cache:', accessory.displayName);
22
- this.accessories.push(accessory);
34
+ this.accessories.set(accessory.UUID, accessory);
23
35
  }
24
36
  discoverDevices() {
25
- for (const device of this.config.devices) {
37
+ const devices = this.config.devices ?? [];
38
+ const discoveredUUIDs = new Set();
39
+ for (const device of devices) {
40
+ if (!device.name || !device.host || !device.deviceId) {
41
+ this.log.warn('Skipping device with missing required fields (name, host, deviceId):', JSON.stringify(device));
42
+ continue;
43
+ }
44
+ device.port = device.port ?? 502;
45
+ device.slaveId = device.slaveId ?? 1;
26
46
  const uuid = this.api.hap.uuid.generate(device.deviceId);
27
- const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid);
47
+ discoveredUUIDs.add(uuid);
48
+ const existingAccessory = this.accessories.get(uuid);
28
49
  if (existingAccessory) {
29
50
  this.log.info('Restoring existing accessory from cache:', existingAccessory.displayName);
30
- new platformAccessory_1.KomfoventPing2Accessory(this, existingAccessory, device, this.config);
51
+ existingAccessory.context.device = device;
52
+ this.activeAccessories.push(new platformAccessory_1.KomfoventPing2Accessory(this, existingAccessory));
31
53
  }
32
54
  else {
33
55
  this.log.info('Adding new accessory:', device.name);
34
56
  const accessory = new this.api.platformAccessory(device.name, uuid);
35
- new platformAccessory_1.KomfoventPing2Accessory(this, accessory, device, this.config);
57
+ accessory.context.device = device;
58
+ this.accessories.set(uuid, accessory);
59
+ this.activeAccessories.push(new platformAccessory_1.KomfoventPing2Accessory(this, accessory));
36
60
  this.api.registerPlatformAccessories(settings_1.PLUGIN_NAME, settings_1.PLATFORM_NAME, [accessory]);
37
61
  }
38
62
  }
63
+ for (const [uuid, accessory] of this.accessories) {
64
+ if (!discoveredUUIDs.has(uuid)) {
65
+ this.log.info('Removing stale accessory from cache:', accessory.displayName);
66
+ this.api.unregisterPlatformAccessories(settings_1.PLUGIN_NAME, settings_1.PLATFORM_NAME, [accessory]);
67
+ this.accessories.delete(uuid);
68
+ }
69
+ }
39
70
  }
40
71
  }
41
72
  exports.KomfoventPing2Platform = KomfoventPing2Platform;
@@ -1 +1 @@
1
- {"version":3,"file":"platform.js","sourceRoot":"","sources":["../src/platform.ts"],"names":[],"mappings":";;;AAEA,yCAAwD;AACxD,2DAA8D;AAE9D,MAAa,sBAAsB;IAMjC,YACkB,GAAW,EACX,MAAsB,EACtB,GAAQ;QAFR,QAAG,GAAH,GAAG,CAAQ;QACX,WAAM,GAAN,MAAM,CAAgB;QACtB,QAAG,GAAH,GAAG,CAAK;QARV,YAAO,GAAmB,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC;QAC/C,mBAAc,GAA0B,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,cAAc,CAAC;QAEpE,gBAAW,GAAwB,EAAE,CAAC;QAOpD,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,iCAAiC,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAEpE,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,oBAAoB,EAAE,GAAG,EAAE;YACrC,GAAG,CAAC,KAAK,CAAC,sCAAsC,CAAC,CAAC;YAClD,IAAI,CAAC,eAAe,EAAE,CAAC;QACzB,CAAC,CAAC,CAAC;IACL,CAAC;IAED,kBAAkB,CAAC,SAA4B;QAC7C,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,+BAA+B,EAAE,SAAS,CAAC,WAAW,CAAC,CAAC;QAEtE,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACnC,CAAC;IAED,eAAe;QACb,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE;YACxC,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;YACzD,MAAM,iBAAiB,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,SAAS,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;YAEtF,IAAI,iBAAiB,EAAE;gBACrB,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,0CAA0C,EAAE,iBAAiB,CAAC,WAAW,CAAC,CAAC;gBACzF,IAAI,2CAAuB,CAAC,IAAI,EAAE,iBAAiB,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;aAC3E;iBAAM;gBACL,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,uBAAuB,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;gBACpD,MAAM,SAAS,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,iBAAiB,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;gBACpE,IAAI,2CAAuB,CAAC,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;gBAClE,IAAI,CAAC,GAAG,CAAC,2BAA2B,CAAC,sBAAW,EAAE,wBAAa,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC;aAC/E;SACF;IACH,CAAC;CACF;AAzCD,wDAyCC"}
1
+ {"version":3,"file":"platform.js","sourceRoot":"","sources":["../src/platform.ts"],"names":[],"mappings":";;;AAGA,2DAA8D;AAC9D,yCAAwD;AAExD,MAAa,sBAAsB;IAOf;IACA;IACA;IARF,OAAO,CAAiB;IACxB,cAAc,CAAwB;IACtC,WAAW,GAAmC,IAAI,GAAG,EAAE,CAAC;IACvD,iBAAiB,GAA8B,EAAE,CAAC;IAEnE,YACkB,GAAY,EACZ,MAAsB,EACtB,GAAQ;QAFR,QAAG,GAAH,GAAG,CAAS;QACZ,WAAM,GAAN,MAAM,CAAgB;QACtB,QAAG,GAAH,GAAG,CAAK;QAExB,IAAI,CAAC,OAAO,GAAG,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC;QAC/B,IAAI,CAAC,cAAc,GAAG,GAAG,CAAC,GAAG,CAAC,cAAc,CAAC;QAE7C,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,iCAAiC,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAEpE,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,oBAAoB,EAAE,GAAG,EAAE;YACrC,GAAG,CAAC,KAAK,CAAC,sCAAsC,CAAC,CAAC;YAClD,IAAI,CAAC,eAAe,EAAE,CAAC;QACzB,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,UAAU,EAAE,GAAG,EAAE;YAC3B,GAAG,CAAC,KAAK,CAAC,yCAAyC,CAAC,CAAC;YACrD,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,iBAAiB,EAAE,CAAC;gBACzC,GAAG,CAAC,QAAQ,EAAE,CAAC;YACjB,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAED,kBAAkB,CAAC,SAA4B;QAC7C,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,+BAA+B,EAAE,SAAS,CAAC,WAAW,CAAC,CAAC;QACtE,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;IAClD,CAAC;IAED,eAAe;QACb,MAAM,OAAO,GAAa,IAAI,CAAC,MAAM,CAAC,OAAO,IAAI,EAAE,CAAC;QACpD,MAAM,eAAe,GAAG,IAAI,GAAG,EAAU,CAAC;QAE1C,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;YAC7B,IAAI,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC;gBACrD,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,sEAAsE,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC;gBAC9G,SAAS;YACX,CAAC;YAED,MAAM,CAAC,IAAI,GAAG,MAAM,CAAC,IAAI,IAAI,GAAG,CAAC;YACjC,MAAM,CAAC,OAAO,GAAG,MAAM,CAAC,OAAO,IAAI,CAAC,CAAC;YAErC,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;YACzD,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YAE1B,MAAM,iBAAiB,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YAErD,IAAI,iBAAiB,EAAE,CAAC;gBACtB,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,0CAA0C,EAAE,iBAAiB,CAAC,WAAW,CAAC,CAAC;gBACzF,iBAAiB,CAAC,OAAO,CAAC,MAAM,GAAG,MAAM,CAAC;gBAC1C,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,IAAI,2CAAuB,CAAC,IAAI,EAAE,iBAAiB,CAAC,CAAC,CAAC;YACpF,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,uBAAuB,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;gBACpD,MAAM,SAAS,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,iBAAiB,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;gBACpE,SAAS,CAAC,OAAO,CAAC,MAAM,GAAG,MAAM,CAAC;gBAClC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;gBACtC,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,IAAI,2CAAuB,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC;gBAC1E,IAAI,CAAC,GAAG,CAAC,2BAA2B,CAAC,sBAAW,EAAE,wBAAa,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC;YAChF,CAAC;QACH,CAAC;QAED,KAAK,MAAM,CAAC,IAAI,EAAE,SAAS,CAAC,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YACjD,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC/B,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,sCAAsC,EAAE,SAAS,CAAC,WAAW,CAAC,CAAC;gBAC7E,IAAI,CAAC,GAAG,CAAC,6BAA6B,CAAC,sBAAW,EAAE,wBAAa,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC;gBAChF,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YAChC,CAAC;QACH,CAAC;IACH,CAAC;CACF;AA1ED,wDA0EC"}
@@ -1,18 +1,21 @@
1
- import { PlatformAccessory, CharacteristicValue, PlatformConfig } from 'homebridge';
2
- import { KomfoventPing2Platform } from './platform';
3
- import { Device } from './types';
1
+ import type { CharacteristicValue, PlatformAccessory } from 'homebridge';
2
+ import type { KomfoventPing2Platform } from './platform';
4
3
  export declare class KomfoventPing2Accessory {
5
4
  private readonly platform;
6
5
  private readonly accessory;
6
+ private readonly fanService;
7
+ private readonly temperatureService;
8
+ private readonly client;
7
9
  private readonly device;
8
- private readonly config;
9
- private service;
10
- private client;
11
- private lastSpeedChangeTime;
12
- constructor(platform: KomfoventPing2Platform, accessory: PlatformAccessory, device: Device, config: PlatformConfig);
10
+ private readonly pollInterval;
11
+ private readonly clockSyncInterval;
12
+ constructor(platform: KomfoventPing2Platform, accessory: PlatformAccessory);
13
+ shutdown(): void;
14
+ private syncClock;
15
+ private pollStatus;
13
16
  getActive(): Promise<CharacteristicValue>;
14
17
  setActive(value: CharacteristicValue): Promise<void>;
18
+ getRotationSpeed(): Promise<CharacteristicValue>;
15
19
  setRotationSpeed(value: CharacteristicValue): Promise<void>;
16
- checkAndRoundValue(value: number): number;
20
+ getSupplyAirTemperature(): Promise<CharacteristicValue>;
17
21
  }
18
- //# sourceMappingURL=platformAccessory.d.ts.map
@@ -2,70 +2,124 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.KomfoventPing2Accessory = void 0;
4
4
  const client_1 = require("./client");
5
+ const POLL_INTERVAL_MS = 30_000;
6
+ const CLOCK_SYNC_INTERVAL_MS = 24 * 60 * 60 * 1000;
5
7
  class KomfoventPing2Accessory {
6
- constructor(platform, accessory, device, config) {
8
+ platform;
9
+ accessory;
10
+ fanService;
11
+ temperatureService;
12
+ client;
13
+ device;
14
+ pollInterval;
15
+ clockSyncInterval;
16
+ constructor(platform, accessory) {
7
17
  this.platform = platform;
8
18
  this.accessory = accessory;
9
- this.device = device;
10
- this.config = config;
11
- this.lastSpeedChangeTime = 0;
12
- // set accessory information
19
+ this.device = accessory.context.device;
20
+ this.client = new client_1.ModbusClient(platform.log, this.device);
13
21
  this.accessory.getService(this.platform.Service.AccessoryInformation)
14
22
  .setCharacteristic(this.platform.Characteristic.Manufacturer, 'Komfovent')
15
- .setCharacteristic(this.platform.Characteristic.Model, 'Ping2')
16
- .setCharacteristic(this.platform.Characteristic.SerialNumber, 'DomektC4Ping2');
17
- this.service = this.accessory.getService(this.platform.Service.Fan) || this.accessory.addService(this.platform.Service.Fan);
18
- this.service.setCharacteristic(this.platform.Characteristic.Name, device.name);
19
- this.service.getCharacteristic(this.platform.Characteristic.On)
23
+ .setCharacteristic(this.platform.Characteristic.Model, 'Domekt C4 / PING2')
24
+ .setCharacteristic(this.platform.Characteristic.SerialNumber, this.device.deviceId);
25
+ // Fan service On/Off + RotationSpeed controlling Mode 2 intensity (5-95%, step 5)
26
+ this.fanService = this.accessory.getService(this.platform.Service.Fan)
27
+ || this.accessory.addService(this.platform.Service.Fan);
28
+ this.fanService.setCharacteristic(this.platform.Characteristic.Name, this.device.name);
29
+ this.fanService.getCharacteristic(this.platform.Characteristic.On)
20
30
  .onSet(this.setActive.bind(this))
21
31
  .onGet(this.getActive.bind(this));
22
- // register handlers for the Brightness Characteristic
23
- this.service.getCharacteristic(this.platform.Characteristic.RotationSpeed)
32
+ this.fanService.getCharacteristic(this.platform.Characteristic.RotationSpeed)
24
33
  .onSet(this.setRotationSpeed.bind(this))
34
+ .onGet(this.getRotationSpeed.bind(this))
25
35
  .setProps({
26
- minValue: 0,
27
- maxValue: 100,
36
+ minValue: 5,
37
+ maxValue: 95,
28
38
  minStep: 5,
29
39
  });
30
- this.client = new client_1.Ping2JsonClient(platform, this.device, this.config);
31
- //setInterval(() => {
32
- // this.platform.log.warn('setInterval');
33
- //}, 10000);
40
+ // Temperature sensor service supply air temperature (read-only)
41
+ this.temperatureService = this.accessory.getService(this.platform.Service.TemperatureSensor)
42
+ || this.accessory.addService(this.platform.Service.TemperatureSensor);
43
+ this.temperatureService.setCharacteristic(this.platform.Characteristic.Name, `${this.device.name} Supply Air`);
44
+ this.temperatureService.getCharacteristic(this.platform.Characteristic.CurrentTemperature)
45
+ .onGet(this.getSupplyAirTemperature.bind(this));
46
+ // Poll periodically to push state updates
47
+ this.pollInterval = setInterval(() => this.pollStatus(), POLL_INTERVAL_MS);
48
+ // Sync PING2 clock from server time on startup and once per day
49
+ this.syncClock();
50
+ this.clockSyncInterval = setInterval(() => this.syncClock(), CLOCK_SYNC_INTERVAL_MS);
51
+ }
52
+ shutdown() {
53
+ clearInterval(this.pollInterval);
54
+ clearInterval(this.clockSyncInterval);
55
+ this.client.disconnect();
56
+ }
57
+ async syncClock() {
58
+ try {
59
+ await this.client.syncClock();
60
+ }
61
+ catch {
62
+ this.platform.log.debug('Clock sync failed, will retry next interval');
63
+ }
64
+ }
65
+ async pollStatus() {
66
+ try {
67
+ const status = await this.client.getStatus();
68
+ this.fanService.updateCharacteristic(this.platform.Characteristic.On, status.active);
69
+ this.fanService.updateCharacteristic(this.platform.Characteristic.RotationSpeed, status.mode2Speed);
70
+ this.temperatureService.updateCharacteristic(this.platform.Characteristic.CurrentTemperature, status.supplyAirTemp);
71
+ }
72
+ catch {
73
+ this.platform.log.debug('Poll failed, will retry next interval');
74
+ const hapError = new this.platform.api.hap.HapStatusError(-70402 /* this.platform.api.hap.HAPStatus.SERVICE_COMMUNICATION_FAILURE */);
75
+ this.fanService.getCharacteristic(this.platform.Characteristic.On).updateValue(hapError);
76
+ this.fanService.getCharacteristic(this.platform.Characteristic.RotationSpeed).updateValue(hapError);
77
+ this.temperatureService.getCharacteristic(this.platform.Characteristic.CurrentTemperature).updateValue(hapError);
78
+ }
34
79
  }
35
80
  async getActive() {
36
- this.platform.log.info('getting state');
37
- return this.client.getStatus()
38
- .then(status => {
39
- this.service.updateCharacteristic(this.platform.Characteristic.RotationSpeed, status.speed);
81
+ try {
82
+ const status = await this.client.getStatus();
83
+ this.fanService.updateCharacteristic(this.platform.Characteristic.RotationSpeed, status.mode2Speed);
40
84
  return status.active;
41
- });
85
+ }
86
+ catch {
87
+ throw new this.platform.api.hap.HapStatusError(-70402 /* this.platform.api.hap.HAPStatus.SERVICE_COMMUNICATION_FAILURE */);
88
+ }
42
89
  }
43
90
  async setActive(value) {
44
- this.platform.log.info('setting active state');
45
- this.client.setPower(value);
91
+ try {
92
+ await this.client.setPower(value);
93
+ }
94
+ catch {
95
+ throw new this.platform.api.hap.HapStatusError(-70402 /* this.platform.api.hap.HAPStatus.SERVICE_COMMUNICATION_FAILURE */);
96
+ }
97
+ }
98
+ async getRotationSpeed() {
99
+ try {
100
+ const status = await this.client.getStatus();
101
+ return status.mode2Speed;
102
+ }
103
+ catch {
104
+ throw new this.platform.api.hap.HapStatusError(-70402 /* this.platform.api.hap.HAPStatus.SERVICE_COMMUNICATION_FAILURE */);
105
+ }
46
106
  }
47
107
  async setRotationSpeed(value) {
48
- value = this.checkAndRoundValue(value);
49
- if (value < 20 || value > 80 || value % 5 !== 0) {
50
- this.platform.log.warn('Invalid speed setting. Speed must be between 20 and 80.');
108
+ try {
109
+ await this.client.setMode2Speed(value);
51
110
  }
52
- else {
53
- this.platform.log.info('setting speed');
54
- this.lastSpeedChangeTime = Date.now();
55
- await this.client.setSpeed(value);
111
+ catch {
112
+ throw new this.platform.api.hap.HapStatusError(-70402 /* this.platform.api.hap.HAPStatus.SERVICE_COMMUNICATION_FAILURE */);
56
113
  }
57
114
  }
58
- checkAndRoundValue(value) {
59
- // Ensure the value is between 20 and 80
60
- if (value < 20) {
61
- value = 20;
115
+ async getSupplyAirTemperature() {
116
+ try {
117
+ const status = await this.client.getStatus();
118
+ return status.supplyAirTemp;
62
119
  }
63
- else if (value > 80) {
64
- value = 80;
120
+ catch {
121
+ throw new this.platform.api.hap.HapStatusError(-70402 /* this.platform.api.hap.HAPStatus.SERVICE_COMMUNICATION_FAILURE */);
65
122
  }
66
- // Round the value to the nearest multiple of 5
67
- value = Math.round(value / 5) * 5;
68
- return value;
69
123
  }
70
124
  }
71
125
  exports.KomfoventPing2Accessory = KomfoventPing2Accessory;
@@ -1 +1 @@
1
- {"version":3,"file":"platformAccessory.js","sourceRoot":"","sources":["../src/platformAccessory.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"platformAccessory.js","sourceRoot":"","sources":["../src/platformAccessory.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,2 @@
1
1
  export declare const PLATFORM_NAME = "KomfoventPing2";
2
2
  export declare const PLUGIN_NAME = "@rnsc/homebridge-komfovent-ping2";
3
- //# sourceMappingURL=settings.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"settings.js","sourceRoot":"","sources":["../src/settings.ts"],"names":[],"mappings":";;;AACa,QAAA,aAAa,GAAG,gBAAgB,CAAC;AAEjC,QAAA,WAAW,GAAG,kCAAkC,CAAC"}
1
+ {"version":3,"file":"settings.js","sourceRoot":"","sources":["../src/settings.ts"],"names":[],"mappings":";;;AAAa,QAAA,aAAa,GAAG,gBAAgB,CAAC;AACjC,QAAA,WAAW,GAAG,kCAAkC,CAAC"}
package/dist/types.d.ts CHANGED
@@ -1,6 +1,7 @@
1
- export declare type Device = {
1
+ export type Device = {
2
2
  name: string;
3
- url: string;
3
+ host: string;
4
+ port?: number;
5
+ slaveId?: number;
4
6
  deviceId: string;
5
7
  };
6
- //# sourceMappingURL=types.d.ts.map
package/package.json CHANGED
@@ -2,8 +2,8 @@
2
2
  "private": false,
3
3
  "displayName": "Komfovent Ping2",
4
4
  "name": "@rnsc/homebridge-komfovent-ping2",
5
- "version": "0.2.3",
6
- "description": "Homebridge plugin to control a Komfovent unit through a PING2 module over HTTP.",
5
+ "version": "0.3.0-beta.1",
6
+ "description": "Homebridge plugin to control a Komfovent unit through a PING2 module over Modbus TCP.",
7
7
  "license": "Apache-2.0",
8
8
  "repository": {
9
9
  "type": "git",
@@ -13,31 +13,34 @@
13
13
  "url": "https://github.com/rnsc/homebridge-komfovent-ping2/issues"
14
14
  },
15
15
  "engines": {
16
- "node": ">=14.18.1",
17
- "homebridge": ">=1.3.5"
16
+ "node": "^20.18.0 || ^22.10.0 || ^24.0.0",
17
+ "homebridge": "^1.8.0 || ^2.0.0-beta.0"
18
18
  },
19
19
  "main": "dist/index.js",
20
20
  "scripts": {
21
- "lint": "eslint src/**.ts --max-warnings=0",
21
+ "test": "vitest run",
22
+ "test:watch": "vitest",
23
+ "lint": "eslint . --max-warnings=0",
22
24
  "watch": "npm run build && npm link && nodemon",
23
25
  "build": "rimraf ./dist && tsc",
24
- "prepublishOnly": "npm run lint && npm run build"
26
+ "prepublishOnly": "npm run lint && npm test && npm run build"
25
27
  },
26
28
  "keywords": [
27
29
  "homebridge-plugin"
28
30
  ],
29
31
  "dependencies": {
30
- "axios": "^1.13.2"
32
+ "modbus-serial": "^8.0.25"
31
33
  },
32
34
  "devDependencies": {
33
- "@types/node": "^16.10.9",
34
- "@typescript-eslint/eslint-plugin": "^5.48.2",
35
- "@typescript-eslint/parser": "^5.0.0",
36
- "eslint": "^8.0.1",
37
- "homebridge": "^1.3.5",
35
+ "@eslint/js": "^9.39.0",
36
+ "@types/node": "^22.19.0",
37
+ "eslint": "^9.39.0",
38
+ "homebridge": "^2.0.0-beta.55",
38
39
  "nodemon": "^3.1.11",
39
- "rimraf": "^3.0.2",
40
- "ts-node": "^10.3.0",
41
- "typescript": "^4.4.4"
40
+ "rimraf": "^6.1.0",
41
+ "ts-node": "^10.9.2",
42
+ "typescript": "^5.9.3",
43
+ "typescript-eslint": "^8.46.0",
44
+ "vitest": "^4.1.1"
42
45
  }
43
46
  }
@@ -1 +0,0 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,sBAAsB,EAAC,MAAM,YAAY,CAAC;AAElD,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAEjC,qBAAa,eAAe;IAEd,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAFN,QAAQ,EAAE,sBAAsB,EAChC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,cAAc;IAG7C,SAAS,IAAI,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAE;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAgBxD,QAAQ,CAAC,KAAK,EAAE,MAAM;IAKtB,QAAQ,CAAC,KAAK,EAAE,MAAM;IAK5B,OAAO,CAAC,UAAU;CAmBnB"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,YAAY,CAAC;8BAQlB,GAAG;AAHlB;;GAEG;AACH,kBAEE"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"platform.d.ts","sourceRoot":"","sources":["../src/platform.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,qBAAqB,EAAE,MAAM,EAAE,iBAAiB,EAAE,cAAc,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAK5H,qBAAa,sBAAuB,YAAW,qBAAqB;aAOhD,GAAG,EAAE,MAAM;aACX,MAAM,EAAE,cAAc;aACtB,GAAG,EAAE,GAAG;IAR1B,SAAgB,OAAO,EAAE,OAAO,OAAO,CAAwB;IAC/D,SAAgB,cAAc,EAAE,OAAO,cAAc,CAA+B;IAEpF,SAAgB,WAAW,EAAE,iBAAiB,EAAE,CAAM;gBAGpC,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,cAAc,EACtB,GAAG,EAAE,GAAG;IAU1B,kBAAkB,CAAC,SAAS,EAAE,iBAAiB;IAM/C,eAAe;CAgBhB"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"platformAccessory.d.ts","sourceRoot":"","sources":["../src/platformAccessory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAW,iBAAiB,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE7F,OAAO,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAEpD,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAIjC,qBAAa,uBAAuB;IAMhC,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,MAAM;IARzB,OAAO,CAAC,OAAO,CAAU;IACzB,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,mBAAmB,CAAK;gBAGb,QAAQ,EAAE,sBAAsB,EAChC,SAAS,EAAE,iBAAiB,EAC5B,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,cAAc;IAiCnC,SAAS,IAAI,OAAO,CAAC,mBAAmB,CAAC;IASzC,SAAS,CAAC,KAAK,EAAE,mBAAmB;IAKpC,gBAAgB,CAAC,KAAK,EAAE,mBAAmB;IAWjD,kBAAkB,CAAC,KAAK,EAAE,MAAM;CAYjC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"settings.d.ts","sourceRoot":"","sources":["../src/settings.ts"],"names":[],"mappings":"AACA,eAAO,MAAM,aAAa,mBAAmB,CAAC;AAE9C,eAAO,MAAM,WAAW,qCAAqC,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AACA,oBAAY,MAAM,GAAG;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC"}