1934 lines
56 KiB
JavaScript
1934 lines
56 KiB
JavaScript
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"];
|
|
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
|
|
*/
|
|
|
|
|
|
//globals
|
|
//FIRMWARE version
|
|
FLOW.OMS_edge_fw_version = "2024-07-08";//rok-mesiac-den
|
|
FLOW.OMS_edgeName = "";
|
|
FLOW.OMS_maintenance_mode = false;
|
|
|
|
//dynamic values
|
|
FLOW.OMS_masterNodeIsResponding = true; //cmd_manager
|
|
//FLOW.OMS_brokerready = false //wsmqttpublish
|
|
FLOW.OMS_no_voltage = new Set();//modbus_citysys - elektromer
|
|
|
|
//see loadSettings() in cmd_manager
|
|
FLOW.OMS_language = "en";//cmd_manager
|
|
FLOW.OMS_rvo_name = "";//cmd_manager
|
|
FLOW.OMS_rvo_tbname = "";//relaysData
|
|
FLOW.OMS_temperature_adress = "";//cmd_manager
|
|
//-----------------------------------------------
|
|
|
|
let alarmStatus = "OFF";
|
|
|
|
const SEND_TO = {
|
|
debug: 0,
|
|
tb: 1,
|
|
cmd_manager: 2
|
|
}
|
|
|
|
var log4js = require("log4js");
|
|
var path = require('path');
|
|
|
|
log4js.configure({
|
|
appenders: {
|
|
errLogs: { type: 'file', compress:true, daysToKeep: 2, maxLogSize: 1048576, backups: 1, keepFileExt: true, filename: path.join(__dirname + "/../", 'err.txt') },
|
|
monitorLogs: { type: 'file', compress:true, daysToKeep: 2, maxLogSize: 1048576, backups: 1, keepFileExt: true, filename: path.join(__dirname + "/../", 'monitor.txt') },
|
|
console: { type: 'console' }
|
|
},
|
|
categories: {
|
|
errLogs: { appenders: ['console', 'errLogs'], level: 'error' },
|
|
monitorLogs: { appenders: ['console', 'monitorLogs'], level: 'trace' },
|
|
//another: { appenders: ['console'], level: 'trace' },
|
|
default: { appenders: ['console'], level: 'trace' }
|
|
}
|
|
});
|
|
|
|
const errLogger = log4js.getLogger("errLogs");
|
|
const logger = log4js.getLogger();
|
|
const monitor = log4js.getLogger("monitorLogs");
|
|
|
|
//console.log(path.join(__dirname, 'err.txt', "-----------------------------"));
|
|
|
|
/*
|
|
process.on('uncaughtException', function (err) {
|
|
|
|
errLogger.error('uncaughtException:', err.message)
|
|
errLogger.error(err.stack);
|
|
|
|
//process.exit(1);
|
|
})
|
|
*/
|
|
|
|
//USAGE
|
|
//logger.debug("text")
|
|
//monitor.info('info');
|
|
//errLogger.error("some error");
|
|
|
|
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 = {temperature: 0};
|
|
let rsPortReceivedData = [];
|
|
|
|
let twilight_sensor_interval = 5;//minutes
|
|
let twilight_sensor = [];
|
|
const twilight_sensor_array = [];
|
|
let twilightError = false;
|
|
|
|
let edgeName = "";
|
|
|
|
monitor.info("DI_DO_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
|
|
};
|
|
*/
|
|
|
|
const dbPins = TABLE("pins");
|
|
let pinsData = {};//key is pin
|
|
|
|
const dbRelays = TABLE("relays");
|
|
let relaysData = {};//key is line
|
|
|
|
//status for calculating Statecodes
|
|
let deviceStatuses = {};//key is device name: temperature,....
|
|
deviceStatuses["state_of_main_switch"] = "Off";//Hlavný istič
|
|
deviceStatuses["rotary_switch_state"] = "Off";//Prevádzkový mód
|
|
deviceStatuses["door_condition"] = "closed";//Dverový kontakt
|
|
deviceStatuses["em"] = "OK";//elektromer rvo
|
|
deviceStatuses["temperature"] = "OK";//templomer
|
|
deviceStatuses["battery"] = "OK";//Batéria
|
|
deviceStatuses["power_supply"] = "OK";//Zdroj
|
|
deviceStatuses["master_node"] = "OK";//MN - FLOW.OMS_masterNodeIsResponding
|
|
deviceStatuses["no_voltage"] = "OK";//FLOW.OMS_no_voltage - výpadok napätia na fáze
|
|
|
|
deviceStatuses["state_of_breaker"] = {};//"Off";//Istič
|
|
deviceStatuses["state_of_contactor"] = {};//"Off";//Stykač
|
|
deviceStatuses["twilight_sensor"] = "OK"; //lux sensor
|
|
|
|
/*
|
|
dbRelays.on('change', function(doc, old) {
|
|
console.log("'DI_DO_Controller - dbRelays.on('change'");
|
|
instance.send(SEND_TO.cmd_manager, "reload_relays");
|
|
});
|
|
*/
|
|
|
|
const SerialPort = require('serialport');
|
|
const WebSocket = require('ws');
|
|
|
|
let ws = null;
|
|
let rsPort = null;
|
|
|
|
//const { exec } = require('child_process');
|
|
const { openPort, runSyncExec, writeData } = require('./helper/serialport_helper.js');
|
|
const { bytesToInt, resizeArray } = require('./helper/utils');
|
|
const { promisifyBuilder, makeMapFromDbResult } = require('./helper/db_helper.js');
|
|
const { sendNotification, ERRWEIGHT } = require('./helper/notification_reporter.js');
|
|
const bitwise = require('bitwise');
|
|
|
|
const ErrorToServiceHandler = require('./helper/ErrorToServiceHandler.js');
|
|
const errorHandler = new ErrorToServiceHandler();
|
|
|
|
//let useTurnOffCounter = false;
|
|
//let turnOffCounter = 0;
|
|
let controller_type = FLOW.OMS_controller_type //"lm" or "unipi" //logicMachine
|
|
if(controller_type == "") controller_type = "lm";
|
|
|
|
console.log(exports.title, "controller type: ", controller_type);
|
|
|
|
async function loadAllDb()
|
|
{
|
|
let responsePins = await promisifyBuilder(dbPins.find());
|
|
pinsData = makeMapFromDbResult(responsePins, "pin");
|
|
|
|
let responseRelays = await promisifyBuilder(dbRelays.find());
|
|
relaysData = makeMapFromDbResult(responseRelays, "line");
|
|
|
|
FLOW.OMS_rvo_tbname = relaysData[0].tbname;
|
|
|
|
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 & set tbname
|
|
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 ", edgeName, ERRWEIGHT.CRITICAL, "local database is corrupted", "", SEND_TO.tb, instance, null );
|
|
sendNotification("set port ", edgeName, "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;
|
|
turnOffLine(line, pin, forceTurnOff, "turn off on startup");
|
|
}
|
|
}
|
|
|
|
//report RVO version relaysData[0].tbname;
|
|
let values = {};
|
|
values["edge_fw_version"] = FLOW.OMS_edge_fw_version;
|
|
values["maintenance_mode"] = FLOW.OMS_maintenance_mode;
|
|
values["status"] = "OK";
|
|
|
|
edgeName = relaysData[0].tbname;
|
|
FLOW.OMS_edgeName = edgeName;
|
|
|
|
dataToTb = {
|
|
[edgeName]: [
|
|
{
|
|
"ts": Date.now(),
|
|
"values": values
|
|
}
|
|
]
|
|
}
|
|
|
|
instance.send(SEND_TO.tb, dataToTb);
|
|
|
|
let time = 3*1000;
|
|
setTimeout(function(){
|
|
instance.send(SEND_TO.cmd_manager, {sender: "dido_controller", cmd: "buildTasks"});
|
|
|
|
sendNotification("rsPort.open()", edgeName, "flow_start", {}, "", SEND_TO.tb, instance );
|
|
monitor.info("-->FLOW bol spustený", edgeName, FLOW.OMS_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) {
|
|
monitor.info(exports.title + "--->Digital in_out has been set (runSyncExec was sucessfull)");
|
|
|
|
turnOffAlarm();
|
|
|
|
//useTurnOffCounter = true;
|
|
//turnOffCounter = relaysData.length - 1;
|
|
|
|
initialSetting();
|
|
})
|
|
|
|
}).catch(function (reason) {
|
|
//instance.send(SEND_TO.debug, exports.title + " runSyncExec - promise rejected:" + 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");
|
|
turnOffAlarm();
|
|
|
|
// 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 = function(data) {
|
|
|
|
data = JSON.parse(data.data);
|
|
|
|
// data comes in array except of "temperature" ==> it comes as an object
|
|
if(!Array.isArray(data))
|
|
{
|
|
let value = data['value'];
|
|
|
|
// temperature value comes very often. To handle it, we check if it change for more than 0.2 degrees, if yes, we send to TB
|
|
if(Math.abs(previousValues["temperature"] - value) > 0.21 )
|
|
{
|
|
const dataToTb = {
|
|
[FLOW.OMS_rvo_tbname]: [
|
|
{
|
|
"ts": Date.now(),
|
|
"values": {temperature: value}
|
|
}
|
|
]
|
|
};
|
|
|
|
deviceStatuses["temperature"] = "OK";
|
|
previousValues["temperature"] = value;
|
|
instance.send(SEND_TO.tb, dataToTb);
|
|
}
|
|
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);
|
|
}
|
|
}
|
|
|
|
// ! do we need requests every minute ???
|
|
// const startRequests = () => {
|
|
// console.log("startRequest function called");
|
|
// start = setInterval(() => {
|
|
// // console.log("data from evok requested");
|
|
// ws.send(JSON.stringify({"cmd":"filter", "devices": "neuron"}));
|
|
// // ws.send(JSON.stringify({"cmd":"filter", "devices":["input", "relay"]}));
|
|
// }, 150000)
|
|
// }
|
|
|
|
|
|
instance.on("close", () => {
|
|
if(rsPort) rsPort.close();
|
|
if(ws) ws.close();
|
|
clearInterval(sendRebuildTasksAt11);
|
|
})
|
|
|
|
loadAllDb();
|
|
|
|
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 turnOnAlarm()
|
|
{
|
|
if(FLOW.OMS_maintenance_mode) return;
|
|
|
|
alarmStatus = "ON";
|
|
|
|
if(rsPort)
|
|
{
|
|
let arr = [0x55];
|
|
arr.push( 13 );
|
|
arr.push( 0 );
|
|
arr.push( 1 );
|
|
|
|
rsPort.write(Buffer.from(arr), function(err) {
|
|
logger.debug("sirena zapnuta");
|
|
});
|
|
}
|
|
else if(ws)
|
|
{
|
|
let cmd = {"cmd": "set", "dev": "relay", "circuit": "1_01", "value": 1};
|
|
ws.send(JSON.stringify(cmd));
|
|
logger.debug("sirena zapnuta");
|
|
}
|
|
}
|
|
|
|
|
|
function turnOffAlarm()
|
|
{
|
|
alarmStatus = "OFF";
|
|
|
|
if(rsPort)
|
|
{
|
|
let arr = [0x55];
|
|
arr.push( 13 );
|
|
arr.push( 0 );
|
|
arr.push( 0 );
|
|
|
|
rsPort.write(Buffer.from(arr), function(err) {
|
|
logger.debug("sirena vypnuta");
|
|
});
|
|
}
|
|
else if(ws)
|
|
{
|
|
let cmd = {"cmd": "set", "dev": "relay", "circuit": "1_01", "value": 0};
|
|
ws.send(JSON.stringify(cmd));
|
|
logger.debug("sirena vypnuta");
|
|
}
|
|
}
|
|
|
|
|
|
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(deviceStatuses["state_of_breaker"][line] == "On")
|
|
{
|
|
bits.push(0);
|
|
}
|
|
else bits.push(1);
|
|
|
|
if(deviceStatuses["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);
|
|
|
|
let values = {
|
|
statecode: byte
|
|
}
|
|
|
|
let dataToTb = {
|
|
[tbname]: [
|
|
{
|
|
"ts": Date.now(),
|
|
"values": values
|
|
}
|
|
]
|
|
}
|
|
|
|
//console.log(values);
|
|
|
|
instance.send(SEND_TO.tb, dataToTb);
|
|
}
|
|
|
|
|
|
function turnOnLine(line, pin, force, info)
|
|
{
|
|
|
|
instance.send(SEND_TO.debug, "turn on line " + line );
|
|
if(force == undefined) force = false;
|
|
|
|
if(line == 0)
|
|
{
|
|
if(alarmStatus == "ON") turnOffAlarm();
|
|
FLOW.OMS_maintenance_mode = true;
|
|
|
|
let values = {};
|
|
values["statecode"] = calculateStateCode();
|
|
values["power_mode"] = "maintenance";
|
|
let tbname = relaysData[line].tbname;
|
|
sendTelemetry(values, tbname);
|
|
|
|
monitor.info("turnOnLine (line, FLOW.OMS_maintenance_mode)", line, FLOW.OMS_maintenance_mode, info);
|
|
|
|
return;
|
|
}
|
|
|
|
if( pin === undefined) pin = getPin(line);
|
|
|
|
monitor.info("turnOnLine (line, pin, force)", line, pin, force, info);
|
|
|
|
if( pin === undefined)
|
|
{
|
|
monitor.info("pin is undefined!", line);
|
|
return;
|
|
}
|
|
|
|
|
|
if(!force)
|
|
{
|
|
if(relaysData[line].contactor == 1)
|
|
{
|
|
instance.send(SEND_TO.debug, "line is already on " + line );
|
|
logger.debug("turnOnLine: line is already on: ", 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( 1 );
|
|
|
|
rsPort.write(Buffer.from(arr), function(err) {
|
|
if(err === undefined)
|
|
{
|
|
console.log("turnONLine zapisal do rsPortu", line, arr);
|
|
switchLogic(arr);
|
|
}
|
|
else
|
|
{
|
|
monitor.info("turnOnLine WRITE error", err);
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
else if(ws)
|
|
{
|
|
console.log("turnONLine pin (relay)", pin);
|
|
//pin = "relay1_03" or "input1_01" ... we must make just "1_01" with slice method
|
|
let cmd = {"cmd": "set", "dev": "relay", "circuit": pin.slice(5), "value": 1};
|
|
ws.send(JSON.stringify(cmd));
|
|
//switchLogic(pin, 1)
|
|
}
|
|
}
|
|
|
|
|
|
function turnOffLine(line, pin, force, info)
|
|
{
|
|
if(force == undefined) force = false;
|
|
|
|
if(line == 0)
|
|
{
|
|
FLOW.OMS_maintenance_mode = false;
|
|
|
|
let values = {};
|
|
values["statecode"] = calculateStateCode();
|
|
values["power_mode"] = "automatic";
|
|
let tbname = relaysData[line].tbname;
|
|
sendTelemetry(values, tbname);
|
|
|
|
return;
|
|
}
|
|
|
|
if( pin === undefined) pin = getPin(line);
|
|
|
|
monitor.info("turnOffLine (line, pin, force)", line, pin, force, info);
|
|
|
|
if( pin === undefined)
|
|
{
|
|
errLogger.error("pin is undefined!", line);
|
|
return;
|
|
}
|
|
|
|
if(!force)
|
|
{
|
|
if(relaysData[line].contactor == 0)
|
|
{
|
|
instance.send(SEND_TO.debug, "line is already off " + line );
|
|
logger.debug("turnOffLine: line already off:", line);
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
// if(!rsPort.isOpen && !ws)
|
|
if(!rsPort && !ws)
|
|
{
|
|
errLogger.error("di do controller - port or websocket is not opened");
|
|
return;
|
|
}
|
|
|
|
if(rsPort)
|
|
{
|
|
let arr = [0x55];
|
|
arr.push( pin );
|
|
arr.push( 0 );
|
|
arr.push( 0 );
|
|
|
|
rsPort.write(Buffer.from(arr), function(err) {
|
|
if(err === undefined)
|
|
{
|
|
console.log("turnOffLine zapisal do rsPort-u", line, arr);
|
|
switchLogic(arr);
|
|
}
|
|
else
|
|
{
|
|
monitor.info("turnOffLine WRITE error", err);
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
else if(ws)
|
|
{
|
|
//pin = "relay1_03" or "input1_01" ... we must make just "1_01" with slice method
|
|
//monitor.info("turnOffLine pin (relay)", pin);
|
|
let cmd = {"cmd": "set", "dev": "relay", "circuit": pin.slice(5), "value": 0};
|
|
ws.send(JSON.stringify(cmd));
|
|
//switchLogic(pin, 0)
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//data from modbus_reader or temperature sensor or twilight sensor or other modbus device
|
|
instance.on("0", flowdata => {
|
|
|
|
if(!flowdata.data instanceof Object) return;
|
|
|
|
// console.log('***********************', flowdata.data)
|
|
instance.send(SEND_TO.debug, flowdata.data);
|
|
|
|
// we handle nok status from modbus_reader component and thermometer
|
|
if(flowdata.data?.status)
|
|
{
|
|
const status = flowdata.data.status;
|
|
if(status == "NOK-twilight_sensor")
|
|
{
|
|
deviceStatuses["twilight_sensor"] = "NOK";
|
|
}
|
|
else if(status == "NOK-em340" || status == "NOK-em111")
|
|
{
|
|
deviceStatuses["em"] = "NOK";
|
|
}
|
|
else if(status == "NOK-thermometer")
|
|
{
|
|
deviceStatuses["temperature"] = "NOK";
|
|
}
|
|
}
|
|
else if(flowdata.data?.values)
|
|
{
|
|
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"]});
|
|
deviceStatuses["twilight_sensor"] = "OK"
|
|
}
|
|
else if(values.hasOwnProperty("temperature"))
|
|
{
|
|
deviceStatuses["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"))
|
|
{
|
|
deviceStatuses["em"] = "OK";
|
|
}
|
|
else
|
|
{
|
|
return;
|
|
}
|
|
|
|
const updateStatus = checkFinalRVOStatus();
|
|
if(updateStatus) values.status = "OK";
|
|
|
|
sendTelemetry(values, FLOW.OMS_rvo_tbname);
|
|
}
|
|
|
|
})
|
|
|
|
|
|
// 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 == "turnOn") turnOnLine(line, undefined, force, info);
|
|
else if(obj.command == "turnOff") turnOffLine(line, undefined, force, info);
|
|
else if(obj.command == "turnOnAlarm") turnOnAlarm();
|
|
else if(obj.command == "turnOffAlarm") turnOffAlarm();
|
|
|
|
|
|
//! 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 bytes = [];
|
|
let bits = [];
|
|
|
|
//Hlavný istič - state_of_main_switch
|
|
if(deviceStatuses["state_of_main_switch"] == "On")
|
|
{
|
|
bits.push(0);
|
|
}
|
|
else if(deviceStatuses["state_of_main_switch"] == "Off")
|
|
{
|
|
bits.push(1);
|
|
}
|
|
|
|
//Prevádzkový mód - Manual, Off, Automatic, maintenance_mode = true/false // DAVA 2 BITY
|
|
if(!FLOW.OMS_maintenance_mode)
|
|
{
|
|
if(deviceStatuses["rotary_switch_state"] == "Manual")
|
|
{
|
|
bits.push(0);
|
|
bits.push(1);
|
|
}
|
|
|
|
if(deviceStatuses["rotary_switch_state"] == "Automatic")
|
|
{
|
|
bits.push(0);
|
|
bits.push(0);
|
|
}
|
|
|
|
if(deviceStatuses["rotary_switch_state"] == "Off")
|
|
{
|
|
bits.push(1);
|
|
bits.push(0);
|
|
}
|
|
}
|
|
else{
|
|
bits.push(1);
|
|
bits.push(1);
|
|
}
|
|
|
|
//Dverový kontakt
|
|
if(deviceStatuses["door_condition"] == "closed")
|
|
{
|
|
bits.push(0);
|
|
}
|
|
else
|
|
{
|
|
bits.push(1);
|
|
}
|
|
|
|
//EM
|
|
if(deviceStatuses["em"] == "NOK")
|
|
{
|
|
bits.push(1);
|
|
}
|
|
else
|
|
{
|
|
bits.push(0);
|
|
}
|
|
|
|
//Teplomer
|
|
if(deviceStatuses["temperature"] == "NOK")
|
|
{
|
|
bits.push(1);
|
|
}
|
|
else
|
|
{
|
|
bits.push(0);
|
|
}
|
|
|
|
//Batéria
|
|
if(deviceStatuses["battery"] == "NOK")
|
|
{
|
|
bits.push(1);
|
|
}
|
|
else
|
|
{
|
|
bits.push(0);
|
|
}
|
|
|
|
//Zdroj
|
|
if(deviceStatuses["power_supply"] == "NOK")
|
|
{
|
|
bits.push(1);
|
|
}
|
|
else
|
|
{
|
|
bits.push(0);
|
|
}
|
|
|
|
//MN
|
|
if(deviceStatuses["master_node"] == "NOK")
|
|
{
|
|
bits.push(1);
|
|
}
|
|
else
|
|
{
|
|
bits.push(0);
|
|
}
|
|
|
|
//výpadok napätia na fáze
|
|
if(deviceStatuses["no_voltage"] == "NOK")
|
|
{
|
|
bits.push(1);
|
|
}
|
|
else
|
|
{
|
|
bits.push(0);
|
|
}
|
|
|
|
if(deviceStatuses["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 - deviceStatuses", deviceStatuses);
|
|
// 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;
|
|
}
|
|
|
|
|
|
function checkFinalRVOStatus() {
|
|
|
|
// we check if any of these pins values are 0 --> it means status RVO is "NOK"
|
|
// pinIndex 6 is door_condition - if open in maintenance mode - status = OK
|
|
|
|
//set RVO state
|
|
|
|
let status = "OK";
|
|
|
|
if(deviceStatuses["em"] == "NOK")
|
|
{
|
|
let writeToFile = errorHandler.processMessage("checkFinalRVOStatus: EM status is NOK");
|
|
if(writeToFile) errLogger.error("checkFinalRVOStatus: EM status is NOK");
|
|
|
|
status = "NOK";
|
|
}
|
|
|
|
if(deviceStatuses["twilight_sensor"] == "NOK")
|
|
{
|
|
let writeToFile = errorHandler.processMessage("checkFinalRVOStatus: twilight_sensor is NOK");
|
|
if(writeToFile) errLogger.error("checkFinalRVOStatus: twilight sensor is NOK");
|
|
|
|
status = "NOK";
|
|
}
|
|
|
|
//ak teplomer NOK, rvo nok
|
|
if(deviceStatuses["temperature"] == "NOK")
|
|
{
|
|
|
|
let writeToFile = errorHandler.processMessage("checkFinalRVOStatus: temperature status is NOK");
|
|
if(writeToFile) errLogger.error("checkFinalRVOStatus: temperature status is NOK");
|
|
|
|
status = "NOK";
|
|
}
|
|
|
|
if(status == "OK")
|
|
{
|
|
let pinIndexes = [1, 4, 6];
|
|
if(controller_type == 'unipi') pinIndexes = ['input1_01', 'input1_04', 'input1_05'];
|
|
|
|
//console.log('-------- previousValues', previousValues);
|
|
|
|
for (const pinIndex of pinIndexes) {
|
|
if (previousValues[pinIndex] === 0) {
|
|
|
|
if ((pinIndex === 6 || pinIndex === 'input1_01' || pinIndex === 'input1_05') && FLOW.OMS_maintenance_mode) continue;
|
|
|
|
let writeToFile = errorHandler.processMessage("checkFinalRVOStatus: value is 0");
|
|
if(writeToFile) errLogger.error("checkFinalRVOStatus: value is 0", pinsData[pinIndex].type);
|
|
|
|
status = "NOK";
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// battery status. If value is 1 - battery is NOK
|
|
if (previousValues[5] === 1)
|
|
{
|
|
let writeToFile = errorHandler.processMessage("checkFinalRVOStatus: NOK status generated by battery");
|
|
if(writeToFile) errLogger.error("checkFinalRVOStatus: NOK status generated by battery");
|
|
|
|
status = "NOK";
|
|
}
|
|
|
|
//console.log("FLOW.OMS_masterNodeIsResponding", FLOW.OMS_masterNodeIsResponding);
|
|
|
|
if(!FLOW.OMS_masterNodeIsResponding)
|
|
{
|
|
//errLogger.error("Master node is not responding");
|
|
errorHandler.sendMessageToService("Master node is not responding");
|
|
status = "NOK";
|
|
|
|
deviceStatuses["master_node"] = "NOK";
|
|
}
|
|
else deviceStatuses["master_node"] = "OK";
|
|
|
|
//console.log("checkFinalRVOStatus", status);
|
|
if(FLOW.OMS_no_voltage.size > 0)
|
|
{
|
|
let writeToFile = errorHandler.processMessage("no voltage detected");
|
|
if(writeToFile) errLogger.error("no voltage detected", FLOW.OMS_no_voltage);
|
|
|
|
status = "NOK";
|
|
|
|
deviceStatuses["no_voltage"] = "NOK";
|
|
}
|
|
else deviceStatuses["no_voltage"] = "OK";
|
|
|
|
if(status == "NOK")
|
|
{
|
|
sendTelemetry({status: "NOK"}, FLOW.OMS_rvo_tbname);
|
|
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
// 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 = {status: "OK"};
|
|
let dataToTb, 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;
|
|
return;
|
|
}
|
|
|
|
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", edgeName, "main_switch_has_been_turned_off", {}, "", SEND_TO.tb, instance , "state_of_main_switch");
|
|
values["status"] = "NOK";
|
|
|
|
deviceStatuses["state_of_main_switch"] = "Off";
|
|
}
|
|
else if (newPinValue === 1 && newPinValue !== previousValues[pinIndex])
|
|
{
|
|
sendNotification("switchLogic", edgeName, "main_switch_has_been_turned_on", {}, "", SEND_TO.tb, instance , "state_of_main_switch");
|
|
|
|
deviceStatuses["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";
|
|
|
|
deviceStatuses["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
|
|
|
|
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", edgeName, ERRWEIGHT.ALERT, "Power supply is not OK", "", SEND_TO.tb, instance);
|
|
sendNotification("switchLogic", edgeName, "power_supply_has_disconnected_input", {}, "", SEND_TO.tb, instance, "power_supply");
|
|
values["status"] = "NOK";
|
|
|
|
deviceStatuses["power_supply"] = "NOK";
|
|
}
|
|
else if (newPinValue === 1 && newPinValue !== previousValues[pinIndex])
|
|
{
|
|
//sendNotification("switchLogic", edgeName, ERRWEIGHT.NOTICE, "Power supply is is OK", "", SEND_TO.tb, instance);
|
|
sendNotification("switchLogic", edgeName, "power_supply_works_correctly", {}, "", SEND_TO.tb, instance, "power_supply");
|
|
|
|
deviceStatuses["power_supply"] = "OK";
|
|
}
|
|
}
|
|
//Batéria - pin 5
|
|
else if (type === "battery")
|
|
{
|
|
if (newPinValue === 1 && newPinValue !== previousValues[pinIndex])
|
|
{
|
|
//sendNotification("switchLogic", edgeName, ERRWEIGHT.ERROR, "Battery is not OK", "", SEND_TO.tb, instance);
|
|
sendNotification("switchLogic", edgeName, "battery_level_is_low", {}, "", SEND_TO.tb, instance, "battery_level");
|
|
values["status"] = "NOK";
|
|
|
|
deviceStatuses["battery"] = "NOK";
|
|
}
|
|
else if (newPinValue === 0 && newPinValue !== previousValues[pinIndex])
|
|
{
|
|
//sendNotification("switchLogic", edgeName, ERRWEIGHT.NOTICE, "Battery is OK", "", SEND_TO.tb, instance);
|
|
sendNotification("switchLogic", edgeName, "battery_level_is_ok", {}, "", SEND_TO.tb, instance, "battery_level");
|
|
|
|
deviceStatuses["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 (newPinValue != previousValues[pinIndex])
|
|
{
|
|
//sendNotification("switchLogic", edgeName, ERRWEIGHT.NOTICE, `RVO door ${value}`, "", SEND_TO.tb, instance, "rvo_door");
|
|
//TODO ? sendNotification("switchLogic", edgeName, "door_value", {value: value}, "", SEND_TO.tb, instance, "rvo_door");
|
|
}
|
|
|
|
if (value === "open" && FLOW.OMS_maintenance_mode)
|
|
{
|
|
sendNotification("switchLogic", edgeName, "door_has_been_open", {}, "", SEND_TO.tb, instance, "rvo_door");
|
|
}
|
|
|
|
if (value === "open" && !FLOW.OMS_maintenance_mode)
|
|
{
|
|
//sendNotification("switchLogic", edgeName, ERRWEIGHT.WARNING, "RVO open door out of maintenance mode", "", SEND_TO.tb, instance);
|
|
sendNotification("switchLogic", edgeName, "door_has_been_open_without_permision_alarm_is_on", {}, "", SEND_TO.tb, instance, "rvo_door");
|
|
values["status"] = "NOK";
|
|
|
|
//console.log(door_has_been_open_without_permision_alarm_is_on);
|
|
|
|
// 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") turnOnAlarm();
|
|
}
|
|
|
|
if (value === "closed")
|
|
{
|
|
if(alarmStatus == "ON") turnOffAlarm();
|
|
//turnOffAlarm();
|
|
|
|
sendNotification("switchLogic", edgeName, "door_has_been_closed", {}, "", SEND_TO.tb, instance, "rvo_door");
|
|
}
|
|
|
|
deviceStatuses["door_condition"] = value;
|
|
|
|
}
|
|
//lux sensor
|
|
else if(type == "twilight_sensor")
|
|
{
|
|
//! TODO - to show nok status, if lux value is not changing more then 10 times. From unipi for example comes value from 0-1000.
|
|
//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.
|
|
values["status"] = "OK";
|
|
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;
|
|
values["status"] = "NOK";
|
|
let value = twilight_sensor_array.shift();
|
|
//sendNotification("switchLogic", edgeName, ERRWEIGHT.ERROR, "Lux sensor error", {"Repeating value": value}, SEND_TO.tb, instance );
|
|
newPinValue = 0;
|
|
}
|
|
else if (set.size !== 1 && twilightError)
|
|
{
|
|
//sendNotification("switchLogic", edgeName, 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)
|
|
{
|
|
values["status"] = "NOK";
|
|
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")
|
|
{
|
|
//sendNotification("switchLogic", edgeName, ERRWEIGHT.INFO, `State of contactor ${line} is now ${value}`, "", SEND_TO.tb, instance );
|
|
|
|
if(!(deviceStatuses["state_of_contactor"][line] == value))
|
|
{
|
|
sendNotification("switchLogic", edgeName, "state_of_contactor_for_line", {line: line, value: value}, "", SEND_TO.tb, instance );
|
|
}
|
|
else
|
|
{
|
|
deviceStatuses["state_of_contactor"][line] = value;
|
|
}
|
|
|
|
//true, false
|
|
if(value === "On") value = true;
|
|
else if(value === "Off") value = false;
|
|
|
|
//modify table relays
|
|
dbRelays.modify({ contactor: newPinValue }).where("line", line).make(function(builder) {
|
|
|
|
builder.callback(function(err, response) {
|
|
|
|
/*
|
|
if(useTurnOffCounter)
|
|
{
|
|
turnOffCounter--;
|
|
|
|
if(turnOffCounter <= 0)
|
|
{
|
|
useTurnOffCounter = false;
|
|
}
|
|
}
|
|
*/
|
|
|
|
if(err == undefined)
|
|
{
|
|
|
|
let time = 0;
|
|
if(value) time = 1000 * 10;//10 sekund
|
|
|
|
let dataChanged = false;
|
|
if(relaysData[line].contactor != value) dataChanged = true;
|
|
relaysData[line].contactor = value;
|
|
|
|
//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);
|
|
}
|
|
|
|
|
|
});
|
|
});
|
|
}
|
|
|
|
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]});
|
|
|
|
deviceStatuses["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});
|
|
|
|
deviceStatuses["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";
|
|
|
|
deviceStatuses["state_of_breaker"][line] = value;
|
|
|
|
reportLineStatus(line);
|
|
}
|
|
|
|
values[type] = value;
|
|
|
|
//if(FLOW.OMS_rvo_tbname == tbname) values["statecode"] = calculateStateCode();
|
|
|
|
if(pinsData.hasOwnProperty(pinIndex))
|
|
{
|
|
let valueChanged = false;
|
|
if(newPinValue != previousValues[pinIndex])
|
|
{
|
|
valueChanged = true;
|
|
//pin was changed
|
|
previousValues[pinIndex] = newPinValue;
|
|
}
|
|
|
|
let result = checkFinalRVOStatus();
|
|
if(!result && line == 0)
|
|
{
|
|
values["status"] = "NOK";
|
|
}
|
|
|
|
if(type == "state_of_contactor") valueChanged = true;
|
|
if(type == "rotary_switch_state") valueChanged = true;
|
|
if(type === "state_of_breaker")
|
|
{
|
|
//console.log(type, values, valueChanged);
|
|
}
|
|
|
|
if(FLOW.OMS_rvo_tbname == "")
|
|
{
|
|
console.log("FLOW.OMS_rvo_tbname is EMPTY");
|
|
}
|
|
|
|
if(FLOW.OMS_rvo_tbname == tbname)
|
|
{
|
|
values["statecode"] = calculateStateCode();
|
|
//console.log('**********************', type, values, valueChanged, FLOW.OMS_rvo_tbname, tbname);
|
|
}
|
|
|
|
if(valueChanged)
|
|
{
|
|
sendTelemetry(values, tbname);
|
|
}
|
|
|
|
if(type == "rotary_switch_state")
|
|
{
|
|
if(FLOW.OMS_maintenance_mode) value = "maintenance";
|
|
value = value.toLowerCase();
|
|
|
|
let values = {};
|
|
values["power_mode"] = value;
|
|
|
|
sendTelemetry(values, tbname);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
logger.debug("no pinIndex", pinsData[pinIndex], pinsData);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
function sendTelemetry(values, tbname)
|
|
{
|
|
let dataToTb = {
|
|
[tbname]: [
|
|
{
|
|
"ts": Date.now(),
|
|
"values": values
|
|
}
|
|
]
|
|
}
|
|
|
|
instance.send(SEND_TO.tb, dataToTb);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//! 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
|
|
// {
|
|
// '16': { pin: '16', type: 'twilight_sensor', line: 0 },
|
|
// al_mswitch: { pin: 'al_mswitch', type: 'state_of_main_switch', line: 0 },
|
|
// al_rswitch1: { pin: 'al_rswitch1', type: 'rotary_switch_state', line: 0 },
|
|
// al_rswitch2: { pin: 'al_rswitch2', type: 'rotary_switch_state', line: 0 },
|
|
// al_power: { pin: 'al_power', type: 'power_supply', line: 0 },
|
|
// al_battery: { pin: 'al_battery', type: 'battery', line: 0 },
|
|
// al_door: { pin: 'al_door', type: 'door_condition', line: 0 },
|
|
// al_breaker1: { pin: 'al_breaker1', type: 'state_of_breaker', line: 1 },
|
|
// al_breaker2: { pin: 'al_breaker2', type: 'state_of_breaker', line: 2 },
|
|
// al_breaker3: { pin: 'al_breaker3', type: 'state_of_breaker', line: 3 },
|
|
// al_breaker4: { pin: 'al_breaker4', type: 'state_of_breaker', line: 4 },
|
|
// al_relay_1: { pin: 'al_relay_1', type: 'state_of_contactor', line: 1 },
|
|
// al_relay_2: { pin: 'al_relay_2', type: 'state_of_contactor', line: 2 },
|
|
// al_relay_3: { pin: 'al_relay_3', type: 'state_of_contactor', line: 3 },
|
|
// al_relay_4: { pin: 'al_relay_4', type: 'state_of_contactor', line: 4 },
|
|
// '28744F7791180257': { pin: '28744F7791180257', type: 'temperature', 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": ""
|
|
// }
|
|
// }
|
|
// }
|
|
// ]
|
|
// }
|