citysys-flowserver/flow/relays.js

357 lines
11 KiB
JavaScript

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 = `<div class="padding">
<div class="row">
<div class="col-md-6">
<div data-jc="textbox" data-jc-path="edge" data-jc-config="placeholder:undefined;required:true" class="m">Edge TB Name</div>
</div>
</div>
</div>`;
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;
}
}