const Modbus = require('jsmodbus') var fs = require("fs") const net = require('net') const mqtt = require("mqtt"); const { InfluxDB, Point } = require('@influxdata/influxdb-client') const socket = new net.Socket() const modbusClient = new Modbus.client.TCP(socket, 0); let mqttClient = null; const options = { 'host': '192.168.178.63', 'port': 502 }; let config = null; let influxOrg = 'heatctrlOrg' let influxBucket = 'measurements' const influxUrl = 'http://influxdb:8086' let influxClient = null; let influxWriteClient = null; let inputValues = {}; let configuredInputs = {}; // for reconnecting see node-net-reconnect npm module // use socket.on('open', ...) when using serialport socket.on('connect', function () { console.log("socket connected starting interval timer"); setInterval(() => { requestTemps(); }, config.interval); }); fs.readFile('config.json', function (err, data) { if (err) { return console.error(err); } else { config = JSON.parse(data.toString()); configuredInputs = config.inputs; configuredInputs.forEach(element => { inputValues[element.label] = { value: null, synced: false, unitConversionDivider: 1 }; }); console.log("config read"); console.log("now connecting to influxdb"); influxClient = new InfluxDB({ url: influxUrl, token: config.influxToken }); influxWriteClient = influxClient.getWriteApi(influxOrg, influxBucket, 'ms'); console.log("connected to influxdb, now trying to connect to modbus tcp and mqtt"); socket.connect(options); mqttClient = mqtt.connect(config.mqttBrokerAddress, { username: config.mqttUser, password: config.mqttPassword }); } }); async function dispatchModbus() { //console.log(CF2values); calculateLogic(); writeToInflux(); clearSynced(); } async function clearSynced() { for (const key in inputValues) { if (Object.hasOwnProperty.call(inputValues, key)) { inputValues[key].synced = false; } } } async function requestTemps() { configuredInputs.forEach(element => { modbusClient.readInputRegisters(element.register, (element.type === "u32" | element.type === "s32") ? 2 : 1).then(function (resp) { let value = null; switch (element.type) { case "u32": { value = resp.response._body._valuesAsBuffer.readUInt32BE() / element.unitConversionDivider; } break; case "s32": { value = resp.response._body._valuesAsBuffer.readInt32BE() / element.unitConversionDivider; } break; case "u16": { value = resp.response._body._valuesAsBuffer.readUInt16BE() / element.unitConversionDivider; } break; case "s16": { value = resp.response._body._valuesAsBuffer.readInt16BE() / element.unitConversionDivider; } break; case "bool": { value = resp.response._body._values[0] / element.unitConversionDivider; } break; default: { value = resp.response._body._values[0] / element.unitConversionDivider; } break; } inputValues[element.label] = { value: value, synced: true }; let allSynced = true; /* if (resp.request._body.start === 9169) { console.log(resp); console.log(resp.response._body._values[0]); } */ for (const key in inputValues) { if (Object.hasOwnProperty.call(inputValues, key)) { const element = inputValues[key]; allSynced &= element.synced; } } if (allSynced) { dispatchModbus(); } }, console.error); }); } async function writeToInflux() { for (const key in inputValues) { if (Object.hasOwnProperty.call(inputValues, key)) { let point = new Point('CF2').floatField(key, inputValues[key].value); influxWriteClient.writePoint(point); } } influxWriteClient.flush(); } async function sendMQTT(topic, msg) { let mqttConfig = config.UmschichtungSolar.mqtt; if (typeof mqttClient !== 'undefined' || mqttClient !== null) { if (mqttClient.connected) { mqttClient.publish(topic, msg, { retain: true }); //console.log(msg); } else { console.log("client not connected to the mqtt broker"); } } else { console.log("mqttClient is undefined or null"); } //send status over mqtt let val = 0.0; if (msg == mqttConfig.msgOn) { val = 100.0; } else if (msg == mqttConfig.msgOff) { val = 0.0; } let point = new Point('Solarumschichtung').floatField("pumpePercent", val); influxWriteClient.writePoint(point); influxWriteClient.flush(); } let outputRegler1 = false; let outputRegler2 = false; async function calculateLogic() { //Notumschichtung regler 1 let umschichtungSolar = config.UmschichtungSolar; let notumschichtung = umschichtungSolar.Notumschichtung let temptNotumschichtung = inputValues[notumschichtung.Temperaturlabel].value; let TonNotumschichtung = notumschichtung.Ton; let ToffNotumschichtung = notumschichtung.Toff; //mqtt relais //console.log(umschichtungSolar); let topic = umschichtungSolar.mqtt.ctrlTopic; let msgOn = umschichtungSolar.mqtt.msgOn; let msgOff = umschichtungSolar.mqtt.msgOff; //Differenzregelung let differenzregelung = umschichtungSolar.Differenzregelung let quellTemperatur = inputValues[differenzregelung.QuelltemperaturLabel].value; let zielTemperatur = inputValues[differenzregelung.ZieltemperaturLabel].value; let dTon = differenzregelung.dTon; let dToff = differenzregelung.dToff; //Freigabe Holzofen let kesselstatus = inputValues["Kesselstatus"].value; let freigabeHolzofen = kesselstatus === umschichtungSolar.FreigabeHolzofen.KesselstatusAus ? true : false; if (temptNotumschichtung >= TonNotumschichtung) { outputRegler1 = true; } else if (temptNotumschichtung <= ToffNotumschichtung) { outputRegler1 = false; } let diff = quellTemperatur - zielTemperatur; if(diff >= dTon){ outputRegler2 = true; }else if (diff <= dToff) { outputRegler2 = false; } let point = new Point('Solarumschichtung').floatField("regler1", outputRegler1 ? 100.0 : 0.0); influxWriteClient.writePoint(point); point = new Point('Solarumschichtung').floatField("regler2", outputRegler2 ? 100.0 : 0.0); influxWriteClient.writePoint(point); point = new Point('Solarumschichtung').floatField("freigabeHolzofen", freigabeHolzofen ? 100.0 : 0.0); influxWriteClient.writePoint(point); influxWriteClient.flush(); if(freigabeHolzofen && outputRegler1 && outputRegler2){ sendMQTT(topic, msgOn); }else{ sendMQTT(topic, msgOff); } }