myenergi-api 2.9.0 → 2.10.0

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
@@ -134,6 +134,22 @@ console.log(result);
134
134
  ```
135
135
 
136
136
 
137
+ ### Libbi charge from grid (myenergi account)
138
+ Charge from grid is not available through the hub serial and API key. It uses the myenergi account API, which needs the email and password of your myenergi account. Unlike `MyEnergi`, the methods of `MyEnergiAccount` throw a `MyEnergiAccountError` when a request fails.
139
+
140
+ The Libbi only charges from the grid up to its charge target, and only during the cheap periods of the tariff configured in the myenergi app.
141
+ ```typescript
142
+ const account = new MyEnergiAccount("me@example.com", "!3uper3ecretPassw0rd");
143
+ const sno = '1234567';
144
+
145
+ const enabled: boolean = await account.getLibbiChargeFromGrid(sno);
146
+ await account.setLibbiChargeFromGrid(sno, true);
147
+
148
+ // Charge target in Wh
149
+ const setup: LibbiChargeSetup = await account.getLibbiChargeSetup(sno);
150
+ await account.setLibbiChargeTarget(sno, 4600);
151
+ ```
152
+
137
153
  ## From myenergi documentation
138
154
  <a name="myenergi_documentation"></a>
139
155
  <a name="charge_mode"></a>
@@ -0,0 +1,22 @@
1
+ import { LibbiChargeSetup } from "./models/LibbiChargeSetup";
2
+ export declare class MyEnergiAccountError extends Error {
3
+ statusCode?: number;
4
+ authFailed: boolean;
5
+ constructor(message: string, statusCode?: number, authFailed?: boolean);
6
+ }
7
+ export declare class MyEnergiAccount {
8
+ private _config;
9
+ private _accessToken?;
10
+ private _refreshToken?;
11
+ private _expiresAt;
12
+ constructor(email: string, password: string, accountBaseUrl?: string, authUrl?: string);
13
+ login(): Promise<void>;
14
+ getLibbiChargeFromGrid(serialNo: string): Promise<boolean>;
15
+ setLibbiChargeFromGrid(serialNo: string, chargeFromGrid: boolean): Promise<void>;
16
+ getLibbiChargeSetup(serialNo: string): Promise<LibbiChargeSetup>;
17
+ setLibbiChargeTarget(serialNo: string, targetEnergyWh: number): Promise<void>;
18
+ private call;
19
+ private getAccessToken;
20
+ private authenticate;
21
+ private request;
22
+ }
@@ -0,0 +1,185 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
26
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
27
+ return new (P || (P = Promise))(function (resolve, reject) {
28
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
29
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
30
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
31
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
32
+ });
33
+ };
34
+ Object.defineProperty(exports, "__esModule", { value: true });
35
+ exports.MyEnergiAccount = exports.MyEnergiAccountError = void 0;
36
+ const https = __importStar(require("https"));
37
+ class MyEnergiAccountError extends Error {
38
+ constructor(message, statusCode, authFailed = false) {
39
+ super(message);
40
+ this.name = "MyEnergiAccountError";
41
+ this.statusCode = statusCode;
42
+ this.authFailed = authFailed;
43
+ }
44
+ }
45
+ exports.MyEnergiAccountError = MyEnergiAccountError;
46
+ class MyEnergiAccount {
47
+ constructor(email, password, accountBaseUrl, authUrl) {
48
+ this._config = {
49
+ email: "",
50
+ password: "",
51
+ base_url: "https://myaccount.myenergi.com",
52
+ auth_url: "https://cognito-idp.eu-west-2.amazonaws.com/",
53
+ client_id: "2fup0dhufn5vurmprjkj599041",
54
+ libbi_mode_url: "/api/AccountAccess/LibbiMode",
55
+ account_access_url: "/api/AccountAccess/",
56
+ };
57
+ this._expiresAt = 0;
58
+ this._config.email = email;
59
+ this._config.password = password;
60
+ if (accountBaseUrl)
61
+ this._config.base_url = accountBaseUrl;
62
+ if (authUrl)
63
+ this._config.auth_url = authUrl;
64
+ }
65
+ login() {
66
+ return __awaiter(this, void 0, void 0, function* () {
67
+ yield this.authenticate("USER_PASSWORD_AUTH", { USERNAME: this._config.email, PASSWORD: this._config.password });
68
+ });
69
+ }
70
+ getLibbiChargeFromGrid(serialNo) {
71
+ return __awaiter(this, void 0, void 0, function* () {
72
+ const content = yield this.call("GET", `${this._config.libbi_mode_url}?serialNo=${encodeURIComponent(serialNo)}`);
73
+ return !!(content && content[serialNo]);
74
+ });
75
+ }
76
+ setLibbiChargeFromGrid(serialNo, chargeFromGrid) {
77
+ return __awaiter(this, void 0, void 0, function* () {
78
+ yield this.call("PUT", `${this._config.libbi_mode_url}?chargeFromGrid=${chargeFromGrid}&serialNo=${encodeURIComponent(serialNo)}`);
79
+ });
80
+ }
81
+ getLibbiChargeSetup(serialNo) {
82
+ return __awaiter(this, void 0, void 0, function* () {
83
+ const content = yield this.call("GET", `${this._config.account_access_url}${encodeURIComponent(serialNo)}/LibbiChargeSetup`);
84
+ return Object.assign({}, content);
85
+ });
86
+ }
87
+ setLibbiChargeTarget(serialNo, targetEnergyWh) {
88
+ return __awaiter(this, void 0, void 0, function* () {
89
+ yield this.call("PUT", `${this._config.account_access_url}${encodeURIComponent(serialNo)}/TargetEnergy?targetEnergy=${Math.round(targetEnergyWh)}`);
90
+ });
91
+ }
92
+ call(method, path, retry = true) {
93
+ return __awaiter(this, void 0, void 0, function* () {
94
+ const token = yield this.getAccessToken();
95
+ const res = yield this.request(method, new URL(path, this._config.base_url), { Authorization: `Bearer ${token}`, Accept: "application/json" });
96
+ if (res.statusCode == 401 && retry) {
97
+ this._accessToken = undefined;
98
+ this._refreshToken = undefined;
99
+ return this.call(method, path, false);
100
+ }
101
+ let jsonData = {};
102
+ try {
103
+ jsonData = JSON.parse(res.body);
104
+ }
105
+ catch (error) {
106
+ }
107
+ if (res.statusCode < 200 || res.statusCode >= 300 || jsonData.status !== true) {
108
+ throw new MyEnergiAccountError(jsonData.message || `Request failed with status code ${res.statusCode}`, res.statusCode, res.statusCode == 401);
109
+ }
110
+ return jsonData.content;
111
+ });
112
+ }
113
+ getAccessToken() {
114
+ return __awaiter(this, void 0, void 0, function* () {
115
+ if (!this._accessToken || Date.now() >= this._expiresAt) {
116
+ if (this._refreshToken) {
117
+ try {
118
+ yield this.authenticate("REFRESH_TOKEN_AUTH", { REFRESH_TOKEN: this._refreshToken });
119
+ }
120
+ catch (error) {
121
+ this._refreshToken = undefined;
122
+ yield this.login();
123
+ }
124
+ }
125
+ else {
126
+ yield this.login();
127
+ }
128
+ }
129
+ return this._accessToken;
130
+ });
131
+ }
132
+ authenticate(authFlow, authParameters) {
133
+ return __awaiter(this, void 0, void 0, function* () {
134
+ const res = yield this.request("POST", new URL(this._config.auth_url), {
135
+ "Content-Type": "application/x-amz-json-1.1",
136
+ "X-Amz-Target": "AWSCognitoIdentityProviderService.InitiateAuth",
137
+ }, JSON.stringify({ AuthFlow: authFlow, AuthParameters: authParameters, ClientId: this._config.client_id }));
138
+ let jsonData = {};
139
+ try {
140
+ jsonData = JSON.parse(res.body);
141
+ }
142
+ catch (error) {
143
+ }
144
+ const result = jsonData.AuthenticationResult;
145
+ if (res.statusCode != 200 || !result || !result.AccessToken) {
146
+ const authFailed = jsonData.__type === "NotAuthorizedException" || jsonData.__type === "UserNotFoundException";
147
+ const message = jsonData.ChallengeName
148
+ ? `Unsupported sign in challenge: ${jsonData.ChallengeName}`
149
+ : jsonData.message || `Sign in failed with status code ${res.statusCode}`;
150
+ throw new MyEnergiAccountError(message, res.statusCode, authFailed);
151
+ }
152
+ this._accessToken = result.AccessToken;
153
+ this._expiresAt = Date.now() + ((result.ExpiresIn || 3600) - 60) * 1000;
154
+ if (result.RefreshToken)
155
+ this._refreshToken = result.RefreshToken;
156
+ });
157
+ }
158
+ request(method, url, headers, data) {
159
+ return new Promise((resolve, reject) => {
160
+ if (data !== undefined)
161
+ headers["Content-Length"] = `${Buffer.byteLength(data)}`;
162
+ const req = https.request(url, { method, headers }, (res) => {
163
+ let resData = "";
164
+ res.setEncoding("utf8");
165
+ res.on("data", (chunk) => {
166
+ resData += chunk;
167
+ });
168
+ res.on("end", () => {
169
+ resolve({ statusCode: res.statusCode || 0, body: resData });
170
+ });
171
+ });
172
+ req.setTimeout(20000, () => {
173
+ req.destroy(new Error("Request timed out"));
174
+ });
175
+ req.on("error", (e) => {
176
+ reject(e);
177
+ });
178
+ if (data !== undefined) {
179
+ req.write(data);
180
+ }
181
+ req.end();
182
+ });
183
+ }
184
+ }
185
+ exports.MyEnergiAccount = MyEnergiAccount;
@@ -2,7 +2,9 @@ import { Eddi } from "./models/Eddi";
2
2
  import { Harvi } from "./models/Harvi";
3
3
  import { HistoryRecord } from "./models/HistoryRecord";
4
4
  import { Libbi } from "./models/Libbi";
5
+ import { LibbiChargeSetup } from "./models/LibbiChargeSetup";
5
6
  import { EddiBoost, EddiHeaterStatus, EddiMode, LibbiMode, ZappiBoostMode, ZappiChargeMode, ZappiPhaseSetting, ZappiStatus } from "./models/Types";
6
7
  import { Zappi } from "./models/Zappi";
7
8
  import { MyEnergi } from "./MyEnergi";
8
- export { MyEnergi, Eddi, Zappi, Harvi, Libbi, HistoryRecord, EddiBoost, EddiMode, EddiHeaterStatus, LibbiMode, ZappiBoostMode, ZappiChargeMode, ZappiPhaseSetting, ZappiStatus };
9
+ import { MyEnergiAccount, MyEnergiAccountError } from "./MyEnergiAccount";
10
+ export { MyEnergi, MyEnergiAccount, MyEnergiAccountError, Eddi, Zappi, Harvi, Libbi, LibbiChargeSetup, HistoryRecord, EddiBoost, EddiMode, EddiHeaterStatus, LibbiMode, ZappiBoostMode, ZappiChargeMode, ZappiPhaseSetting, ZappiStatus };
package/dist/src/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ZappiStatus = exports.ZappiPhaseSetting = exports.ZappiChargeMode = exports.ZappiBoostMode = exports.LibbiMode = exports.EddiHeaterStatus = exports.EddiMode = exports.EddiBoost = exports.MyEnergi = void 0;
3
+ exports.ZappiStatus = exports.ZappiPhaseSetting = exports.ZappiChargeMode = exports.ZappiBoostMode = exports.LibbiMode = exports.EddiHeaterStatus = exports.EddiMode = exports.EddiBoost = exports.MyEnergiAccountError = exports.MyEnergiAccount = exports.MyEnergi = void 0;
4
4
  const Types_1 = require("./models/Types");
5
5
  Object.defineProperty(exports, "EddiBoost", { enumerable: true, get: function () { return Types_1.EddiBoost; } });
6
6
  Object.defineProperty(exports, "EddiHeaterStatus", { enumerable: true, get: function () { return Types_1.EddiHeaterStatus; } });
@@ -12,3 +12,6 @@ Object.defineProperty(exports, "ZappiPhaseSetting", { enumerable: true, get: fun
12
12
  Object.defineProperty(exports, "ZappiStatus", { enumerable: true, get: function () { return Types_1.ZappiStatus; } });
13
13
  const MyEnergi_1 = require("./MyEnergi");
14
14
  Object.defineProperty(exports, "MyEnergi", { enumerable: true, get: function () { return MyEnergi_1.MyEnergi; } });
15
+ const MyEnergiAccount_1 = require("./MyEnergiAccount");
16
+ Object.defineProperty(exports, "MyEnergiAccount", { enumerable: true, get: function () { return MyEnergiAccount_1.MyEnergiAccount; } });
17
+ Object.defineProperty(exports, "MyEnergiAccountError", { enumerable: true, get: function () { return MyEnergiAccount_1.MyEnergiAccountError; } });
@@ -0,0 +1,5 @@
1
+ export interface LibbiChargeSetup {
2
+ deviceSerial: string;
3
+ chargeFromGrid: boolean;
4
+ energyTarget: number;
5
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "myenergi-api",
3
- "version": "2.9.0",
3
+ "version": "2.10.0",
4
4
  "description": "NodeJS implementation of MyEnergi API for controlling Zappi, Eddi and other MyEnergi products",
5
5
  "main": "dist/src/index.js",
6
6
  "types": "dist/src/index.d.ts",