added nodejs container to log configured data to influxdb and ctrl solar redistribution in case of a full storage
This commit is contained in:
parent
f356f92a1f
commit
732eb79cb3
2
.gitignore
vendored
2
.gitignore
vendored
@ -1 +1,3 @@
|
||||
/data
|
||||
/nodeApp/node_modules
|
||||
/nodeApp/package-lock.json
|
||||
@ -5,24 +5,23 @@ services:
|
||||
image: influxdb:2.7-alpine
|
||||
env_file:
|
||||
- ./influxv2.env
|
||||
restart: always
|
||||
volumes:
|
||||
# Mount for influxdb data directory and configuration
|
||||
- /DockerDataPool/solarCtrl/influxDB:/var/lib/influxdb2:rw
|
||||
- ./influxDbConfig.yml:/etc/influxdb2/config.yml
|
||||
ports:
|
||||
- 8080:8086
|
||||
networks:
|
||||
- solarctrlInternal
|
||||
# telegraf:
|
||||
# image: telegraf:1.27-alpine
|
||||
# depends_on:
|
||||
# - influxdb
|
||||
# volumes:
|
||||
# # Mount for telegraf config
|
||||
# - ./telegraf/telegraf.conf:/etc/telegraf/telegraf.conf:ro
|
||||
# env_file:
|
||||
# - ./influxv2.env
|
||||
mosquitto:
|
||||
- 8086:8086
|
||||
# telegraf:
|
||||
# image: telegraf:1.27-alpine
|
||||
# depends_on:
|
||||
# - influxdb
|
||||
# volumes:
|
||||
# # Mount for telegraf config
|
||||
# - ./telegraf/telegraf.conf:/etc/telegraf/telegraf.conf:ro
|
||||
# env_file:
|
||||
# - ./influxv2.env
|
||||
mosquitto:
|
||||
image: eclipse-mosquitto:2.0.17
|
||||
restart: always
|
||||
volumes:
|
||||
@ -32,8 +31,22 @@ services:
|
||||
- ./data/mosquitto/log:/mosquitto/log
|
||||
ports:
|
||||
- 1883:1883
|
||||
networks:
|
||||
- solarctrlInternal
|
||||
networks:
|
||||
solarctrlInternal:
|
||||
|
||||
app:
|
||||
depends_on:
|
||||
- influxdb
|
||||
- mosquitto
|
||||
build: ./nodeApp
|
||||
restart: always
|
||||
volumes:
|
||||
- ./nodeApp/config.json:/app/config.json
|
||||
grafana:
|
||||
image: grafana/grafana:10.3.1
|
||||
container_name: grafana
|
||||
depends_on:
|
||||
- influxdb
|
||||
restart: always
|
||||
ports:
|
||||
- 3000:3000
|
||||
volumes:
|
||||
- "/DockerDataPool/solarCtrl/grafana:/var/lib/grafana"
|
||||
user: "1000"
|
||||
|
||||
@ -1 +1,2 @@
|
||||
heatCtrl:$7$101$Q0URo3gi5IgUwTLB$2M0eLGYBq4xP/RD1p3SC3IBJQs2hkEOH7HNm/DNt2/Zq+qmDMVNUic0Mom34sgXSLYKqmXfLQhVi8TjO8Tcu0Q==
|
||||
heatCtrl:$7$101$7MPYVzvwM+vfvapK$gF4xFS7QLeWa3mDuWmKqnI2rNysyPZyo5ZnYyIYF+R00FmU/uHxP1me7w3xRKJlwZ28rXKX0eEaUKNluiBjToQ==
|
||||
relais:$7$101$KKzqmsAlu8/mmywt$DhhJvf51AmXBrRW1BLOqhKYla/uNhRTFUbeope8/RJ2/FLfupz42spBZij3lHs8GobNrGylo9aT0NcrZcrtnvA==
|
||||
|
||||
7
nodeApp/Dockerfile
Normal file
7
nodeApp/Dockerfile
Normal file
@ -0,0 +1,7 @@
|
||||
FROM node:lts-iron
|
||||
WORKDIR /app
|
||||
COPY package.json .
|
||||
RUN npm install
|
||||
COPY index.js .
|
||||
ENTRYPOINT ["node"]
|
||||
CMD ["index.js"]
|
||||
201
nodeApp/config.json
Normal file
201
nodeApp/config.json
Normal file
@ -0,0 +1,201 @@
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"register": 8708,
|
||||
"label": "PufferHeizraumTemperatur1",
|
||||
"unitConversionDivider": 10,
|
||||
"type": "s16"
|
||||
},
|
||||
{
|
||||
"register": 8776,
|
||||
"label": "PufferHeizraumTemperatur3",
|
||||
"unitConversionDivider": 10,
|
||||
"type": "s16"
|
||||
},
|
||||
{
|
||||
"register": 8810,
|
||||
"label": "PufferHeizraumTemperatur4",
|
||||
"unitConversionDivider": 10,
|
||||
"type": "s16"
|
||||
},
|
||||
{
|
||||
"register": 8844,
|
||||
"label": "PufferHeizraumTemperatur5",
|
||||
"unitConversionDivider": 10,
|
||||
"type": "s16"
|
||||
},
|
||||
{
|
||||
"register": 8710,
|
||||
"label": "PufferHolzraumTemperatur1",
|
||||
"unitConversionDivider": 10,
|
||||
"type": "s16"
|
||||
},
|
||||
{
|
||||
"register": 8778,
|
||||
"label": "PufferHolzraumTemperatur3",
|
||||
"unitConversionDivider": 10,
|
||||
"type": "s16"
|
||||
},
|
||||
{
|
||||
"register": 8846,
|
||||
"label": "PufferHolzraumTemperatur5",
|
||||
"unitConversionDivider": 10,
|
||||
"type": "s16"
|
||||
},
|
||||
{
|
||||
"register": 8215,
|
||||
"label": "Flammtemperatur",
|
||||
"unitConversionDivider": 10,
|
||||
"type": "s16"
|
||||
},
|
||||
{
|
||||
"register": 8214,
|
||||
"label": "Sauerstoff",
|
||||
"unitConversionDivider": 10,
|
||||
"type": "s16"
|
||||
},
|
||||
{
|
||||
"register": 8242,
|
||||
"label": "Primärluftklappe",
|
||||
"unitConversionDivider": 10,
|
||||
"type": "s16"
|
||||
},
|
||||
{
|
||||
"register": 8243,
|
||||
"label": "Sekundärluftklappe",
|
||||
"unitConversionDivider": 10,
|
||||
"type": "s16"
|
||||
},
|
||||
{
|
||||
"register": 9498,
|
||||
"label": "DrehzahlSaugzug",
|
||||
"unitConversionDivider": 1,
|
||||
"type": "s16"
|
||||
},
|
||||
{
|
||||
"register": 8197,
|
||||
"label": "Kesseltemperatur",
|
||||
"unitConversionDivider": 10,
|
||||
"type": "s16"
|
||||
},
|
||||
{
|
||||
"register": 8202,
|
||||
"label": "Rücklauftemperatur",
|
||||
"unitConversionDivider": 10,
|
||||
"type": "s16"
|
||||
},
|
||||
{
|
||||
"register": 8212,
|
||||
"label": "Kesselstatus",
|
||||
"unitConversionDivider": 1,
|
||||
"type": "u16"
|
||||
},
|
||||
{
|
||||
"register": 8250,
|
||||
"label": "Außentemperatur",
|
||||
"unitConversionDivider": 10,
|
||||
"type": "s16"
|
||||
},
|
||||
{
|
||||
"register": 9049,
|
||||
"label": "StatusSolar",
|
||||
"unitConversionDivider": 1,
|
||||
"type": "u16"
|
||||
},
|
||||
{
|
||||
"register": 9080,
|
||||
"label": "SolarKollektortemperatur",
|
||||
"unitConversionDivider": 10,
|
||||
"type": "s16"
|
||||
},
|
||||
{
|
||||
"register": 9110,
|
||||
"label": "SolarSpeichertemperatur",
|
||||
"unitConversionDivider": 10,
|
||||
"type": "s16"
|
||||
},
|
||||
{
|
||||
"register": 9169,
|
||||
"label": "Solarpumpe",
|
||||
"unitConversionDivider": 1,
|
||||
"type": "bool"
|
||||
},
|
||||
{
|
||||
"register": 9215,
|
||||
"label": "SolarWärmeleistung",
|
||||
"unitConversionDivider": 1000,
|
||||
"type": "u32"
|
||||
},
|
||||
{
|
||||
"register": 9245,
|
||||
"label": "SolarWärmemengeTag",
|
||||
"unitConversionDivider": 1000,
|
||||
"type": "u32"
|
||||
},
|
||||
{
|
||||
"register": 9275,
|
||||
"label": "SolarWärmemengeGesamt",
|
||||
"unitConversionDivider": 1000,
|
||||
"type": "u32"
|
||||
},
|
||||
{
|
||||
"register": 9305,
|
||||
"label": "SolarKollektorVorlauftemperatur",
|
||||
"unitConversionDivider": 10,
|
||||
"type": "s16"
|
||||
},
|
||||
{
|
||||
"register": 9335,
|
||||
"label": "SolarKollektorRücklauftemperatur",
|
||||
"unitConversionDivider": 10,
|
||||
"type": "s16"
|
||||
},
|
||||
{
|
||||
"register": 9365,
|
||||
"label": "SolarDurchfluss",
|
||||
"unitConversionDivider": 100,
|
||||
"type": "s16"
|
||||
},
|
||||
{
|
||||
"register": 9466,
|
||||
"label": "SolarpumpePWM",
|
||||
"unitConversionDivider": 10,
|
||||
"type": "u16"
|
||||
},
|
||||
{
|
||||
"register": 8200,
|
||||
"label": "Kesselpumpe",
|
||||
"unitConversionDivider": 1,
|
||||
"type": "bool"
|
||||
},
|
||||
{
|
||||
"register": 8201,
|
||||
"label": "KesselpumpePWM",
|
||||
"unitConversionDivider": 10,
|
||||
"type": "u16"
|
||||
},
|
||||
{
|
||||
"register": 8206,
|
||||
"label": "VerbraucherAnforderung",
|
||||
"unitConversionDivider": 1,
|
||||
"type": "u16"
|
||||
}
|
||||
],
|
||||
"influxToken": "cMHBovac4VeXe60efDcBjItDxXz5LvQ7xcrN0R8yNMM9tEHFPK41hUSBsPsZWrVigXHm6T55EsnegIBSVeUFaQ==",
|
||||
"interval": 5000,
|
||||
"mqttBrokerAddress": "mqtt://192.168.1.241:1883",
|
||||
"mqttUser": "heatCtrl",
|
||||
"mqttPassword": "637013",
|
||||
"UmschichtungSolar": {
|
||||
"Notumschichtung": {
|
||||
"Temperaturlabel": "PufferHeizraumTemperatur5",
|
||||
"Ton": 70.0,
|
||||
"Toff": 65.0,
|
||||
"mqtt": {
|
||||
"ctrlTopic": "RelaisUmschichtung/cmnd/POWER1",
|
||||
"msgOn": "ON",
|
||||
"msgOff": "OFF"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
163
nodeApp/index.js
Normal file
163
nodeApp/index.js
Normal file
@ -0,0 +1,163 @@
|
||||
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 () {
|
||||
|
||||
// make some calls
|
||||
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 };
|
||||
});
|
||||
influxClient = new InfluxDB({ url: influxUrl, token: config.influxToken });
|
||||
influxWriteClient = influxClient.getWriteApi(influxOrg, influxBucket, 'ms');
|
||||
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 notumschichtung = config.UmschichtungSolar.Notumschichtung
|
||||
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 == notumschichtung.mqtt.msgOn) {
|
||||
val = 100.0;
|
||||
} else if (msg == notumschichtung.mqtt.msgOff) {
|
||||
val = 0.0;
|
||||
}
|
||||
let point = new Point('Solarumschichtung').floatField("pumpePercent", val);
|
||||
influxWriteClient.writePoint(point);
|
||||
influxWriteClient.flush();
|
||||
}
|
||||
|
||||
async function calculateLogic() {
|
||||
let notumschichtung = config.UmschichtungSolar.Notumschichtung
|
||||
let temp = inputValues[notumschichtung.Temperaturlabel];
|
||||
let topic = notumschichtung.mqtt.ctrlTopic;
|
||||
let msgOn = notumschichtung.mqtt.msgOn;
|
||||
let msgOff = notumschichtung.mqtt.msgOff;
|
||||
let Ton = notumschichtung.Ton;
|
||||
let Toff = notumschichtung.Toff;
|
||||
|
||||
if (temp.value >= Ton) {
|
||||
sendMQTT(topic, msgOn);
|
||||
} else if (temp.value <= Toff) {
|
||||
sendMQTT(topic, msgOff);
|
||||
}
|
||||
}
|
||||
|
||||
3
nodeApp/ips
Normal file
3
nodeApp/ips
Normal file
@ -0,0 +1,3 @@
|
||||
192.168.178.63 heizung relais
|
||||
192.168.1.19 umschichtung relais
|
||||
pw mqtt: 637013
|
||||
16
nodeApp/package.json
Normal file
16
nodeApp/package.json
Normal file
@ -0,0 +1,16 @@
|
||||
{
|
||||
"name": "solarctrl",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@influxdata/influxdb-client": "^1.33.2",
|
||||
"jsmodbus": "^4.0.10",
|
||||
"mqtt": "^5.9.1"
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user