iobroker.easee 2.0.0-alpha.0 → 2.0.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.
@@ -0,0 +1,89 @@
1
+ "use strict";
2
+
3
+ const CHARGER_STATE_OBSERVATION_IDS = [
4
+ 46, 48, 68, 80, 96, 102, 103, 109, 111, 112, 113, 114, 120, 122, 124, 132,
5
+ 182, 183, 184, 185, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 250,
6
+ ];
7
+
8
+ const STATE_FIELDS_BY_OBSERVATION_ID = {
9
+ 46: "ledMode",
10
+ 48: "dynamicChargerCurrent",
11
+ 68: "wiFiAPEnabled",
12
+ 80: "chargerFirmware",
13
+ 96: "reasonForNoCurrent",
14
+ 102: "smartCharging",
15
+ 103: "cableLocked",
16
+ 109: "chargerOpMode",
17
+ 111: "dynamicCircuitCurrentP1",
18
+ 112: "dynamicCircuitCurrentP2",
19
+ 113: "dynamicCircuitCurrentP3",
20
+ 114: "outputCurrent",
21
+ 120: "totalPower",
22
+ 122: "energyPerHour",
23
+ 124: "lifetimeEnergy",
24
+ 132: "wiFiRSSI",
25
+ 182: "inCurrentT2",
26
+ 183: "inCurrentT3",
27
+ 184: "inCurrentT4",
28
+ 185: "inCurrentT5",
29
+ 190: "inVoltageT1T2",
30
+ 191: "inVoltageT1T3",
31
+ 192: "inVoltageT1T4",
32
+ 193: "inVoltageT1T5",
33
+ 194: "inVoltageT2T3",
34
+ 195: "inVoltageT2T4",
35
+ 196: "inVoltageT2T5",
36
+ 197: "inVoltageT3T4",
37
+ 198: "inVoltageT3T5",
38
+ 199: "inVoltageT4T5",
39
+ };
40
+
41
+ const SUPPLY_VOLTAGE_FIELDS = [
42
+ "inVoltageT2T3",
43
+ "inVoltageT1T3",
44
+ "inVoltageT1T4",
45
+ "inVoltageT1T5",
46
+ "inVoltageT2T4",
47
+ "inVoltageT2T5",
48
+ ];
49
+
50
+ function observationsToChargerState(responseData) {
51
+ const observations = Array.isArray(responseData?.observations)
52
+ ? responseData.observations
53
+ : [];
54
+ /** @type {Record<string, any>} */
55
+ const chargerState = Object.fromEntries(
56
+ Object.values(STATE_FIELDS_BY_OBSERVATION_ID).map((field) => [field, null]),
57
+ );
58
+
59
+ for (const observation of observations) {
60
+ const field = STATE_FIELDS_BY_OBSERVATION_ID[observation.id];
61
+ if (field !== undefined) {
62
+ chargerState[field] = observation.value;
63
+ }
64
+ }
65
+
66
+ const cloudObservation = observations.find(
67
+ (observation) => observation.id === 250,
68
+ );
69
+ if (cloudObservation) {
70
+ chargerState.isOnline = Boolean(cloudObservation.value);
71
+ }
72
+ chargerState.voltage = null;
73
+ for (const field of SUPPLY_VOLTAGE_FIELDS) {
74
+ const value = chargerState[field];
75
+ if (
76
+ typeof value === "number" &&
77
+ Number.isFinite(value) &&
78
+ value >= 100 &&
79
+ value <= 300
80
+ ) {
81
+ chargerState.voltage = value;
82
+ break;
83
+ }
84
+ }
85
+
86
+ return chargerState;
87
+ }
88
+
89
+ module.exports = { CHARGER_STATE_OBSERVATION_IDS, observationsToChargerState };
@@ -0,0 +1,83 @@
1
+ "use strict";
2
+
3
+ const axios = require("axios").default;
4
+ const signalR = require("@microsoft/signalr");
5
+ const { CookieJar } = require("tough-cookie");
6
+
7
+ function hasHeader(headers, name) {
8
+ return Object.keys(headers).some(
9
+ (headerName) => headerName.toLowerCase() === name.toLowerCase(),
10
+ );
11
+ }
12
+
13
+ class AxiosSignalRHttpClient extends signalR.HttpClient {
14
+ /** @param {any} [httpClient] */
15
+ constructor(httpClient = axios) {
16
+ super();
17
+ this.httpClient = httpClient;
18
+ this.cookieJar = new CookieJar();
19
+ }
20
+
21
+ async send(request) {
22
+ if (!request.url) {
23
+ throw new Error("SignalR HTTP request URL is missing");
24
+ }
25
+ const headers = { ...request.headers };
26
+ const cookie = this.cookieJar.getCookieStringSync(request.url);
27
+ if (cookie && !hasHeader(headers, "cookie")) {
28
+ headers.Cookie = cookie;
29
+ }
30
+ const cancelSource = axios.CancelToken.source();
31
+ const abortHandler = () =>
32
+ cancelSource.cancel("SignalR HTTP request aborted");
33
+ if (request.abortSignal) {
34
+ request.abortSignal.onabort = abortHandler;
35
+ }
36
+ try {
37
+ const response = await this.httpClient.request({
38
+ method: request.method || "GET",
39
+ url: request.url,
40
+ headers,
41
+ data: request.content,
42
+ timeout: request.timeout,
43
+ cancelToken: cancelSource.token,
44
+ responseType:
45
+ request.responseType === "arraybuffer" ? "arraybuffer" : "text",
46
+ transformResponse: [(data) => data],
47
+ validateStatus: () => true,
48
+ });
49
+ for (const setCookie of response.headers?.["set-cookie"] || []) {
50
+ await this.cookieJar.setCookie(setCookie, request.url, {
51
+ ignoreError: true,
52
+ });
53
+ }
54
+ let content = response.data;
55
+ if (Buffer.isBuffer(content) && request.responseType === "arraybuffer") {
56
+ content = content.buffer.slice(
57
+ content.byteOffset,
58
+ content.byteOffset + content.byteLength,
59
+ );
60
+ } else if (
61
+ typeof content !== "string" &&
62
+ request.responseType !== "arraybuffer"
63
+ ) {
64
+ content = content == null ? "" : JSON.stringify(content);
65
+ }
66
+ return new signalR.HttpResponse(
67
+ response.status,
68
+ response.statusText,
69
+ content,
70
+ );
71
+ } finally {
72
+ if (request.abortSignal?.onabort === abortHandler) {
73
+ request.abortSignal.onabort = null;
74
+ }
75
+ }
76
+ }
77
+
78
+ getCookieString(url) {
79
+ return this.cookieJar.getCookieStringSync(url);
80
+ }
81
+ }
82
+
83
+ module.exports = AxiosSignalRHttpClient;
package/lib/tools.js CHANGED
@@ -2,84 +2,96 @@ const axios = require("axios").default;
2
2
 
3
3
  /**
4
4
  * Tests whether the given variable is a real object and not an Array
5
+ *
5
6
  * @param {any} it The variable to test
6
7
  * @returns {it is Record<string, any>} True if the variable is an object, false otherwise
7
8
  */
8
9
  function isObject(it) {
9
- return Object.prototype.toString.call(it) === '[object Object]';
10
+ return Object.prototype.toString.call(it) === "[object Object]";
10
11
  }
11
12
 
12
13
  /**
13
14
  * Tests whether the given variable is really an Array
15
+ *
14
16
  * @param {any} it The variable to test
15
17
  * @returns {it is any[]} True if the variable is an array, false otherwise
16
18
  */
17
19
  function isArray(it) {
18
- return Array.isArray(it);
20
+ return Array.isArray(it);
19
21
  }
20
22
 
21
23
  /**
22
24
  * Translates text to the target language. Automatically chooses the right translation API.
25
+ *
23
26
  * @param {string} text The text to translate
24
27
  * @param {string} targetLang The target language
25
28
  * @param {string} [yandexApiKey] The yandex API key. You can create one for free at https://translate.yandex.com/developers
26
29
  * @returns {Promise<string>} The translated text
27
30
  */
28
31
  async function translateText(text, targetLang, yandexApiKey) {
29
- if (!text) return '';
30
- if (targetLang === 'en') return text;
32
+ if (!text) {
33
+ return "";
34
+ }
35
+ if (targetLang === "en") {
36
+ return text;
37
+ }
31
38
 
32
- return yandexApiKey
33
- ? translateYandex(text, targetLang, yandexApiKey)
34
- : translateGoogle(text, targetLang);
39
+ return yandexApiKey
40
+ ? translateYandex(text, targetLang, yandexApiKey)
41
+ : translateGoogle(text, targetLang);
35
42
  }
36
43
 
37
44
  /**
38
45
  * Translates text with Yandex API
46
+ *
39
47
  * @param {string} text The text to translate
40
48
  * @param {string} targetLang The target language
41
49
  * @param {string} apiKey The yandex API key. You can create one for free at https://translate.yandex.com/developers
42
50
  * @returns {Promise<string>} The translated text
43
51
  */
44
52
  async function translateYandex(text, targetLang, apiKey) {
45
- if (targetLang === 'zh-cn') targetLang = 'zh';
53
+ if (targetLang === "zh-cn") {
54
+ targetLang = "zh";
55
+ }
46
56
 
47
- const url = `https://translate.yandex.net/api/v1.5/tr.json/translate?key=${apiKey}&text=${encodeURIComponent(text)}&lang=en-${targetLang}`;
48
- try {
49
- const response = await axios.get(url, { timeout: 15000 });
50
- if (response.data?.text && isArray(response.data.text)) {
51
- return response.data.text[0];
52
- }
53
- throw new Error('Invalid response for translate request');
54
- } catch (e) {
55
- throw new Error(`Could not translate to "${targetLang}": ${e.message}`);
57
+ const url = `https://translate.yandex.net/api/v1.5/tr.json/translate?key=${apiKey}&text=${encodeURIComponent(text)}&lang=en-${targetLang}`;
58
+ try {
59
+ const response = await axios.get(url, { timeout: 15000 });
60
+ if (response.data?.text && isArray(response.data.text)) {
61
+ return response.data.text[0];
56
62
  }
63
+ throw new Error("Invalid response for translate request");
64
+ } catch (e) {
65
+ throw new Error(`Could not translate to "${targetLang}": ${e.message}`);
66
+ }
57
67
  }
58
68
 
59
69
  /**
60
70
  * Translates text with Google API
71
+ *
61
72
  * @param {string} text The text to translate
62
73
  * @param {string} targetLang The target language
63
74
  * @returns {Promise<string>} The translated text
64
75
  */
65
76
  async function translateGoogle(text, targetLang) {
66
- const url = `http://translate.googleapis.com/translate_a/single?client=gtx&sl=en&tl=${targetLang}&dt=t&q=${encodeURIComponent(text)}&ie=UTF-8&oe=UTF-8`;
67
- try {
68
- const response = await axios.get(url, { timeout: 15000 });
69
- if (isArray(response.data)) {
70
- return response.data[0][0][0];
71
- }
72
- throw new Error('Invalid response for translate request');
73
- } catch (e) {
74
- const errorMessage = e.response?.status === 429
75
- ? `Rate-limited by Google Translate`
76
- : e.message;
77
- throw new Error(`Could not translate to "${targetLang}": ${errorMessage}`);
77
+ const url = `http://translate.googleapis.com/translate_a/single?client=gtx&sl=en&tl=${targetLang}&dt=t&q=${encodeURIComponent(text)}&ie=UTF-8&oe=UTF-8`;
78
+ try {
79
+ const response = await axios.get(url, { timeout: 15000 });
80
+ if (isArray(response.data)) {
81
+ return response.data[0][0][0];
78
82
  }
83
+ throw new Error("Invalid response for translate request");
84
+ } catch (e) {
85
+ const errorMessage =
86
+ e.response?.status === 429
87
+ ? `Rate-limited by Google Translate`
88
+ : e.message;
89
+ throw new Error(`Could not translate to "${targetLang}": ${errorMessage}`);
90
+ }
79
91
  }
80
92
 
81
93
  module.exports = {
82
- isArray,
83
- isObject,
84
- translateText
94
+ isArray,
95
+ isObject,
96
+ translateText,
85
97
  };