1524 lines
47 KiB
JavaScript
Executable file
1524 lines
47 KiB
JavaScript
Executable file
exports.id = 'dido_controller';
|
|
exports.title = 'DIDO_Controller';
|
|
exports.version = '2.0.0';
|
|
exports.group = 'Worksys';
|
|
exports.color = '#2134B0';
|
|
exports.input = 3;
|
|
exports.output = ["red", "white", "yellow", "green"];
|
|
exports.click = false;
|
|
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
|
|
*/
|
|
|
|
const { errLogger, logger, monitor } = require('./helper/logger');
|
|
const SerialPort = require('serialport');
|
|
const WebSocket = require('ws');
|
|
//const { exec } = require('child_process');
|
|
const { runSyncExec } = require('./helper/serialport_helper');
|
|
const { bytesToInt, resizeArray } = require('./helper/utils');
|
|
const { sendNotification } = require('./helper/notification_reporter');
|
|
const bitwise = require('bitwise');
|
|
|
|
const DataToTbHandler = require('./helper/DataToTbHandler');
|
|
let tbHandler;
|
|
|
|
const ErrorToServiceHandler = require('./helper/ErrorToServiceHandler');
|
|
const errorHandler = new ErrorToServiceHandler();
|
|
|
|
let ws = null;
|
|
let rsPort = null;
|
|
|
|
let pinsData;
|
|
let relaysData;
|
|
let rvoTbName;
|
|
let GLOBALS; //FLOW global GLOBALS
|
|
let SETTINGS; // GLOBALS.settings
|
|
let controller_type;
|
|
|
|
let alarmStatus = "OFF";
|
|
|
|
const SEND_TO = {
|
|
debug: 0,
|
|
tb: 1,
|
|
cmd_manager: 2
|
|
}
|
|
|
|
|
|
exports.install = function(instance) {
|
|
|
|
process.on('uncaughtException', function(err) {
|
|
|
|
//TODO send to service
|
|
|
|
errLogger.error('uncaughtException:', err.message)
|
|
errLogger.error(err.stack);
|
|
|
|
errorHandler.sendMessageToService(err.message + "\n" + err.stack, 0, "js_error");
|
|
|
|
//process.exit(1);
|
|
})
|
|
|
|
let previousValues = {};
|
|
let rsPortReceivedData = [];
|
|
|
|
//to be able to get proper twilight values, when
|
|
let twilight_sensor_interval = 5;//minutes
|
|
let twilight_sensor = [];
|
|
const twilight_sensor_array = [];
|
|
let twilightError = false;
|
|
|
|
monitor.info("DIDO_Relay_Controller installed");
|
|
|
|
//key is PIN number , line: 0 = RVO
|
|
/*
|
|
let conversionTable = {
|
|
"1": {tbname: "", type: "state_of_main_switch", "line": 0}, //state_of_main_switch pin1
|
|
"2": {tbname: "", type: "rotary_switch_state", "line": 0}, //rotary_switch_state - poloha manual = pin2
|
|
"3": {tbname: "", type: "rotary_switch_state", "line": 0}, //rotary_switch_state - poloha auto = pin3
|
|
"4": {tbname: "", type: "power_supply", "line": 0},
|
|
"5": {tbname: "", type: "battery", "line": 0},
|
|
"6": {tbname: "", type: "door_condition", "line": 0}, // door_condition = pin6, 1 -> vyreportuje Closed, 0 -> vyreportuje Open
|
|
"8": {tbname: "", type: "state_of_breaker", "line": 1}, // state_of_breaker linia 1 0=off, 1=on
|
|
"9": {tbname: "", type: "state_of_breaker", "line": 2}, // state_of_breaker linia 2 0=off, 1=on
|
|
"10": {tbname: "", type: "state_of_breaker", "line": 3}, // state_of_breaker linia 3 0=off, 1=on
|
|
"11": {tbname: "", type: "state_of_contactor", "line": 1}, // state_of_contactor linia 1 0=off, 1=on
|
|
"12": {tbname: "", type: "state_of_contactor", "line": 2}, // state_of_contactor linia 2 0=off, 1=on
|
|
"13": {tbname: "", type: "state_of_contactor", "line": 3}, // state_of_contactor linia 3 0=off, 1=on
|
|
"16": {tbname: "", type: "twilight_sensor", "line": 0}, // twilight_sensor = pin16
|
|
};
|
|
*/
|
|
|
|
//status for calculating Statecodes
|
|
let deviceStatus = { //key is device name: temperature,....
|
|
"state_of_main_switch": "Off", //Hlavný istič
|
|
"rotary_switch_state": "Off", //Prevádzkový mód
|
|
"door_condition": "closed", //Dverový kontakt
|
|
"em": "OK", //elektromer rvo
|
|
"temperature": "OK", //templomer
|
|
"battery": "OK", //Batéria
|
|
"power_supply": "OK", //Zdroj
|
|
"master_node": "OK", //MN - GLOBALS.settings.masterNodeIsResponding
|
|
"no_voltage": "OK", //GLOBALS.settings.no_voltage - výpadok napätia na fáze
|
|
"state_of_breaker": {}, //"Off",//Istič
|
|
"state_of_contactor": {}, //"Off",//Stykač
|
|
"twilight_sensor": "OK" //lux sensor
|
|
};
|
|
|
|
|
|
function main() {
|
|
|
|
GLOBALS = FLOW.GLOBALS;
|
|
SETTINGS = FLOW.GLOBALS.settings;
|
|
rvoTbName = SETTINGS.rvoTbName;
|
|
pinsData = GLOBALS.pinsData;
|
|
relaysData = GLOBALS.relaysData;
|
|
|
|
tbHandler = new DataToTbHandler(SEND_TO.tb)
|
|
tbHandler.setSender(exports.title);
|
|
|
|
controller_type = SETTINGS.controller_type //"lm" or "unipi" //logicMachine
|
|
if (controller_type == "") controller_type = "lm";
|
|
|
|
console.log(exports.title, "controller type: ", controller_type);
|
|
|
|
if (controller_type === "lm") {
|
|
handleRsPort();
|
|
}
|
|
else if (controller_type === "unipi") {
|
|
handleWebSocket();
|
|
}
|
|
else {
|
|
errLogger.debug("UNKNOWN controller_type:", controller_type);
|
|
}
|
|
}
|
|
|
|
|
|
function initialSetting() {
|
|
//force turn off relays
|
|
|
|
let keys = Object.keys(pinsData);
|
|
for (let i = 0; i < keys.length; i++) {
|
|
let key = keys[i];
|
|
let line = pinsData[key].line;
|
|
|
|
if (line != undefined) {
|
|
if (relaysData[line] != undefined) {
|
|
pinsData[key].tbname = relaysData[line].tbname;
|
|
//relaysData[line].contactor = 0;
|
|
}
|
|
else {
|
|
errLogger.error("CRITICAL!!! undefined relay", relaysData[line], line);
|
|
sendNotification("set port ", rvoTbName, "local_database_is_corrupted", {}, "", SEND_TO.tb, instance);
|
|
}
|
|
}
|
|
|
|
if (pinsData[key].type == "state_of_contactor") {
|
|
let pin = key - 1;
|
|
if (controller_type === "unipi") pin = key;
|
|
|
|
//this will modify database
|
|
let forceTurnOff = true;
|
|
turnLine("off", line, pin, forceTurnOff, "turn off on startup");
|
|
}
|
|
}
|
|
|
|
//report RVO version relaysData[0].tbname;
|
|
let values = {};
|
|
values["edge_fw_version"] = SETTINGS.edge_fw_version;
|
|
values["maintenance_mode"] = SETTINGS.maintenance_mode;
|
|
|
|
sendTelemetry(values, rvoTbName);
|
|
|
|
let time = 5 * 1000;
|
|
setTimeout(function() {
|
|
instance.send(SEND_TO.cmd_manager, { sender: "dido_controller", cmd: "buildTasks" });
|
|
|
|
sendNotification("rsPort.open()", rvoTbName, "flow_start", {}, "", SEND_TO.tb, instance);
|
|
monitor.info("-->FLOW bol spustený", rvoTbName, SETTINGS.edge_fw_version);
|
|
}, time);
|
|
}
|
|
|
|
|
|
function handleRsPort() {
|
|
//TODO build according to pins!!!
|
|
//! rsPort to open are the same for lm and unipi and electromer ("/dev/ttymxc0")
|
|
const setRSPortData = [0xAA, 6, 6, 6, 6, 6, 6, 0, 6, 6, 6, 1, 1, 1, 1, 0, 0, 10, 10, 10, 10, 10, 10, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 15, 15, 15, 15, 15, 15, 0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 30, 0, 0, 0];
|
|
rsPort = new SerialPort("/dev/ttymxc0", { autoOpen: false });
|
|
|
|
rsPort.on('error', function(err) {
|
|
logger.debug("rsPort opened error - failed", err.message);
|
|
instance.send(SEND_TO.debug, err.message);
|
|
|
|
errorHandler.sendMessageToService(exports.title + " rsPort opened error - failed: " + err.message);
|
|
})
|
|
|
|
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) {
|
|
|
|
//set port
|
|
rsPort.write(Buffer.from(setRSPortData), function(err) {
|
|
if (!err) {
|
|
monitor.info(exports.title + "--->Digital in_out has been set (runSyncExec was sucessfull)");
|
|
|
|
turnAlarm("off");
|
|
initialSetting();
|
|
}
|
|
})
|
|
|
|
}).catch(function(reason) {
|
|
errLogger.error(exports.title + " runSyncExec - promise rejected:" + reason);
|
|
errorHandler.sendMessageToService(exports.title + " runSyncExec - promise rejected:" + reason);
|
|
});
|
|
|
|
});
|
|
|
|
|
|
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("close", () => {
|
|
rsPort.close();
|
|
})
|
|
|
|
rsPort.open();
|
|
}
|
|
|
|
|
|
function handleWebSocket() {
|
|
|
|
//to keep websocket opened, we send request every 150 seconds
|
|
let startRequests = null;
|
|
|
|
console.log("handleWebSocket function called");
|
|
ws = new WebSocket('ws:/0.0.0.0:1234/ws');
|
|
|
|
ws.onopen = function open() {
|
|
|
|
instance.send(0, exports.title + " running");
|
|
turnAlarm("off");
|
|
|
|
// useTurnOffCounter = true;
|
|
// turnOffCounter = relaysData.length - 1;
|
|
initialSetting();
|
|
ws.send(JSON.stringify({ "cmd": "all" }));
|
|
|
|
// we request dev info about neuron device from evok to keep websocket connection alive
|
|
// for some reason this request returns no data, but connection keeps alive
|
|
// https://evok.api-docs.io/1.0/mpqzDwPwirsoq7i5A/websocket
|
|
startRequests = setInterval(() => {
|
|
// console.log(" *** data from evok requested");
|
|
ws.send(JSON.stringify({ "cmd": "filter", "dev": ["neuron"] }));
|
|
}, 150000)
|
|
};
|
|
|
|
|
|
// SAMPLE DATA FROM WEBSOCKET
|
|
// {
|
|
// glob_dev_id: 1,
|
|
// modes: [ 'Simple' ],
|
|
// value: 0,
|
|
// circuit: '1_07',
|
|
// pending: false,
|
|
// relay_type: 'physical',
|
|
// dev: 'relay',
|
|
// mode: 'Simple'
|
|
// },
|
|
// {
|
|
// counter_modes: [ 'Enabled', 'Disabled' ],
|
|
// glob_dev_id: 1,
|
|
// modes: [ 'Simple', 'DirectSwitch' ],
|
|
// value: 0,
|
|
// circuit: '1_08',
|
|
// debounce: 50,
|
|
// counter: 0,
|
|
// counter_mode: 'Enabled',
|
|
// dev: 'input',
|
|
// mode: 'Simple'
|
|
// },
|
|
ws.onmessage = async function(data) {
|
|
|
|
data = JSON.parse(data.data);
|
|
|
|
// data comes in array except of "temperature" ==> it comes as an object
|
|
// we do not handle temperature from evok any more => we return, if temperature comes:
|
|
if (isObject(data)) return;
|
|
|
|
data.map(item => {
|
|
|
|
let value = item['value'];
|
|
let pin = item["dev"] + item["circuit"]; // for example "relay1_03" or "input1_01"
|
|
|
|
if (pin == undefined) return;
|
|
switchLogic(pin, value);
|
|
})
|
|
}
|
|
|
|
|
|
ws.on('error', (err) => {
|
|
monitor.info('websocket error, reconnect')
|
|
instance.send(SEND_TO.debug, err.message);
|
|
clearInterval(startRequests);
|
|
ws = null;
|
|
setTimeout(handleWebSocket, 1000);
|
|
})
|
|
|
|
|
|
ws.onclose = function() {
|
|
// connection closed, discard old websocket and create a new one in 5s
|
|
// stopRequests();
|
|
monitor.info('websocket onclose, reconnect')
|
|
clearInterval(startRequests);
|
|
ws = null;
|
|
console.log("ws is null now, reconnecting...");
|
|
setTimeout(handleWebSocket, 1000);
|
|
}
|
|
}
|
|
|
|
instance.on("close", () => {
|
|
if (rsPort) rsPort.close();
|
|
if (ws) ws.close();
|
|
})
|
|
|
|
|
|
function getPin(line) {
|
|
//conversionTable
|
|
let keys = Object.keys(pinsData);
|
|
for (let i = 0; i < keys.length; i++) {
|
|
let key = keys[i];
|
|
|
|
if (pinsData[key].type == "state_of_contactor" && pinsData[key].line == line) {
|
|
if (rsPort) return key - 1;
|
|
if (ws) return key;
|
|
}
|
|
}
|
|
|
|
logger.debug("no pin detected");
|
|
|
|
return null;
|
|
}
|
|
|
|
|
|
function turnAlarm(onOrOff) {
|
|
let value = 0;
|
|
if (onOrOff == "on") value = 1;
|
|
|
|
if (value == 1 && SETTINGS.maintenance_mode) return;
|
|
|
|
alarmStatus = "OFF";
|
|
if (value == 1) alarmStatus = "ON";
|
|
|
|
if (rsPort) {
|
|
let arr = [0x55];
|
|
arr.push(13);
|
|
arr.push(0);
|
|
arr.push(value);
|
|
|
|
rsPort.write(Buffer.from(arr), function(err) {
|
|
logger.debug(`sirena - ${onOrOff}`);
|
|
});
|
|
}
|
|
else if (ws) {
|
|
let cmd = { "cmd": "set", "dev": "relay", "circuit": "1_01", "value": value };
|
|
ws.send(JSON.stringify(cmd));
|
|
logger.debug(`sirena - ${onOrOff}`);
|
|
}
|
|
}
|
|
|
|
|
|
function reportLineStatus(line) {
|
|
//Tá hodnota by mala fungovať tak že LSB bit číslo je stav ističa (1 - On, 0 - Off) a druhý bit je stav stýkača (1 - true, 0 - false).
|
|
let tbname = relaysData[line].tbname;
|
|
let bits = [];
|
|
|
|
if (deviceStatus["state_of_breaker"][line] == "On") {
|
|
bits.push(0);
|
|
}
|
|
else bits.push(1);
|
|
|
|
if (deviceStatus["state_of_contactor"][line] == "On") {
|
|
bits.push(0);
|
|
}
|
|
else bits.push(1);
|
|
|
|
resizeArray(bits, 8, 0);
|
|
|
|
let byte = bitwise.byte.write(bits.reverse());
|
|
|
|
//console.log("line", line, bits, byte);
|
|
sendTelemetry({ statecode: byte }, tbname);
|
|
}
|
|
|
|
|
|
// turn line on or off
|
|
function turnLine(onOrOff, line, pin, force, info) {
|
|
//onOrOff => "on" or "off"
|
|
let value = 0;
|
|
if (onOrOff == "on") value = 1;
|
|
|
|
if (force == undefined) force = false;
|
|
|
|
if (line == 0) {
|
|
if (value == 1 && alarmStatus == "ON") turnAlarm("off");
|
|
SETTINGS.maintenance_mode = value ? true : false;
|
|
|
|
let values = {};
|
|
values["statecode"] = calculateStateCode();
|
|
values["power_mode"] = value ? "maintenance" : "Automatic";
|
|
sendTelemetry(values, rvoTbName);
|
|
|
|
monitor.info(`turnLine ${onOrOff} - (line, SETTINGS.maintenance_mode)`, line, SETTINGS.maintenance_mode, info);
|
|
return;
|
|
}
|
|
|
|
if (pin === undefined) pin = getPin(line);
|
|
|
|
if (pin === undefined) {
|
|
errLogger.error("pin is undefined!", line);
|
|
return;
|
|
}
|
|
|
|
if (!force) {
|
|
if (relaysData[line].contactor == value) {
|
|
instance.send(SEND_TO.debug, `line is already ${onOrOff} ` + line);
|
|
logger.debug(`turnLine: line is already ${onOrOff} `, line);
|
|
return;
|
|
}
|
|
}
|
|
|
|
// if(!rsPort.isOpen && !ws)
|
|
if (!rsPort && !ws) {
|
|
errLogger.error("dido controller - port or websocket is not opened");
|
|
return;
|
|
}
|
|
|
|
if (rsPort) {
|
|
let arr = [0x55];
|
|
arr.push(pin);
|
|
arr.push(0);
|
|
arr.push(value);
|
|
|
|
rsPort.write(Buffer.from(arr), function(err) {
|
|
if (err === undefined) {
|
|
monitor.info(`turnLine ${onOrOff} zapisal do rsPort-u`, line, pin, arr, info);
|
|
switchLogic(arr);
|
|
}
|
|
else {
|
|
monitor.info(`turnLine ${onOrOff} WRITE error`, err);
|
|
}
|
|
});
|
|
|
|
}
|
|
else if (ws) {
|
|
//pin = "relay1_03" or "input1_01" ... we must make just "1_01" with slice method
|
|
monitor.info(`turnLine ${onOrOff} - (line, pin, force)`, line, pin, force, info);
|
|
let cmd = { "cmd": "set", "dev": "relay", "circuit": pin.slice(5), "value": value };
|
|
ws.send(JSON.stringify(cmd));
|
|
switchLogic(pin, value)
|
|
}
|
|
|
|
//if rvo is 24/7, it has just one switching profile point at 13:00. we do not want to send notification as it repeats every day.
|
|
//const d = new Date();
|
|
//if(d.getHours() != 13) sendNotification("Dido_controller: ", SETTINGS.rvoTbName, "switching_profile_point_applied_to_line", { line: line, value: onOrOff }, "", SEND_TO.tb, instance);
|
|
}
|
|
|
|
|
|
// main opening
|
|
instance.on("2", _ => {
|
|
main();
|
|
})
|
|
|
|
|
|
//data from modbus_reader or temperature sensor or twilight sensor or other modbus device
|
|
instance.on("0", flowdata => {
|
|
|
|
if (!isObject(flowdata.data)) return;
|
|
|
|
// console.log('***********************', flowdata.data)
|
|
instance.send(SEND_TO.debug, flowdata.data);
|
|
|
|
// we handle nok status from modbus_reader component and thermometer
|
|
if ("status" in flowdata.data) {
|
|
const status = flowdata.data.status;
|
|
if (status == "NOK-twilight_sensor") {
|
|
deviceStatus["twilight_sensor"] = "NOK";
|
|
}
|
|
else if (status == "NOK-em340" || status == "NOK-em111") {
|
|
deviceStatus["em"] = "NOK";
|
|
}
|
|
else if (status == "NOK-thermometer") {
|
|
deviceStatus["temperature"] = "NOK";
|
|
}
|
|
}
|
|
else if ("values" in flowdata.data) {
|
|
const values = flowdata.data.values;
|
|
if (values.hasOwnProperty("twilight_sensor")) {
|
|
instance.send(SEND_TO.cmd_manager, { sender: "dido_controller", cmd: "lux_sensor", value: values["twilight_sensor"] });
|
|
deviceStatus["twilight_sensor"] = "OK"
|
|
}
|
|
else if (values.hasOwnProperty("temperature")) {
|
|
deviceStatus["temperature"] = "OK";
|
|
}
|
|
// EM
|
|
else if (values.hasOwnProperty("total_power") || values.hasOwnProperty("total_energy") || values.hasOwnProperty("power_factor") || values.hasOwnProperty("Phase_1_voltage") || values.hasOwnProperty("Phase_1_current")) {
|
|
deviceStatus["em"] = "OK";
|
|
SETTINGS.no_voltage.size > 0 ? deviceStatus["no_voltage"] = "NOK" : deviceStatus["no_voltage"] = "OK";
|
|
}
|
|
|
|
sendTelemetry(values, rvoTbName);
|
|
}
|
|
|
|
sendRvoStatus();
|
|
})
|
|
|
|
|
|
// we expect array as flowdata.data
|
|
instance.on("1", flowdata => {
|
|
|
|
console.log(flowdata.data);
|
|
|
|
if (!flowdata.data instanceof Object) return;
|
|
|
|
let obj = flowdata.data;
|
|
let line = obj.line;
|
|
let force = obj.force;
|
|
let info = obj.info;
|
|
|
|
if (obj.command == "on") turnLine("on", line, undefined, force, info);
|
|
else if (obj.command == "off") turnLine("off", line, undefined, force, info);
|
|
else if (obj.command == "turnOnAlarm") turnAlarm("on");
|
|
else if (obj.command == "turnOffAlarm") turnAlarm("off");
|
|
|
|
//! ake data prichadzaju z cmd_manager.js ???
|
|
//TODO transform to websocket
|
|
if (Array.isArray(obj)) {
|
|
|
|
rsPort.write(Buffer.from(obj), function(err) {
|
|
switchLogic(obj);
|
|
|
|
instance.send(SEND_TO.debug, { "WRITE": obj });
|
|
});
|
|
}
|
|
})
|
|
|
|
|
|
function calculateStateCode() {
|
|
|
|
let bits = [];
|
|
|
|
//Hlavný istič - state_of_main_switch => v rvo senica je to druhy door pre silovu cast (EM)
|
|
if (deviceStatus["state_of_main_switch"] == "closed") {
|
|
bits.push(0);
|
|
}
|
|
else {
|
|
bits.push(1);
|
|
}
|
|
|
|
//Prevádzkový mód - Manual, Off, Automatic, maintenance_mode = true/false // DAVA 2 BITY
|
|
if (!SETTINGS.maintenance_mode) {
|
|
if (deviceStatus["rotary_switch_state"] == "Manual") {
|
|
bits.push(0);
|
|
bits.push(1);
|
|
}
|
|
|
|
if (deviceStatus["rotary_switch_state"] == "Automatic") {
|
|
bits.push(0);
|
|
bits.push(0);
|
|
}
|
|
|
|
if (deviceStatus["rotary_switch_state"] == "Off") {
|
|
bits.push(1);
|
|
bits.push(0);
|
|
}
|
|
}
|
|
else {
|
|
bits.push(1);
|
|
bits.push(1);
|
|
}
|
|
|
|
//Dverový kontakt
|
|
if (deviceStatus["door_condition"] == "closed") {
|
|
bits.push(0);
|
|
}
|
|
else {
|
|
bits.push(1);
|
|
}
|
|
|
|
//EM
|
|
if (deviceStatus["em"] == "NOK") {
|
|
bits.push(1);
|
|
}
|
|
else {
|
|
bits.push(0);
|
|
}
|
|
|
|
//Teplomer
|
|
if (deviceStatus["temperature"] == "NOK") {
|
|
bits.push(1);
|
|
}
|
|
else {
|
|
bits.push(0);
|
|
}
|
|
|
|
//Batéria
|
|
if (deviceStatus["battery"] == "NOK") {
|
|
bits.push(1);
|
|
}
|
|
else {
|
|
bits.push(0);
|
|
}
|
|
|
|
//Zdroj
|
|
if (deviceStatus["power_supply"] == "NOK") {
|
|
bits.push(1);
|
|
}
|
|
else {
|
|
bits.push(0);
|
|
}
|
|
|
|
//MN
|
|
if (deviceStatus["master_node"] == "NOK") {
|
|
bits.push(1);
|
|
}
|
|
else {
|
|
bits.push(0);
|
|
}
|
|
|
|
//výpadok napätia na fáze
|
|
if (deviceStatus["no_voltage"] == "NOK") {
|
|
bits.push(1);
|
|
}
|
|
else {
|
|
bits.push(0);
|
|
}
|
|
|
|
if (deviceStatus["twilight_sensor"] == "NOK") {
|
|
bits.push(1);
|
|
}
|
|
else {
|
|
bits.push(0);
|
|
}
|
|
|
|
// doplnime do 16 bitov (2 byty)
|
|
for (let i = bits.length; i < 16; i++) {
|
|
bits.push(0);
|
|
}
|
|
|
|
// console.log("calculateStateCode - deviceStatus", deviceStatus);
|
|
// console.log("calculateStateCode", bits);
|
|
|
|
let byte0 = bitwise.byte.write(bits.slice(0, 8).reverse());
|
|
let byte1 = bitwise.byte.write(bits.slice(8).reverse());
|
|
|
|
let byte = bytesToInt([byte1, byte0]);
|
|
|
|
//console.log("calculateStateCode -------------------", byte);
|
|
|
|
return byte;
|
|
}
|
|
|
|
|
|
async function sendRvoStatus() {
|
|
|
|
if (SETTINGS === undefined) return;
|
|
SETTINGS.masterNodeIsResponding ? deviceStatus["master_node"] = "OK" : deviceStatus["master_node"] = "NOK";
|
|
|
|
const table = {
|
|
"OK": 1,
|
|
"NOK": 0
|
|
};
|
|
|
|
const dataToTb = {
|
|
"electrometer_status": table[deviceStatus["em"]],
|
|
"twilight_sensor_status": table[deviceStatus["twilight_sensor"]],
|
|
"thermometer_status": table[deviceStatus["temperature"]],
|
|
"phase_1_status": 1,
|
|
"phase_2_status": 1,
|
|
"phase_3_status": 1,
|
|
"master_node_status": table[deviceStatus["master_node"]]
|
|
};
|
|
|
|
for (const phase of SETTINGS.no_voltage) dataToTb[`phase_${phase}_status`] = 0;
|
|
|
|
dataToTb["status"] = checkRvoStatus();
|
|
dataToTb["statecode"] = calculateStateCode();
|
|
|
|
//console.log(dataToTb);
|
|
sendTelemetry(dataToTb, rvoTbName);
|
|
}
|
|
|
|
|
|
function checkRvoStatus() {
|
|
|
|
// we check if any of these pins values are 0 --> it means status RVO is "NOK"
|
|
// pinIndex 6 is door_condition - if it is opened in maintenance mode - status = OK
|
|
//set RVO state
|
|
let status = "OK";
|
|
|
|
for (const [key, value] of Object.entries(deviceStatus)) {
|
|
if (["em", "twilight_sensor", "temperature", "master_node"].includes(key) && value == "NOK") status = "NOK";
|
|
}
|
|
|
|
if (status == "OK") {
|
|
let pinIndexes = [1, 4, 6];
|
|
if (controller_type == 'unipi') pinIndexes = ['input1_01', 'input1_04', 'input1_05'];
|
|
|
|
for (const pinIndex of pinIndexes) {
|
|
if (previousValues[pinIndex] === 0) {
|
|
if ((pinIndex === 6 || pinIndex === 'input1_01' || pinIndex === 'input1_05') && SETTINGS.maintenance_mode) continue;
|
|
status = "NOK";
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// battery status. If value is 1 - battery is NOK
|
|
if (previousValues[5] === 1) status = "NOK";
|
|
if (SETTINGS.no_voltage.size > 0) status = "NOK";
|
|
|
|
// console.log("rvo status",status)
|
|
return status;
|
|
}
|
|
|
|
|
|
// we pass array to function in case of rsPort ==> switchLogic([55,3,0,1]) ==> [[55,3,0,1]]
|
|
// we pass two values in case of websocket ==> switchLogic("relay1_03",1) ==> ["relay1_03",1]
|
|
const switchLogic = (...args) => {
|
|
|
|
let values = {};
|
|
let pinIndex, newPinValue, twilight;
|
|
|
|
//data from rsPort
|
|
if (args.length == 1) {
|
|
pinIndex = args[0][1] + 1;
|
|
if (pinIndex === 17) pinIndex--;
|
|
newPinValue = args[0][3];
|
|
twilight = args[0][2];
|
|
}
|
|
//data from websocket
|
|
else {
|
|
pinIndex = args[0];
|
|
newPinValue = args[1];
|
|
}
|
|
|
|
let obj = pinsData[pinIndex];
|
|
if (obj == undefined) {
|
|
previousValues[pinIndex] = newPinValue;
|
|
//logger.debug("dido-switchLogic ==> no pinIndex", pinIndex);
|
|
return;
|
|
}
|
|
|
|
//tbname is added to pinsData in initialSettings function
|
|
let type = obj.type;
|
|
let line = obj.line;
|
|
let tbname = obj.tbname;
|
|
|
|
//default value
|
|
let value = "On";
|
|
if (newPinValue === 0) value = "Off";
|
|
|
|
//Hlavný istič
|
|
//! po novom uz 'state of main switch' nemame. Namiesto neho je 'door_condition', kedze mame dvoje dveri
|
|
//! takze ked pride z evoku signal pre 'input1_05', handlujeme ho ako 'door_condition'
|
|
// if(type === "!!!state_of_main_switch")
|
|
// {
|
|
// if (newPinValue === 0 && newPinValue !== previousValues[pinIndex])
|
|
// {
|
|
// sendNotification("switchLogic", rvoTbName, "main_switch_has_been_turned_off", {}, "", SEND_TO.tb, instance , "state_of_main_switch");
|
|
// values["status"] = "NOK";
|
|
|
|
// deviceStatus["state_of_main_switch"] = "Off";
|
|
// }
|
|
// else if (newPinValue === 1 && newPinValue !== previousValues[pinIndex])
|
|
// {
|
|
// sendNotification("switchLogic", rvoTbName, "main_switch_has_been_turned_on", {}, "", SEND_TO.tb, instance , "state_of_main_switch");
|
|
|
|
// deviceStatus["state_of_main_switch"] = "On";
|
|
// }
|
|
// }
|
|
|
|
//Prevádzkový mód
|
|
if (type == "rotary_switch_state") {
|
|
// combination of these two pins required to get result
|
|
let pin2, pin3;
|
|
if (pinIndex == 2 || pinIndex == "input1_02") {
|
|
pin2 = newPinValue;
|
|
pin3 = previousValues[3] || previousValues["input1_03"];
|
|
|
|
if (pin3 == undefined) {
|
|
previousValues[pinIndex] = newPinValue;
|
|
return;
|
|
}
|
|
}
|
|
else if (pinIndex == 3 || pinIndex == "input1_03") {
|
|
pin3 = newPinValue;
|
|
pin2 = previousValues[2] || previousValues["input1_02"];
|
|
|
|
if (pin2 == undefined) {
|
|
previousValues[pinIndex] = newPinValue;
|
|
return;
|
|
}
|
|
}
|
|
|
|
//console.log('***********************', pin2, pin3)
|
|
if (pin2 == 1 && pin3 == 0) value = "Manual";
|
|
if (pin2 == 0 && pin3 == 0) value = "Off";
|
|
if (pin2 == 0 && pin3 == 1) value = "Automatic";
|
|
|
|
deviceStatus["rotary_switch_state"] = value;
|
|
|
|
//automatic - profilu pre nody sa vykonavaju
|
|
//ak je spracovany, a automatic - tak ho zapnem
|
|
//ak nie je spracovany, iba profil zapisem
|
|
|
|
if (pin2 != undefined && pin3 != undefined) instance.send(SEND_TO.cmd_manager, { sender: "dido_controller", cmd: "rotary_switch_state", value: value });
|
|
|
|
//console.log("rotary_switch_state pin", pin2, pin3, value);
|
|
}
|
|
|
|
//Zdroj - pin 4
|
|
else if (type === "power_supply") {
|
|
if (newPinValue === 0 && newPinValue !== previousValues[pinIndex]) {
|
|
sendNotification("switchLogic", rvoTbName, "power_supply_has_disconnected_input", {}, "", SEND_TO.tb, instance, "power_supply");
|
|
|
|
deviceStatus["power_supply"] = "NOK";
|
|
}
|
|
else if (newPinValue === 1 && newPinValue !== previousValues[pinIndex]) {
|
|
sendNotification("switchLogic", rvoTbName, "power_supply_works_correctly", {}, "", SEND_TO.tb, instance, "power_supply");
|
|
|
|
deviceStatus["power_supply"] = "OK";
|
|
}
|
|
}
|
|
|
|
//Batéria - pin 5
|
|
else if (type === "battery") {
|
|
if (newPinValue === 1 && newPinValue !== previousValues[pinIndex]) {
|
|
sendNotification("switchLogic", rvoTbName, "battery_level_is_low", {}, "", SEND_TO.tb, instance, "battery_level");
|
|
|
|
deviceStatus["battery"] = "NOK";
|
|
}
|
|
else if (newPinValue === 0 && newPinValue !== previousValues[pinIndex]) {
|
|
sendNotification("switchLogic", rvoTbName, "battery_level_is_ok", {}, "", SEND_TO.tb, instance, "battery_level");
|
|
|
|
deviceStatus["battery"] = "OK";
|
|
}
|
|
}
|
|
|
|
//Dverový kontakt - pin 6
|
|
//! Po novom mame dva dverove kontakty, nie jeden. Druhy je teraz tam, kde bol digital input "state_of_main_switch"
|
|
//! preto ked pride z evoku signal z input1_05, co bol predytm "main switch" handlujeme ho teraz ako 'door_condition'
|
|
else if (type == "door_condition" || type === "state_of_main_switch") {
|
|
newPinValue === 0 ? value = "open" : value = "closed";
|
|
|
|
if (value === "open" && SETTINGS.maintenance_mode) {
|
|
sendNotification("switchLogic", rvoTbName, "door_opened", {}, "", SEND_TO.tb, instance, "rvo_door");
|
|
}
|
|
|
|
if (value === "open" && !SETTINGS.maintenance_mode) {
|
|
sendNotification("switchLogic", rvoTbName, "door_opened_without_permission", {}, "", SEND_TO.tb, instance, "rvo_door");
|
|
|
|
// zapneme sirenu
|
|
// ak sa otvoria dvere len na elektromeri (type === "state_of_main_switch") alarm sa nema spustit. alarm sa spusti len ked sa otvoria hlavne dvere (type === "door_condition")
|
|
if (type === "door_condition") turnAlarm("on");
|
|
}
|
|
|
|
if (value === "closed") {
|
|
if (alarmStatus == "ON") turnAlarm("off");
|
|
sendNotification("switchLogic", rvoTbName, "door_closed", {}, "", SEND_TO.tb, instance, "rvo_door");
|
|
}
|
|
|
|
deviceStatus[type] = value;
|
|
}
|
|
|
|
//lux sensor
|
|
else if (type == "twilight_sensor") {
|
|
//! TODO - to show nok status, if lux value is not changing more then 10 times.
|
|
//Daylight is far more than 1000. So most of the day, when it is sunshine comes just value 1000. But lux sensor is not NOK.
|
|
//This is not the case in LM. If value from LM is the same 10x, there is 99% possibility, that sensor is NOK.
|
|
value = newPinValue;
|
|
|
|
if (controller_type === 'lm') {
|
|
value = parseFloat(newPinValue + (256 * twilight));
|
|
|
|
let now = new Date();
|
|
//new Date(dusk.getTime()
|
|
|
|
let obj = { timestamp: now.getTime(), value: value };
|
|
|
|
//test
|
|
//twilight_sensor_interval = 1;
|
|
|
|
twilight_sensor.push(obj);
|
|
//twilight_sensor_array.push(value);
|
|
|
|
//check if we receive just 1 constant value from lux sensor ==> error
|
|
if (twilight_sensor_array.length > 10) {
|
|
|
|
let set = new Set(twilight_sensor_array);
|
|
if (set.size === 1 && !twilightError) {
|
|
twilightError = true;
|
|
let value = twilight_sensor_array.shift();
|
|
|
|
newPinValue = 0;
|
|
}
|
|
else if (set.size !== 1 && twilightError) {
|
|
//sendNotification("switchLogic", rvoTbName, ERRWEIGHT.NOTICE, "Lux sensor is working again", "", SEND_TO.tb, instance );
|
|
twilightError = false;
|
|
twilight_sensor_array.shift();
|
|
|
|
newPinValue = value;
|
|
}
|
|
else if (set.size === 1 && twilightError) {
|
|
twilight_sensor_array.shift();
|
|
newPinValue = 0;
|
|
}
|
|
}
|
|
|
|
let diff = twilight_sensor[twilight_sensor.length - 1].timestamp - twilight_sensor[0].timestamp;
|
|
if (diff >= twilight_sensor_interval * 60 * 1000) {
|
|
const average = twilight_sensor.reduce((acc, c) => acc + c.value, 0) / twilight_sensor.length;
|
|
instance.send(SEND_TO.cmd_manager, { sender: "dido_controller", cmd: "lux_sensor", value: average });
|
|
|
|
twilight_sensor = [];
|
|
|
|
//console.log("lux_sensor send", average);
|
|
}
|
|
//else console.log("lux_sensor", value, diff);
|
|
}
|
|
}
|
|
|
|
else if (type == "state_of_contactor") {
|
|
if (!(deviceStatus["state_of_contactor"][line] == value)) {
|
|
sendNotification("switchLogic", rvoTbName, "state_of_contactor_for_line", { line: line, value: value }, "", SEND_TO.tb, instance);
|
|
}
|
|
|
|
deviceStatus["state_of_contactor"][line] = value;
|
|
|
|
//true, false
|
|
if (value === "On") value = true;
|
|
else if (value === "Off") value = false;
|
|
|
|
//TODO do we need to modify relays table with contactor value, if we do not use it on startup ??
|
|
let dataChanged = false;
|
|
if (relaysData[line].contactor !== newPinValue) {
|
|
dataChanged = true;
|
|
relaysData[line].contactor = newPinValue;
|
|
}
|
|
|
|
instance.send(SEND_TO.cmd_manager, { sender: "dido_controller", cmd: "reload_relays", line: line, value: value, dataChanged: dataChanged });
|
|
reportLineStatus(line);
|
|
|
|
//modify table relays
|
|
// dbRelays.modify({ contactor: newPinValue }).where("line", line).make(function(builder) {
|
|
// builder.callback(function(err, response) {
|
|
// if(!err)
|
|
// {
|
|
// let time = 0;
|
|
// if(value) time = 1000 * 10;//10 sekund
|
|
|
|
// let dataChanged = false;
|
|
// if(relaysData[line].contactor != newPinValue) dataChanged = true;
|
|
// relaysData[line].contactor = newPinValue; // 0,1
|
|
|
|
// //ak bola predchadzajuci stav off a novy stav je on, budu sa nastavovat nespracovane node profiles
|
|
// //a budu sa odosielat commandy, tie vsak mozu zlyhat, a preto potrebujeme ich spusti trochu neskor
|
|
// setTimeout(function(){
|
|
// instance.send(SEND_TO.cmd_manager, {sender: "dido_controller", cmd: "reload_relays", line: line, time: time, value: value, dataChanged: dataChanged});
|
|
// }, time);
|
|
|
|
// reportLineStatus(line);
|
|
// }
|
|
// else
|
|
// {
|
|
// errLogger.error("modify table relays failed", err);
|
|
// }
|
|
|
|
// });
|
|
// });
|
|
}
|
|
|
|
else if (type === "state_of_breaker") {
|
|
|
|
let valueChanged = false;
|
|
if (newPinValue != previousValues[pinIndex]) valueChanged = true;
|
|
|
|
if (valueChanged) {
|
|
instance.send(SEND_TO.cmd_manager, { sender: "dido_controller", cmd: "state_of_breaker", value: value, line: line });
|
|
|
|
//mame iba 3 istice. vyreportujeme a ohandlujeme liniu na tom istom istici ako paralelna linia (napr linia 1, paralelna s nou je linia 4, key je string "4")
|
|
// ak je 7 linii, na 1 istici je linia 1,4,7
|
|
|
|
if (line == 1) {
|
|
|
|
const lineOnSameBraker = [4, 7];
|
|
|
|
for (var i = 0; i < lineOnSameBraker.length; i++) {
|
|
if (!relaysData.hasOwnProperty(lineOnSameBraker[i])) continue;
|
|
|
|
instance.send(SEND_TO.cmd_manager, { sender: "dido_controller", cmd: "state_of_breaker", value: value, line: lineOnSameBraker[i] });
|
|
|
|
deviceStatus["state_of_breaker"][lineOnSameBraker[i]] = value;
|
|
reportLineStatus(lineOnSameBraker[i]);
|
|
|
|
values[type] = value;
|
|
const tbname = relaysData[lineOnSameBraker[i]].tbname;
|
|
sendTelemetry(values, tbname);
|
|
|
|
delete values[type];
|
|
}
|
|
|
|
}
|
|
else {
|
|
const lineOnSameBraker = line + 3 + "";
|
|
|
|
if (relaysData.hasOwnProperty(lineOnSameBraker)) {
|
|
instance.send(SEND_TO.cmd_manager, { sender: "dido_controller", cmd: "state_of_breaker", value: value, line: line + 3 });
|
|
|
|
deviceStatus["state_of_breaker"][line + 3] = value;
|
|
reportLineStatus(line + 3);
|
|
|
|
values[type] = value;
|
|
const tbname = relaysData[lineOnSameBraker].tbname;
|
|
sendTelemetry(values, tbname);
|
|
|
|
delete values[type];
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
if (value == "Off") values["status"] = "NOK";
|
|
deviceStatus["state_of_breaker"][line] = value;
|
|
|
|
reportLineStatus(line);
|
|
}
|
|
else return;
|
|
|
|
values[type] = value;
|
|
|
|
if (type == "rotary_switch_state") {
|
|
if (SETTINGS.maintenance_mode) value = "maintenance";
|
|
value = value.toLowerCase();
|
|
values["power_mode"] = value;
|
|
}
|
|
|
|
if (newPinValue != previousValues[pinIndex]) previousValues[pinIndex] = newPinValue;
|
|
if (Object.keys(values).length > 0 && tbname) sendTelemetry(values, tbname);
|
|
}
|
|
|
|
|
|
function sendTelemetry(values, tbname, date = Date.now()) {
|
|
let dataToTb = {
|
|
[tbname]: [
|
|
{
|
|
"ts": date,
|
|
"values": values
|
|
}
|
|
]
|
|
};
|
|
|
|
tbHandler.sendToTb(dataToTb, instance);
|
|
}
|
|
|
|
|
|
function isObject(item) {
|
|
return (typeof item === "object" && !Array.isArray(item) && item !== null);
|
|
}
|
|
|
|
} //end of instance
|
|
|
|
|
|
|
|
|
|
//! incomming data to websocket
|
|
// [
|
|
// {
|
|
// glob_dev_id: 1,
|
|
// modes: [ 'Simple' ],
|
|
// value: 0,
|
|
// circuit: '1_08',
|
|
// pending: false,
|
|
// relay_type: 'physical',
|
|
// dev: 'relay',
|
|
// mode: 'Simple'
|
|
// },
|
|
// {
|
|
// glob_dev_id: 1,
|
|
// modes: [ 'Simple' ],
|
|
// value: 0,
|
|
// circuit: '1_01',
|
|
// alias: 'al_lights_kitchen',
|
|
// pending: false,
|
|
// relay_type: 'physical',
|
|
// dev: 'relay',
|
|
// mode: 'Simple'
|
|
// },
|
|
// {
|
|
// glob_dev_id: 1,
|
|
// modes: [ 'Simple' ],
|
|
// value: 0,
|
|
// circuit: '1_02',
|
|
// alias: 'al_lights_bedroom',
|
|
// pending: false,
|
|
// relay_type: 'physical',
|
|
// dev: 'relay',
|
|
// mode: 'Simple'
|
|
// },
|
|
// {
|
|
// glob_dev_id: 1,
|
|
// modes: [ 'Simple' ],
|
|
// value: 0,
|
|
// circuit: '1_03',
|
|
// pending: false,
|
|
// relay_type: 'physical',
|
|
// dev: 'relay',
|
|
// mode: 'Simple'
|
|
// },
|
|
// {
|
|
// glob_dev_id: 1,
|
|
// modes: [ 'Simple' ],
|
|
// value: 0,
|
|
// circuit: '1_04',
|
|
// pending: false,
|
|
// relay_type: 'physical',
|
|
// dev: 'relay',
|
|
// mode: 'Simple'
|
|
// },
|
|
// {
|
|
// glob_dev_id: 1,
|
|
// modes: [ 'Simple' ],
|
|
// value: 0,
|
|
// circuit: '1_05',
|
|
// pending: false,
|
|
// relay_type: 'physical',
|
|
// dev: 'relay',
|
|
// mode: 'Simple'
|
|
// },
|
|
// {
|
|
// glob_dev_id: 1,
|
|
// modes: [ 'Simple' ],
|
|
// value: 0,
|
|
// circuit: '1_06',
|
|
// pending: false,
|
|
// relay_type: 'physical',
|
|
// dev: 'relay',
|
|
// mode: 'Simple'
|
|
// },
|
|
// {
|
|
// glob_dev_id: 1,
|
|
// modes: [ 'Simple' ],
|
|
// value: 0,
|
|
// circuit: '1_07',
|
|
// pending: false,
|
|
// relay_type: 'physical',
|
|
// dev: 'relay',
|
|
// mode: 'Simple'
|
|
// },
|
|
// {
|
|
// counter_modes: [ 'Enabled', 'Disabled' ],
|
|
// glob_dev_id: 1,
|
|
// modes: [ 'Simple', 'DirectSwitch' ],
|
|
// value: 0,
|
|
// circuit: '1_08',
|
|
// debounce: 50,
|
|
// counter: 0,
|
|
// counter_mode: 'Enabled',
|
|
// dev: 'input',
|
|
// mode: 'Simple'
|
|
// },
|
|
// {
|
|
// counter_mode: 'Enabled',
|
|
// counter_modes: [ 'Enabled', 'Disabled' ],
|
|
// glob_dev_id: 1,
|
|
// dev: 'input',
|
|
// modes: [ 'Simple', 'DirectSwitch' ],
|
|
// debounce: 50,
|
|
// counter: 1,
|
|
// value: 1,
|
|
// alias: 'al_main_switch',
|
|
// mode: 'Simple',
|
|
// circuit: '1_01'
|
|
// },
|
|
// {
|
|
// counter_modes: [ 'Enabled', 'Disabled' ],
|
|
// glob_dev_id: 1,
|
|
// modes: [ 'Simple', 'DirectSwitch' ],
|
|
// value: 1,
|
|
// circuit: '1_02',
|
|
// debounce: 50,
|
|
// counter: 2,
|
|
// counter_mode: 'Enabled',
|
|
// dev: 'input',
|
|
// mode: 'Simple'
|
|
// },
|
|
// {
|
|
// counter_modes: [ 'Enabled', 'Disabled' ],
|
|
// glob_dev_id: 1,
|
|
// modes: [ 'Simple', 'DirectSwitch' ],
|
|
// value: 1,
|
|
// circuit: '1_03',
|
|
// debounce: 50,
|
|
// counter: 2,
|
|
// counter_mode: 'Enabled',
|
|
// dev: 'input',
|
|
// mode: 'Simple'
|
|
// },
|
|
// {
|
|
// counter_modes: [ 'Enabled', 'Disabled' ],
|
|
// glob_dev_id: 1,
|
|
// modes: [ 'Simple', 'DirectSwitch' ],
|
|
// value: 0,
|
|
// circuit: '1_04',
|
|
// debounce: 50,
|
|
// counter: 1,
|
|
// counter_mode: 'Enabled',
|
|
// dev: 'input',
|
|
// mode: 'Simple'
|
|
// },
|
|
// {
|
|
// counter_modes: [ 'Enabled', 'Disabled' ],
|
|
// glob_dev_id: 1,
|
|
// modes: [ 'Simple', 'DirectSwitch' ],
|
|
// value: 0,
|
|
// circuit: '1_05',
|
|
// debounce: 50,
|
|
// counter: 0,
|
|
// counter_mode: 'Enabled',
|
|
// dev: 'input',
|
|
// mode: 'Simple'
|
|
// },
|
|
// {
|
|
// counter_modes: [ 'Enabled', 'Disabled' ],
|
|
// glob_dev_id: 1,
|
|
// modes: [ 'Simple', 'DirectSwitch' ],
|
|
// value: 0,
|
|
// circuit: '1_06',
|
|
// debounce: 50,
|
|
// counter: 0,
|
|
// counter_mode: 'Enabled',
|
|
// dev: 'input',
|
|
// mode: 'Simple'
|
|
// },
|
|
// {
|
|
// counter_modes: [ 'Enabled', 'Disabled' ],
|
|
// glob_dev_id: 1,
|
|
// modes: [ 'Simple', 'DirectSwitch' ],
|
|
// value: 0,
|
|
// circuit: '1_07',
|
|
// debounce: 50,
|
|
// counter: 0,
|
|
// counter_mode: 'Enabled',
|
|
// dev: 'input',
|
|
// mode: 'Simple'
|
|
// },
|
|
// {
|
|
// interval: 3,
|
|
// value: 24.5,
|
|
// circuit: '28744F7791180257',
|
|
// address: '28744F7791180257',
|
|
// time: 1631873896.48797,
|
|
// typ: 'DS18B20',
|
|
// lost: false,
|
|
// dev: 'temp'
|
|
// },
|
|
// {
|
|
// bus: '/dev/i2c-2',
|
|
// interval: 3,
|
|
// dev: 'owbus',
|
|
// scan_interval: 300,
|
|
// circuit: '1',
|
|
// do_scan: false,
|
|
// do_reset: false
|
|
// },
|
|
// {
|
|
// glob_dev_id: 1,
|
|
// last_comm: 0.014672994613647461,
|
|
// ver2: '0.1',
|
|
// sn: 42,
|
|
// circuit: '1',
|
|
// model: 'S207',
|
|
// dev: 'neuron',
|
|
// board_count: 1
|
|
// },
|
|
// {
|
|
// circuit: '1_01',
|
|
// value: 0,
|
|
// glob_dev_id: 1,
|
|
// dev: 'wd',
|
|
// timeout: 5000,
|
|
// was_wd_reset: 0,
|
|
// nv_save: 0
|
|
// }
|
|
// ]
|
|
|
|
//! loaded pins_data --> from LM
|
|
// {
|
|
// '1': { pin: 1, type: 'state_of_main_switch', line: 0 },
|
|
// '2': { pin: 2, type: 'rotary_switch_state', line: 0 },
|
|
// '3': { pin: 3, type: 'rotary_switch_state', line: 0 },
|
|
// '4': { pin: 4, type: 'power_supply', line: 0 },
|
|
// '5': { pin: 5, type: 'battery', line: 0 },
|
|
// '6': { pin: 6, type: 'door_condition', line: 0 },
|
|
// '8': { pin: 8, type: 'state_of_breaker', line: 1 },
|
|
// '9': { pin: 9, type: 'state_of_breaker', line: 2 },
|
|
// '10': { pin: 10, type: 'state_of_breaker', line: 3 },
|
|
// '11': { pin: 11, type: 'state_of_contactor', line: 1 },
|
|
// '12': { pin: 12, type: 'state_of_contactor', line: 2 },
|
|
// '13': { pin: 13, type: 'state_of_contactor', line: 3 },
|
|
// '16': { pin: 16, type: 'twilight_sensor', line: 0 }
|
|
// }
|
|
|
|
//! pins.table --> from LM
|
|
// pin:number|type:string|line:number
|
|
// *|1|state_of_main_switch|0|...........
|
|
// *|2|rotary_switch_state|0|...........
|
|
// *|3|rotary_switch_state|0|...........
|
|
// *|4|power_supply|0|...........
|
|
// *|5|battery|0|...........
|
|
// *|6|door_condition|0|...........
|
|
// *|8|state_of_breaker|1|...........
|
|
// *|9|state_of_breaker|2|...........
|
|
// *|10|state_of_breaker|3|...........
|
|
// *|11|state_of_contactor|1|...........
|
|
// *|12|state_of_contactor|2|...........
|
|
// *|13|state_of_contactor|3|...........
|
|
// *|16|twilight_sensor|0|...........
|
|
|
|
//! pins.table --> from UNIPI
|
|
// pin:string|type:string|line:number
|
|
// *|input1_01|state_of_main_switch|0|...........
|
|
// *|input1_02|rotary_switch_state|0|...........
|
|
// *|input1_03|rotary_switch_state|0|...........
|
|
// *|intut1_04|power_supply|0|...........
|
|
// *|input1_05|door_condition|0|...........
|
|
// *|input1_06|state_of_breaker|1|...........
|
|
// *|input1_07|state_of_breaker|2|...........
|
|
// *|input1_08|state_of_breaker|3|...........
|
|
// *|relay1_02|state_of_contactor|1|...........
|
|
// *|relay1_03|state_of_contactor|2|...........
|
|
// *|relay1_04|state_of_contactor|3|...........
|
|
// *|287D8776E0013CE9|temperature|0|...........
|
|
|
|
|
|
//! pins_data --> from UNIPI
|
|
// {
|
|
// input1_01: {
|
|
// pin: 'input1_01',
|
|
// type: 'door_condition',
|
|
// line: 0,
|
|
// tbname: 'PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8'
|
|
// },
|
|
// input1_02: {
|
|
// pin: 'input1_02',
|
|
// type: 'rotary_switch_state',
|
|
// line: 0,
|
|
// tbname: 'PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8'
|
|
// },
|
|
// input1_03: {
|
|
// pin: 'input1_03',
|
|
// type: 'rotary_switch_state',
|
|
// line: 0,
|
|
// tbname: 'PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8'
|
|
// },
|
|
// input1_04: {
|
|
// pin: 'input1_04',
|
|
// type: 'power_supply',
|
|
// line: 0,
|
|
// tbname: 'PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8'
|
|
// },
|
|
// input1_05: {
|
|
// pin: 'input1_05',
|
|
// type: 'state_of_main_switch',
|
|
// line: 0,
|
|
// tbname: 'PLBJzmK1r3Gynd6OW0gGYz0e5wV4vx9bDEqNgYR8'
|
|
// },
|
|
// input1_06: {
|
|
// pin: 'input1_06',
|
|
// type: 'state_of_breaker',
|
|
// line: 1,
|
|
// tbname: '52dD6ZlV1QaOpRBmbAqK8bkKnGzWMLj4eJq38Pgo'
|
|
// },
|
|
// relay1_02: {
|
|
// pin: 'relay1_02',
|
|
// type: 'state_of_contactor',
|
|
// line: 1,
|
|
// tbname: '52dD6ZlV1QaOpRBmbAqK8bkKnGzWMLj4eJq38Pgo'
|
|
// },
|
|
// '28F46E9D0E00008B': { pin: '28F46E9D0E00008B', type: 'temperature', line: 0 },
|
|
// twilight_sensor: { pin: 'twilight_sensor', type: 'twilight_sensor', line: 0 }
|
|
// }
|
|
|
|
//! relays_data
|
|
// {
|
|
// '0': {
|
|
// line: 0,
|
|
// tbname: 'KjbN4q7JPZmexgdnz2yKQ98YAWwO0Q3BMX6ERLoV',
|
|
// contactor: 1,
|
|
// profile: ''
|
|
// },
|
|
// '1': {
|
|
// line: 1,
|
|
// tbname: 'RMgnK93rkoAazbqdQ4yBG95Z1YXGx6pmwBeVEP2O',
|
|
// contactor: 0,
|
|
// profile: '{"intervals":[{"value":0,"end_time":"20:00","start_time":"13:00"},{"value":1,"end_time":"10:00","start_time":"20:00"},{"value":0,"end_time":"10:20","start_time":"10:00"},{"value":1,"end_time":"10:40","start_time":"10:20"},{"value":0,"end_time":"11:00","start_time":"10:40"},{"value":1,"end_time":"11:30","start_time":"11:00"},{"value":0,"end_time":"11:50","start_time":"11:30"},{"value":1,"end_time":"13:00","start_time":"11:50"}],"astro_clock":false,"dawn_lux_sensor":false,"dusk_lux_sensor":false,"dawn_lux_sensor_value":5,"dusk_lux_sensor_value":5,"dawn_astro_clock_offset":0,"dusk_astro_clock_offset":0,"dawn_lux_sensor_time_window":30,"dusk_lux_sensor_time_window":30,"dawn_astro_clock_time_window":60,"dusk_astro_clock_time_window":60}'
|
|
// },
|
|
// '2': {
|
|
// line: 2,
|
|
// tbname: 'dlE1VQjYrNx9gZRmb38gG08oLBO4qaAk2M6JPnG7',
|
|
// contactor: 0,
|
|
// profile: '{"intervals":[{"value":0,"end_time":"20:00","start_time":"13:00"},{"value":1,"end_time":"10:00","start_time":"20:00"},{"value":0,"end_time":"10:20","start_time":"10:00"},{"value":1,"end_time":"10:40","start_time":"10:20"},{"value":0,"end_time":"11:00","start_time":"10:40"},{"value":1,"end_time":"11:30","start_time":"11:00"},{"value":0,"end_time":"11:50","start_time":"11:30"},{"value":1,"end_time":"13:00","start_time":"11:50"}],"astro_clock":false,"dawn_lux_sensor":false,"dusk_lux_sensor":false,"dawn_lux_sensor_value":5,"dusk_lux_sensor_value":5,"dawn_astro_clock_offset":0,"dusk_astro_clock_offset":0,"dawn_lux_sensor_time_window":30,"dusk_lux_sensor_time_window":30,"dawn_astro_clock_time_window":60,"dusk_astro_clock_time_window":60}'
|
|
// },
|
|
// '3': {
|
|
// line: 3,
|
|
// tbname: 'vnmG4kJxaXWNBgMQq0D7Aj5e9oZzOAlr6LdR3w2V',
|
|
// contactor: 0,
|
|
// profile: '{"intervals":[{"value":0,"end_time":"20:30","start_time":"13:00"},{"value":1,"end_time":"00:10","start_time":"20:30"},{"value":0,"end_time":"13:00","start_time":"05:40"},{"value":1,"end_time":"05:40","start_time":"00:10"}],"astro_clock":true,"dawn_lux_sensor":false,"dusk_lux_sensor":false,"dawn_lux_sensor_value":5,"dusk_lux_sensor_value":5,"dawn_astro_clock_offset":0,"dusk_astro_clock_offset":0,"dawn_lux_sensor_time_window":30,"dusk_lux_sensor_time_window":30,"dawn_astro_clock_time_window":60,"dusk_astro_clock_time_window":60}'
|
|
// }
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
// {
|
|
// "jbN4q7JPZmexgdnz2yKbWGDYAWwO0Q3BMX6ERLoV": [
|
|
// {
|
|
// "ts": 1700409326353,
|
|
// "values": {
|
|
// "_event": {
|
|
// "type": "notice",
|
|
// "status": "new",
|
|
// "source": {
|
|
// "func": "rsPort.open()",
|
|
// "component": "1700343402190",
|
|
// "component_name": "DIDO_Controller",
|
|
// "edge": "jbN4q7JPZmexgdnz2yKbWGDYAWwO0Q3BMX6ERLoV"
|
|
// },
|
|
// "message": "al_shariff_10.0.0.38: FLOW has been started ",
|
|
// "message_data": ""
|
|
// }
|
|
// }
|
|
// }
|
|
// ]
|
|
// }
|