exports.id = 'relay'; exports.title = 'DI_DO_Controller'; exports.version = '1.0.0'; exports.group = 'Worksys'; exports.color = '#2134B0'; exports.input = 1; exports.output = ["red", "white", "yellow"]; exports.click = false; exports.author = 'Daniel Segeš'; exports.icon = 'bolt'; exports.options = { edge: "undefined" }; exports.html = `
Edge TB Name
`; exports.readme = `# Sets RS232 port and all digital pins on device. Then it starts to receive data from sensors. It receives: rotary_switch_state, rotary_switch_state, door_condition, state_of_breaker, state_of_contactor, twilight_sensor `; /* we open rsPort "/dev/ttymxc0" and set digital input and output pins with "setRSPortData" Currently we are interested in pins no. 1,2,3,6,8,9,10,16 pins number 11, 12, 13 (we receive 10,11,12 in rsPortReceivedData) are "stykace" When port receives data, it must be exactly 4 bytes long. Second byte is pin, that changed its value, fourth byte is value itself. After that, we set this value to "previousValues[allPins[whichpin]]" variable */ /* RVO objekt: state_of_main_switch - sem sa bude reportovať stav hlavného ističa : 0-> off 1-> on (toto nie je na platforme, ale Rado to už do entity type doplnil) rotary_switch_state - sem by sa mal reportovať stav vstupov manual a auto podľa nasledovnej logiky: Manual = 1 a Auto = 0 -> vyreportuje Manual Manual = 0 a Auto = 0 -> vyreportuje Off Manual = 0 a Auto = 1 -> vyreportuje Automatic door_condition - tuto ide pin 6, dverový kontakt -> 1 -> vyreportuje Closed, 0 -> vyreportuje Open twilight_sensor - hodnotu, ktorú vracia ten analógový vstup (17) treba poslať sem ako float number. Zrejme tu potom pridáme nejaký koeficient prevodu na luxy zjavne nám v jsone chýba stav hlavného ističa. Musíme to potom doplniť Na každú líniu: state_of_breaker - podľa indexu ističa sa reportuje jeho stav, teda istič 1 na líniu 1: 0-> off 1-> on state_of_contactor - podľa indexu stykača sa reportuje jeho stav, teda stykač 1 na líniu 1: 0-> off 1-> on momentálne sa stav zmení len keď vo flow klikneš aby sa zmenil, ale tá zmena by sa mala ukázať aj na platforme */ exports.install = function(instance) { let previousValues = {}; let rsPortReceivedData = []; console.log("DI_DO_Relay_Controller installed"); //key is PIN number const conversionTable = { "1": {tbname: "KjbN4q7JPZmexgdnz2yKQ98YAWwO0Q3BMX6ERLoV", type: "state_of_main_switch"}, //state_of_main_switch pin1 "2": {tbname: "KjbN4q7JPZmexgdnz2yKQ98YAWwO0Q3BMX6ERLoV", type: "rotary_switch_state"}, //rotary_switch_state - poloha manual = pin2 "3": {tbname: "KjbN4q7JPZmexgdnz2yKQ98YAWwO0Q3BMX6ERLoV", type: "rotary_switch_state"}, //rotary_switch_state - poloha auto = pin3 "6": {tbname: "KjbN4q7JPZmexgdnz2yKQ98YAWwO0Q3BMX6ERLoV", type: "door_condition"}, // door_condition = pin6, 1 -> vyreportuje Closed, 0 -> vyreportuje Open "8": {tbname: "RMgnK93rkoAazbqdQ4yBG95Z1YXGx6pmwBeVEP2O", type: "state_of_breaker", "line": 1}, // state_of_breaker linia 1 0=off, 1=on "9": {tbname: "dlE1VQjYrNx9gZRmb38gG08oLBO4qaAk2M6JPnG7", type: "state_of_breaker", "line": 2}, // state_of_breaker linia 2 0=off, 1=on "10": {tbname: "vnmG4kJxaXWNBgMQq0D7Aj5e9oZzOAlr6LdR3w2V", type: "state_of_breaker", "line": 3}, // state_of_breaker linia 3 0=off, 1=on "11": {tbname: "RMgnK93rkoAazbqdQ4yBG95Z1YXGx6pmwBeVEP2O", type: "state_of_contactor", "line": 1}, // state_of_contactor linia 1 0=off, 1=on "12": {tbname: "dlE1VQjYrNx9gZRmb38gG08oLBO4qaAk2M6JPnG7", type: "state_of_contactor", "line": 2}, // state_of_contactor linia 2 0=off, 1=on "13": {tbname: "vnmG4kJxaXWNBgMQq0D7Aj5e9oZzOAlr6LdR3w2V", type: "state_of_contactor", "line": 3}, // state_of_contactor linia 3 0=off, 1=on "16": {tbname: "KjbN4q7JPZmexgdnz2yKQ98YAWwO0Q3BMX6ERLoV", type: "state_of_main_switch"}, // twilight_sensor = pin16 }; const dbRelays = TABLE("relays"); dbRelays.on('change', function(doc, old) { instance.send(2, "reload_relays"); }); //modify const SerialPort = require('serialport'); //const { exec } = require('child_process'); const { openPort, runSyncExec, writeData } = require('./serialport_helper.js'); const setRSPortData = [0xAA,6,6,6,6,0,6,0,6,6,6,1,1,1,1,0,0,10,10,10,10,0,10,0,10,10,10,0,0,0,0,0,0,5,0,0,0,15,15,15,15,0,15,0,15,15,15,0,0,0,0,0,0,30,0,0,0]; const rsPort = new SerialPort("/dev/ttymxc0", { autoOpen: false }); rsPort.on('open', async function() { await runSyncExec("stty -F /dev/ttymxc0 115200 min 1 time 5 ignbrk -brkint -icrnl -imaxbel -opost -isig -icanon -iexten -echo -echoe -echok -echoctl -echoke").then(function (status) { instance.send(0, exports.title + " runSyncExec - Promise Resolved:" + status); //set port rsPort.write(Buffer.from(setRSPortData), function(err) { instance.send(0, exports.title + " Digital in_out has been set"); //force turn off relays let keys = Object.keys(conversionTable); for(let i = 0; i < keys.length; i++) { let key = keys[i]; if(conversionTable[key].type == "state_of_contactor") { let pin = key - 1; let line = conversionTable[key].line; turnOff(line, pin); } } //dbRelays.modify({ contactor: 0 }); }) }).catch(function (reason) { instance.send(0, exports.title + " runSyncExec - promise rejected:" + reason); }); }); rsPort.open(); rsPort.on('data', function (data){ rsPortReceivedData = [...rsPortReceivedData, ...data]; if (rsPortReceivedData[0] != 85) { rsPortReceivedData = []; return; } let l = rsPortReceivedData.length; if (l < 4 ) return; if (l > 4 ) { // if array length is greater than 4, we take first 4 byte and do the logic, second 4 bytes, do the logic and so on let i, j, temparray, chunk = 4; for ( i = 0, j = l; i < j; i += chunk ) { temparray = rsPortReceivedData.slice(i, i + chunk); if ( temparray.length < 4 ){ rsPortReceivedData = [...temparray]; return; } switchLogic(temparray); } rsPortReceivedData = []; return; } switchLogic(rsPortReceivedData); rsPortReceivedData = []; }); rsPort.on('error', function(err) { instance.send(0, err.message); }) rsPort.on("close", () => { rsPort.close(); }) instance.on("close", () => { rsPort.close(); }) function getPin(line) { //conversionTable let keys = Object.keys(conversionTable); for(let i = 0; i < keys.length; i++) { let key = keys[i]; if(conversionTable[key].type == "state_of_contactor" && conversionTable[key].line == line) { return key - 1; } } console.log("no pin detected"); return null; } function turnOn(line, pin) { if( pin === undefined) pin = getPin(line); if( pin === undefined) return; let arr = [0x55]; arr.push( pin ); arr.push( 0 ); arr.push( 1 ); if(!rsPort.isOpen) { console.log("port is not opened"); return; } rsPort.write(Buffer.from(arr), function(err) { switchLogic(arr); }); } function turnOff(line, pin) { if( pin === undefined) pin = getPin(line); if( pin === undefined) return; let arr = [0x55]; arr.push( pin ); arr.push( 0 ); arr.push( 0 ); if(!rsPort.isOpen) { console.log("port is not opened"); return; } rsPort.write(Buffer.from(arr), function(err) { switchLogic(arr); }); } // we expect array as flowdata.data instance.on("data", (flowdata) => { //console.log(flowdata.data); if(flowdata.data instanceof Object) { let obj = flowdata.data; let line = obj.line; if(obj.command == "turnOn") turnOn(line); else if(obj.command == "turnOff") turnOff(line); return; } if (Array.isArray(flowdata.data)){ rsPort.write(Buffer.from(flowdata.data), function(err) { switchLogic(flowdata.data); instance.send(0,{"WRITE":flowdata.data}); }); } }) const switchLogic = (rsPortReceivedData) => { let dataToTb; let values = {}; let pinIndex = rsPortReceivedData[1] + 1; if (pinIndex === 17) pinIndex--; let newPinValue = rsPortReceivedData[3]; let obj = conversionTable[pinIndex]; if(obj == undefined) { //console.log("undefined pinIndex", pinIndex, rsPortReceivedData); return; } let type = obj.type; let line = obj.line; let tbname = obj.tbname; //default value let value = "On"; if(newPinValue === 0) value = "Off"; if(type == "rotary_switch_state") { // combination of these two pins required to get result let pin2, pin3; if(pinIndex == 2) { pin2 = newPinValue; pin3 = previousValues[pinIndex]; if (pin3 == undefined) pin3 = 0; } else if(pinIndex == 3) { pin3 = newPinValue; pin2 = previousValues[1]; if (pin2 == undefined) pin2 = 0; } if (pin2 == 1 && pin3 == 0) value = "Manual"; if (pin2 == 0 && pin3 == 0) value = "Off"; if (pin2 == 0 && pin3 == 1) value = "Automatic"; } else if(type == "door_condition") { newPinValue === 0 ? value = "Open" : value = "Closed"; } else if(type == "twilight_sensor") { value = parseFloat(newPinValue + (256*rsPortReceivedData[2])); } else if(type == "state_of_contactor") { //modify table relays dbRelays.modify({ contactor: newPinValue }).where("line", line); } values[obj.type] = value; if(conversionTable.hasOwnProperty(pinIndex)) { let insertIntoTb = false; if(newPinValue != previousValues[pinIndex]) insertIntoTb = true; if(obj.hasOwnProperty("state_of_contactor")) insertIntoTb = true; if(insertIntoTb) { dataToTb = { [tbname]: [ { "ts": Date.now(), "values": values } ] } instance.send(1, dataToTb); } } //pin was changed previousValues[pinIndex] = newPinValue; } }