homebridge-sensus 1.1.0 → 1.1.2

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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "pluginAlias": "SensusAnalytics",
3
3
  "pluginType": "platform",
4
- "singular": false,
4
+ "singular": true,
5
5
  "schema": {
6
6
  "type": "object",
7
7
  "properties": {
@@ -49,6 +49,26 @@
49
49
  "type": "number",
50
50
  "default": 30,
51
51
  "description": "How often to fetch new data from Sensus Analytics, in minutes. Default: 30."
52
+ },
53
+ "displayUnit": {
54
+ "title": "HomeKit Display Unit",
55
+ "type": "string",
56
+ "default": "gal",
57
+ "oneOf": [
58
+ {
59
+ "title": "Gallons (gal)",
60
+ "enum": [
61
+ "gal"
62
+ ]
63
+ },
64
+ {
65
+ "title": "Liters (l)",
66
+ "enum": [
67
+ "l"
68
+ ]
69
+ }
70
+ ],
71
+ "description": "The unit of measurement to display in the HomeKit/Eve app. Default: Gallons."
52
72
  }
53
73
  }
54
74
  },
@@ -63,7 +83,11 @@
63
83
  "type": "fieldset",
64
84
  "title": "Advanced Options",
65
85
  "expandable": true,
66
- "items": ["leakThreshold", "pollInterval"]
86
+ "items": [
87
+ "leakThreshold",
88
+ "pollInterval",
89
+ "displayUnit"
90
+ ]
67
91
  }
68
92
  ]
69
93
  }
@@ -8,15 +8,27 @@ export declare class SensusWaterMeterAccessory {
8
8
  private readonly leakService;
9
9
  private readonly leakThreshold;
10
10
  private readonly pollIntervalMs;
11
+ private readonly displayUnit;
11
12
  private readonly eveConsumptionChar;
12
- private readonly historyService;
13
+ private readonly eveTotalChar;
13
14
  private lastData;
14
- private lastLoggedTimestamps;
15
15
  constructor(platform: SensusAnalyticsPlatform, accessory: PlatformAccessory, apiClient: SensusAnalyticsApi);
16
+ /**
17
+ * Helper to get the conversion factor from the Sensus API unit to Gallons.
18
+ */
19
+ private getSensusUnitMultiplier;
20
+ /**
21
+ * Converts a value in Gallons to the user's configured HomeKit display unit (gal or l).
22
+ */
23
+ private convertGallonsToDisplayUnit;
24
+ /**
25
+ * Creates and registers a custom Characteristic on the LeakSensor service.
26
+ * If the characteristic already exists (restored from cache), it is returned as-is.
27
+ */
16
28
  private addEveCharacteristic;
29
+ /** Called by HomeKit to read the current leak state. */
17
30
  private handleLeakDetectedGet;
18
- /** Log hourly entries to fakegato, skipping already-logged timestamps. */
19
- private logHourlyHistory;
31
+ /** Fetch latest data from Sensus Analytics and push updates to HomeKit. */
20
32
  private poll;
21
33
  }
22
34
  //# sourceMappingURL=accessory.d.ts.map
package/dist/accessory.js CHANGED
@@ -1,8 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.SensusWaterMeterAccessory = void 0;
4
- // Eve custom characteristic UUID for current consumption
5
- const EVE_UUID_WATER_CONSUMPTION = 'E863F10D-079E-48FF-8F27-9C2605A29F52';
4
+ // Eve for HomeKit custom characteristic UUIDs for water meters
5
+ const EVE_UUID_WATER_CONSUMPTION = 'E863F10D-079E-48FF-8F27-9C2605A29F52'; // daily usage
6
+ const EVE_UUID_TOTAL_WATER = 'E863F10C-079E-48FF-8F27-9C2605A29F52'; // odometer / total
6
7
  const DEFAULT_POLL_INTERVAL_MINUTES = 30;
7
8
  class SensusWaterMeterAccessory {
8
9
  constructor(platform, accessory, apiClient) {
@@ -10,7 +11,6 @@ class SensusWaterMeterAccessory {
10
11
  this.accessory = accessory;
11
12
  this.apiClient = apiClient;
12
13
  this.lastData = null;
13
- this.lastLoggedTimestamps = new Set();
14
14
  const { hap } = platform.api;
15
15
  const { Service: Svc, Characteristic: Char } = platform;
16
16
  this.leakThreshold = platform.config.leakThreshold ?? 150;
@@ -18,6 +18,7 @@ class SensusWaterMeterAccessory {
18
18
  (platform.config.pollInterval ?? DEFAULT_POLL_INTERVAL_MINUTES) *
19
19
  60 *
20
20
  1000;
21
+ this.displayUnit = platform.config.displayUnit ?? 'gal';
21
22
  // ── Accessory Information ─────────────────────────────────────────────
22
23
  this.accessory
23
24
  .getService(Svc.AccessoryInformation)
@@ -25,6 +26,7 @@ class SensusWaterMeterAccessory {
25
26
  .setCharacteristic(Char.Model, 'Smart Water Meter')
26
27
  .setCharacteristic(Char.SerialNumber, accessory.context.meterNumber ?? 'Unknown');
27
28
  // ── Leak Sensor (primary HomeKit service) ─────────────────────────────
29
+ // Visible in Apple Home app as a leak sensor tile with alert notifications
28
30
  this.leakService =
29
31
  this.accessory.getService(Svc.LeakSensor) ?? this.accessory.addService(Svc.LeakSensor);
30
32
  this.leakService.setCharacteristic(Char.Name, accessory.displayName);
@@ -34,25 +36,44 @@ class SensusWaterMeterAccessory {
34
36
  this.leakService
35
37
  .getCharacteristic(Char.StatusActive)
36
38
  .onGet(() => true);
37
- // ── Remove old Total Water characteristic if cached ───────────────────
38
- const oldTotalChar = this.leakService.characteristics.find((c) => c.UUID === 'E863F10C-079E-48FF-8F27-9C2605A29F52');
39
- if (oldTotalChar) {
40
- this.leakService.removeCharacteristic(oldTotalChar);
41
- }
42
- // ── Eve Consumption Characteristic ────────────────────────────────────
43
- this.eveConsumptionChar = this.addEveCharacteristic('Water Consumption', EVE_UUID_WATER_CONSUMPTION, "float" /* hap.Formats.FLOAT */, ["ev" /* hap.Perms.NOTIFY */, "pr" /* hap.Perms.PAIRED_READ */], 0, 1000000, 0.001);
44
- // ── Fakegato History Service ──────────────────────────────────────────
45
- // eslint-disable-next-line @typescript-eslint/no-require-imports
46
- const FakeGatoHistoryService = require('fakegato-history')(platform.api);
47
- this.historyService = new FakeGatoHistoryService('energy', this.accessory, {
48
- log: platform.log,
49
- storage: 'fs',
50
- size: 4032,
51
- });
39
+ // ── Eve Custom Characteristics ────────────────────────────────────────
40
+ // These are shown in the Eve for HomeKit app as consumption graphs.
41
+ // They are attached to the LeakSensor service so they share one accessory tile.
42
+ this.eveConsumptionChar = this.addEveCharacteristic('Water Consumption', EVE_UUID_WATER_CONSUMPTION, hap.Formats.FLOAT, [hap.Perms.NOTIFY, hap.Perms.PAIRED_READ], 0, 1000000, 0.001);
43
+ this.eveTotalChar = this.addEveCharacteristic('Total Water Consumption', EVE_UUID_TOTAL_WATER, hap.Formats.FLOAT, [hap.Perms.NOTIFY, hap.Perms.PAIRED_READ], 0, 1000000000, 0.001);
52
44
  // ── Start polling ─────────────────────────────────────────────────────
53
45
  this.poll();
54
46
  setInterval(() => this.poll(), this.pollIntervalMs);
55
47
  }
48
+ /**
49
+ * Helper to get the conversion factor from the Sensus API unit to Gallons.
50
+ */
51
+ getSensusUnitMultiplier(sensusUnit) {
52
+ const unit = sensusUnit.toUpperCase().trim();
53
+ if (unit === 'CCF' || unit === 'HCF') {
54
+ return 748.052; // 1 CCF = 748.052 Gallons
55
+ }
56
+ if (unit === 'CF' || unit === 'CUBIC_FOOT' || unit === 'CUBIC_FEET' || unit === 'CUBIC FEET') {
57
+ return 7.48052; // 1 Cubic Foot = 7.48052 Gallons
58
+ }
59
+ if (unit === 'L' || unit === 'LITER' || unit === 'LITERS' || unit === 'LITRES') {
60
+ return 0.264172; // 1 Liter = 0.264172 Gallons
61
+ }
62
+ return 1.0; // Default to 1 (already gallons or unknown)
63
+ }
64
+ /**
65
+ * Converts a value in Gallons to the user's configured HomeKit display unit (gal or l).
66
+ */
67
+ convertGallonsToDisplayUnit(gallons) {
68
+ if (this.displayUnit === 'l') {
69
+ return gallons * 3.78541; // 1 Gallon = 3.78541 Liters
70
+ }
71
+ return gallons; // Default to Gallons
72
+ }
73
+ /**
74
+ * Creates and registers a custom Characteristic on the LeakSensor service.
75
+ * If the characteristic already exists (restored from cache), it is returned as-is.
76
+ */
56
77
  addEveCharacteristic(displayName, uuid, format, perms, minValue, maxValue, minStep) {
57
78
  const { hap } = this.platform.api;
58
79
  const existing = this.leakService.characteristics.find((c) => c.UUID === uuid);
@@ -60,42 +81,25 @@ class SensusWaterMeterAccessory {
60
81
  return existing;
61
82
  }
62
83
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
63
- const props = { format, unit: 'gal', minValue, maxValue, minStep, perms };
84
+ const props = { format, unit: this.displayUnit, minValue, maxValue, minStep, perms };
64
85
  const char = new hap.Characteristic(displayName, uuid, props);
65
86
  char.setValue(0);
66
87
  this.leakService.addCharacteristic(char);
67
88
  return char;
68
89
  }
90
+ /** Called by HomeKit to read the current leak state. */
69
91
  handleLeakDetectedGet() {
70
92
  const { LEAK_DETECTED, LEAK_NOT_DETECTED } = this.platform.Characteristic.LeakDetected;
71
93
  if (!this.lastData) {
72
94
  return LEAK_NOT_DETECTED;
73
95
  }
74
- return this.lastData.daily.dailyUsage > this.leakThreshold
96
+ const multiplier = this.getSensusUnitMultiplier(this.lastData.daily.usageUnit);
97
+ const dailyUsageGallons = this.lastData.daily.dailyUsage * multiplier;
98
+ return dailyUsageGallons > this.leakThreshold
75
99
  ? LEAK_DETECTED
76
100
  : LEAK_NOT_DETECTED;
77
101
  }
78
- /** Log hourly entries to fakegato, skipping already-logged timestamps. */
79
- logHourlyHistory(hourly) {
80
- for (const entry of hourly) {
81
- if (this.lastLoggedTimestamps.has(entry.timestamp)) {
82
- continue;
83
- }
84
- this.historyService.addEntry({
85
- time: Math.floor(entry.timestamp / 1000),
86
- power: entry.usage,
87
- });
88
- this.lastLoggedTimestamps.add(entry.timestamp);
89
- }
90
- // Keep only the last 48 hours of timestamps to avoid unbounded growth
91
- if (this.lastLoggedTimestamps.size > 48) {
92
- const sorted = [...this.lastLoggedTimestamps].sort((a, b) => a - b);
93
- const toRemove = sorted.slice(0, sorted.length - 48);
94
- for (const ts of toRemove) {
95
- this.lastLoggedTimestamps.delete(ts);
96
- }
97
- }
98
- }
102
+ /** Fetch latest data from Sensus Analytics and push updates to HomeKit. */
99
103
  async poll() {
100
104
  this.platform.log.debug('Sensus Analytics: polling for new data...');
101
105
  const data = await this.apiClient.fetchData();
@@ -106,21 +110,30 @@ class SensusWaterMeterAccessory {
106
110
  this.lastData = data;
107
111
  const { daily, hourly } = data;
108
112
  const { LEAK_DETECTED, LEAK_NOT_DETECTED } = this.platform.Characteristic.LeakDetected;
109
- const isLeaking = daily.dailyUsage > this.leakThreshold;
110
- // Push updates to HomeKit
113
+ // Convert raw API values (which can be in CCF, CF, liters, etc.) to Gallons
114
+ const multiplier = this.getSensusUnitMultiplier(daily.usageUnit);
115
+ const dailyUsageGallons = daily.dailyUsage * multiplier;
116
+ const odometerGallons = daily.odometer * multiplier;
117
+ const billingUsageGallons = daily.billingUsage * multiplier;
118
+ // Perform leak check in Gallons
119
+ const isLeaking = dailyUsageGallons > this.leakThreshold;
120
+ // Push leak status to HomeKit
111
121
  this.leakService.updateCharacteristic(this.platform.Characteristic.LeakDetected, isLeaking ? LEAK_DETECTED : LEAK_NOT_DETECTED);
112
- // Update current consumption value
113
- this.eveConsumptionChar.updateValue(daily.dailyUsage);
114
- // Log hourly data to fakegato history for Eve graphs
115
- if (hourly.length > 0) {
116
- this.logHourlyHistory(hourly);
117
- this.platform.log.debug(`Logged ${hourly.length} hourly entries to history`);
118
- }
119
- // Log a summary
122
+ // Convert from Gallons to configured display unit (gal or l)
123
+ const dailyUsageDisplay = this.convertGallonsToDisplayUnit(dailyUsageGallons);
124
+ const odometerDisplay = this.convertGallonsToDisplayUnit(odometerGallons);
125
+ // Update custom Eve characteristics
126
+ // - eveConsumptionChar (E863F10D, Current Power / Consumption in Watts) displays daily value
127
+ this.eveConsumptionChar.updateValue(dailyUsageDisplay);
128
+ // - eveTotalChar (E863F10C, Total Consumption in kWh) displays cumulative odometer
129
+ // Multiply by 1000 because Eve app divides E863F10C by 1000 to show kWh
130
+ this.eveTotalChar.updateValue(odometerDisplay * 1000);
131
+ // Log a summary showing both raw units and HomeKit display units
120
132
  const lastHour = hourly.at(-1);
121
133
  this.platform.log.info(`[${this.accessory.displayName}] ` +
122
- `daily=${daily.dailyUsage} ${daily.usageUnit} | ` +
123
- `billing=${daily.billingUsage} ${daily.usageUnit} | ` +
134
+ `daily=${dailyUsageDisplay.toFixed(2)} ${this.displayUnit} (raw=${daily.dailyUsage} ${daily.usageUnit}) | ` +
135
+ `odometer=${odometerDisplay.toFixed(2)} ${this.displayUnit} (raw=${daily.odometer} ${daily.usageUnit}) | ` +
136
+ `billing=${billingUsageGallons.toFixed(2)} gal (raw=${daily.billingUsage} ${daily.usageUnit}) | ` +
124
137
  `leak=${isLeaking}` +
125
138
  (lastHour ? ` | lastHourUsage=${lastHour.usage} | temp=${lastHour.temp}°F` : ''));
126
139
  }
package/dist/index.js CHANGED
@@ -2,6 +2,6 @@
2
2
  const platform_1 = require("./platform");
3
3
  const settings_1 = require("./settings");
4
4
  module.exports = (api) => {
5
- api.registerPlatform(settings_1.PLUGIN_NAME, settings_1.PLATFORM_NAME, platform_1.SensusAnalyticsPlatform);
5
+ api.registerPlatform(settings_1.PLATFORM_NAME, platform_1.SensusAnalyticsPlatform);
6
6
  };
7
7
  //# sourceMappingURL=index.js.map
package/dist/sensusApi.js CHANGED
@@ -4,8 +4,6 @@ exports.SensusAnalyticsApi = void 0;
4
4
  const axios_1 = require("axios");
5
5
  const axios_cookiejar_support_1 = require("axios-cookiejar-support");
6
6
  const tough_cookie_1 = require("tough-cookie");
7
- // 1 CCF (hundred cubic feet) = 748.052 gallons
8
- const CCF_TO_GALLONS = 748.052;
9
7
  class SensusAnalyticsApi {
10
8
  constructor(baseUrl, username, password, accountNumber, meterNumber, log) {
11
9
  this.baseUrl = baseUrl;
@@ -91,18 +89,16 @@ class SensusAnalyticsApi {
91
89
  this.log.warn('Sensus Analytics: unexpected daily data structure');
92
90
  return null;
93
91
  }
94
- const rawUnit = (device.usageUnit || 'CCF').toUpperCase();
95
- const toGallons = rawUnit === 'CCF' ? CCF_TO_GALLONS : 1;
96
92
  return {
97
- dailyUsage: Math.round(((parseFloat(device.dailyUsage) || 0) * toGallons) * 100) / 100,
98
- usageUnit: 'GAL',
93
+ dailyUsage: parseFloat(device.dailyUsage) || 0,
94
+ usageUnit: device.usageUnit || 'CCF',
99
95
  meterAddress: device.meterAddress1 || '',
100
96
  lastRead: device.lastRead || '',
101
97
  meterId: String(device.meterId || ''),
102
98
  meterLat: parseFloat(device.meterLat) || 0,
103
99
  meterLong: parseFloat(device.meterLong) || 0,
104
- odometer: Math.round(((parseFloat(device.latestReadUsage) || 0) * toGallons) * 100) / 100,
105
- billingUsage: Math.round(((parseFloat(device.billingUsage) || 0) * toGallons) * 100) / 100,
100
+ odometer: parseFloat(device.latestReadUsage) || 0,
101
+ billingUsage: parseFloat(device.billingUsage) || 0,
106
102
  };
107
103
  }
108
104
  async fetchHourlyData() {
@@ -131,15 +127,14 @@ class SensusAnalyticsApi {
131
127
  return [];
132
128
  }
133
129
  // First element is units row: [usageUnit, rainUnit, tempUnit, altUnit]
134
- const [rawUsageUnit, rainUnit, tempUnit] = usageArray[0];
130
+ const [usageUnit, rainUnit, tempUnit] = usageArray[0];
135
131
  const rows = usageArray.slice(1);
136
- const toGallons = (rawUsageUnit ?? 'CCF').toUpperCase() === 'CCF' ? CCF_TO_GALLONS : 1;
137
132
  return rows.map((row) => ({
138
133
  timestamp: row[0],
139
- usage: Math.round(((row[1] ?? 0) * toGallons) * 100) / 100,
134
+ usage: row[1] ?? 0,
140
135
  rain: row[2] ?? 0,
141
136
  temp: row[3] ?? 0,
142
- usageUnit: 'GAL',
137
+ usageUnit: usageUnit ?? 'CCF',
143
138
  rainUnit: rainUnit ?? 'INCHES',
144
139
  tempUnit: tempUnit ?? 'FAHRENHEIT',
145
140
  }));
package/package.json CHANGED
@@ -1,26 +1,14 @@
1
1
  {
2
2
  "name": "homebridge-sensus",
3
- "displayName": "Homebridge Sensus",
4
- "version": "1.1.0",
3
+ "version": "1.1.2",
5
4
  "description": "Homebridge plugin for Sensus Analytics water meters",
6
5
  "license": "MIT",
7
- "repository": {
8
- "type": "git",
9
- "url": "https://github.com/jmarrmd/homebridge-sensus.git"
10
- },
11
- "bugs": {
12
- "url": "https://github.com/jmarrmd/homebridge-sensus/issues"
13
- },
14
- "homepage": "https://github.com/jmarrmd/homebridge-sensus#readme",
15
6
  "main": "dist/index.js",
16
- "files": [
17
- "dist/",
18
- "config.schema.json"
19
- ],
20
7
  "scripts": {
21
- "build": "true",
22
- "compile": "tsc",
23
- "watch": "tsc --watch"
8
+ "build": "tsc",
9
+ "watch": "tsc --watch",
10
+ "prepare": "npm run build",
11
+ "prepublishOnly": "npm run build"
24
12
  },
25
13
  "keywords": [
26
14
  "homebridge-plugin",
@@ -31,21 +19,20 @@
31
19
  ],
32
20
  "engines": {
33
21
  "node": ">=18.0.0",
34
- "homebridge": ">=1.6.0"
22
+ "homebridge": ">=1.6.0 <3.0.0"
35
23
  },
36
24
  "dependencies": {
37
25
  "axios": "^1.6.0",
38
26
  "axios-cookiejar-support": "^4.0.7",
39
- "fakegato-history": "^0.6.7",
40
27
  "tough-cookie": "^4.1.3"
41
28
  },
42
29
  "devDependencies": {
43
30
  "@types/node": "^20.0.0",
44
31
  "@types/tough-cookie": "^4.0.5",
45
- "homebridge": "^1.8.0",
32
+ "homebridge": "^2.0.0",
46
33
  "typescript": "^5.3.0"
47
34
  },
48
35
  "peerDependencies": {
49
- "homebridge": ">=1.6.0"
36
+ "homebridge": ">=1.6.0 <3.0.0"
50
37
  }
51
38
  }
@@ -0,0 +1,210 @@
1
+ import { PlatformAccessory, CharacteristicValue, Service, Characteristic } from 'homebridge';
2
+ import { SensusAnalyticsPlatform } from './platform';
3
+ import { SensusAnalyticsApi, SensusData } from './sensusApi';
4
+
5
+ // Eve for HomeKit custom characteristic UUIDs for water meters
6
+ const EVE_UUID_WATER_CONSUMPTION = 'E863F10D-079E-48FF-8F27-9C2605A29F52'; // daily usage
7
+ const EVE_UUID_TOTAL_WATER = 'E863F10C-079E-48FF-8F27-9C2605A29F52'; // odometer / total
8
+
9
+ const DEFAULT_POLL_INTERVAL_MINUTES = 30;
10
+
11
+ export class SensusWaterMeterAccessory {
12
+ private readonly leakService: Service;
13
+ private readonly leakThreshold: number;
14
+ private readonly pollIntervalMs: number;
15
+ private readonly displayUnit: string;
16
+
17
+ // Direct references to Eve custom characteristics to avoid UUID lookups on update
18
+ private readonly eveConsumptionChar: Characteristic;
19
+ private readonly eveTotalChar: Characteristic;
20
+
21
+ private lastData: SensusData | null = null;
22
+
23
+ constructor(
24
+ private readonly platform: SensusAnalyticsPlatform,
25
+ private readonly accessory: PlatformAccessory,
26
+ private readonly apiClient: SensusAnalyticsApi,
27
+ ) {
28
+ const { hap } = platform.api;
29
+ const { Service: Svc, Characteristic: Char } = platform;
30
+
31
+ this.leakThreshold = (platform.config.leakThreshold as number | undefined) ?? 150;
32
+ this.pollIntervalMs =
33
+ ((platform.config.pollInterval as number | undefined) ?? DEFAULT_POLL_INTERVAL_MINUTES) *
34
+ 60 *
35
+ 1000;
36
+ this.displayUnit = (platform.config.displayUnit as string | undefined) ?? 'gal';
37
+
38
+ // ── Accessory Information ─────────────────────────────────────────────
39
+ this.accessory
40
+ .getService(Svc.AccessoryInformation)!
41
+ .setCharacteristic(Char.Manufacturer, 'Sensus')
42
+ .setCharacteristic(Char.Model, 'Smart Water Meter')
43
+ .setCharacteristic(
44
+ Char.SerialNumber,
45
+ (accessory.context.meterNumber as string | undefined) ?? 'Unknown',
46
+ );
47
+
48
+ // ── Leak Sensor (primary HomeKit service) ─────────────────────────────
49
+ // Visible in Apple Home app as a leak sensor tile with alert notifications
50
+ this.leakService =
51
+ this.accessory.getService(Svc.LeakSensor) ?? this.accessory.addService(Svc.LeakSensor);
52
+
53
+ this.leakService.setCharacteristic(Char.Name, accessory.displayName);
54
+
55
+ this.leakService
56
+ .getCharacteristic(Char.LeakDetected)
57
+ .onGet(this.handleLeakDetectedGet.bind(this));
58
+
59
+ this.leakService
60
+ .getCharacteristic(Char.StatusActive)
61
+ .onGet(() => true);
62
+
63
+ // ── Eve Custom Characteristics ────────────────────────────────────────
64
+ // These are shown in the Eve for HomeKit app as consumption graphs.
65
+ // They are attached to the LeakSensor service so they share one accessory tile.
66
+
67
+ this.eveConsumptionChar = this.addEveCharacteristic(
68
+ 'Water Consumption',
69
+ EVE_UUID_WATER_CONSUMPTION,
70
+ hap.Formats.FLOAT,
71
+ [hap.Perms.NOTIFY, hap.Perms.PAIRED_READ],
72
+ 0, 1_000_000, 0.001,
73
+ );
74
+
75
+ this.eveTotalChar = this.addEveCharacteristic(
76
+ 'Total Water Consumption',
77
+ EVE_UUID_TOTAL_WATER,
78
+ hap.Formats.FLOAT,
79
+ [hap.Perms.NOTIFY, hap.Perms.PAIRED_READ],
80
+ 0, 1_000_000_000, 0.001,
81
+ );
82
+
83
+ // ── Start polling ─────────────────────────────────────────────────────
84
+ this.poll();
85
+ setInterval(() => this.poll(), this.pollIntervalMs);
86
+ }
87
+
88
+ /**
89
+ * Helper to get the conversion factor from the Sensus API unit to Gallons.
90
+ */
91
+ private getSensusUnitMultiplier(sensusUnit: string): number {
92
+ const unit = sensusUnit.toUpperCase().trim();
93
+ if (unit === 'CCF' || unit === 'HCF') {
94
+ return 748.052; // 1 CCF = 748.052 Gallons
95
+ }
96
+ if (unit === 'CF' || unit === 'CUBIC_FOOT' || unit === 'CUBIC_FEET' || unit === 'CUBIC FEET') {
97
+ return 7.48052; // 1 Cubic Foot = 7.48052 Gallons
98
+ }
99
+ if (unit === 'L' || unit === 'LITER' || unit === 'LITERS' || unit === 'LITRES') {
100
+ return 0.264172; // 1 Liter = 0.264172 Gallons
101
+ }
102
+ return 1.0; // Default to 1 (already gallons or unknown)
103
+ }
104
+
105
+ /**
106
+ * Converts a value in Gallons to the user's configured HomeKit display unit (gal or l).
107
+ */
108
+ private convertGallonsToDisplayUnit(gallons: number): number {
109
+ if (this.displayUnit === 'l') {
110
+ return gallons * 3.78541; // 1 Gallon = 3.78541 Liters
111
+ }
112
+ return gallons; // Default to Gallons
113
+ }
114
+
115
+ /**
116
+ * Creates and registers a custom Characteristic on the LeakSensor service.
117
+ * If the characteristic already exists (restored from cache), it is returned as-is.
118
+ */
119
+ private addEveCharacteristic(
120
+ displayName: string,
121
+ uuid: string,
122
+ format: string,
123
+ perms: string[],
124
+ minValue: number,
125
+ maxValue: number,
126
+ minStep: number,
127
+ ): Characteristic {
128
+ const { hap } = this.platform.api;
129
+
130
+ const existing = this.leakService.characteristics.find((c) => c.UUID === uuid);
131
+ if (existing) {
132
+ return existing;
133
+ }
134
+
135
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
136
+ const props: any = { format, unit: this.displayUnit, minValue, maxValue, minStep, perms };
137
+ const char = new hap.Characteristic(displayName, uuid, props);
138
+ char.setValue(0);
139
+ this.leakService.addCharacteristic(char);
140
+ return char;
141
+ }
142
+
143
+ /** Called by HomeKit to read the current leak state. */
144
+ private handleLeakDetectedGet(): CharacteristicValue {
145
+ const { LEAK_DETECTED, LEAK_NOT_DETECTED } = this.platform.Characteristic.LeakDetected;
146
+
147
+ if (!this.lastData) {
148
+ return LEAK_NOT_DETECTED;
149
+ }
150
+
151
+ const multiplier = this.getSensusUnitMultiplier(this.lastData.daily.usageUnit);
152
+ const dailyUsageGallons = this.lastData.daily.dailyUsage * multiplier;
153
+
154
+ return dailyUsageGallons > this.leakThreshold
155
+ ? LEAK_DETECTED
156
+ : LEAK_NOT_DETECTED;
157
+ }
158
+
159
+ /** Fetch latest data from Sensus Analytics and push updates to HomeKit. */
160
+ private async poll(): Promise<void> {
161
+ this.platform.log.debug('Sensus Analytics: polling for new data...');
162
+
163
+ const data = await this.apiClient.fetchData();
164
+ if (!data) {
165
+ this.platform.log.warn('Sensus Analytics: no data returned, will retry next interval');
166
+ return;
167
+ }
168
+
169
+ this.lastData = data;
170
+ const { daily, hourly } = data;
171
+ const { LEAK_DETECTED, LEAK_NOT_DETECTED } = this.platform.Characteristic.LeakDetected;
172
+
173
+ // Convert raw API values (which can be in CCF, CF, liters, etc.) to Gallons
174
+ const multiplier = this.getSensusUnitMultiplier(daily.usageUnit);
175
+ const dailyUsageGallons = daily.dailyUsage * multiplier;
176
+ const odometerGallons = daily.odometer * multiplier;
177
+ const billingUsageGallons = daily.billingUsage * multiplier;
178
+
179
+ // Perform leak check in Gallons
180
+ const isLeaking = dailyUsageGallons > this.leakThreshold;
181
+
182
+ // Push leak status to HomeKit
183
+ this.leakService.updateCharacteristic(
184
+ this.platform.Characteristic.LeakDetected,
185
+ isLeaking ? LEAK_DETECTED : LEAK_NOT_DETECTED,
186
+ );
187
+
188
+ // Convert from Gallons to configured display unit (gal or l)
189
+ const dailyUsageDisplay = this.convertGallonsToDisplayUnit(dailyUsageGallons);
190
+ const odometerDisplay = this.convertGallonsToDisplayUnit(odometerGallons);
191
+
192
+ // Update custom Eve characteristics
193
+ // - eveConsumptionChar (E863F10D, Current Power / Consumption in Watts) displays daily value
194
+ this.eveConsumptionChar.updateValue(dailyUsageDisplay);
195
+ // - eveTotalChar (E863F10C, Total Consumption in kWh) displays cumulative odometer
196
+ // Multiply by 1000 because Eve app divides E863F10C by 1000 to show kWh
197
+ this.eveTotalChar.updateValue(odometerDisplay * 1000);
198
+
199
+ // Log a summary showing both raw units and HomeKit display units
200
+ const lastHour = hourly.at(-1);
201
+ this.platform.log.info(
202
+ `[${this.accessory.displayName}] ` +
203
+ `daily=${dailyUsageDisplay.toFixed(2)} ${this.displayUnit} (raw=${daily.dailyUsage} ${daily.usageUnit}) | ` +
204
+ `odometer=${odometerDisplay.toFixed(2)} ${this.displayUnit} (raw=${daily.odometer} ${daily.usageUnit}) | ` +
205
+ `billing=${billingUsageGallons.toFixed(2)} gal (raw=${daily.billingUsage} ${daily.usageUnit}) | ` +
206
+ `leak=${isLeaking}` +
207
+ (lastHour ? ` | lastHourUsage=${lastHour.usage} | temp=${lastHour.temp}°F` : ''),
208
+ );
209
+ }
210
+ }
package/src/index.ts ADDED
@@ -0,0 +1,7 @@
1
+ import { API } from 'homebridge';
2
+ import { SensusAnalyticsPlatform } from './platform';
3
+ import { PLATFORM_NAME } from './settings';
4
+
5
+ export = (api: API): void => {
6
+ api.registerPlatform(PLATFORM_NAME, SensusAnalyticsPlatform);
7
+ };
@@ -0,0 +1,79 @@
1
+ import {
2
+ API,
3
+ Characteristic,
4
+ DynamicPlatformPlugin,
5
+ Logger,
6
+ PlatformAccessory,
7
+ PlatformConfig,
8
+ Service,
9
+ } from 'homebridge';
10
+
11
+ import { PLATFORM_NAME, PLUGIN_NAME } from './settings';
12
+ import { SensusWaterMeterAccessory } from './accessory';
13
+ import { SensusAnalyticsApi } from './sensusApi';
14
+
15
+ export class SensusAnalyticsPlatform implements DynamicPlatformPlugin {
16
+ public readonly Service: typeof Service;
17
+ public readonly Characteristic: typeof Characteristic;
18
+
19
+ // Restored cached accessories from disk
20
+ public readonly cachedAccessories: PlatformAccessory[] = [];
21
+
22
+ constructor(
23
+ public readonly log: Logger,
24
+ public readonly config: PlatformConfig,
25
+ public readonly api: API,
26
+ ) {
27
+ this.Service = this.api.hap.Service;
28
+ this.Characteristic = this.api.hap.Characteristic;
29
+
30
+ this.log.debug('Sensus Analytics platform initialising');
31
+
32
+ this.api.on('didFinishLaunching', () => {
33
+ this.discoverDevices();
34
+ });
35
+ }
36
+
37
+ /** Called by Homebridge to restore cached accessories on startup. */
38
+ configureAccessory(accessory: PlatformAccessory): void {
39
+ this.log.info('Restoring cached accessory:', accessory.displayName);
40
+ this.cachedAccessories.push(accessory);
41
+ }
42
+
43
+ private discoverDevices(): void {
44
+ const { baseUrl, username, password, accountNumber, meterNumber } = this.config;
45
+
46
+ if (!baseUrl || !username || !password || !accountNumber || !meterNumber) {
47
+ this.log.error(
48
+ 'Sensus Analytics: missing required config fields ' +
49
+ '(baseUrl, username, password, accountNumber, meterNumber)',
50
+ );
51
+ return;
52
+ }
53
+
54
+ const apiClient = new SensusAnalyticsApi(
55
+ baseUrl,
56
+ username,
57
+ password,
58
+ accountNumber,
59
+ meterNumber,
60
+ this.log,
61
+ );
62
+
63
+ const displayName = (this.config.name as string | undefined) || 'Sensus Water Meter';
64
+ const uuid = this.api.hap.uuid.generate(`sensus-${meterNumber}`);
65
+
66
+ const existing = this.cachedAccessories.find((a) => a.UUID === uuid);
67
+
68
+ if (existing) {
69
+ this.log.info('Restoring water meter accessory:', existing.displayName);
70
+ new SensusWaterMeterAccessory(this, existing, apiClient);
71
+ } else {
72
+ this.log.info('Adding new water meter accessory:', displayName);
73
+ const accessory = new this.api.platformAccessory(displayName, uuid);
74
+ accessory.context.meterNumber = meterNumber;
75
+ new SensusWaterMeterAccessory(this, accessory, apiClient);
76
+ this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]);
77
+ }
78
+ }
79
+ }
@@ -0,0 +1,197 @@
1
+ import axios, { AxiosInstance } from 'axios';
2
+ import { wrapper } from 'axios-cookiejar-support';
3
+ import { CookieJar } from 'tough-cookie';
4
+ import { Logger } from 'homebridge';
5
+
6
+ export interface DailyData {
7
+ dailyUsage: number;
8
+ usageUnit: string;
9
+ meterAddress: string;
10
+ lastRead: string;
11
+ meterId: string;
12
+ meterLat: number;
13
+ meterLong: number;
14
+ odometer: number;
15
+ billingUsage: number;
16
+ }
17
+
18
+ export interface HourlyEntry {
19
+ timestamp: number;
20
+ usage: number;
21
+ rain: number;
22
+ temp: number;
23
+ usageUnit: string;
24
+ rainUnit: string;
25
+ tempUnit: string;
26
+ }
27
+
28
+ export interface SensusData {
29
+ daily: DailyData;
30
+ hourly: HourlyEntry[];
31
+ }
32
+
33
+ export class SensusAnalyticsApi {
34
+ private readonly client: AxiosInstance;
35
+ private readonly jar: CookieJar;
36
+ private loggedIn = false;
37
+
38
+ constructor(
39
+ private readonly baseUrl: string,
40
+ private readonly username: string,
41
+ private readonly password: string,
42
+ private readonly accountNumber: string,
43
+ private readonly meterNumber: string,
44
+ private readonly log: Logger,
45
+ ) {
46
+ this.jar = new CookieJar();
47
+ this.client = wrapper(
48
+ axios.create({
49
+ baseURL: baseUrl.replace(/\/$/, ''),
50
+ jar: this.jar,
51
+ withCredentials: true,
52
+ // Follow redirects but treat 302 as success for login
53
+ maxRedirects: 5,
54
+ timeout: 15000,
55
+ }),
56
+ );
57
+ }
58
+
59
+ async login(): Promise<boolean> {
60
+ try {
61
+ this.log.debug('Sensus Analytics: attempting login...');
62
+ await this.client.post(
63
+ '/j_spring_security_check',
64
+ new URLSearchParams({
65
+ j_username: this.username,
66
+ j_password: this.password,
67
+ }).toString(),
68
+ {
69
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
70
+ // A 302 redirect means login was processed; axios follows it automatically
71
+ validateStatus: (s) => s < 400,
72
+ },
73
+ );
74
+ this.loggedIn = true;
75
+ this.log.debug('Sensus Analytics: login successful');
76
+ return true;
77
+ } catch (err) {
78
+ this.loggedIn = false;
79
+ this.log.error('Sensus Analytics: login failed:', (err as Error).message);
80
+ return false;
81
+ }
82
+ }
83
+
84
+ async fetchData(): Promise<SensusData | null> {
85
+ if (!this.loggedIn) {
86
+ const ok = await this.login();
87
+ if (!ok) {
88
+ return null;
89
+ }
90
+ }
91
+
92
+ try {
93
+ const [daily, hourly] = await Promise.all([
94
+ this.fetchDailyData(),
95
+ this.fetchHourlyData(),
96
+ ]);
97
+
98
+ if (!daily) {
99
+ // Session may have expired — clear and retry once
100
+ this.loggedIn = false;
101
+ const ok = await this.login();
102
+ if (!ok) {
103
+ return null;
104
+ }
105
+ const retried = await this.fetchDailyData();
106
+ if (!retried) {
107
+ return null;
108
+ }
109
+ return { daily: retried, hourly: hourly ?? [] };
110
+ }
111
+
112
+ return { daily, hourly: hourly ?? [] };
113
+ } catch (err) {
114
+ this.loggedIn = false;
115
+ this.log.error('Sensus Analytics: error fetching data:', (err as Error).message);
116
+ return null;
117
+ }
118
+ }
119
+
120
+ private async fetchDailyData(): Promise<DailyData | null> {
121
+ const response = await this.client.post('/water/widget/byPage', {
122
+ group: 'meters',
123
+ accountNumber: this.accountNumber,
124
+ deviceId: this.meterNumber,
125
+ });
126
+
127
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
128
+ const device = (response.data as any)?.widgetList?.[0]?.data?.devices?.[0];
129
+ if (!device) {
130
+ this.log.warn('Sensus Analytics: unexpected daily data structure');
131
+ return null;
132
+ }
133
+
134
+ return {
135
+ dailyUsage: parseFloat(device.dailyUsage) || 0,
136
+ usageUnit: device.usageUnit || 'CCF',
137
+ meterAddress: device.meterAddress1 || '',
138
+ lastRead: device.lastRead || '',
139
+ meterId: String(device.meterId || ''),
140
+ meterLat: parseFloat(device.meterLat) || 0,
141
+ meterLong: parseFloat(device.meterLong) || 0,
142
+ odometer: parseFloat(device.latestReadUsage) || 0,
143
+ billingUsage: parseFloat(device.billingUsage) || 0,
144
+ };
145
+ }
146
+
147
+ private async fetchHourlyData(): Promise<HourlyEntry[] | null> {
148
+ // Fetch the previous day's data (Sensus updates at midnight)
149
+ const yesterday = new Date();
150
+ yesterday.setDate(yesterday.getDate() - 1);
151
+ const startOfDay = new Date(
152
+ yesterday.getFullYear(),
153
+ yesterday.getMonth(),
154
+ yesterday.getDate(),
155
+ );
156
+ const endOfDay = new Date(startOfDay.getTime() + 86_400_000 - 1);
157
+
158
+ const response = await this.client.get(
159
+ `/water/usage/${this.accountNumber}/${this.meterNumber}`,
160
+ {
161
+ params: {
162
+ start: startOfDay.getTime(),
163
+ end: endOfDay.getTime(),
164
+ zoom: 'day',
165
+ page: 'null',
166
+ weather: '1',
167
+ },
168
+ },
169
+ );
170
+
171
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
172
+ const data = response.data as any;
173
+ if (!data?.operationSuccess) {
174
+ this.log.warn('Sensus Analytics: hourly data fetch unsuccessful');
175
+ return null;
176
+ }
177
+
178
+ const usageArray: unknown[][] = data?.data?.usage;
179
+ if (!Array.isArray(usageArray) || usageArray.length < 2) {
180
+ return [];
181
+ }
182
+
183
+ // First element is units row: [usageUnit, rainUnit, tempUnit, altUnit]
184
+ const [usageUnit, rainUnit, tempUnit] = usageArray[0] as string[];
185
+ const rows = usageArray.slice(1);
186
+
187
+ return rows.map((row) => ({
188
+ timestamp: row[0] as number,
189
+ usage: (row[1] as number) ?? 0,
190
+ rain: (row[2] as number) ?? 0,
191
+ temp: (row[3] as number) ?? 0,
192
+ usageUnit: usageUnit ?? 'CCF',
193
+ rainUnit: rainUnit ?? 'INCHES',
194
+ tempUnit: tempUnit ?? 'FAHRENHEIT',
195
+ }));
196
+ }
197
+ }
@@ -0,0 +1,2 @@
1
+ export const PLATFORM_NAME = 'SensusAnalytics';
2
+ export const PLUGIN_NAME = 'homebridge-sensus';
package/tsconfig.json ADDED
@@ -0,0 +1,18 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "module": "commonjs",
5
+ "lib": ["ES2020"],
6
+ "strict": true,
7
+ "noImplicitAny": true,
8
+ "strictNullChecks": true,
9
+ "moduleResolution": "node",
10
+ "experimentalDecorators": true,
11
+ "skipLibCheck": true,
12
+ "outDir": "dist",
13
+ "declaration": true,
14
+ "declarationMap": true,
15
+ "sourceMap": true
16
+ },
17
+ "include": ["src"]
18
+ }
@@ -1 +0,0 @@
1
- {"version":3,"file":"accessory.d.ts","sourceRoot":"","sources":["../src/accessory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAgD,MAAM,YAAY,CAAC;AAC7F,OAAO,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,EAAE,kBAAkB,EAA2B,MAAM,aAAa,CAAC;AAO1E,qBAAa,yBAAyB;IAelC,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,SAAS;IAhB5B,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAU;IACtC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IACvC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;IAExC,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAiB;IAIpD,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAM;IAErC,OAAO,CAAC,QAAQ,CAA2B;IAC3C,OAAO,CAAC,oBAAoB,CAA0B;gBAGnC,QAAQ,EAAE,uBAAuB,EACjC,SAAS,EAAE,iBAAiB,EAC5B,SAAS,EAAE,kBAAkB;IAkEhD,OAAO,CAAC,oBAAoB;IAwB5B,OAAO,CAAC,qBAAqB;IAY7B,0EAA0E;IAC1E,OAAO,CAAC,gBAAgB;YAwBV,IAAI;CAwCnB"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"accessory.js","sourceRoot":"","sources":["../src/accessory.ts"],"names":[],"mappings":"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"}
@@ -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;yBAIvB,KAAK,GAAG,KAAG,IAAI;AAAzB,kBAEE"}
package/dist/index.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,yCAAqD;AACrD,yCAAwD;AAExD,iBAAS,CAAC,GAAQ,EAAQ,EAAE;IAC1B,GAAG,CAAC,gBAAgB,CAAC,sBAAW,EAAE,wBAAa,EAAE,kCAAuB,CAAC,CAAC;AAC5E,CAAC,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"platform.d.ts","sourceRoot":"","sources":["../src/platform.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,GAAG,EACH,cAAc,EACd,qBAAqB,EACrB,MAAM,EACN,iBAAiB,EACjB,cAAc,EACd,OAAO,EACR,MAAM,YAAY,CAAC;AAMpB,qBAAa,uBAAwB,YAAW,qBAAqB;aAQjD,GAAG,EAAE,MAAM;aACX,MAAM,EAAE,cAAc;aACtB,GAAG,EAAE,GAAG;IAT1B,SAAgB,OAAO,EAAE,OAAO,OAAO,CAAC;IACxC,SAAgB,cAAc,EAAE,OAAO,cAAc,CAAC;IAGtD,SAAgB,iBAAiB,EAAE,iBAAiB,EAAE,CAAM;gBAG1C,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,cAAc,EACtB,GAAG,EAAE,GAAG;IAY1B,qEAAqE;IACrE,kBAAkB,CAAC,SAAS,EAAE,iBAAiB,GAAG,IAAI;IAKtD,OAAO,CAAC,eAAe;CAoCxB"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"platform.js","sourceRoot":"","sources":["../src/platform.ts"],"names":[],"mappings":";;;AAUA,yCAAwD;AACxD,2CAAwD;AACxD,2CAAiD;AAEjD,MAAa,uBAAuB;IAOlC,YACkB,GAAW,EACX,MAAsB,EACtB,GAAQ;QAFR,QAAG,GAAH,GAAG,CAAQ;QACX,WAAM,GAAN,MAAM,CAAgB;QACtB,QAAG,GAAH,GAAG,CAAK;QAN1B,wCAAwC;QACxB,sBAAiB,GAAwB,EAAE,CAAC;QAO1D,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC;QACpC,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,cAAc,CAAC;QAElD,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,wCAAwC,CAAC,CAAC;QAEzD,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,oBAAoB,EAAE,GAAG,EAAE;YACrC,IAAI,CAAC,eAAe,EAAE,CAAC;QACzB,CAAC,CAAC,CAAC;IACL,CAAC;IAED,qEAAqE;IACrE,kBAAkB,CAAC,SAA4B;QAC7C,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,6BAA6B,EAAE,SAAS,CAAC,WAAW,CAAC,CAAC;QACpE,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACzC,CAAC;IAEO,eAAe;QACrB,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,aAAa,EAAE,WAAW,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC;QAEhF,IAAI,CAAC,OAAO,IAAI,CAAC,QAAQ,IAAI,CAAC,QAAQ,IAAI,CAAC,aAAa,IAAI,CAAC,WAAW,EAAE,CAAC;YACzE,IAAI,CAAC,GAAG,CAAC,KAAK,CACZ,mDAAmD;gBACnD,2DAA2D,CAC5D,CAAC;YACF,OAAO;QACT,CAAC;QAED,MAAM,SAAS,GAAG,IAAI,8BAAkB,CACtC,OAAO,EACP,QAAQ,EACR,QAAQ,EACR,aAAa,EACb,WAAW,EACX,IAAI,CAAC,GAAG,CACT,CAAC;QAEF,MAAM,WAAW,GAAI,IAAI,CAAC,MAAM,CAAC,IAA2B,IAAI,oBAAoB,CAAC;QACrF,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU,WAAW,EAAE,CAAC,CAAC;QAEjE,MAAM,QAAQ,GAAG,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;QAErE,IAAI,QAAQ,EAAE,CAAC;YACb,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,kCAAkC,EAAE,QAAQ,CAAC,WAAW,CAAC,CAAC;YACxE,IAAI,qCAAyB,CAAC,IAAI,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC;QAC3D,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,mCAAmC,EAAE,WAAW,CAAC,CAAC;YAChE,MAAM,SAAS,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,iBAAiB,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;YACpE,SAAS,CAAC,OAAO,CAAC,WAAW,GAAG,WAAW,CAAC;YAC5C,IAAI,qCAAyB,CAAC,IAAI,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;YAC1D,IAAI,CAAC,GAAG,CAAC,2BAA2B,CAAC,sBAAW,EAAE,wBAAa,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC;QAChF,CAAC;IACH,CAAC;CACF;AAhED,0DAgEC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"sensusApi.d.ts","sourceRoot":"","sources":["../src/sensusApi.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAEpC,MAAM,WAAW,SAAS;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,SAAS,CAAC;IACjB,MAAM,EAAE,WAAW,EAAE,CAAC;CACvB;AAKD,qBAAa,kBAAkB;IAM3B,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,aAAa;IAC9B,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,GAAG;IAVtB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAgB;IACvC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAY;IAChC,OAAO,CAAC,QAAQ,CAAS;gBAGN,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,aAAa,EAAE,MAAM,EACrB,WAAW,EAAE,MAAM,EACnB,GAAG,EAAE,MAAM;IAexB,KAAK,IAAI,OAAO,CAAC,OAAO,CAAC;IAyBzB,SAAS,IAAI,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;YAoC/B,cAAc;YA8Bd,eAAe;CAmD9B"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"sensusApi.js","sourceRoot":"","sources":["../src/sensusApi.ts"],"names":[],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"settings.d.ts","sourceRoot":"","sources":["../src/settings.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,aAAa,oBAAoB,CAAC;AAC/C,eAAO,MAAM,WAAW,sBAAsB,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"settings.js","sourceRoot":"","sources":["../src/settings.ts"],"names":[],"mappings":";;;AAAa,QAAA,aAAa,GAAG,iBAAiB,CAAC;AAClC,QAAA,WAAW,GAAG,mBAAmB,CAAC"}