iobroker.smartm 0.0.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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Christian Müller
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,50 @@
1
+ ![Logo](admin/smartm.svg)
2
+
3
+ # ioBroker.smartm
4
+
5
+ [![NPM version](https://img.shields.io/npm/v/iobroker.smartm.svg)](https://www.npmjs.com/package/iobroker.smartm)
6
+ [![Downloads](https://img.shields.io/npm/dm/iobroker.smartm.svg)](https://www.npmjs.com/package/iobroker.smartm)
7
+ ![Number of Installations](https://iobroker.live/badges/smartm-installed.svg)
8
+ ![Current version in stable repository](https://iobroker.live/badges/smartm-stable.svg)
9
+
10
+ [![NPM](https://nodei.co/npm/iobroker.smartm.svg?downloads=true)](https://nodei.co/npm/iobroker.smartm/)
11
+
12
+ **Tests:** ![Test and Release](https://github.com/strulli85/ioBroker.smartm/workflows/Test%20and%20Release/badge.svg)
13
+
14
+ ## smartm adapter for ioBroker
15
+
16
+ reads Data of Slenergy-Photovoltaic-Plants over SmartM
17
+
18
+ ## Changelog
19
+
20
+ <!--
21
+ Placeholder for the next version (at the beginning of the line):
22
+ ### **WORK IN PROGRESS**
23
+ -->
24
+ ### 0.0.2 (2025-11-14)
25
+
26
+ - (Christian Müller) initial release
27
+
28
+ ## License
29
+
30
+ MIT License
31
+
32
+ Copyright (c) 2025 Christian Müller
33
+
34
+ Permission is hereby granted, free of charge, to any person obtaining a copy
35
+ of this software and associated documentation files (the "Software"), to deal
36
+ in the Software without restriction, including without limitation the rights
37
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
38
+ copies of the Software, and to permit persons to whom the Software is
39
+ furnished to do so, subject to the following conditions:
40
+
41
+ The above copyright notice and this permission notice shall be included in all
42
+ copies or substantial portions of the Software.
43
+
44
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
45
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
46
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
47
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
48
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
49
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
50
+ SOFTWARE.
@@ -0,0 +1,8 @@
1
+ {
2
+ "Benutzername": "Benutzername",
3
+ "China": "China",
4
+ "Europa": "Europa",
5
+ "International": "International",
6
+ "Passwort": "Passwort",
7
+ "Server": "Server"
8
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "China": "China",
3
+ "International": "International",
4
+ "Europa": "Europe",
5
+ "Server": "Server",
6
+ "Benutzername": "Username",
7
+ "Passwort": "Password"
8
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "Benutzername": "Nombre de usuario",
3
+ "China": "Porcelana",
4
+ "Europa": "Europa",
5
+ "International": "Internacional",
6
+ "Passwort": "Contraseña",
7
+ "Server": "Servidor"
8
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "Benutzername": "Nom d'utilisateur",
3
+ "China": "Chine",
4
+ "Europa": "Europe",
5
+ "International": "International",
6
+ "Passwort": "Mot de passe",
7
+ "Server": "Serveur"
8
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "Benutzername": "Nome utente",
3
+ "China": "Cina",
4
+ "Europa": "Europa",
5
+ "International": "Internazionale",
6
+ "Passwort": "Password",
7
+ "Server": "Server"
8
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "Benutzername": "Gebruikersnaam",
3
+ "China": "China",
4
+ "Europa": "Europa",
5
+ "International": "Internationale",
6
+ "Passwort": "Wachtwoord",
7
+ "Server": "Server"
8
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "Benutzername": "Nazwa użytkownika",
3
+ "China": "Chiny",
4
+ "Europa": "Europa",
5
+ "International": "Międzynarodowy",
6
+ "Passwort": "Hasło",
7
+ "Server": "Serwer"
8
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "Benutzername": "Nome de usuário",
3
+ "China": "China",
4
+ "Europa": "Europa",
5
+ "International": "Internacional",
6
+ "Passwort": "Senha",
7
+ "Server": "Servidor"
8
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "Benutzername": "Имя пользователя",
3
+ "China": "Китай",
4
+ "Europa": "Европа",
5
+ "International": "Международный",
6
+ "Passwort": "Пароль",
7
+ "Server": "Сервер"
8
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "Benutzername": "Ім'я користувача",
3
+ "China": "Китай",
4
+ "Europa": "Європа",
5
+ "International": "Міжнародний",
6
+ "Passwort": "Пароль",
7
+ "Server": "Сервер"
8
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "Benutzername": "用户名",
3
+ "China": "中国",
4
+ "Europa": "欧洲",
5
+ "International": "国际的",
6
+ "Passwort": "密码",
7
+ "Server": "服务器"
8
+ }
@@ -0,0 +1,31 @@
1
+ {
2
+ "i18n": true,
3
+ "type": "panel",
4
+ "items": {
5
+ "server": {
6
+ "type": "select",
7
+ "label": "Server",
8
+ "options": [
9
+ { "value": "slenergytech.com", "label": "China" },
10
+ { "value": "global.slenergytech.com", "label": "International" },
11
+ { "value": "eu.slenergytech.com", "label": "Europa" }
12
+ ],
13
+ "default": "eu.slenergytech.com"
14
+ },
15
+ "username": {
16
+ "type": "text",
17
+ "label": "Benutzername",
18
+ "newLine": true,
19
+ "sm": 12,
20
+ "md": 6,
21
+ "lg": 6
22
+ },
23
+ "password": {
24
+ "type": "password",
25
+ "label": "Passwort",
26
+ "sm": 12,
27
+ "md": 6,
28
+ "lg": 6
29
+ }
30
+ }
31
+ }
@@ -0,0 +1,54 @@
1
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
2
+ <!-- Created with Inkscape (http://www.inkscape.org/) -->
3
+
4
+ <svg
5
+ width="113mm"
6
+ height="113mm"
7
+ viewBox="0 0 113 113"
8
+ version="1.1"
9
+ id="svg1"
10
+ xml:space="preserve"
11
+ inkscape:version="1.4 (86a8ad7, 2024-10-11)"
12
+ sodipodi:docname="smartm.svg"
13
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
14
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
15
+ xmlns="http://www.w3.org/2000/svg"
16
+ xmlns:svg="http://www.w3.org/2000/svg"><sodipodi:namedview
17
+ id="namedview1"
18
+ pagecolor="#000000"
19
+ bordercolor="#000000"
20
+ borderopacity="0.25"
21
+ inkscape:showpageshadow="2"
22
+ inkscape:pageopacity="0.0"
23
+ inkscape:pagecheckerboard="true"
24
+ inkscape:deskcolor="#d1d1d1"
25
+ inkscape:document-units="mm"
26
+ inkscape:export-bgcolor="#00000f00"
27
+ inkscape:zoom="2.8548345"
28
+ inkscape:cx="317.70668"
29
+ inkscape:cy="264.28852"
30
+ inkscape:window-width="2560"
31
+ inkscape:window-height="1351"
32
+ inkscape:window-x="3191"
33
+ inkscape:window-y="196"
34
+ inkscape:window-maximized="1"
35
+ inkscape:current-layer="layer1" /><defs
36
+ id="defs1" /><g
37
+ inkscape:label="Ebene 1"
38
+ inkscape:groupmode="layer"
39
+ id="layer1"><g
40
+ id="g8"
41
+ transform="translate(1.2975071,1.8535809)"><path
42
+ style="fill:#73ac89"
43
+ d="m 55.033335,66.894587 c 0,-0.07326 0.277813,-0.351069 0.617362,-0.617361 0.559525,-0.43881 0.572003,-0.426332 0.133193,0.133193 -0.460859,0.587639 -0.750555,0.774516 -0.750555,0.484168 z"
44
+ id="path13" /><path
45
+ style="fill:#53934f"
46
+ d="m 57.855558,63.719587 c 0,-0.07326 0.277812,-0.351069 0.617361,-0.617361 0.559525,-0.43881 0.572003,-0.426332 0.133193,0.133193 -0.460858,0.587639 -0.750554,0.774516 -0.750554,0.484168 z"
47
+ id="path12" /><path
48
+ style="fill:#016801"
49
+ d="m 54.14258,66.410419 1.603392,-3.263194 H 52.74382 c -1.651183,0 -3.002151,-0.05953 -3.002151,-0.132287 0,-0.07276 1.500559,-3.247758 3.334576,-7.055556 l 3.334577,-6.923269 h 2.32094 c 1.877435,0 2.365826,0.116972 2.555838,0.612134 0.154526,0.40269 -0.751925,2.515017 -2.649248,6.173612 l -2.884146,5.561477 h 2.14534 2.14534 l -2.241192,2.494334 c -1.232656,1.371885 -2.921438,3.237197 -3.752849,4.14514 l -1.511657,1.650804 z"
50
+ id="path9" /><path
51
+ style="fill:#000000"
52
+ d="m 51.636838,94.575601 c -2.385189,-0.196865 -2.589365,-0.284696 -3.96875,-1.707251 -2.652804,-2.24729 -1.454197,-6.141232 -1.454197,-9.572622 0,-8.019197 -0.0054,-8.076427 -0.806075,-8.601073 -1.488204,-0.975109 -4.158964,-3.922435 -5.178115,-5.714326 -2.995001,-5.265871 -2.988394,-12.056737 0.01687,-17.34014 2.555492,-4.492681 8.12185,-8.24322 13.287458,-8.952916 5.58097,-0.766762 11.34132,1.160318 15.346512,5.134055 3.195253,3.170159 4.778116,6.506198 5.388671,11.357146 0.14392,1.143466 -0.544362,5.378206 -0.745193,6.109582 -0.977687,3.349375 -2.938773,6.23766 -5.930321,8.734173 l -1.447863,1.208273 -0.176389,4.453501 -0.176389,4.4535 c -1.103283,0.19673 -2.020328,0.03581 -2.94766,0.03152 -0.195149,-9.02e-4 -0.326746,-2.295197 -0.357202,-4.872445 l -0.05538,-4.685906 2.209286,-1.604495 c 2.543652,-1.84733 4.523267,-4.525129 5.593215,-7.565867 0.610407,-1.734747 0.720408,-2.721372 0.609643,-5.468056 -0.115235,-2.857527 -0.299349,-3.701452 -1.249413,-5.726946 -1.419202,-3.025676 -2.909784,-4.872863 -5.211174,-6.457891 -5.011285,-3.451404 -11.926909,-3.451404 -16.938194,0 -2.30139,1.585028 -3.791972,3.432215 -5.211174,6.457891 -0.950064,2.025494 -1.134178,2.869419 -1.249413,5.726946 -0.110765,2.746684 -7.64e-4,3.733309 0.609643,5.468056 0.94889,2.696698 2.943915,5.60002 4.817946,7.011463 0.880738,0.663336 1.909317,1.945483 2.582458,3.219093 l 1.118721,2.116667 -0.01,5.71604 c -0.006,3.437162 0.145172,6.056514 0.379151,6.570042 0.21401,0.469701 1.001295,1.19807 1.749522,1.618597 1.325732,0.745103 1.637321,0.761977 12.222696,0.661903 9.755996,-0.09223 10.996766,-0.169542 12.182713,-0.759069 2.997374,-1.489975 5.769331,-5.491264 6.777608,-9.783401 0.431999,-1.838975 0.494545,-4.002566 0.335593,-11.608835 -0.107449,-5.141736 -0.06104,-10.062986 0.103142,-10.936111 0.254941,-1.355819 0.432959,-1.603215 1.219798,-1.695177 0.658929,-0.07701 1.133876,0.162577 1.667779,0.841325 0.719927,0.915238 0.375337,1.295605 0.363626,10.691011 -0.07534,4.695162 0.112512,7.645776 -0.656397,12.314776 -0.707605,4.296747 -3.371064,8.976334 -7.183326,11.253282 -5.209323,3.11137 -7.589801,2.20007 -13.85907,2.1683 -6.190672,-0.0314 -12.387352,-0.150467 -13.770356,-0.264615 z M 18.697223,74.612503 V 61.030558 h 2.116667 2.116666 V 74.612503 88.194448 H 20.81389 18.697223 Z m -5.40763,-21.399771 c -0.597807,-0.763856 -0.790535,-1.288664 -0.570573,-1.553702 0.182687,-0.220125 5.982457,-4.670644 12.888379,-9.890044 6.905922,-5.2194 16.702242,-12.627415 21.7696,-16.462256 5.067359,-3.83484 9.372566,-6.919375 9.567127,-6.854521 0.194561,0.06485 9.995331,7.568076 21.779489,16.673826 l 21.425745,16.555911 -1.214581,1.228466 c -1.172455,1.185863 -1.246165,1.2093 -2.125403,0.67581 C 96.308423,53.282261 87.033433,46.498513 76.198289,38.511228 65.363145,30.523942 56.318437,23.98889 56.098938,23.98889 c -0.656283,0 -6.018924,3.5718 -5.827548,3.881453 C 50.493626,28.229928 15.755574,54.112689 14.854627,54.2588 14.44398,54.3254 13.849313,53.927922 13.289593,53.212732 Z M 83.041106,29.054865 c -3.471565,-3.034548 -6.367542,-5.66199 -6.435505,-5.838761 -0.06796,-0.17677 0.07778,-0.807505 0.323878,-1.401631 0.425198,-1.026518 0.523685,-1.069781 1.980678,-0.870078 1.373864,0.188309 2.186208,0.798752 7.815313,5.872884 5.827228,5.252722 6.270964,5.738474 6.128545,6.708838 -0.145456,0.991054 -0.241617,1.046107 -1.827254,1.046107 -1.65604,0 -1.740389,-0.05828 -7.985655,-5.517359 z"
53
+ id="path8"
54
+ sodipodi:nodetypes="ssscssssssscccsscsssssssssssccsssssssssssscscccccccccsssssscsssssssssssssss" /></g></g></svg>
@@ -0,0 +1,132 @@
1
+ {
2
+ "common": {
3
+ "name": "smartm",
4
+ "version": "0.0.2",
5
+ "news": {
6
+ "0.0.2": {
7
+ "en": "initial release",
8
+ "de": "erstausstrahlung",
9
+ "ru": "первоначальное освобождение",
10
+ "pt": "libertação inicial",
11
+ "nl": "eerste release",
12
+ "fr": "libération initiale",
13
+ "it": "rilascio iniziale",
14
+ "es": "liberación inicial",
15
+ "pl": "początkowe zwolnienie",
16
+ "uk": "початковий реліз",
17
+ "zh-cn": "初步释放"
18
+ },
19
+ "0.0.1": {
20
+ "en": "initial release",
21
+ "de": "Erstveröffentlichung",
22
+ "ru": "Начальная версия",
23
+ "pt": "lançamento inicial",
24
+ "nl": "Eerste uitgave",
25
+ "fr": "Première version",
26
+ "it": "Versione iniziale",
27
+ "es": "Versión inicial",
28
+ "pl": "Pierwsze wydanie",
29
+ "uk": "Початкова версія",
30
+ "zh-cn": "首次出版"
31
+ }
32
+ },
33
+ "titleLang": {
34
+ "en": "Slenergy - SmartM",
35
+ "de": "Slenergy - SmartM",
36
+ "ru": "Сленергия - СмартМ",
37
+ "pt": "Slenergy - SmartM",
38
+ "nl": "Slenergie - SmartM",
39
+ "fr": "Slenergy - SmartM",
40
+ "it": "Slenergy - SmartM",
41
+ "es": "Slenergia - SmartM",
42
+ "pl": "Sleenergy - SmartM",
43
+ "uk": "Slenergy - SmartM",
44
+ "zh-cn": "Slenergy-SmartM"
45
+ },
46
+ "desc": {
47
+ "en": "reads Data of Slenergy-Photovoltaic-Plants over SmartM",
48
+ "de": "liest Daten von Slenergy-Photovoltaik-Anlagen über SmartM",
49
+ "ru": "читает данные фотоэлектрических станций Slenergy через SmartM",
50
+ "pt": "lê dados de plantas fotovoltaicas Slenergy sobre SmartM",
51
+ "nl": "leest gegevens van Slenergy-fotovoltaïsche installaties via SmartM",
52
+ "fr": "lit les données des installations photovoltaïques Slenergy via SmartM",
53
+ "it": "legge i dati degli impianti fotovoltaici Slenergy su SmartM",
54
+ "es": "lee los datos de las plantas fotovoltaicas de Slenergy sobre SmartM",
55
+ "pl": "czyta Dane Slenergy-Fotowoltaiki-Plants na SmartM",
56
+ "uk": "читає дані Slenergy-Photovoltaic-Plants через SmartM",
57
+ "zh-cn": "通过 SmartM 读取 Slenergy 光伏电站的数据"
58
+ },
59
+ "authors": [
60
+ "Christian Müller"
61
+ ],
62
+ "keywords": [
63
+ "Photovoltaic",
64
+ "Slenergy",
65
+ "SmartM"
66
+ ],
67
+ "licenseInformation": {
68
+ "type": "free",
69
+ "license": "MIT"
70
+ },
71
+ "platform": "Javascript/Node.js",
72
+ "icon": "smartm.svg",
73
+ "enabled": true,
74
+ "extIcon": "https://raw.githubusercontent.com/strulli85/ioBroker.smartm/main/admin/smartm.svg",
75
+ "readme": "https://github.com/strulli85/ioBroker.smartm/blob/main/README.md",
76
+ "loglevel": "info",
77
+ "tier": 3,
78
+ "mode": "daemon",
79
+ "type": "energy",
80
+ "compact": true,
81
+ "connectionType": "cloud",
82
+ "dataSource": "poll",
83
+ "adminUI": {
84
+ "config": "json"
85
+ },
86
+ "dependencies": [
87
+ {
88
+ "js-controller": ">=6.0.11"
89
+ }
90
+ ],
91
+ "globalDependencies": [
92
+ {
93
+ "admin": ">=7.7.19"
94
+ }
95
+ ]
96
+ },
97
+ "native": {
98
+ "server": "eu.slenergytech.com",
99
+ "username": "",
100
+ "password": ""
101
+ },
102
+ "encryptedNative": [
103
+ "password"
104
+ ],
105
+ "protectedNative": [
106
+ "password"
107
+ ],
108
+ "objects": [],
109
+ "instanceObjects": [
110
+ {
111
+ "_id": "info",
112
+ "type": "channel",
113
+ "common": {
114
+ "name": "Information"
115
+ },
116
+ "native": {}
117
+ },
118
+ {
119
+ "_id": "info.connection",
120
+ "type": "state",
121
+ "common": {
122
+ "role": "indicator.connected",
123
+ "name": "Device or service connected",
124
+ "type": "boolean",
125
+ "read": true,
126
+ "write": false,
127
+ "def": false
128
+ },
129
+ "native": {}
130
+ }
131
+ ]
132
+ }
@@ -0,0 +1,19 @@
1
+ // This file extends the AdapterConfig type from "@types/iobroker"
2
+ // using the actual properties present in io-package.json
3
+ // in order to provide typings for adapter.config properties
4
+
5
+ import { native } from "../io-package.json";
6
+
7
+ type _AdapterConfig = typeof native;
8
+
9
+ // Augment the globally declared type ioBroker.AdapterConfig
10
+ declare global {
11
+ namespace ioBroker {
12
+ interface AdapterConfig extends _AdapterConfig {
13
+ // Do not enter anything here!
14
+ }
15
+ }
16
+ }
17
+
18
+ // this is required so the above AdapterConfig is found by TypeScript / type checking
19
+ export {};
package/main.js ADDED
@@ -0,0 +1,349 @@
1
+ "use strict";
2
+
3
+ /*
4
+ * Created with @iobroker/create-adapter v2.6.5
5
+ */
6
+
7
+ // The adapter-core module gives you access to the core ioBroker functions
8
+ // you need to create an adapter
9
+ const utils = require("@iobroker/adapter-core");
10
+ const axios = require("axios");
11
+
12
+ class Smartm extends utils.Adapter {
13
+ /**
14
+ * @param {Partial<utils.AdapterOptions>} [options] - some options
15
+ */
16
+ constructor(options) {
17
+ super({
18
+ ...options,
19
+ name: "smartm",
20
+ });
21
+
22
+ this.accessToken = null;
23
+ this.powerStationIds = [];
24
+
25
+ this.on("ready", this.onReady.bind(this));
26
+ this.on("unload", this.onUnload.bind(this));
27
+ }
28
+
29
+ /**
30
+ * Is called when databases are connected and adapter received configuration.
31
+ */
32
+ async onReady() {
33
+ if (!this.config.server) {
34
+ this.setState("info.connection", false, true);
35
+ this.terminate(
36
+ `Server is empty - please check instance configuration of ${this.namespace}`,
37
+ utils.EXIT_CODES.INVALID_ADAPTER_CONFIG,
38
+ );
39
+ return;
40
+ }
41
+
42
+ if (!this.config.username || !this.config.password) {
43
+ this.setState("info.connection", false, true);
44
+ this.terminate(
45
+ `User name and/or user password empty - please check instance configuration of ${this.namespace}`,
46
+ utils.EXIT_CODES.INVALID_ADAPTER_CONFIG,
47
+ );
48
+ return;
49
+ }
50
+
51
+ this.reLoginTimeout = null;
52
+ this.reloadFlowDataInterval = null;
53
+ this.reloadStatisticsInterval = null;
54
+ this.login();
55
+ }
56
+
57
+ /**
58
+ * Is called when adapter shuts down - callback has to be called under any circumstances!
59
+ *
60
+ * @param {() => void} callback - callback function
61
+ */
62
+ onUnload(callback) {
63
+ try {
64
+ this.setState("info.connection", false, true);
65
+ this.reLoginTimeout && clearTimeout(this.reLoginTimeout);
66
+ this.reloadFlowDataInterval && clearInterval(this.reloadFlowDataInterval);
67
+ this.reloadStatisticsInterval && clearInterval(this.reloadStatisticsInterval);
68
+ callback();
69
+ } catch (error) {
70
+ this.log.error(`Error in Unload Function: ${error}`);
71
+ callback();
72
+ }
73
+ }
74
+
75
+ /*
76
+ * Login to smart-m server and obtain access token
77
+ */
78
+ async login() {
79
+ this.log.info(`login to smart-m server ${this.config.server}`);
80
+
81
+ //stop previous intervals
82
+ this.reloadFlowDataInterval && clearInterval(this.reloadFlowDataInterval);
83
+ this.reloadFlowDataInterval = null;
84
+
85
+ this.reloadStatisticsInterval && clearInterval(this.reloadStatisticsInterval);
86
+ this.reloadStatisticsInterval = null;
87
+ try {
88
+ const response = await axios.post(`https://${this.config.server}/backend/slenergy-sys/sys/login`, {
89
+ captcha: "",
90
+ checkKey: "",
91
+ username: this.config.username,
92
+ password: this.config.password,
93
+ remember_me: true,
94
+ });
95
+ if (response.data.success) {
96
+ this.log.info("Login successful");
97
+ this.setState("info.connection", true, true);
98
+ this.accessToken = response.data.result.token;
99
+ this.parseUserInfo(response.data.result.userInfo);
100
+ this.parsePowerStationList(response.data.result.powerStationList);
101
+
102
+ //start reloading flow data every minute
103
+ this.reloadFlowData();
104
+ this.reloadFlowDataInterval = setInterval(() => {
105
+ this.reloadFlowData();
106
+ }, 1000 * 60);
107
+
108
+ //start reloading statistics every minute
109
+ this.reloadStatistics();
110
+ this.reloadStatisticsInterval = setInterval(() => {
111
+ this.reloadStatistics();
112
+ }, 1000 * 60);
113
+ } else {
114
+ this.setState("info.connection", false, true);
115
+ this.log.error(`Login failed: ${JSON.stringify(response.data, null, 2)}`);
116
+ //retry login in 1 minute
117
+ this.reLoginTimeout = setTimeout(() => {
118
+ this.login();
119
+ }, 1000 * 60);
120
+ }
121
+ } catch (error) {
122
+ this.setState("info.connection", false, true);
123
+ this.log.error(`Error obtaining access token: ${error}`);
124
+ //retry login in 1 minute
125
+ this.reLoginTimeout = setTimeout(() => {
126
+ this.login();
127
+ }, 1000 * 60);
128
+ }
129
+ }
130
+
131
+ /*
132
+ * parse UserInfo from login response
133
+ * @param {object} userInfo - user info object from login response
134
+ */
135
+ parseUserInfo(userInfo) {
136
+ this.log.debug("Parsing user info");
137
+
138
+ //create subtree for userInfo
139
+ this.setObjectNotExists("userInfo", {
140
+ type: "channel",
141
+ common: {
142
+ name: "Benutzerinformationen",
143
+ },
144
+ native: {},
145
+ });
146
+
147
+ this.parseData("userInfo", userInfo);
148
+ }
149
+
150
+ /*
151
+ * parse PowerStationList from login response
152
+ * @param {array} powerStationList - array of power station objects from login response
153
+ */
154
+ parsePowerStationList(powerStationList) {
155
+ this.log.debug("Parsing power station list");
156
+
157
+ //create subtree for powerStationList
158
+ this.setObjectNotExists("powerStationList", {
159
+ type: "channel",
160
+ common: {
161
+ name: "Anlageninformationen",
162
+ },
163
+ native: {},
164
+ });
165
+
166
+ //create a subtree for each powerStation
167
+ this.powerStationIds = [];
168
+ for (const powerStation of powerStationList) {
169
+ this.powerStationIds.push(powerStation.id);
170
+ this.setObjectNotExists(`powerStationList.${powerStation.id}`, {
171
+ type: "channel",
172
+ common: {
173
+ name: powerStation.powerStationName,
174
+ },
175
+ native: {},
176
+ });
177
+
178
+ //fill each powerStation subtree with data
179
+ this.parseData(`powerStationList.${powerStation.id}`, powerStation);
180
+ }
181
+ }
182
+
183
+ /*
184
+ * Reload flow data for all power stations
185
+ */
186
+ async reloadFlowData() {
187
+ this.log.debug("Reloading flow data from smart-m server");
188
+
189
+ for (const powerStationId of this.powerStationIds) {
190
+ this.log.debug(`Reloading flow data of plant ${powerStationId}`);
191
+ try {
192
+ const currentDate = new Date();
193
+ const response = await axios.post(
194
+ `https://${this.config.server}/backend/slenergy-ops/ops/energy/storage/home/flow`,
195
+ {
196
+ powerStationId: powerStationId,
197
+ year: currentDate.getFullYear(),
198
+ month: currentDate.getMonth() + 1, //month is zero based
199
+ day: currentDate.getDate(),
200
+ },
201
+ {
202
+ headers: {
203
+ "X-Access-Token": this.accessToken,
204
+ },
205
+ },
206
+ );
207
+ if (response.data.success) {
208
+ this.log.debug(`flow data request successful${JSON.stringify(response.data, null, 2)}`);
209
+
210
+ this.setObjectNotExists(`powerStationList.${powerStationId}.flow`, {
211
+ type: "channel",
212
+ common: {
213
+ name: `powerStationList.${powerStationId}.flow`,
214
+ },
215
+ native: {},
216
+ });
217
+
218
+ this.parseData(`powerStationList.${powerStationId}.flow`, response.data.result);
219
+ } else {
220
+ this.log.error(`reading flow data failed: ${JSON.stringify(response.data, null, 2)}`);
221
+ //retry login in 1 minute
222
+ this.reLoginTimeout = setTimeout(() => {
223
+ this.login();
224
+ }, 1000 * 60);
225
+ return;
226
+ }
227
+ } catch (error) {
228
+ this.log.error(`reading flow data failed: ${error}`);
229
+ //retry login in 1 minute
230
+ this.reLoginTimeout = setTimeout(() => {
231
+ this.login();
232
+ }, 1000 * 60);
233
+ return;
234
+ }
235
+ }
236
+ }
237
+
238
+ /*
239
+ * Reload statistics
240
+ */
241
+ async reloadStatistics() {
242
+ this.log.debug("Reloading statistics from smart-m server");
243
+
244
+ for (const powerStationId of this.powerStationIds) {
245
+ this.log.debug(`Reloading statistic of plant ${powerStationId}`);
246
+ try {
247
+ const response = await axios.get(
248
+ `https://${this.config.server}/backend/slenergy-ops/ops/energy/storage/overview-statistics/${
249
+ powerStationId
250
+ }`,
251
+ {
252
+ headers: {
253
+ "X-Access-Token": this.accessToken,
254
+ },
255
+ },
256
+ );
257
+ if (response.data.success) {
258
+ this.log.debug(`statistic data request successful${JSON.stringify(response.data, null, 2)}`);
259
+
260
+ this.setObjectNotExists(`powerStationList.${powerStationId}.statistics`, {
261
+ type: "channel",
262
+ common: {
263
+ name: `powerStationList.${powerStationId}.statistics`,
264
+ },
265
+ native: {},
266
+ });
267
+
268
+ this.parseData(`powerStationList.${powerStationId}.statistics`, response.data.result);
269
+ } else {
270
+ this.log.error(`reading statistics failed: ${JSON.stringify(response.data, null, 2)}`);
271
+ //retry login in 1 minute
272
+ this.reLoginTimeout = setTimeout(() => {
273
+ this.login();
274
+ }, 1000 * 60);
275
+ return;
276
+ }
277
+ } catch (error) {
278
+ this.log.error(`reading statistics data failed: ${error}`);
279
+ //retry login in 1 minute
280
+ this.reLoginTimeout = setTimeout(() => {
281
+ this.login();
282
+ }, 1000 * 60);
283
+ return;
284
+ }
285
+ }
286
+ }
287
+
288
+ parseData(parentIoBrokerId, jsonObject) {
289
+ const objectKeys = Object.keys(jsonObject);
290
+ for (const key of objectKeys) {
291
+ const jsType = typeof jsonObject[key];
292
+ const iobId = `${parentIoBrokerId}.${key}`;
293
+
294
+ if (jsType === "object") {
295
+ if (jsonObject[key] !== null) {
296
+ this.setObjectNotExists(iobId, {
297
+ type: "channel",
298
+ common: {
299
+ name: iobId,
300
+ },
301
+ native: {},
302
+ });
303
+ this.parseData(iobId, jsonObject[key]);
304
+ }
305
+ } else {
306
+ //create state
307
+ let iobType;
308
+ switch (jsType) {
309
+ case "number":
310
+ iobType = "number";
311
+ break;
312
+ case "string":
313
+ iobType = "string";
314
+ break;
315
+ case "boolean":
316
+ iobType = "boolean";
317
+ break;
318
+ default:
319
+ iobType = "string";
320
+ }
321
+
322
+ this.setObjectNotExists(iobId, {
323
+ type: "state",
324
+ common: {
325
+ name: iobId,
326
+ type: iobType,
327
+ role: "state",
328
+ read: true,
329
+ write: false,
330
+ },
331
+ native: {},
332
+ });
333
+
334
+ this.setStateChanged(iobId, jsonObject[key], true);
335
+ }
336
+ }
337
+ }
338
+ }
339
+
340
+ if (require.main !== module) {
341
+ // Export the constructor in compact mode
342
+ /**
343
+ * @param {Partial<utils.AdapterOptions>} [options] - some options
344
+ */
345
+ module.exports = options => new Smartm(options);
346
+ } else {
347
+ // otherwise start the instance directly
348
+ new Smartm();
349
+ }
package/package.json ADDED
@@ -0,0 +1,70 @@
1
+ {
2
+ "name": "iobroker.smartm",
3
+ "version": "0.0.2",
4
+ "description": "This Adapter reads Data of Slenergy-Photovoltaic-Plants over SmartM",
5
+ "author": {
6
+ "name": "Christian Müller",
7
+ "email": ""
8
+ },
9
+ "homepage": "https://github.com/strulli85/ioBroker.smartm",
10
+ "license": "MIT",
11
+ "keywords": [
12
+ "ioBroker",
13
+ "ioBroker-Adapter",
14
+ "Photovoltaic",
15
+ "Slenergy",
16
+ "SmartM"
17
+ ],
18
+ "repository": {
19
+ "type": "git",
20
+ "url": "git@github.com:strulli85/ioBroker.smartm.git"
21
+ },
22
+ "engines": {
23
+ "node": ">= 22"
24
+ },
25
+ "dependencies": {
26
+ "@iobroker/adapter-core": "^3.3.2"
27
+ },
28
+ "devDependencies": {
29
+ "@alcalzone/release-script": "^5.0.0",
30
+ "@alcalzone/release-script-plugin-iobroker": "^4.0.0",
31
+ "@alcalzone/release-script-plugin-license": "^4.0.0",
32
+ "@alcalzone/release-script-plugin-manual-review": "^4.0.0",
33
+ "@iobroker/adapter-dev": "^1.5.0",
34
+ "@iobroker/eslint-config": "^2.2.0",
35
+ "@iobroker/testing": "^5.1.1",
36
+ "@tsconfig/node22": "^22.0.2",
37
+ "@types/node": "^22.18.12",
38
+ "@types/proxyquire": "^1.3.31",
39
+ "eslint": "^9.0.0",
40
+ "prettier": "^3.6.2",
41
+ "proxyquire": "^2.1.3",
42
+ "typescript": "~5.0.4"
43
+ },
44
+ "main": "main.js",
45
+ "files": [
46
+ "admin{,/!(src)/**}/!(tsconfig|tsconfig.*|.eslintrc).{json,json5}",
47
+ "admin{,/!(src)/**}/*.{html,css,png,svg,jpg,js}",
48
+ "lib/",
49
+ "www/",
50
+ "io-package.json",
51
+ "LICENSE",
52
+ "main.js"
53
+ ],
54
+ "scripts": {
55
+ "test:js": "mocha --config test/mocharc.custom.json \"{!(node_modules|test)/**/*.test.js,*.test.js,test/**/test!(PackageFiles|Startup).js}\"",
56
+ "test:package": "mocha test/package --exit",
57
+ "test:integration": "mocha test/integration --exit",
58
+ "test": "npm run test:js && npm run test:package",
59
+ "check": "tsc --noEmit -p tsconfig.check.json",
60
+ "lint": "eslint .",
61
+ "translate": "translate-adapter",
62
+ "release": "release-script patch --yes",
63
+ "release-minor": "release-script minor --yes",
64
+ "release-major": "release-script major --yes"
65
+ },
66
+ "bugs": {
67
+ "url": "https://github.com/strulli85/ioBroker.smartm/issues"
68
+ },
69
+ "readmeFilename": "README.md"
70
+ }