Skip to content

Commit

Permalink
feat: add support for watermeter (#15)
Browse files Browse the repository at this point in the history
* feat: add support for watermeter

* chore: make husky hooks executable

* chore: fix linting error
  • Loading branch information
Th3S4mur41 committed Apr 20, 2023
1 parent 6d2f402 commit 0acfe3f
Show file tree
Hide file tree
Showing 6 changed files with 96 additions and 28 deletions.
Empty file modified .husky/commit-msg
100644 → 100755
Empty file.
Empty file modified .husky/pre-commit
100644 → 100755
Empty file.
4 changes: 3 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ RUN npm ci
COPY . .

ENV energyid ''
# p1 is deprecated, use meter instead
ENV p1 ''
ENV meter ${p1}

CMD npx hw2energyid--energyid=${energyid} --p1=${p1} -r
CMD npx hw2energyid--energyid=${energyid} --meter=${meter} -r
52 changes: 42 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,20 +41,33 @@ npx hw2energyid --energyid=<url of the webhook> <options>
| Option | Alias | Description |
| --- | --- | --- |
| `--energyid`| `-e` | The URL of the EnergyID Webhook |
| `--p1` | `-p` | The name or IP address of the P1 Meter device |
| `--meter` | `-m` `-p` `--p1` | The name or IP address of the Homewizard meter |
| `--offset` | `-o` | Add an offset to the meter's value (to compensate for consumption before installation) |
| `--dry-run` | `-d` | Dry run. No data will be sent to EnergyID |
| `--recurring` | `-r` | Run the tool every hour |
| `--help` | `-h` | Show help |
| `--version` | `-v` | Show version number |

### Docker

First, you need to retreive the IP address of your P1 Meter device.
First, you need to retreive the IP address of your Homewizard meter.

> **Note**
>
> The hostname is formatted as <product-name>-<last 6 characters of serial>, so devices with serial AABBCCDDEEFF the hostname is as following:
>
> | Device | Example hostname |
> | --- | --- |
> | P1 meter | p1meter-DDEEFF |
> | Energy Socket | energysocket-DDEEFF |
> | Watermeter | watermeter-DDEEFF |
> | kWh meter (single phase) | kwhmeter-DDEEFF |
> | kWh meter (three phase) | kwhmeter-DDEEFF |
Open a terminal/console and run the following script:

```sh
ping hw-p1meter-<last 6 charachter of serial>
ping <product-name>-<last 6 charachter of serial>
```

Create a docker compose file with the following content:
Expand All @@ -67,7 +80,7 @@ services:
image: ghcr.io/th3s4mur41/hw2energyid
environment:
- energyid=<the URL of the EnergyId webhook>
- p1=<the IP address of the P1 Meter device>
- =<the IP address of the Meter device>
network_mode: host
dns:
- 1.1.1.1
Expand All @@ -80,16 +93,17 @@ services:
| Environment Variable | Description |
| --- | --- |
| `energyid` | The URL of the EnergyID Webhook |
| `p1` | The IP address of the P1 Meter device |
| `meter` | The IP address of the Homewizard meter |

## Examples

> **Note**
> hw2energyid currently only supports synchronizing electricity and water readings

### P1 Meter

The HomeWizard [P1 Meter](https://www.homewizard.com/p1-meter/) connects into the P1 port on your smart meter and shows your electricity and gas usage.

> **Note**
> hw2energyid currently only supports synchronizing electricity readings

The P1 meter can be discoverd on your network using [Multicast DNS (mDNS)](https://www.ionos.com/digitalguide/server/know-how/multicast-dns/).
The name of the device is 'hw-p1meter-' followed by the last six charachters of its serial number.

Expand All @@ -101,12 +115,30 @@ The name of the device is 'hw-p1meter-' followed by the last six charachters of
Now that you have all the data you need. Open a terminal/console and run the following script:

```sh
npx hw2energyid --p1=hw-p1meter-<last 6 charachter of serial> --energyid=<url of the webhook>
npx hw2energyid --meter=hw-p1meter-<last 6 charachter of serial> --energyid=<url of the webhook>
```

E.g.: The command with your data should look similar to this:
```sh
npx hw2energyid --meter=hw-p1meter-65d8c7 --energyid=https://hooks.energyid.eu/services/WebhookIn/46535693-fe25-48ba-96fa-ea827e987318/OS753GD97A11
```

### Water Meter

The HomeWizard [Water Meter](https://www.homewizard.com/watermeter/) reads your analog water meter.

The Water meter can be discoverd on your network using [Multicast DNS (mDNS)](https://www.ionos.com/digitalguide/server/know-how/multicast-dns/).
The name of the device is 'watermeter-' followed by the last six charachters of its serial number.

Now that you have all the data you need. Open a terminal/console and run the following script:

```sh
npx hw2energyid --meter=watermeter-<last 6 charachter of serial> --energyid=<url of the webhook>
```

E.g.: The command with your data should look similar to this:
```sh
npx hw2energyid --p1=hw-p1meter-65d8c7 --energyid=https://hooks.energyid.eu/services/WebhookIn/46535693-fe25-48ba-96fa-ea827e987318/OS753GD97A11
npx hw2energyid --meter=watermeter-65d8c7 --offset=22.334 --energyid=https://hooks.energyid.eu/services/WebhookIn/46535693-fe25-48ba-96fa-ea827e987318/OS753GD97A11
```

## Links
Expand Down
17 changes: 11 additions & 6 deletions bin/cli.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,27 @@ import cron from "node-cron";
// https://www.npmjs.com/package/node-cron

const yargsBin = yargs(hideBin(process.argv))
.usage("$0--energyid <energyid webhook> --p1 <hw p1 host or ip> [options]")
.usage("$0--energyid <energyid webhook> --meter <homewizard meter host or ip> [options]")
.option("e", {
alias: "energyid",
description: "URL of the EnergyId Webhook",
type: "string",
})
.option("p", {
alias: "p1",
description: "Hostname or IP address of the HomeWizard P1 device",
.option("m", {
alias: ["meter", "p", "p1"],
description: "Hostname or IP address of the HomeWizard meter",
type: "string",
})
.option("r", {
alias: "recurring",
description: "Run the task every hour",
type: "boolean",
})
.option("o", {
alias: "offset",
description: "Add an offset to the meter's value (to compensate for consumption before installation)",
type: "number",
})
.option("d", {
alias: "dry-run",
description: "Read the data and simulate sending the readings",
Expand All @@ -38,15 +43,15 @@ const yargsBin = yargs(hideBin(process.argv))

const argv = yargsBin.argv;

if (!(argv.p1 && argv.energyid)) {
if (!(argv.meter && argv.energyid)) {
yargsBin.showHelp("log");
process.exit(1);
}

console.log(`${process.env.npm_package_name} ${process.env.npm_package_version}`);
console.log("");

init(argv.p1, argv.energyid);
init(argv.meter, argv.energyid, argv.offset);
if (argv.r) {
console.log("Scheduling hw2energyid to run every hour");
cron.schedule("1 * * * *", () => {
Expand Down
51 changes: 40 additions & 11 deletions src/index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@
* energyid-homewizard-connector
*/
let initialized = false;
let hw_p1_api = "";
let hwe_api = "";
let energyid_hook = "";
let readingOffset = 0;

const typeMap = [
[
Expand All @@ -12,6 +13,8 @@ const typeMap = [
id: "electricity-import-day",
name: "Electricity Import (day)",
metric: "electricityImport",
metricKind: "cumulative",
unit: "kWh",
},
],
[
Expand All @@ -20,6 +23,8 @@ const typeMap = [
id: "electricity-import-night",
name: "Electricity Import (night)",
metric: "electricityImport",
metricKind: "cumulative",
unit: "kWh",
},
],
[
Expand All @@ -28,6 +33,8 @@ const typeMap = [
id: "electricity-export-day",
name: "Electricity Export (day)",
metric: "electricityExport",
metricKind: "cumulative",
unit: "kWh",
},
],
[
Expand All @@ -36,6 +43,18 @@ const typeMap = [
id: "electricity-export-night",
name: "Electricity Export (night)",
metric: "electricityExport",
metricKind: "cumulative",
unit: "kWh",
},
],
[
"total_liter_m3",
{
id: "drinking-water-import",
name: "Drinking Water Import",
metric: "drinkingWaterImport",
metricKind: "cumulative",
unit: "m³",
},
],
];
Expand All @@ -45,8 +64,8 @@ class Reading {
this.remoteId = type[1].id;
this.remoteName = type[1].name;
this.metric = type[1].metric;
this.metricKind = "cumulative";
this.unit = "kWh";
this.metricKind = type[1].metricKind;
this.unit = type[1].unit;
this.interval = "P1D";
this.data = [[date, value]];
}
Expand All @@ -61,29 +80,33 @@ class Reading {
*/

const getData = async () => {
console.log("Retrieving data from Homewizard P1 API...");
console.log("Retrieving data from Homewizard API...");

return fetch(hw_p1_api)
return fetch(hwe_api)
.then((result) => {
console.log("HomeWizard P1 data:");
console.log("HomeWizard Meter data:");
return result.json();
})
.then((data) => {
console.log(data);
return data;
})
.catch((error) => {
console.error(`Cannot retreive data from ${hw_p1_api}`);
console.error(`Cannot retreive data from ${hwe_api}`);
});
};

const setReadings = (data) => {
console.log(data);
const readings = [];
const readingDate = new Date();
readingDate.setMinutes(0, 0, 0);

typeMap.forEach((type) => {
readings.push(new Reading(type, readingDate.toISOString(), data[type[0]]));
if (data[type[0]]) {
const value = (readingOffset + data[type[0]]).toFixed(4);
readings.push(new Reading(type, readingDate.toISOString(), value));
}
});
return readings;
};
Expand Down Expand Up @@ -119,10 +142,16 @@ const sendReadings = (readings, dryRun) => {
* Public functions
*/

export const init = (hwP1, energyidWebhook) => {
hw_p1_api = `http://${hwP1}/api/v1/data/`;
export const init = (hwe, energyidWebhook, offset = 0) => {
hwe_api = `http://${hwe}/api/v1/data/`;
energyid_hook = energyidWebhook;
initialized = hw_p1_api && energyid_hook;
initialized = hwe_api && energyid_hook;

if (Number.isNaN(Number.parseFloat(offset))) {
readingOffset = 0;
} else {
readingOffset = Number.parseFloat(offset);
}
};

export const sync = async (dryRun = false) => {
Expand Down

0 comments on commit 0acfe3f

Please sign in to comment.