Actual running flowserver on test panel LM 10.0.0.5

This commit is contained in:
rasta5man 2024-04-13 20:00:05 +02:00
commit 67c503d980
57 changed files with 16678 additions and 0 deletions

View file

@ -0,0 +1,163 @@
class DataToTbHandler
{
constructor(index) {
this.index = index;
this.previousValues = {};
this.debug = false;
this.messageCounter = 0;
this.sender = "";
}
dump()
{
console.log("----------------------------");
console.log("previousValues", this.previousValues);
console.log("----------------------------");
}
setSender(sender)
{
this.sender = sender;
}
isEmptyObject( obj ) {
for ( var name in obj ) {
return false;
}
return true;
}
sendToTb(dataToTb, instance)
{
if(!FLOW.OMS_brokerready)
{
return dataToTb;
}
let keys = Object.keys(dataToTb);
if(keys.length == 0)
{
if(this.debug) console.log("sendToTb received epty object", dataToTb);
return;
}
let tbname = keys[0];
let ts;
let arrayOfValues = dataToTb[tbname];
let arrayOfValuesToSend = [];
for(let i = 0; i < arrayOfValues.length; i++)
{
ts = arrayOfValues[i].ts;
//console.log("sendToTb------------>before", arrayOfValues[i].values, tbname);
let values = this.prepareValuesForTb(tbname, ts, arrayOfValues[i].values);
//console.log("sendToTb------------>after", values);
if(!this.isEmptyObject(values))
{
arrayOfValuesToSend.push({ts: ts, values: values});
}
}
if(arrayOfValuesToSend.length == 0)
{
//if(this.debug) console.log("data not sent - empty array");
return;
}
/*
let dataToTb = {
[tbname]: [
{
"ts": Date.now(),
"values": values
}
]
}
*/
this.messageCounter++;
let dataToTbModified = {
[tbname]: arrayOfValuesToSend
}
//console.log(this.sender + " DATA SEND TO TB ", tbname, this.messageCounter, new Date(ts), dataToTbModified[tbname][0].values, this.instance);
if(this.debug) console.log(this.sender + " DATA SEND TO TB ", this.index, tbname, arrayOfValuesToSend);
instance.send(this.index, dataToTbModified);
}
getDiffTimestamp(key)
{
let seconds = 60*60;//1h
//seconds = 1;//for testing
//TODO set different value for given key!!!
//if(key == "status") seconds = 2*60*60;//2h
let timestampDiffToRemoveKey = seconds*1000;
return timestampDiffToRemoveKey;
}
prepareValuesForTb(tbname, timestamp, values)
{
let keys = Object.keys(values);
if(!this.previousValues.hasOwnProperty(tbname))
{
this.previousValues[tbname] = {};
}
//if(this.debug) console.log("prepareValuesForTb", tbname, timestamp, values);
for(let i = 0; i < keys.length; i++)
{
let key = keys[i];
let value = values[key];
if(!this.previousValues[tbname].hasOwnProperty(key))
{
this.previousValues[tbname][key] = {ts: timestamp, value: value};
continue;
}
if(this.previousValues[tbname][key].value === value)
{
let diff = timestamp - this.previousValues[tbname][key].ts;
let timestampDiffToRemoveKey = this.getDiffTimestamp(key);
if(diff > timestampDiffToRemoveKey)
{
this.previousValues[tbname][key].ts = Date.now();
//if(this.debug) console.log(this.sender + ": update ts for key", key, "diff is", diff, "messageCounter", this.messageCounter);
}
else
{
delete values[key];
//if(this.debug) console.log(this.sender + ": delete key", key, "diff is", diff, "messageCounter", this.messageCounter, timestampDiffToRemoveKey);
}
}
else
{
this.previousValues[tbname][key].value = value;
this.previousValues[tbname][key].ts = timestamp;
}
}
return values;
}
}
module.exports = DataToTbHandler;

View file

@ -0,0 +1,124 @@
const { MD5 } = require('./md5.js');
const { networkInterfaces } = require('os');
class ErrorToServiceHandler
{
constructor() {
this.previousValues = {};
this.projects_id = undefined;
this.message_type = "error_message";
const nets = networkInterfaces();
this.ipAddresses = Object.create(null); // Or just '{}', an empty object
for (const name of Object.keys(nets)) {
for (const net of nets[name]) {
// Skip over non-IPv4 and internal (i.e. 127.0.0.1) addresses
if (net.family === 'IPv4' && !net.internal) {
if (!this.ipAddresses[name]) {
this.ipAddresses[name] = [];
}
this.ipAddresses[name].push(net.address);
}
}
}
//console.log(this.ipAddresses);
}
setProjectsId(projects_id)
{
this.projects_id = projects_id;
}
processMessage(message, seconds, message_type)
{
if(Array.isArray(message)) message = message.join(', ');
//keep in memory - default value is 1h
if (seconds === undefined) seconds = 60*60;
if(message_type) this.message_type = message_type;
let key = MD5(message);
let timestamp = new Date().getTime();
if(!this.previousValues.hasOwnProperty(key))
{
this.previousValues[key] = {ts: timestamp, duration: seconds};
}
let diff = (timestamp - this.previousValues[key].ts);
if(diff < this.previousValues[key].duration*1000) return false;
this.previousValues[key].ts = timestamp;
return true;
}
sendMessageToService(message, seconds, message_type)
{
let f = this.processMessage(message, seconds, message_type);
if(!f) return;
/*
//-------------
if(message_type == undefined) message_type = "error_message";
if(Array.isArray(message)) message = message.join(', ');
let key = MD5(message);
let timestamp = new Date().getTime();
//keep in memory
if (seconds === undefined) seconds = 60*60;
if(!this.previousValues.hasOwnProperty(key))
{
this.previousValues[key] = {ts: timestamp, duration: seconds};
}
let diff = (timestamp - this.previousValues[key].ts);
if(diff < this.previousValues[key].duration*1000) return;
this.previousValues[key].ts = timestamp;
*/
//-------------------------
//send to service
let dataToInfoSender = {id: this.projects_id};
//js_error || error_message
dataToInfoSender[this.message_type] = message;
dataToInfoSender.ipAddresses = this.ipAddresses;
console.log("ErrorToServiceHandler------------------------>send to service", dataToInfoSender);
//TODO UGLY!!!
if(this.projects_id === undefined) this.projects_id = FLOW.OMS_projects_id;
/*
if(this.projects_id === undefined)
{
console.log("this.projects_id is undefined");
return;
}
*/
RESTBuilder.make(function(builder) {
builder.method('POST');
builder.post(dataToInfoSender);
builder.url('http://192.168.252.2:8004/sentmessage');
builder.callback(function(err, response, output) {
console.log("process.on error send", err, response, output, dataToInfoSender);
});
});
}
}
module.exports = ErrorToServiceHandler;

44
flow/helper/db_helper.js Normal file
View file

@ -0,0 +1,44 @@
function promisifyBuilder(builder)
{
return new Promise((resolve, reject) => {
try{
builder.callback(function(err, response) {
if(err != null) reject(err);
resolve(response);
});
} catch (error) {
reject(error);
}
})
}
function makeMapFromDbResult(response, ...keys)
{
let s = "-";
let data = {};
for(let i = 0; i < response.length; i++)
{
let record = response[i];
let k = [];
for(let j = 0; j < keys.length; j++)
{
k.push( record[keys[j]] );
}
let key = k.join(s);
data[ key ] = record;
}
return data;
}
module.exports = {
promisifyBuilder,
makeMapFromDbResult
}

View file

@ -0,0 +1,72 @@
//key is device, value = str
let sentValues= {};
function sendError(func, device, weight, str, extra, tb_output, instance, type) {
// if ((weight === ERRWEIGHT.DEBUG) && (instance.CONFIG.debug === false)){
// return; // Allow debug messages only if CONFIG.debug is active
// }
let key = device;
if(type != undefined) key = type;
if(sentValues.hasOwnProperty(key))
{
if(sentValues[key] == str)
{
return;
}
}
sentValues[key] = str;
let content = {
"type": weight,
"status": "new",
"source": {
"func":func,
"component":instance.id,
"component_name":instance.name,
"edge":device
},
"message":str,
"message_data": extra
};
let msg = {};
msg[device] = [
{
"ts": Date.now(),
"values": {
"_event":content
}
}
];
// Msg can be outputted from components only after configuration
/*if (canSendErrData()){
sendBufferedErrors();
} else {
bufferError(msg);
}*/
instance.send(tb_output, msg); // Even if error server is unavailable, send this message to output, for other possible component connections
}
let ERRWEIGHT = {
EMERGENCY: "emergency", // System unusable
ALERT: "alert", // Action must be taken immidiately
CRITICAL: "critical", // Component unable to function
ERROR: "error", // Error, but component able to recover from it
WARNING: "warning", // Possibility of error, system running futher
NOTICE: "notice", // Significant message but not an error, things user might want to know about
INFO: "informational", // Info
DEBUG: "debug" // Debug - only if CONFIG.debug is enabled
};
module.exports = {
sendError,
ERRWEIGHT
}

View file

@ -0,0 +1,56 @@
const ERRWEIGHT = {
EMERGENCY: "emergency", // System unusable
ALERT: "alert", // Action must be taken immidiately
CRITICAL: "critical", // Component unable to function
ERROR: "error", // Error, but component able to recover from it
WARNING: "warning", // Possibility of error, system running futher
NOTICE: "notice", // Significant message but not an error, things user might want to know about
INFO: "informational", // Info
DEBUG: "debug" // Debug - only if CONFIG.debug is enabled
};
function sendError(func, device, weight, str, extra){
if ((weight === ERRWEIGHT.DEBUG) && (instance.CONFIG.debug === false)){
return; // Allow debug messages only if CONFIG.debug is active
}
let content = {
"type": weight,
"status": "new",
"source": {
"func":func,
"component":instance.id,
"component_name":instance.name,
"edge":myEdge
},
"message":str,
"message_data": extra
};
let msg = {};
msg[device] = [
{
"ts": Date.now(),
"values": {
"_event":content
}
}
];
// Msg can be outputted from components only after configuration
/*if (canSendErrData()){
sendBufferedErrors();
} else {
bufferError(msg);
}*/
instance.send(0, msg); // Even if error server is unavailable, send this message to output, for other possible component connections
}
module.exports = {
sendError,
ERRWEIGHT,
}

5
flow/helper/md5.js Normal file
View file

@ -0,0 +1,5 @@
function MD5(d){var r = M(V(Y(X(d),8*d.length)));return r.toLowerCase()};function M(d){for(var _,m="0123456789ABCDEF",f="",r=0;r<d.length;r++)_=d.charCodeAt(r),f+=m.charAt(_>>>4&15)+m.charAt(15&_);return f}function X(d){for(var _=Array(d.length>>2),m=0;m<_.length;m++)_[m]=0;for(m=0;m<8*d.length;m+=8)_[m>>5]|=(255&d.charCodeAt(m/8))<<m%32;return _}function V(d){for(var _="",m=0;m<32*d.length;m+=8)_+=String.fromCharCode(d[m>>5]>>>m%32&255);return _}function Y(d,_){d[_>>5]|=128<<_%32,d[14+(_+64>>>9<<4)]=_;for(var m=1732584193,f=-271733879,r=-1732584194,i=271733878,n=0;n<d.length;n+=16){var h=m,t=f,g=r,e=i;f=md5_ii(f=md5_ii(f=md5_ii(f=md5_ii(f=md5_hh(f=md5_hh(f=md5_hh(f=md5_hh(f=md5_gg(f=md5_gg(f=md5_gg(f=md5_gg(f=md5_ff(f=md5_ff(f=md5_ff(f=md5_ff(f,r=md5_ff(r,i=md5_ff(i,m=md5_ff(m,f,r,i,d[n+0],7,-680876936),f,r,d[n+1],12,-389564586),m,f,d[n+2],17,606105819),i,m,d[n+3],22,-1044525330),r=md5_ff(r,i=md5_ff(i,m=md5_ff(m,f,r,i,d[n+4],7,-176418897),f,r,d[n+5],12,1200080426),m,f,d[n+6],17,-1473231341),i,m,d[n+7],22,-45705983),r=md5_ff(r,i=md5_ff(i,m=md5_ff(m,f,r,i,d[n+8],7,1770035416),f,r,d[n+9],12,-1958414417),m,f,d[n+10],17,-42063),i,m,d[n+11],22,-1990404162),r=md5_ff(r,i=md5_ff(i,m=md5_ff(m,f,r,i,d[n+12],7,1804603682),f,r,d[n+13],12,-40341101),m,f,d[n+14],17,-1502002290),i,m,d[n+15],22,1236535329),r=md5_gg(r,i=md5_gg(i,m=md5_gg(m,f,r,i,d[n+1],5,-165796510),f,r,d[n+6],9,-1069501632),m,f,d[n+11],14,643717713),i,m,d[n+0],20,-373897302),r=md5_gg(r,i=md5_gg(i,m=md5_gg(m,f,r,i,d[n+5],5,-701558691),f,r,d[n+10],9,38016083),m,f,d[n+15],14,-660478335),i,m,d[n+4],20,-405537848),r=md5_gg(r,i=md5_gg(i,m=md5_gg(m,f,r,i,d[n+9],5,568446438),f,r,d[n+14],9,-1019803690),m,f,d[n+3],14,-187363961),i,m,d[n+8],20,1163531501),r=md5_gg(r,i=md5_gg(i,m=md5_gg(m,f,r,i,d[n+13],5,-1444681467),f,r,d[n+2],9,-51403784),m,f,d[n+7],14,1735328473),i,m,d[n+12],20,-1926607734),r=md5_hh(r,i=md5_hh(i,m=md5_hh(m,f,r,i,d[n+5],4,-378558),f,r,d[n+8],11,-2022574463),m,f,d[n+11],16,1839030562),i,m,d[n+14],23,-35309556),r=md5_hh(r,i=md5_hh(i,m=md5_hh(m,f,r,i,d[n+1],4,-1530992060),f,r,d[n+4],11,1272893353),m,f,d[n+7],16,-155497632),i,m,d[n+10],23,-1094730640),r=md5_hh(r,i=md5_hh(i,m=md5_hh(m,f,r,i,d[n+13],4,681279174),f,r,d[n+0],11,-358537222),m,f,d[n+3],16,-722521979),i,m,d[n+6],23,76029189),r=md5_hh(r,i=md5_hh(i,m=md5_hh(m,f,r,i,d[n+9],4,-640364487),f,r,d[n+12],11,-421815835),m,f,d[n+15],16,530742520),i,m,d[n+2],23,-995338651),r=md5_ii(r,i=md5_ii(i,m=md5_ii(m,f,r,i,d[n+0],6,-198630844),f,r,d[n+7],10,1126891415),m,f,d[n+14],15,-1416354905),i,m,d[n+5],21,-57434055),r=md5_ii(r,i=md5_ii(i,m=md5_ii(m,f,r,i,d[n+12],6,1700485571),f,r,d[n+3],10,-1894986606),m,f,d[n+10],15,-1051523),i,m,d[n+1],21,-2054922799),r=md5_ii(r,i=md5_ii(i,m=md5_ii(m,f,r,i,d[n+8],6,1873313359),f,r,d[n+15],10,-30611744),m,f,d[n+6],15,-1560198380),i,m,d[n+13],21,1309151649),r=md5_ii(r,i=md5_ii(i,m=md5_ii(m,f,r,i,d[n+4],6,-145523070),f,r,d[n+11],10,-1120210379),m,f,d[n+2],15,718787259),i,m,d[n+9],21,-343485551),m=safe_add(m,h),f=safe_add(f,t),r=safe_add(r,g),i=safe_add(i,e)}return Array(m,f,r,i)}function md5_cmn(d,_,m,f,r,i){return safe_add(bit_rol(safe_add(safe_add(_,d),safe_add(f,i)),r),m)}function md5_ff(d,_,m,f,r,i,n){return md5_cmn(_&m|~_&f,d,_,r,i,n)}function md5_gg(d,_,m,f,r,i,n){return md5_cmn(_&f|m&~f,d,_,r,i,n)}function md5_hh(d,_,m,f,r,i,n){return md5_cmn(_^m^f,d,_,r,i,n)}function md5_ii(d,_,m,f,r,i,n){return md5_cmn(m^(_|~f),d,_,r,i,n)}function safe_add(d,_){var m=(65535&d)+(65535&_);return(d>>16)+(_>>16)+(m>>16)<<16|65535&m}function bit_rol(d,_){return d<<_|d>>>32-_}
module.exports = {
MD5
}

View file

@ -0,0 +1,135 @@
const { promisifyBuilder, makeMapFromDbResult } = require('./db_helper.js');
const dbNotifications = TABLE("notifications");
//key is device, value = str
let sentValues= {};
let notificationsData = {};
let ERRWEIGHT = {
EMERGENCY: "emergency", // System unusable
ALERT: "alert", // Action must be taken immidiately
CRITICAL: "critical", // Component unable to function
ERROR: "error", // Error, but component able to recover from it
WARNING: "warning", // Possibility of error, system running futher
NOTICE: "notice", // Significant message but not an error, things user might want to know about
INFO: "informational", // Info
DEBUG: "debug" // Debug - only if CONFIG.debug is enabled
};
function getKey(map, val) {
return Object.keys(map).findItem(key => map[key] === val);
}
//https://stackoverflow.com/questions/41117799/string-interpolation-on-variable
var template = (tpl, args) => tpl.replace(/\${(\w+)}/g, (_, v) => args[v]);
async function initNotifications()
{
let response = await promisifyBuilder(dbNotifications.find());
notificationsData = makeMapFromDbResult(response, "key");
console.log("initNotifications done" );
}
function sendNotification(func, device, key, params, extra, tb_output, instance, saveKey) {
let storeToSendValues = true;
if(saveKey == undefined) storeToSendValues = false;
let lang = FLOW.OMS_language;
if(lang != "en" || lang != "sk") lang = "en";
let tpl = key;
let weight = "";
if(notificationsData[key])
{
weight = notificationsData[key].weight;
weight = weight.toLowerCase();
tpl = notificationsData[key][lang];
tpl = template(tpl, params);
}
else
{
console.error("sendNotification: Notifications: undefined key", key, func, notificationsData);
return false;
}
//detect invalid err weight
if(getKey(ERRWEIGHT, weight) == undefined)
{
console.error("sendNotification: Notifications: undefined weight", weight, key, func);
return false;
}
if(sentValues.hasOwnProperty(saveKey))
{
if(sentValues[saveKey] == tpl)
{
return false;
}
}
if(sentValues[saveKey] == undefined)
{
if(storeToSendValues)
{
//do not send - flow is was started
sentValues[saveKey] = tpl;
return false;
}
}
if(saveKey == "rvo_door")
{
//console.log("******", saveKey, sentValues[saveKey], tpl);
}
if(storeToSendValues) sentValues[saveKey] = tpl;
let str = FLOW.OMS_rvo_name;
if(str != "") str = str + ": ";
str = str + tpl;
let content = {
"type": weight,
"status": "new",
"source": {
"func":func,
"component":instance.id,
"component_name":instance.name,
"edge":device
},
"message":str,
"message_data": extra
};
let msg = {};
msg[device] = [
{
"ts": Date.now(),
"values": {
"_event":content
}
}
];
// Msg can be outputted from components only after configuration
/*if (canSendErrData()){
sendBufferedErrors();
} else {
bufferError(msg);
}*/
instance.send(tb_output, msg); // Even if error server is unavailable, send this message to output, for other possible component connections
return true;
}
module.exports = {
sendNotification,
initNotifications,
ERRWEIGHT
}

144
flow/helper/register.js Normal file
View file

@ -0,0 +1,144 @@
/*
0 - cislo registra / prikaz
1 - recepient - 0 = master, 1 = slave (slave je automaticky group a broadcast)
2 - r/rw - read/write
3- register name - nazov registra / prikazu (len pre info - zobrazenie v aplikacii)
4,5,6,7, - jednotlive byte-y - nazov byte-u
4-7 - RES. a prazdny string "" sa nezobrazia!!!
*/
//124 zaznamov
const registers = [
["0","1","R","Status","","",""],
["1","1","RW","Dimming","R-Channel ","G-Channel","B-Channel ","W - Channel"],
["2","1","R","Device types","","",".",""],
["3","1","RW","Group addresses 1-4","Groups Add. 4","Groups Add. 3","Groups Add. 2","Groups Add. 1"],
["4","1","RW","Group addresses 5-8","Groups Add. 8","Groups Add. 7","Groups Add. 6","Groups Add. 5"],
["5","1","RW","Serial number (MAC)","","","",""],
["6","1","RW","Time of dusk","HH","MM","SS","EXTRA"],
["7","1","RW","Time of dawn","HH","MM","SS","EXTRA"],
["8","1","RW","Time Schedule settings","TBD","TBD","Movement sensor","Time Schedule"],
["9","1","RW","TS1 Time point 1","HH","MM","SS","Ext. Device"],
["10","1","RW","TS1 Time point 1 Levels","R-Channel","G-Channel","B-Channel","W - Channel"],
["11","1","RW","TS1 Time point 2","HH","MM","SS","Ext. Device"],
["12","1","RW","TS1 Time point 2 Levels","R-Channel","G-Channel","B-Channel","W - Channel"],
["13","1","RW","TS1 Time point 3","HH","MM","SS","Ext. Device"],
["14","1","RW","TS1 Time point 3 Levels","R-Channel","G-Channel","B-Channel","W - Channel"],
["15","1","RW","TS1 Time point 4","HH","MM","SS","Ext. Device"],
["16","1","RW","TS1 Time point 4 Levels","R-Channel","G-Channel","B-Channel","W - Channel"],
["17","1","RW","TS1 Time point 5","HH","MM","SS","Ext. Device"],
["18","1","RW","TS1 Time point 5 Levels","R-Channel","G-Channel","B-Channel","W - Channel"],
["19","1","RW","TS1 Time point 6","HH","MM","SS","Ext. Device"],
["20","1","RW","TS1 Time point 6 Levels","R-Channel","G-Channel","B-Channel","W - Channel"],
["21","1","RW","TS1 Time point 7","HH","MM","SS","Ext. Device"],
["22","1","RW","TS1 Time point 7 Levels","R-Channel","G-Channel","B-Channel","W - Channel"],
["23","1","RW","TS1 Time point 8","HH","MM","SS","Ext. Device"],
["24","1","RW","TS1 Time point 8 Levels","R-Channel","G-Channel","B-Channel","W - Channel"],
["25","1","RW","TS1 Time point 9","HH","MM","SS","Ext. Device"],
["26","1","RW","TS1 Time point 9 Levels","R-Channel","G-Channel","B-Channel","W - Channel"],
["27","1","RW","TS1 Time point 10","HH","MM","SS","Ext. Device"],
["28","1","RW","TS1 Time point 10 Levels","R-Channel","G-Channel","B-Channel","W - Channel"],
["29","1","RW","TS1 Time point 11","HH","MM","SS","Ext. Device"],
["30","1","RW","TS1 Time point 11 Levels","R-Channel","G-Channel","B-Channel","W - Channel"],
["31","1","RW","TS1 Time point 12","HH","MM","SS","Ext. Device"],
["32","1","RW","TS1 Time point 12 Levels","R-Channel","G-Channel","B-Channel","W - Channel"],
["33","1","RW","TS1 Time point 13","HH","MM","SS","Ext. Device"],
["34","1","RW","TS1 Time point 13 Levels","R-Channel","G-Channel","B-Channel","W - Channel"],
["35","1","RW","TS1 Time point 14","HH","MM","SS","Ext. Device"],
["36","1","RW","TS1 Time point 14 Levels","R-Channel","G-Channel","B-Channel","W - Channel"],
["37","1","RW","TS1 Time point 15","HH","MM","SS","Ext. Device"],
["38","1","RW","TS1 Time point 15 Levels","R-Channel","G-Channel","B-Channel","W - Channel"],
["39","1","RW","TS1 Time point 16","HH","MM","SS","Ext. Device"],
["40","1","RW","TS1 Time point 16 Levels","R-Channel","G-Channel","B-Channel","W - Channel"],
["41","1","RW","TS2 Time point 1","HH","MM","SS","Ext. Device"],
["42","1","RW","TS2 Time point 1 Levels","R-Channel","G-Channel","B-Channel","W - Channel"],
["43","1","RW","TS2 Time point 2","HH","MM","SS","Ext. Device"],
["44","1","RW","TS2 Time point 2 Levels","R-Channel","G-Channel","B-Channel","W - Channel"],
["45","1","RW","TS2 Time point 3","HH","MM","SS","Ext. Device"],
["46","1","RW","TS2 Time point 3 Levels","R-Channel","G-Channel","B-Channel","W - Channel"],
["47","1","RW","TS2 Time point 4","HH","MM","SS","Ext. Device"],
["48","1","RW","TS2 Time point 4 Levels","R-Channel","G-Channel","B-Channel","W - Channel"],
["49","1","RW","TS2 Time point 5","HH","MM","SS","Ext. Device"],
["50","1","RW","TS2 Time point 5 Levels","R-Channel","G-Channel","B-Channel","W - Channel"],
["51","1","RW","TS2 Time point 6","HH","MM","SS","Ext. Device"],
["52","1","RW","TS2 Time point 6 Levels","R-Channel","G-Channel","B-Channel","W - Channel"],
["53","1","RW","TS2 Time point 7","HH","MM","SS","Ext. Device"],
["54","1","RW","TS2 Time point 7 Levels","R-Channel","G-Channel","B-Channel","W - Channel"],
["55","1","RW","TS2 Time point 8","HH","MM","SS","Ext. Device"],
["56","1","RW","TS2 Time point 8 Levels","R-Channel","G-Channel","B-Channel","W - Channel"],
["57","1","RW","TS2 Time point 9","HH","MM","SS","Ext. Device"],
["58","1","RW","TS2 Time point 9 Levels","R-Channel","G-Channel","B-Channel","W - Channel"],
["59","1","RW","TS2 Time point 10","HH","MM","SS","Ext. Device"],
["60","1","RW","TS2 Time point 10 Levels","R-Channel","G-Channel","B-Channel","W - Channel"],
["61","1","RW","TS2 Time point 11","HH","MM","SS","Ext. Device"],
["62","1","RW","TS2 Time point 11 Levels","R-Channel","G-Channel","B-Channel","W - Channel"],
["63","1","RW","TS2 Time point 12","HH","MM","SS","Ext. Device"],
["64","1","RW","TS2 Time point 12 Levels","R-Channel","G-Channel","B-Channel","W - Channel"],
["65","1","RW","TS2 Time point 13","HH","MM","SS","Ext. Device"],
["66","1","RW","TS2 Time point 13 Levels","R-Channel","G-Channel","B-Channel","W - Channel"],
["67","1","RW","TS2 Time point 14","HH","MM","SS","Ext. Device"],
["68","1","RW","TS2 Time point 14 Levels","R-Channel","G-Channel","B-Channel","W - Channel"],
["69","1","RW","TS2 Time point 15","HH","MM","SS","Ext. Device"],
["70","1","RW","TS2 Time point 15 Levels","R-Channel","G-Channel","B-Channel","W - Channel"],
["71","1","RW","TS2 Time point 16","HH","MM","SS","Ext. Device"],
["72","1","RW","TS2 Time point 16 Levels","R-Channel","G-Channel","B-Channel","W - Channel"],
["73","1","RW","Power meter status","TBD","","",""],
["74","1","R","Input Voltage","","","",""],
["75","1","R","Input Current","","","",""],
["76","1","R","Input Power","","","",""],
["77","1","R","Cos phi","","","",""],
["78","1","R","Frequency","","","",""],
["79","1","RW","Energy","","","",""],
["80","1","RW","Lifetime","","","",""],
["81","1","RW","Power on cycles (input)","","","",""],
["82","1","RW","Power on cycles (relay)","","","",""],
["83","1","R","Time since last power on","","","",""],
["84","1","R","Accelerometer data","","","",""],
["85","1","RW","GPS latitude","pos/neg","deg","min ","sec"],
["86","1","RW","GPS longitude","pos/neg","deg","min ","sec"],
["87","1","RW","Actual time","HH","MM","SS","RES."],
["88","1","RW","Actual date","Day of week","Day","Month","Year"],
["89","1","R","Production data 1","","","",""],
["90","1","R","Production data 2","","","",""],
["91","1","RW","Network ID","NID3","NID2","NID1","NID0"],
["95","1","RW","Actual Lux level from cabinet","RES.","RES.","HB","LB"],
["96","1","RW","Threshold lux level","Dusk HB","Dusk LB","Dawn HB","Dawn LB"],
["97","1","RW","Adjust period","Dusk HB","Dusk LB","Dawn HB","Dawn LB"],
["98","1","RW","Offset","RES.","RES.","Dusk","Dawn"],
["99","1","RW","CCT min/max range","max-H","max-L","min-H","min-L"],
["100","1","RW","DALI interface","Cmd ID","Add","Cmd","Resp"],
["101","1","RW","Module FW ver","v1","v2","v3","v4"],
["102","1","RW","Module MAC-H","unused","unused","M1","M2"],
["103","1","RW","Module MAC-L","M3","M4","M5","M6"],
["122","1","R","FW update status/control register","Byte3","Byte2","Byte1","Byte0"],
["123","1","R","FW update - data index","Byte3","Byte2","Byte1","Byte0"],
["124","1","R","FW update - data","Byte3","Byte2","Byte1","Byte0"],
["0","0","R","Status","","","",""],
["1","0","RW","Control register","RES.","RES.","RES.","init mode enable"],
["2","0","R","Device types","","","",""],
["3","0","R","Serial number (MAC)","","","",""],
["4","0","R","Production data 1","","","",""],
["5","0","R","Production data 2","","","",""],
["6","0","RW","Network ID","NID3","NID2","NID1","NID0"],
["7","0","RW","RS232 settings","param.","param.","Baudrate H","Baudrate L"],
["8","0","R","Accelerometer data","","","",""],
["9","0","RW","Module FW ver","v1","v2","v3","v4"],
["10","0","RW","Module MAC-H","unused","unused","M1","M2"],
["11","0","RW","Module MAC-L","M3","M4","M5","M6"],
["32","0","RW","FW update status/control register","Byte3","Byte2","Byte1","Byte0"],
["33","0","RW","FW update - data index","Byte3","Byte2","Byte1","Byte0"],
["34","0","RW","FW update - data","Byte3","Byte2","Byte1","Byte0"],
["125","0","RW","Debug Register","Byte3","Byte2","Byte1","Byte0"],
["126","0","RW","Network Control Register","Byte3","Byte2","Byte1","Byte0"],
["127","0","R","Network Status Register","Byte3","Byte2","Byte1","Byte0"],
["128","0","RW","Node XX Serial Number Register","SER3","SER2","SER1","SER0"],
["256","0","R","Node XX Network Status Register","","","",""]
];
let register = {};
module.exports = {
registers,
register
}

View file

@ -0,0 +1,94 @@
const { exec } = require('child_process');
function openPort(port){
return new Promise((resolve, reject) => {
var callbackError = function(err) {
port.removeListener('error', callbackError);
port.removeListener('open', callbackError);
reject(err.message);
};
var callbackOpen = function(data) {
port.removeListener('error', callbackError);
port.removeListener('open', callbackOpen);
resolve("port open: ok");
};
port.on('error', callbackError);
port.on('open', callbackOpen);
port.open();
})
}
function runSyncExec(command){
return new Promise((resolve, reject) => {
exec(command, (error, stdout, stderr) => {
if(error == null) resolve(stdout);
reject(error);
});
})
}
async function writeData(port, data, readbytes, timeout){
return new Promise((resolve, reject) => {
//readbytes = 0 = broadcast
if(readbytes == undefined) readbytes = 0;
if(timeout == undefined) timeout = 10000;//10s, default timeout MASTERA je 3s
//cmd-manager mame http route POST / terminal a tomu sa tiez nastavuje timeout!!!
var callback = function(data) {
rsPortReceivedData.push(...data);
let l = rsPortReceivedData.length;
if(l >= readbytes)
{
port.removeListener('data', callback);
clearTimeout(t);
resolve(rsPortReceivedData);
}
};
port.removeListener('data', callback);
let t = setTimeout(() => {
port.removeListener('data', callback);
console.log("serialport helper: writeData TIMEOUT READING", rsPortReceivedData);
reject("TIMEOUT READING");
}, timeout);
let rsPortReceivedData = [];
if(readbytes > 0) port.on('data', callback);
port.write(Buffer.from(data), function(err) {
if (err) {
port.removeListener('data', callback);
reject(err.message);
}
if(readbytes == 0)
{
resolve(rsPortReceivedData);
}
});
})
}
module.exports = {
openPort,
runSyncExec,
writeData
}

317
flow/helper/suncalc.js Normal file
View file

@ -0,0 +1,317 @@
/*
(c) 2011-2015, Vladimir Agafonkin
SunCalc is a JavaScript library for calculating sun/moon position and light phases.
https://github.com/mourner/suncalc
*/
(function () { 'use strict';
// shortcuts for easier to read formulas
var PI = Math.PI,
sin = Math.sin,
cos = Math.cos,
tan = Math.tan,
asin = Math.asin,
atan = Math.atan2,
acos = Math.acos,
rad = PI / 180;
// sun calculations are based on http://aa.quae.nl/en/reken/zonpositie.html formulas
// date/time constants and conversions
var dayMs = 1000 * 60 * 60 * 24,
J1970 = 2440588,
J2000 = 2451545;
function toJulian(date) { return date.valueOf() / dayMs - 0.5 + J1970; }
function fromJulian(j) { return new Date((j + 0.5 - J1970) * dayMs); }
function toDays(date) { return toJulian(date) - J2000; }
// general calculations for position
var e = rad * 23.4397; // obliquity of the Earth
function rightAscension(l, b) { return atan(sin(l) * cos(e) - tan(b) * sin(e), cos(l)); }
function declination(l, b) { return asin(sin(b) * cos(e) + cos(b) * sin(e) * sin(l)); }
function azimuth(H, phi, dec) { return atan(sin(H), cos(H) * sin(phi) - tan(dec) * cos(phi)); }
function altitude(H, phi, dec) { return asin(sin(phi) * sin(dec) + cos(phi) * cos(dec) * cos(H)); }
function siderealTime(d, lw) { return rad * (280.16 + 360.9856235 * d) - lw; }
function astroRefraction(h) {
if (h < 0) // the following formula works for positive altitudes only.
h = 0; // if h = -0.08901179 a div/0 would occur.
// formula 16.4 of "Astronomical Algorithms" 2nd edition by Jean Meeus (Willmann-Bell, Richmond) 1998.
// 1.02 / tan(h + 10.26 / (h + 5.10)) h in degrees, result in arc minutes -> converted to rad:
return 0.0002967 / Math.tan(h + 0.00312536 / (h + 0.08901179));
}
// general sun calculations
function solarMeanAnomaly(d) { return rad * (357.5291 + 0.98560028 * d); }
function eclipticLongitude(M) {
var C = rad * (1.9148 * sin(M) + 0.02 * sin(2 * M) + 0.0003 * sin(3 * M)), // equation of center
P = rad * 102.9372; // perihelion of the Earth
return M + C + P + PI;
}
function sunCoords(d) {
var M = solarMeanAnomaly(d),
L = eclipticLongitude(M);
return {
dec: declination(L, 0),
ra: rightAscension(L, 0)
};
}
var SunCalc = {};
// calculates sun position for a given date and latitude/longitude
SunCalc.getPosition = function (date, lat, lng) {
var lw = rad * -lng,
phi = rad * lat,
d = toDays(date),
c = sunCoords(d),
H = siderealTime(d, lw) - c.ra;
return {
azimuth: azimuth(H, phi, c.dec),
altitude: altitude(H, phi, c.dec)
};
};
// sun times configuration (angle, morning name, evening name)
var times = SunCalc.times = [
[-0.833, 'sunrise', 'sunset' ],
[ -0.3, 'sunriseEnd', 'sunsetStart' ],
[ -6, 'dawn', 'dusk' ],
[ -12, 'nauticalDawn', 'nauticalDusk'],
[ -18, 'nightEnd', 'night' ],
[ 6, 'goldenHourEnd', 'goldenHour' ]
];
// adds a custom time to the times config
SunCalc.addTime = function (angle, riseName, setName) {
times.push([angle, riseName, setName]);
};
// calculations for sun times
var J0 = 0.0009;
function julianCycle(d, lw) { return Math.round(d - J0 - lw / (2 * PI)); }
function approxTransit(Ht, lw, n) { return J0 + (Ht + lw) / (2 * PI) + n; }
function solarTransitJ(ds, M, L) { return J2000 + ds + 0.0053 * sin(M) - 0.0069 * sin(2 * L); }
function hourAngle(h, phi, d) { return acos((sin(h) - sin(phi) * sin(d)) / (cos(phi) * cos(d))); }
function observerAngle(height) { return -2.076 * Math.sqrt(height) / 60; }
// returns set time for the given sun altitude
function getSetJ(h, lw, phi, dec, n, M, L) {
var w = hourAngle(h, phi, dec),
a = approxTransit(w, lw, n);
return solarTransitJ(a, M, L);
}
// calculates sun times for a given date, latitude/longitude, and, optionally,
// the observer height (in meters) relative to the horizon
SunCalc.getTimes = function (date, lat, lng, height) {
height = height || 0;
var lw = rad * -lng,
phi = rad * lat,
dh = observerAngle(height),
d = toDays(date),
n = julianCycle(d, lw),
ds = approxTransit(0, lw, n),
M = solarMeanAnomaly(ds),
L = eclipticLongitude(M),
dec = declination(L, 0),
Jnoon = solarTransitJ(ds, M, L),
i, len, time, h0, Jset, Jrise;
var result = {
solarNoon: fromJulian(Jnoon),
nadir: fromJulian(Jnoon - 0.5)
};
for (i = 0, len = times.length; i < len; i += 1) {
time = times[i];
h0 = (time[0] + dh) * rad;
Jset = getSetJ(h0, lw, phi, dec, n, M, L);
Jrise = Jnoon - (Jset - Jnoon);
result[time[1]] = fromJulian(Jrise);
result[time[2]] = fromJulian(Jset);
}
return result;
};
// moon calculations, based on http://aa.quae.nl/en/reken/hemelpositie.html formulas
function moonCoords(d) { // geocentric ecliptic coordinates of the moon
var L = rad * (218.316 + 13.176396 * d), // ecliptic longitude
M = rad * (134.963 + 13.064993 * d), // mean anomaly
F = rad * (93.272 + 13.229350 * d), // mean distance
l = L + rad * 6.289 * sin(M), // longitude
b = rad * 5.128 * sin(F), // latitude
dt = 385001 - 20905 * cos(M); // distance to the moon in km
return {
ra: rightAscension(l, b),
dec: declination(l, b),
dist: dt
};
}
SunCalc.getMoonPosition = function (date, lat, lng) {
var lw = rad * -lng,
phi = rad * lat,
d = toDays(date),
c = moonCoords(d),
H = siderealTime(d, lw) - c.ra,
h = altitude(H, phi, c.dec),
// formula 14.1 of "Astronomical Algorithms" 2nd edition by Jean Meeus (Willmann-Bell, Richmond) 1998.
pa = atan(sin(H), tan(phi) * cos(c.dec) - sin(c.dec) * cos(H));
h = h + astroRefraction(h); // altitude correction for refraction
return {
azimuth: azimuth(H, phi, c.dec),
altitude: h,
distance: c.dist,
parallacticAngle: pa
};
};
// calculations for illumination parameters of the moon,
// based on http://idlastro.gsfc.nasa.gov/ftp/pro/astro/mphase.pro formulas and
// Chapter 48 of "Astronomical Algorithms" 2nd edition by Jean Meeus (Willmann-Bell, Richmond) 1998.
SunCalc.getMoonIllumination = function (date) {
var d = toDays(date || new Date()),
s = sunCoords(d),
m = moonCoords(d),
sdist = 149598000, // distance from Earth to Sun in km
phi = acos(sin(s.dec) * sin(m.dec) + cos(s.dec) * cos(m.dec) * cos(s.ra - m.ra)),
inc = atan(sdist * sin(phi), m.dist - sdist * cos(phi)),
angle = atan(cos(s.dec) * sin(s.ra - m.ra), sin(s.dec) * cos(m.dec) -
cos(s.dec) * sin(m.dec) * cos(s.ra - m.ra));
return {
fraction: (1 + cos(inc)) / 2,
phase: 0.5 + 0.5 * inc * (angle < 0 ? -1 : 1) / Math.PI,
angle: angle
};
};
function hoursLater(date, h) {
return new Date(date.valueOf() + h * dayMs / 24);
}
// calculations for moon rise/set times are based on http://www.stargazing.net/kepler/moonrise.html article
SunCalc.getMoonTimes = function (date, lat, lng, inUTC) {
var t = new Date(date);
if (inUTC) t.setUTCHours(0, 0, 0, 0);
else t.setHours(0, 0, 0, 0);
var hc = 0.133 * rad,
h0 = SunCalc.getMoonPosition(t, lat, lng).altitude - hc,
h1, h2, rise, set, a, b, xe, ye, d, roots, x1, x2, dx;
// go in 2-hour chunks, each time seeing if a 3-point quadratic curve crosses zero (which means rise or set)
for (var i = 1; i <= 24; i += 2) {
h1 = SunCalc.getMoonPosition(hoursLater(t, i), lat, lng).altitude - hc;
h2 = SunCalc.getMoonPosition(hoursLater(t, i + 1), lat, lng).altitude - hc;
a = (h0 + h2) / 2 - h1;
b = (h2 - h0) / 2;
xe = -b / (2 * a);
ye = (a * xe + b) * xe + h1;
d = b * b - 4 * a * h1;
roots = 0;
if (d >= 0) {
dx = Math.sqrt(d) / (Math.abs(a) * 2);
x1 = xe - dx;
x2 = xe + dx;
if (Math.abs(x1) <= 1) roots++;
if (Math.abs(x2) <= 1) roots++;
if (x1 < -1) x1 = x2;
}
if (roots === 1) {
if (h0 < 0) rise = i + x1;
else set = i + x1;
} else if (roots === 2) {
rise = i + (ye < 0 ? x2 : x1);
set = i + (ye < 0 ? x1 : x2);
}
if (rise && set) break;
h0 = h2;
}
var result = {};
if (rise) result.rise = hoursLater(t, rise);
if (set) result.set = hoursLater(t, set);
if (!rise && !set) result[ye > 0 ? 'alwaysUp' : 'alwaysDown'] = true;
return result;
};
// export as Node module / AMD module / browser variable
if (typeof exports === 'object' && typeof module !== 'undefined') module.exports = SunCalc;
else if (typeof define === 'function' && define.amd) define(SunCalc);
else window.SunCalc = SunCalc;
}());

124
flow/helper/utils.js Normal file
View file

@ -0,0 +1,124 @@
function bytesToInt(bytes, numberOfBytes)
{
let buffer = [];
if(Array.isArray(bytes))
{
buffer = bytes.slice(0);
if(numberOfBytes != undefined)
{
buffer = bytes.slice(bytes.length - numberOfBytes);
}
}
else buffer.push(bytes);
//var decimal = (buffer[0] << 24) + (buffer[1] << 16) + (buffer[2] << 8) + buffer[3];
let l = (buffer.length - 1) * 8;
let decimal = 0;
for(let i = 0; i < buffer.length; i++)
{
var s = buffer[i] << l;
if(l < 8) s = buffer[i]
decimal = decimal + s;
l = l - 8;
}
return decimal;
}
function resizeArray(arr, newSize, defaultValue) {
while(newSize > arr.length)
arr.push(defaultValue);
arr.length = newSize;
}
longToByteArray = function(/*long*/long) {
// we want to represent the input as a 8-bytes array
var byteArray = [0, 0, 0, 0, 0, 0, 0, 0];
for ( var index = 0; index < byteArray.length; index ++ ) {
var byte = long & 0xff;
byteArray [ index ] = byte;
long = (long - byte) / 256 ;
}
return byteArray;
};
function addDays(date, days) {
var result = new Date(date);
result.setDate(result.getDate() + days);
return result;
}
/*
sleep(2000).then(() => {
// Do something after the sleep!
});
*/
function sleep (time) {
return new Promise((resolve) => setTimeout(resolve, time));
}
function isEmptyObject( obj ) {
for ( var name in obj ) {
return false;
}
return true;
}
function convertUTCDateToLocalDate(date) {
var newDate = new Date(date);
newDate.setMinutes(date.getMinutes() + date.getTimezoneOffset());
return newDate;
}
function addZeroBefore(n) {
return (n < 10 ? '0' : '') + n;
}
var convertBase = function () {
function convertBase(baseFrom, baseTo) {
return function (num) {
return parseInt(num, baseFrom).toString(baseTo);
};
}
// binary to decimal
convertBase.bin2dec = convertBase(2, 10);
// binary to hexadecimal
convertBase.bin2hex = convertBase(2, 16);
// decimal to binary
convertBase.dec2bin = convertBase(10, 2);
// decimal to hexadecimal
convertBase.dec2hex = convertBase(10, 16);
// hexadecimal to binary
convertBase.hex2bin = convertBase(16, 2);
// hexadecimal to decimal
convertBase.hex2dec = convertBase(16, 10);
return convertBase;
}();
module.exports = {
bytesToInt,
longToByteArray,
addDays,
addZeroBefore,
resizeArray,
isEmptyObject,
sleep,
convertUTCDateToLocalDate
}