exports.id = 'socomec'; exports.title = 'Energomonitor socomec'; exports.version = '1.0.3'; exports.group = 'Worksys'; exports.color = '#2134B0'; exports.output = ["red", "white", "yellow"]; exports.click = false; exports.author = 'Rastislav Kovac'; exports.icon = 'bolt'; exports.readme = `Modbus requests to energomonitor socomec suitcase`; const streamBuilder = require("./helper/energo_streambuilder"); const structure = { "192.168.1.31": { 3: "i-35", 2: "i-30", 11: "i-35", "12A": "i-60A", "12B": "i-60B", "13A": "i-60A", "13B": "i-60B", "14A": "i-60A", "14B": "i-60B", "15A": "i-60A", "15B": "i-60B", 16: "i-30", 21: "i-30", "22A": "i-60A", "22B": "i-60B", "23A": "i-60A", "23B": "i-60B", "24A": "i-60A", "24B": "i-60B", // 76: "i-30"//vymyslene pre testovanie } }; exports.install = function(instance) { const modbus = require('jsmodbus'); const net = require('net'); require('events').EventEmitter.defaultMaxListeners = 20; const allModulesEnergy = {unipi_76: ""}; // key to identify source data const date = new Date(); let hour = date.getHours(); let sendAllModulesEnergy = setInterval(() => { const d = new Date(); const h = d.getHours(); if(h != hour) { instance.send(2, allModulesEnergy); hour = h; } }, 180000); instance.on('close', function(){ clearInterval(sendAllModulesEnergy); }); const conversionTable = streamBuilder.makeStreamsTable(structure); // const conversionTable = // { // "192.168.1.11": { // "streams": [ // { // "unitId": 1, // "section": "", // "name": 18488, // "tb_value":"phase_1_power", // "bytes": 2, // "multiplier":1, // }, // ] // }, // "192.168.1.12": { // "streams": [ // { // "unitId": 18, // "section": "", // "name": 18488, // "tb_value": "total_energy", // "bytes": 2, // "multiplier": 1, // "month": 0 // } // ] // } // } const tbNames = { "192.168.1.31": { "3": "JX1ObgmqGZ54DMyYL7aJMlAEVdve38WKRzwjNrQ9", "2": "RO8rjaBDy21qPQJzW7oKN17pK3xmNleVZg9Ed4Gw", "11": "RvmwNz8QPblKp41GD7l4NY7JrLVYoBO92dMegn6W", "12A": "K94XLav1glVRnyQ6r01VZ3kme3YJwBxM5oOzdP2j", "12B": "3JjOWdylwgNLzxVab7NPpJ0Z2vG64rq8PEB5QmDo", "13A": "Z5KyJe9nEg1QNbWlX0wmNP7oDjBLdqzR83VGv624", "13B": "PjLblDgRBO6WQqnxmkJwpb7Jv3ewZN4p5a89yKdY", "14A": "dz4ojlpP85JMgDLZWkQ1p3kaKYqQexEr62GXRV1y", "14B": "d9x2V5LGYBzXp4mMRAOPpV0PloaqJwnQj6DgrNe3", "15A": "1JMYvnx2RzKEo4aWQ7D9pXAL8yZV3m9NBePXbrdj", "15B": "d5xjWYMwEJon6rLlK7ylNxkqgV4DaOeNB9ZX3Gzb", "16": "gRoJEyXVx4qD9er287LwpEkwBzGldaPjLWQKm3Mv", "21": "3JjOWdylwgNLzxVab7NPyn0Z2vG64rq8PEB5QmDo", "22A": "Z5KyJe9nEg1QNbWlX0wmEB7oDjBLdqzR83VGv624", "22B": "1JMYvnx2RzKEo4aWQ7D9y5AL8yZV3m9NBePXbrdj", "23A": "PjLblDgRBO6WQqnxmkJwyr7Jv3ewZN4p5a89yKdY", "23B": "dz4ojlpP85JMgDLZWkQ1GGkaKYqQexEr62GXRV1y", "24A": "d5xjWYMwEJon6rLlK7ylZmkqgV4DaOeNB9ZX3Gzb", "24B": "gRoJEyXVx4qD9er287LwyvkwBzGldaPjLWQKm3Mv" // "76": "vymyslene pre testovanie" } }; class SocketWithClients { constructor (ip, data) { this.ip = ip; this.data = data; this.options = { 'host': this.ip, 'port': '502' } this.streams = data.streams; //pole this.startSocket(); } startSocket = () => { let obj = this; this.index = 0; this.clients = {}; this.socket = new net.Socket(); this.socket.connect(this.options, function() { console.log('Connected to socket server'); }); this.socket.on('error', function(e) { console.log('socket connection error', e); if(e.code == 'ECONNREFUSED' || e.code == 'ECONNRESET') { console.log(exports.title + ' Waiting 10 seconds before trying to connect again'); setTimeout(obj.startSocket, 10000); } }); this.socket.on('close', function() { console.log('Socket connection closed ' + exports.title + ' Waiting 10 seconds before trying to connect again'); setTimeout(obj.startSocket, 10000); }); // we create client for all modules (unitIds) and push them into dictionary for( let i = 0; i < obj.data.streams.length; i++) { if(!this.clients.hasOwnProperty(obj.data.streams[i].unitId)) { this.clients[obj.data.streams[i].unitId] = new modbus.client.TCP(this.socket, obj.data.streams[i].unitId); } } this.socket.on('connect', function () { console.log("socket connected"); setTimeout(obj.readRegisters, 10000); }); }; readRegisters = () => { const lenghtOfStreams = this.streams.length; if(this.index >= lenghtOfStreams) { this.index = 0; setTimeout(this.readRegisters, 300000); return; } let unitId = this.streams[this.index].unitId; let section = this.streams[this.index].section; let register = this.streams[this.index].name; let bytes = this.streams[this.index].bytes; let date = Date.now(); let tbval = this.streams[this.index].tb_value; // console.log("citam tieto hodnoty", unitId, register, tbval); let obj = this; this.clients[unitId].readHoldingRegisters(register, bytes) .then( function (resp) { resp = resp.response._body.valuesAsArray; // console.log(unitId, register, tbval, resp); obj.sendData(resp, register, date, unitId, section); obj.index++; setTimeout(obj.readRegisters, 0); }).catch (function () { console.log("error pri citani z grafie", register, unitId, section, tbNames[obj.ip][unitId + section], tbval); // IMPLEMENTOVAT POSIELANIE CHYB PODLA POSLEDNHO REGISTRA V MODULE === "total_power_factor" if(tbval === "total_power_factor") { obj.sendNokStatus(tbNames[obj.ip][unitId + section], date); if(arguments["0"].err == "Offline") { obj.socket.emit("close"); return; } } // POSIELANIE NOK STATUSU - posle sa az pri poslednom registri z daneho unitu, nie pri kazdej chybnej hlaske // if(obj.index + 1 == lenghtOfStreams) // { // obj.sendNokStatus(tbNames[obj.ip][unitId + section], date); // } // else if(obj.streams[obj.index + 1].unitId != unitId || obj.streams[obj.index + 1].section != section) // { // obj.sendNokStatus(tbNames[obj.ip][unitId + section], date); // } console.error(require('util').inspect(arguments, { depth: null })) obj.index++; setTimeout(obj.readRegisters, 0); }) }; sendNokStatus = (tbName, date) => { let dataToTB = { [tbName]: [ { "ts": date, "values": { "status": "NOK", } } ] }; instance.send(1, dataToTB); // console.log("poslane do tb po chybe", dataToTB[tbName][0], dataToTB); }; sendData = (response, register, date, unitId, section) => { let l = this.streams.length; for (let i=0; i= (2**31)) // ak je MSB bit nastavený, eventuálne sa dá použiť aj (temp_val & 0x80000000), ak vieš robiť logický súčin { temp_val = temp_val - "0xFFFFFFFF" + 1; } } else if (l === 1) { temp_val = response[0]; if(temp_val >= (2**15)) // ak je MSB bit nastavený, eventuálne sa dá použiť aj (temp_val & 0x8000), ak vieš robiť logický súčin { temp_val = temp_val - "0xFFFF" + 1; } } value = temp_val; value = value / a.multiplier; let tbName = tbNames[this.ip][unitId.toString() + section]; // console.log(unitId, register, tbName, tb_value, response, a.multiplier, value, section); // console.log(unitId, register, tb_value, value); if(tbName == undefined) return; const values = { "status": "OK", [tb_value]: value }; // we send "energy_last_month" value, that is equal to "total_energy" value, on first day of new month ==> it means when month changes if(tb_value == "total_energy") { const previousEnergy = a.previousEnergy; a.previousEnergy = value; if(previousEnergy != null) { values["energy_update"] = value - previousEnergy; } const d = new Date(date); const currentMonth = d.getMonth(); const month = a.month; if(month != currentMonth) { values["energy_last_month"] = value; a.month = currentMonth; } allModulesEnergy[this.ip + '@' + unitId + section] = value; } let dataToTB = { [tbName]: [ { "ts": date, "values": values } ] }; instance.send(1, dataToTB); break; } } }; } const newSocket = new SocketWithClients("192.168.1.31", conversionTable["192.168.1.31"]); }