Danke für die Hinweise hier im Forum.
Ich habe das noch mal etwas anders gelöst, da ich unterschiedliche Adressen brauche, die teilweise weit auseinander liegen (und ich kann ja nicht tausende Adressen abfragen). Außerdem wollte ich kein polling, sondern einfach manuell die Daten abfragen. (man könnte mit dem Konstrukt auch pollen, dazu müsste man nur den ping node mit dem set payload node verbinden).
Um die Verbindung wiederzuverwenden, habe ich auch nur einen modbus node, der allerdings nur einen ping erzeugt (damit die Verbindung sich nicht schließt). Auf die daraus resultierenden Daten kommt es gar nicht an. Stattdessen habe ich einen node vorangestellt, der die passende payload erzeugt. Man muss leider immer ein interval definieren, daher habe ich hier das JavaScript-Maximum gewählt. Beim nächsten Aufruf wird das plugin das interval clearen und damit kommt es nie zum erneuten Aufruf (solange ich sie ca. alle 24 Tage einmal aufrufe - wenn nicht ists aber auch nicht schlimm).
Anschließend habe ich noch einen parsing node, der die Werte gleich passend umwandelt.
Hier der flow:
- Bildschirmfoto von 2023-02-25 09.46.51.png (18.8 KiB) 2536 mal betrachtet
Der modbus node:
Hier noch der code der payload function. Ich habe ein paar Argumente definiert, um u.a. das Ergebnis gleich richtig konvertieren zu können und zwischen den verschiedenen Datentypen zu unterscheiden. Die data points sind natürlich nur ein Beispiel, man kann das natürlich auf den eigenen Bedarf zuschneiden. Ich benutze msg.topic, um ein paar der Infos über den modbus node hinaus zu transportieren.
Code: Alles auswählen
const addDataPoint = (name, multiplier, unit, startAddress, quantity = 1, doubleWord = null, register = 'FC4') => {
if (doubleWord === null) {
doubleWord = quantity === 2;
}
return {
name,
topic: `${name}:${doubleWord ? 'double' : 'single'}:${unit}*${multiplier}`,
multiplier,
unit,
address: startAddress,
quantity,
dataType: register,
ieeeType: 'off',
interval: 2147483647 // max interval
};
};
msg.payload = [
addDataPoint('dcPower', 1, 'W', 5016, 2), // * 1W
addDataPoint('loadPower', 1, 'W', 13007, 2), // * 1W
addDataPoint('exportPower', 1, 'W', 13009, 2), // * 1W
addDataPoint('totalActivePower', 1, 'W', 13033, 2), // * 1W
addDataPoint('batteryPower', 1, 'W', 13021), // * 1W
addDataPoint('batteryLevel', 0.1, '%', 13022), // * 0.1%
addDataPoint('runningState', 1, '', 13000), // documentation appendix 1.2
addDataPoint('mppt1Voltage', 0.1, 'V', 5010), // * 0.1V
addDataPoint('mppt1Current', 0.1, 'A', 5011), // * 0.1A
addDataPoint('mppt2Voltage', 0.1, 'V', 5012), // * 0.1V
addDataPoint('mppt2Current', 0.1, 'A', 5013), // * 0.1A
addDataPoint('directConsumptionToday', 0.1, 'kWh', 13016), // * 0.1kWh
addDataPoint('directConsumptionPerDay', 0.1, 'kWh', 6385, 31), // * 0.1kWh; 01. - 31. of month
addDataPoint('directConsumptionPerMonth', 0.1, 'kWh', 6416, 12), // * 0.1kWh; Jan - Dez
];
return msg;
Und hier noch der Code der parsing function:
Code: Alles auswählen
const { payload } = msg;
const [name, wordLength, conversion] = msg.topic.split(':');
const isDoubleWord = wordLength === 'double';
const [unit, multiplier] = conversion.split('*');
const valuesCount = Math.floor((payload?.length ?? 0) / (isDoubleWord ? 2 : 1));
let values = isDoubleWord
? new Array(valuesCount).fill(null).map((_, index) => (payload[index * 2 + 1] << 16) + payload[index * 2])
: payload;
values = values.map(value => parseFloat((value * parseFloat(multiplier)).toFixed(1)));
msg.topic = name;
msg.payload = {
name,
unit,
value: values.length > 1 ? values : values[0] ?? null,
raw: payload
};
return msg;
Und hier ein Beispiel-Screenshot der Ausgabe:
Vielleicht hilfts ja jemandem weiter
Gruß