homebridge-octopus-energy 0.0.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,58 @@
1
+ # Homebridge Octopus Energy
2
+
3
+ Homebridge platform plugin that surfaces Octopus Energy SMETS2 import (and optional export) meters into HomeKit. It polls the Octopus public API, converts interval kWh readings into watts, and exposes Eve-style energy characteristics (instantaneous watts and today’s total kWh). Apple Home will show the Outlet accessory; rich energy data appears in Eve, Home+, and other advanced HomeKit apps.
4
+
5
+ ## Requirements
6
+ - Node.js >= 18
7
+ - Homebridge >= 1.7
8
+ - Octopus API key plus MPAN and meter serial(s)
9
+
10
+ ## Installation
11
+ ### Homebridge UI X
12
+ 1. Open **Config UI X** → **Plugins**.
13
+ 2. Search for `homebridge-octopus-energy`.
14
+ 3. Install and restart Homebridge.
15
+
16
+ ### npm (global)
17
+ ```bash
18
+ npm i -g homebridge-octopus-energy
19
+ ```
20
+
21
+ ## Configuration
22
+ Add to `config.json` (or use the UI form powered by `config.schema.json`):
23
+ ```json
24
+ {
25
+ "platform": "OctopusEnergyPlatform",
26
+ "name": "Octopus Energy",
27
+ "apiKey": "sk_live_your_key",
28
+ "pollSeconds": 300,
29
+ "import": {
30
+ "name": "Octopus Import",
31
+ "mpan": "YOUR_IMPORT_MPAN",
32
+ "meterSerial": "IMPORT_SERIAL"
33
+ },
34
+ "export": {
35
+ "name": "Octopus Export",
36
+ "mpan": "YOUR_EXPORT_MPAN",
37
+ "meterSerial": "EXPORT_SERIAL"
38
+ }
39
+ }
40
+ ```
41
+
42
+ Notes:
43
+ - Import is required; export is optional (requires both MPAN and meter serial).
44
+ - Polls immediately on startup, then every `pollSeconds` (min 60s).
45
+ - Eve characteristics expose live watts and a rolling “today” total (kWh). Apple Home won’t show these values, but Eve/Home+ will.
46
+
47
+ ## What it does
48
+ - Calls the Octopus REST API for electricity consumption.
49
+ - Converts the latest interval kWh to watts; sums today’s intervals for total kWh.
50
+ - Exposes an `Outlet` service for Home visibility plus Eve Energy characteristics for power and total energy.
51
+ - Keeps last values if the API fails and logs warnings instead of crashing.
52
+
53
+ ## Links
54
+ - GitHub: https://github.com/icebondx/homebridge-octopus-energy
55
+ - Issues: https://github.com/icebondx/homebridge-octopus-energy/issues
56
+
57
+ ## License
58
+ MIT
@@ -0,0 +1,71 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "pluginAlias": "OctopusEnergyPlatform",
4
+ "pluginType": "platform",
5
+ "singular": false,
6
+ "schema": {
7
+ "type": "object",
8
+ "properties": {
9
+ "name": {
10
+ "type": "string",
11
+ "title": "Platform Name",
12
+ "default": "Octopus Energy"
13
+ },
14
+ "apiKey": {
15
+ "type": "string",
16
+ "title": "Octopus API Key",
17
+ "description": "Create an API key in your Octopus Energy account.",
18
+ "required": true
19
+ },
20
+ "pollSeconds": {
21
+ "type": "number",
22
+ "title": "Polling Interval (seconds)",
23
+ "default": 300,
24
+ "minimum": 60
25
+ },
26
+ "import": {
27
+ "type": "object",
28
+ "title": "Import Meter",
29
+ "properties": {
30
+ "name": {
31
+ "type": "string",
32
+ "title": "Accessory Name",
33
+ "default": "Octopus Import"
34
+ },
35
+ "mpan": {
36
+ "type": "string",
37
+ "title": "MPAN",
38
+ "required": true
39
+ },
40
+ "meterSerial": {
41
+ "type": "string",
42
+ "title": "Meter Serial",
43
+ "required": true
44
+ }
45
+ },
46
+ "required": ["mpan", "meterSerial"]
47
+ },
48
+ "export": {
49
+ "type": "object",
50
+ "title": "Export Meter (optional)",
51
+ "properties": {
52
+ "name": {
53
+ "type": "string",
54
+ "title": "Accessory Name",
55
+ "default": "Octopus Export"
56
+ },
57
+ "mpan": {
58
+ "type": "string",
59
+ "title": "MPAN"
60
+ },
61
+ "meterSerial": {
62
+ "type": "string",
63
+ "title": "Meter Serial"
64
+ }
65
+ }
66
+ }
67
+ },
68
+ "required": ["apiKey", "import"],
69
+ "additionalProperties": false
70
+ }
71
+ }
@@ -0,0 +1,165 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.OctopusMeterAccessory = void 0;
7
+ const node_fetch_1 = __importDefault(require("node-fetch"));
8
+ class OctopusMeterAccessory {
9
+ constructor(platform, accessory, meter, apiKey, pollSeconds) {
10
+ this.platform = platform;
11
+ this.accessory = accessory;
12
+ this.meter = meter;
13
+ this.apiKey = apiKey;
14
+ this.pollSeconds = pollSeconds;
15
+ this.evePower = null;
16
+ this.eveTotal = null;
17
+ this.lastWatts = 0;
18
+ this.lastTotalKWh = 0;
19
+ const { Service, Characteristic } = this.platform;
20
+ const info = this.accessory.getService(Service.AccessoryInformation);
21
+ info?.setCharacteristic(Characteristic.Manufacturer, 'Octopus Energy');
22
+ info?.setCharacteristic(Characteristic.Model, `${meter.side.toUpperCase()} meter`);
23
+ info?.setCharacteristic(Characteristic.SerialNumber, meter.meterSerial);
24
+ const outlet = this.accessory.getService(Service.Outlet)
25
+ || this.accessory.addService(Service.Outlet);
26
+ outlet.setCharacteristic(Characteristic.Name, meter.name);
27
+ outlet.updateCharacteristic(Characteristic.On, true);
28
+ outlet.updateCharacteristic(Characteristic.OutletInUse, true);
29
+ outlet.getCharacteristic(Characteristic.On).onSet(async () => {
30
+ // This accessory is read-only; keep it "on" for Home UI presence.
31
+ outlet.updateCharacteristic(Characteristic.On, true);
32
+ });
33
+ this.outletService = outlet;
34
+ this.evePower = this.ensureEveCharacteristic(this.platform.Eve.Power);
35
+ this.eveTotal = this.ensureEveCharacteristic(this.platform.Eve.TotalConsumption);
36
+ this.refreshNow().catch((error) => {
37
+ this.platform.log.warn(`Initial fetch failed for ${this.meter.name}: ${error instanceof Error ? error.message : String(error)}`);
38
+ });
39
+ this.timer = setInterval(() => {
40
+ this.refreshNow().catch((error) => {
41
+ this.platform.log.warn(`Refresh failed for ${this.meter.name}: ${error instanceof Error ? error.message : String(error)}`);
42
+ });
43
+ }, this.pollSeconds * 1000);
44
+ this.platform.api.on('shutdown', () => this.stopPolling());
45
+ }
46
+ stopPolling() {
47
+ if (this.timer) {
48
+ clearInterval(this.timer);
49
+ this.timer = undefined;
50
+ }
51
+ }
52
+ ensureEveCharacteristic(charType) {
53
+ try {
54
+ return this.outletService.getCharacteristic(charType);
55
+ }
56
+ catch (error) {
57
+ try {
58
+ return this.outletService.addCharacteristic(charType);
59
+ }
60
+ catch (innerError) {
61
+ this.platform.log.warn(`Failed to register Eve characteristic on ${this.meter.name}: ${innerError instanceof Error ? innerError.message : String(innerError)}`);
62
+ return null;
63
+ }
64
+ }
65
+ }
66
+ async refreshNow() {
67
+ await this.refreshPower();
68
+ await this.refreshTotal();
69
+ }
70
+ async refreshPower() {
71
+ try {
72
+ const watts = await this.fetchLatestWatts();
73
+ this.lastWatts = watts;
74
+ this.accessory.context.lastWatts = watts;
75
+ const safeValue = Math.max(0, watts);
76
+ if (this.evePower) {
77
+ this.evePower.updateValue(safeValue);
78
+ }
79
+ this.platform.log.debug(`${this.meter.name} Eve power updated to ${safeValue.toFixed(2)} W`);
80
+ }
81
+ catch (error) {
82
+ this.platform.log.warn(`Failed to update power for ${this.meter.name}: ${error instanceof Error ? error.message : String(error)}`);
83
+ }
84
+ }
85
+ async refreshTotal() {
86
+ try {
87
+ const totalKWh = await this.fetchTodayTotalKWh();
88
+ this.lastTotalKWh = totalKWh;
89
+ this.accessory.context.totalKWh = totalKWh;
90
+ if (this.eveTotal) {
91
+ this.eveTotal.updateValue(totalKWh);
92
+ }
93
+ this.platform.log.debug(`${this.meter.name} Eve total updated to ${totalKWh.toFixed(3)} kWh (today)`);
94
+ }
95
+ catch (error) {
96
+ this.platform.log.warn(`Failed to update total consumption for ${this.meter.name}: ${error instanceof Error ? error.message : String(error)}`);
97
+ }
98
+ }
99
+ async fetchLatestWatts() {
100
+ const url = `https://api.octopus.energy/v1/electricity-meter-points/${this.meter.mpan}/meters/${this.meter.meterSerial}/consumption/?page_size=1&order_by=-period_start`;
101
+ const response = await (0, node_fetch_1.default)(url, {
102
+ headers: {
103
+ Authorization: `Basic ${Buffer.from(`${this.apiKey}:`).toString('base64')}`,
104
+ },
105
+ });
106
+ if (!response.ok) {
107
+ throw new Error(`HTTP ${response.status}`);
108
+ }
109
+ const payload = (await response.json());
110
+ const record = payload.results?.[0];
111
+ if (!record) {
112
+ throw new Error('No consumption records returned');
113
+ }
114
+ const consumption = record.consumption;
115
+ if (typeof consumption !== 'number') {
116
+ throw new Error('Consumption value missing or invalid');
117
+ }
118
+ const intervalStart = record.interval_start ?? record.period_start;
119
+ const intervalEnd = record.interval_end ?? record.period_end;
120
+ let intervalHours = 0.5;
121
+ if (intervalStart && intervalEnd) {
122
+ const start = Date.parse(intervalStart);
123
+ const end = Date.parse(intervalEnd);
124
+ if (!Number.isNaN(start) && !Number.isNaN(end)) {
125
+ const hours = (end - start) / (1000 * 60 * 60);
126
+ if (hours > 0) {
127
+ intervalHours = hours;
128
+ }
129
+ }
130
+ }
131
+ const watts = (consumption * 1000) / intervalHours;
132
+ return Math.max(0, Math.round(watts * 100) / 100);
133
+ }
134
+ async fetchTodayTotalKWh() {
135
+ const now = new Date();
136
+ const start = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate(), 0, 0, 0));
137
+ const end = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate() + 1, 0, 0, 0));
138
+ const params = new URLSearchParams({
139
+ page_size: '96',
140
+ order_by: 'period_start',
141
+ period_from: start.toISOString(),
142
+ period_to: end.toISOString(),
143
+ });
144
+ const url = `https://api.octopus.energy/v1/electricity-meter-points/${this.meter.mpan}/meters/${this.meter.meterSerial}/consumption/?${params.toString()}`;
145
+ const response = await (0, node_fetch_1.default)(url, {
146
+ headers: {
147
+ Authorization: `Basic ${Buffer.from(`${this.apiKey}:`).toString('base64')}`,
148
+ },
149
+ });
150
+ if (!response.ok) {
151
+ throw new Error(`HTTP ${response.status}`);
152
+ }
153
+ const payload = (await response.json());
154
+ const records = payload.results ?? [];
155
+ let total = 0;
156
+ for (const record of records) {
157
+ if (typeof record.consumption === 'number') {
158
+ total += record.consumption;
159
+ }
160
+ }
161
+ return Math.max(0, Math.round(total * 1000) / 1000);
162
+ }
163
+ }
164
+ exports.OctopusMeterAccessory = OctopusMeterAccessory;
165
+ //# sourceMappingURL=accessory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"accessory.js","sourceRoot":"","sources":["../src/accessory.ts"],"names":[],"mappings":"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"}
package/dist/eve.js ADDED
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getEveCharacteristics = getEveCharacteristics;
4
+ const UUID_POWER = 'E863F10A-079E-48FF-8F27-9C2605A29F52';
5
+ const UUID_TOTAL_CONSUMPTION = 'E863F10C-079E-48FF-8F27-9C2605A29F52';
6
+ let cached;
7
+ function getEveCharacteristics(api) {
8
+ if (cached) {
9
+ return cached;
10
+ }
11
+ const { Characteristic, Formats, Perms } = api.hap;
12
+ class EvePower extends Characteristic {
13
+ constructor() {
14
+ super('Eve Instantaneous Power', EvePower.UUID, {
15
+ format: "float" /* Formats.FLOAT */,
16
+ unit: 'W',
17
+ perms: ["pr" /* Perms.READ */, "ev" /* Perms.NOTIFY */],
18
+ minValue: 0,
19
+ });
20
+ }
21
+ }
22
+ EvePower.UUID = UUID_POWER;
23
+ class EveTotalConsumption extends Characteristic {
24
+ constructor() {
25
+ super('Eve Total Consumption', EveTotalConsumption.UUID, {
26
+ format: "float" /* Formats.FLOAT */,
27
+ unit: 'kWh',
28
+ perms: ["pr" /* Perms.READ */, "ev" /* Perms.NOTIFY */],
29
+ minValue: 0,
30
+ });
31
+ }
32
+ }
33
+ EveTotalConsumption.UUID = UUID_TOTAL_CONSUMPTION;
34
+ cached = {
35
+ Power: EvePower,
36
+ TotalConsumption: EveTotalConsumption,
37
+ };
38
+ return cached;
39
+ }
40
+ //# sourceMappingURL=eve.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eve.js","sourceRoot":"","sources":["../src/eve.ts"],"names":[],"mappings":";;AAYA,sDAuCC;AA5CD,MAAM,UAAU,GAAG,sCAAsC,CAAC;AAC1D,MAAM,sBAAsB,GAAG,sCAAsC,CAAC;AAEtE,IAAI,MAAsC,CAAC;AAE3C,SAAgB,qBAAqB,CAAC,GAAQ;IAC5C,IAAI,MAAM,EAAE,CAAC;QACX,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,MAAM,EAAE,cAAc,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,GAAG,CAAC,GAAG,CAAC;IAEnD,MAAM,QAAS,SAAQ,cAAc;QAGnC;YACE,KAAK,CAAC,yBAAyB,EAAE,QAAQ,CAAC,IAAI,EAAE;gBAC9C,MAAM,6BAAe;gBACrB,IAAI,EAAE,GAAG;gBACT,KAAK,EAAE,gDAA0B;gBACjC,QAAQ,EAAE,CAAC;aACZ,CAAC,CAAC;QACL,CAAC;;IATsB,aAAI,GAAG,UAAU,CAAC;IAY3C,MAAM,mBAAoB,SAAQ,cAAc;QAG9C;YACE,KAAK,CAAC,uBAAuB,EAAE,mBAAmB,CAAC,IAAI,EAAE;gBACvD,MAAM,6BAAe;gBACrB,IAAI,EAAE,KAAK;gBACX,KAAK,EAAE,gDAA0B;gBACjC,QAAQ,EAAE,CAAC;aACZ,CAAC,CAAC;QACL,CAAC;;IATsB,wBAAI,GAAG,sBAAsB,CAAC;IAYvD,MAAM,GAAG;QACP,KAAK,EAAE,QAAQ;QACf,gBAAgB,EAAE,mBAAmB;KACtC,CAAC;IAEF,OAAO,MAAM,CAAC;AAChB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ const settings_1 = require("./settings");
3
+ const platform_1 = require("./platform");
4
+ module.exports = (api) => {
5
+ api.registerPlatform(settings_1.PLATFORM_NAME, platform_1.OctopusEnergyPlatform);
6
+ };
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,yCAA2C;AAC3C,yCAAmD;AAEnD,iBAAS,CAAC,GAAQ,EAAE,EAAE;IACpB,GAAG,CAAC,gBAAgB,CAAC,wBAAa,EAAE,gCAAqB,CAAC,CAAC;AAC7D,CAAC,CAAC"}
@@ -0,0 +1,78 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.OctopusEnergyPlatform = void 0;
4
+ const accessory_1 = require("./accessory");
5
+ const settings_1 = require("./settings");
6
+ const eve_1 = require("./eve");
7
+ class OctopusEnergyPlatform {
8
+ constructor(log, config, api) {
9
+ this.log = log;
10
+ this.config = config;
11
+ this.api = api;
12
+ this.Service = this.api.hap.Service;
13
+ this.Characteristic = this.api.hap.Characteristic;
14
+ this.accessories = [];
15
+ this.managed = [];
16
+ this.Eve = (0, eve_1.getEveCharacteristics)(this.api);
17
+ this.pollSeconds = Math.max(60, typeof config?.pollSeconds === 'number' ? config.pollSeconds : 300);
18
+ if (!config || !config.apiKey) {
19
+ this.log.error('Missing apiKey in configuration; plugin will not start.');
20
+ }
21
+ this.api.on("didFinishLaunching" /* APIEvent.DID_FINISH_LAUNCHING */, () => {
22
+ this.log.debug('Finished launching, starting discovery');
23
+ this.discoverMeters();
24
+ });
25
+ this.api.on("shutdown" /* APIEvent.SHUTDOWN */, () => {
26
+ this.managed.forEach((meter) => meter.stopPolling());
27
+ });
28
+ }
29
+ configureAccessory(accessory) {
30
+ this.log.info('Restored accessory from cache:', accessory.displayName);
31
+ this.accessories.push(accessory);
32
+ }
33
+ discoverMeters() {
34
+ if (!this.config || !this.config.apiKey) {
35
+ return;
36
+ }
37
+ if (!this.config.import) {
38
+ this.log.error('Import meter configuration missing.');
39
+ return;
40
+ }
41
+ this.registerMeter('import', this.config.import);
42
+ if (this.config.export) {
43
+ if (this.config.export.mpan && this.config.export.meterSerial) {
44
+ this.registerMeter('export', this.config.export);
45
+ }
46
+ else {
47
+ this.log.warn('Export configuration incomplete; skipping export accessory.');
48
+ }
49
+ }
50
+ }
51
+ registerMeter(side, meter) {
52
+ const name = meter.name || (side === 'import' ? 'Octopus Import' : 'Octopus Export');
53
+ const uuid = this.api.hap.uuid.generate(`${side}-${meter.mpan}-${meter.meterSerial}`);
54
+ const existing = this.accessories.find((accessory) => accessory.UUID === uuid);
55
+ let accessory;
56
+ if (existing) {
57
+ accessory = existing;
58
+ accessory.displayName = name;
59
+ this.log.info('Updating cached accessory', name);
60
+ }
61
+ else {
62
+ accessory = new this.api.platformAccessory(name, uuid);
63
+ this.log.info('Registering new accessory', name);
64
+ this.api.registerPlatformAccessories(settings_1.PLUGIN_NAME, settings_1.PLATFORM_NAME, [accessory]);
65
+ }
66
+ accessory.context.meter = {
67
+ side,
68
+ mpan: meter.mpan,
69
+ meterSerial: meter.meterSerial,
70
+ name,
71
+ };
72
+ const octopusAccessory = new accessory_1.OctopusMeterAccessory(this, accessory, accessory.context.meter, this.config.apiKey, this.pollSeconds);
73
+ this.managed.push(octopusAccessory);
74
+ this.api.updatePlatformAccessories([accessory]);
75
+ }
76
+ }
77
+ exports.OctopusEnergyPlatform = OctopusEnergyPlatform;
78
+ //# sourceMappingURL=platform.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"platform.js","sourceRoot":"","sources":["../src/platform.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PLATFORM_NAME = exports.PLUGIN_NAME = void 0;
4
+ exports.PLUGIN_NAME = 'homebridge-octopus-energy';
5
+ exports.PLATFORM_NAME = 'OctopusEnergyPlatform';
6
+ //# sourceMappingURL=settings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"settings.js","sourceRoot":"","sources":["../src/settings.ts"],"names":[],"mappings":";;;AAAa,QAAA,WAAW,GAAG,2BAA2B,CAAC;AAC1C,QAAA,aAAa,GAAG,uBAAuB,CAAC"}
package/package.json ADDED
@@ -0,0 +1,62 @@
1
+ {
2
+ "name": "homebridge-octopus-energy",
3
+ "version": "0.0.1",
4
+ "description": "Homebridge plugin to expose Octopus Energy smart meter import/export consumption to HomeKit",
5
+ "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/icebondx/homebridge-octopus-energy.git"
9
+ },
10
+ "homepage": "https://github.com/icebondx/homebridge-octopus-energy",
11
+ "bugs": {
12
+ "url": "https://github.com/icebondx/homebridge-octopus-energy/issues"
13
+ },
14
+ "main": "dist/index.js",
15
+ "files": [
16
+ "dist",
17
+ "config.schema.json"
18
+ ],
19
+ "keywords": [
20
+ "homebridge-plugin",
21
+ "octopus",
22
+ "energy",
23
+ "electricity",
24
+ "homekit",
25
+ "octopus-energy",
26
+ "smart-meter",
27
+ "eve",
28
+ "power-monitoring"
29
+ ],
30
+ "engines": {
31
+ "node": ">=18",
32
+ "homebridge": ">=1.7.0"
33
+ },
34
+ "scripts": {
35
+ "build": "tsc -p tsconfig.json",
36
+ "watch": "tsc -w -p tsconfig.json",
37
+ "lint": "eslint src --ext .ts",
38
+ "clean": "rimraf dist",
39
+ "prepare": "npm run build"
40
+ },
41
+ "homebridge": {
42
+ "platforms": [
43
+ {
44
+ "platform": "OctopusEnergyPlatform",
45
+ "name": "Octopus Energy"
46
+ }
47
+ ]
48
+ },
49
+ "dependencies": {
50
+ "homebridge": "^1.7.0",
51
+ "node-fetch": "^2.6.11"
52
+ },
53
+ "devDependencies": {
54
+ "@types/node": "^20.14.2",
55
+ "@types/node-fetch": "^2.6.11",
56
+ "@typescript-eslint/eslint-plugin": "^7.8.0",
57
+ "@typescript-eslint/parser": "^7.8.0",
58
+ "eslint": "^8.57.0",
59
+ "rimraf": "^5.0.5",
60
+ "typescript": "^5.4.5"
61
+ }
62
+ }