-
Notifications
You must be signed in to change notification settings - Fork 0
/
hoymiles-begrenzung.js
247 lines (216 loc) · 9.86 KB
/
hoymiles-begrenzung.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
/*
* Script zur Begrenzung von Hoymiles Wechselrichter in Verbindung mit openDTU
* v0.0.3 2023/12/12 by Schmakus
* http://www.github.com/Schmakus/ioBroker-Scripte/
*
* Es werden folgende eigene Datenpunkte erstellt:
* BegrenzungSoll: Vorgabe der Gesamtbegrenzung
* BegrenzungIst: Aktuelle Begrenzung in Watt über alle Wechselrichter
* BegrenzungIstInProzent: Aktuelle Begrenzung in Prozent über alle Wechselrichter
*
* Info: Die Objekt-IDs im Wechselrichter Objekt sind nur zum Test und müssen mit den richtigen Datenpunkten der Wechselrichter, usw. ersetzt werden!
*/
//Wo sollen die eigenen Datenpunkte angelegt werden?
const path = "0_userdata.0.PV";
//** Angaben zu den Wechselrichtern */
const wechselrichter = {
1: {
name: "Wechselrichter 1",
maxLeistung: 1600,
objLeistung: "0_userdata.0.PV.LeistungWR1", // Datenpunkt des Wechselrichters der aktuellen Leistung in Watt
objBegrenzung: "0_userdata.0.PV.BegrenzungWR1", // Beispiel: opendtu.0.xxxxxx.power_control.limit_persistent_absolute)
aktuelleLeistung: 0, // Nichts ändern!
begrenzteLeistung: 0, // Nichts ändern!
},
2: {
name: "Wechselrichter 2",
maxLeistung: 1600,
objLeistung: "0_userdata.0.PV.LeistungWR2", // Datenpunkt des Wechselrichters der aktuellen Leistung in Watt
objBegrenzung: "0_userdata.0.PV.BegrenzungWR2", // Beispiel: opendtu.0.xxxxxx.power_control.limit_persistent_absolute)
aktuelleLeistung: 0, // Nichts ändern!
begrenzteLeistung: 0, // Nichts ändern!
},
3: {
name: "Wechselrichter 3",
maxLeistung: 1600,
objLeistung: "0_userdata.0.PV.LeistungWR3", // Datenpunkt des Wechselrichters der aktuellen Leistung in Watt
objBegrenzung: "0_userdata.0.PV.BegrenzungWR3", // Beispiel: opendtu.0.xxxxxx.power_control.limit_persistent_absolute)
aktuelleLeistung: 0, // Nichts ändern!
begrenzteLeistung: 0, // Nichts ändern!
},
};
//Objekt-ID aktuelle Leistungsaufnahme des Hauses
const objLeistungHaus = "0_userdata.0.PV.LeistungHaus"; // Hier den Datenpunkt zum Smartmeter angeben (Shelly, IR-Lesekopf, etc...)
//Entscheidung ob Batterie geladen werden soll?
const batterie = {
laden: true, // true = laden, false = nicht laden
maxLadeleistung: 600, //maximale Ladeleistung in Watt,
unit: "volt", // "volt", "watt" or "percent"
objLadungWatt: "0_userdata.0.PV.LadeleistungBatterie", // Hier den Datenpunkt zum Ladegerät angeben
objLadungProzent: "0_userdata.0.PV.LadeleistungBatterieInProzent", // Hier den Datenpunkt zum Ladegerät angeben
objLadungVolt: "0_userdata.0.PV.LadeleistungBatterieInVolt" // Hier den Datenpunkt zum Ladegerät angeben
}
//**************************** */
// AB HIER NICHTS MEHR ÄNDERN! //
//**************************** */
//Variablen
let wechselrichterLeistungen = [];
let maximaleLeistungen = [];
let entpreller = null;
let maxGesamtLeistung = 0;
let objBegrenzung = "";
let objBegrenzungIst = "";
let objBegrenzungIstProzent = "";
/**
* Diese Funktion wird aufgerufen, wenn das System bereit ist.
*/
async function onReady() {
await setStates();
await getWechselrichterLeistungen();
for (const wr of Object.values(wechselrichter)) {
on({ id: wr.objLeistung, change: "ne" }, async (obj) => {
wr.aktuelleLeistung = obj.state.val;
console.log(`Aktuelle Leistung eines Wechselrichters aktualisiert. Wechselrichter: ${wr.name}, aktuelle Leistung: ${wr.aktuelleLeistung}`);
await setWechselrichterLeistungen();
});
}
const updateMaxGesamtLeistung = async (obj) => {
maxGesamtLeistung = (await getStateAsync(objBegrenzung)).val || 800;
await setStateAsync(objBegrenzung, { val: maxGesamtLeistung, ack: true });
console.log(`Aktuelle Begrenzung Soll: ${maxGesamtLeistung}`);
await setWechselrichterLeistungen();
};
on({ id: [objLeistungHaus, objBegrenzung], change: "ne" }, updateMaxGesamtLeistung);
}
/**
* Diese Funktion erstellt und initialisiert die eigenen Datenpunkte.
*/
async function setStates() {
// Maximal zulässige Gesamtleistung
await createStateAsync(`${path}.BegrenzungSoll`, 800, { read: true, write: true, name: 'Begrenzung Wechselrichter in Summe', type: "number", role: "state", unit: "W", def: 800 });
await createStateAsync(`${path}.BegrenzungIst`, 0, { read: true, write: false, name: 'Ist-Begrenzung Wechselrichter in Summe [Watt]', type: "number", role: "value", unit: "W", def: 0 });
await createStateAsync(`${path}.BegrenzungIstInProzent`, 0, { read: true, write: false, name: 'Ist-Begrenzung Wechselrichter in Summe [Prozent]', type: "number", role: "value", unit: "%", def: 0 });
objBegrenzung = `${path}.BegrenzungSoll`;
objBegrenzungIst = `${path}.BegrenzungIst`;
objBegrenzungIstProzent = `${path}.BegrenzungIstInProzent`;
maxGesamtLeistung = getState(objBegrenzung).val ?? 800;
}
/**
* Diese Funktion ruft die aktuellen Leistungen aller Wechselrichter ab.
*/
async function getWechselrichterLeistungen() {
for (const wr of Object.values(wechselrichter)) {
try {
const leistung = await getStateAsync(wr.objLeistung);
if (leistung) {
wr.aktuelleLeistung = leistung.val;
} else {
console.error(
`Could not retrieve state for ${wr.objLeistung}`
);
wr.aktuelleLeistung = 0; // Use 0 as a default value
}
} catch (error) {
console.error(
`Error retrieving state for ${wr.objLeistung}: ${error}`
);
wr.aktuelleLeistung = 0; // Use 0 as a default value
}
}
}
/**
* Diese Funktion gibt ein Array der maximalen Leistungen aller Wechselrichter zurück.
*/
async function getMaximaleLeistungen() {
return Object.values(wechselrichter).map(
(wechselrichter) => wechselrichter.maxLeistung
);
}
/**
* Berechnet die Summe aller aktuellen Leistungen der Wechselrichter.
*/
async function getAktuelleLeistungSumme() {
let summe = 0;
// Iteriere durch jedes Wechselrichter-Objekt
for (const wr of Object.values(wechselrichter)) {
summe = summe + wr.aktuelleLeistung;
}
return summe;
};
/**
* Berechnet die Summe aller maxLeistung-Werte im Wechselrichter-Objekt.
*/
async function getMaxLeistungSumme() {
let summe = 0;
// Iteriere durch jedes Wechselrichter-Objekt
for (const wr of Object.values(wechselrichter)) {
summe = summe + wr.maxLeistung;
}
return summe;
};
/**
* Berechnet die Summe aller begrenzteLeistung-Werte im Wechselrichter-Objekt.
*/
async function getMaxBegrenzungSumme() {
let summe = 0;
// Iteriere durch jedes Wechselrichter-Objekt
for (const wr of Object.values(wechselrichter)) {
summe = summe + wr.begrenzteLeistung;
}
return summe;
};
/**
* Berechnet die maximale Leistung und setzt die Begrenzung der Wechselrichter.
*/
async function setWechselrichterLeistungen() {
const aktuelleLeistungen = await getAktuelleLeistungSumme();
console.log(`Aktuelle Gesamtleistung der Wechselrichter: ${aktuelleLeistungen}`);
const faktor = maxGesamtLeistung / aktuelleLeistungen;
console.log(`Reduktionsfaktor der Wechselrichter: ${faktor}`);
await Promise.all(
Object.values(wechselrichter).map(async (wr) => {
let begrenzung = Math.floor(wr.aktuelleLeistung * faktor);
// Begrenze die einzelnen Wechselrichter auf mindestens 50W
begrenzung = Math.max(begrenzung, 50);
// Begrenze die einzelnen Wechselrichter auf maxGesamtLeistung
begrenzung = Math.min(begrenzung, maxGesamtLeistung);
wr.begrenzteLeistung = begrenzung;
await setStateAsync(wr.objBegrenzung, { val: wr.begrenzteLeistung, ack: false });
const prozentualeLeistung = (wr.begrenzteLeistung / wr.maxLeistung) * 100;
console.log(`${wr.name}: ${wr.begrenzteLeistung}W (${prozentualeLeistung.toFixed(2)}%)`);
})
);
const begrenzteLeistungIst = await getMaxBegrenzungSumme();
const begrenzteLeistungIstInProzent = Math.round((begrenzteLeistungIst / await getMaxLeistungSumme()) * 10000) / 100; // Runden auf 2 Nachkommastellen
await Promise.all([
setStateAsync(objBegrenzungIst, { val: begrenzteLeistungIst, ack: true }),
setStateAsync(objBegrenzungIstProzent, { val: begrenzteLeistungIstInProzent, ack: true })
]);
console.log(`Gesamtbegrenzung nach Anpassung: ${begrenzteLeistungIst}W, ${begrenzteLeistungIstInProzent}%, maxLeistungWR: ${maxGesamtLeistung}W`);
//Batterieladung
await loadBattery(aktuelleLeistungen);
}
async function loadBattery(aktuelleLeistungen) {
if (batterie.laden) {
const leistungHaus = (await getStateAsync(objLeistungHaus)).val;
const ueberschuss = Math.max(aktuelleLeistungen - leistungHaus, 0);
const ladeLeistung = Math.min(ueberschuss, batterie.maxLadeleistung);
const ladeLeistungProzent = Math.round((ueberschuss / batterie.maxLadeleistung) * 10000) / 100; // Runden auf 2 Nachkommastellen
const ladeLeistungVolt = Math.round(10 * (ladeLeistungProzent / 100) * 100) / 100; // Runden auf 2 Nachkommastellen
switch (batterie.unit) {
case "watt":
await setStateAsync(batterie.objLadungWatt, { val: ladeLeistung, ack: false });
break;
case "percent":
await setStateAsync(batterie.objLadungProzent, { val: ladeLeistungProzent, ack: false });
break;
case "volt":
await setStateAsync(batterie.objLadungVolt, { val: ladeLeistungVolt, ack: false });
break;
default:
console.warn(`Keine Einheit für die Batterieladung angegeben oder Einheit entspricht nicht 'watt', 'volt' oder 'percent'!`);
};
console.log(`Aktueller Überschuss: ${ueberschuss}, Ladeleistung: ${ladeLeistung}W, ${ladeLeistungProzent}%, ${ladeLeistungVolt}`);
}
}
onReady();