Backup senica-RVO37 on 16.10.2025
This commit is contained in:
parent
b62cd9729b
commit
301ca1d97b
60 changed files with 18605 additions and 0 deletions
187
RVO37/flow/helper/DataToTbHandler.js
Executable file
187
RVO37/flow/helper/DataToTbHandler.js
Executable file
|
|
@ -0,0 +1,187 @@
|
|||
class DataToTbHandler {
|
||||
|
||||
constructor(index) {
|
||||
this.index = index;
|
||||
|
||||
// time, after new value for the given key will be resend to tb (e.g. {status: "OK"})
|
||||
this.timeToHoldTbValue = 30 * 60; //30 minutes
|
||||
this.previousValues = {};
|
||||
this.debug = false;
|
||||
this.messageCounter = 0;
|
||||
this.itIsNodeReadout = false;
|
||||
this.sender = "";
|
||||
|
||||
// if attribute change difference is less than limit value, we do not send to tb.
|
||||
this.attributeChangeLimit = {
|
||||
temperature: 0.5,
|
||||
Phase_1_voltage: 2,
|
||||
Phase_2_voltage: 2,
|
||||
Phase_3_voltage: 2,
|
||||
Phase_1_current: 0.1,
|
||||
Phase_2_current: 0.1,
|
||||
Phase_3_current: 0.1,
|
||||
Phase_1_power: 2,
|
||||
Phase_2_power: 2,
|
||||
Phase_3_power: 2,
|
||||
total_power: 2,
|
||||
total_energy: 1,
|
||||
Phase_1_pow_factor: 0.1,
|
||||
Phase_2_pow_factor: 0.1,
|
||||
Phase_3_pow_factor: 0.1,
|
||||
power_factor: 0.1,
|
||||
lifetime: 2,
|
||||
voltage: 2,
|
||||
power: 2,
|
||||
frequency: 3,
|
||||
energy: 0.1,
|
||||
current: 2,
|
||||
inclination_x: 10,
|
||||
inclination_y: 10,
|
||||
inclination_z: 10
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
dump() {
|
||||
console.log("----------------------------");
|
||||
console.log("previousValues", this.previousValues);
|
||||
console.log("----------------------------");
|
||||
}
|
||||
|
||||
setSender(sender) {
|
||||
this.sender = sender;
|
||||
}
|
||||
|
||||
isEmptyObject(obj) {
|
||||
for (var _ in obj) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
sendToTb(data, instance) {
|
||||
|
||||
//not to modify data object, we do deep copy:
|
||||
let dataCopy = JSON.parse(JSON.stringify(data));
|
||||
|
||||
let keys = Object.keys(dataCopy);
|
||||
|
||||
if (keys.length == 0) {
|
||||
if (this.debug) console.log("sendToTb received empty object", dataCopy);
|
||||
return;
|
||||
}
|
||||
|
||||
let tbname = keys[0];
|
||||
let ts;
|
||||
|
||||
let arrayOfValues = dataCopy[tbname];
|
||||
let arrayOfValuesToSend = [];
|
||||
|
||||
for (let i = 0; i < arrayOfValues.length; i++) {
|
||||
|
||||
ts = arrayOfValues[i].ts;
|
||||
let values = this.prepareValuesForTb(tbname, ts, arrayOfValues[i].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;
|
||||
}
|
||||
|
||||
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) {
|
||||
//TODO set different value for given key!!!
|
||||
//if(key == "status") this.timeToHoldTbValue = 2*60*60;//2h
|
||||
return this.timeToHoldTbValue * 1000;
|
||||
}
|
||||
|
||||
|
||||
prepareValuesForTb(tbname, timestamp, values) {
|
||||
|
||||
let keys = Object.keys(values);
|
||||
|
||||
if (keys.includes("lifetime")) this.itIsNodeReadout = true;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// attributeData ==> {voltage: {ts:333333, value:5}}
|
||||
let attributeData = this.previousValues[tbname][key];
|
||||
let attributeToChange = false;
|
||||
if (key in this.attributeChangeLimit) attributeToChange = true;
|
||||
let limit = this.attributeChangeLimit[key];
|
||||
let timestampDiffToRemoveKey;
|
||||
|
||||
//this will ensure "node statecode" will be sent just once an hour
|
||||
if (this.itIsNodeReadout && key === "statecode") {
|
||||
attributeData.value = value;
|
||||
this.itIsNodeReadout = false;
|
||||
timestampDiffToRemoveKey = 1 * 60 * 60 * 1000; // 1 hour
|
||||
}
|
||||
|
||||
if (key === "twilight_sensor" && value > 100) {
|
||||
attributeData.value = value;
|
||||
}
|
||||
|
||||
//if edge, master or node version do not change, send just once a day:
|
||||
if (["edge_fw_version", "master_node_version", "fw_version"].includes(key)) {
|
||||
timestampDiffToRemoveKey = 24 * 60 * 60 * 1000;
|
||||
}
|
||||
|
||||
if (attributeData.value === value || attributeToChange && Math.abs(attributeData.value - value) < limit) {
|
||||
|
||||
let diff = timestamp - attributeData.ts;
|
||||
if (!timestampDiffToRemoveKey) timestampDiffToRemoveKey = this.getDiffTimestamp(key);
|
||||
|
||||
if (diff > timestampDiffToRemoveKey) {
|
||||
attributeData.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 {
|
||||
attributeData.value = value;
|
||||
attributeData.ts = timestamp;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return values;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = DataToTbHandler;
|
||||
|
||||
91
RVO37/flow/helper/ErrorToServiceHandler.js
Executable file
91
RVO37/flow/helper/ErrorToServiceHandler.js
Executable file
|
|
@ -0,0 +1,91 @@
|
|||
const { MD5 } = require('./md5.js');
|
||||
const { networkInterfaces } = require('os');
|
||||
|
||||
class ErrorToServiceHandler {
|
||||
constructor() {
|
||||
this.previousValues = {};
|
||||
|
||||
this.project_id = undefined;
|
||||
|
||||
const nets = networkInterfaces();
|
||||
this.ipAddresses = {};
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setProjectId(project_id) {
|
||||
this.project_id = project_id;
|
||||
}
|
||||
|
||||
processMessage(message, seconds) {
|
||||
if (Array.isArray(message)) message = message.join(', ');
|
||||
|
||||
let key = MD5(message);
|
||||
let ts = Date.now();
|
||||
|
||||
//keep in memory - default value is 1h
|
||||
if (seconds === undefined) seconds = 60 * 60;
|
||||
|
||||
if (!this.previousValues.hasOwnProperty(key)) {
|
||||
this.previousValues[key] = { ts: ts, duration: seconds };
|
||||
}
|
||||
|
||||
let diff = (ts - this.previousValues[key].ts);
|
||||
if (diff < this.previousValues[key].duration * 1000) return false;
|
||||
|
||||
this.previousValues[key].ts = ts;
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
sendMessageToService(message, seconds, message_type) {
|
||||
|
||||
// if error occures too early FLOW.GLOBALS.settings.project_id is still undefined
|
||||
if (this.project_id === undefined) {
|
||||
console.log("ErrorToServiceHandler.js: no project_id");
|
||||
return;
|
||||
}
|
||||
|
||||
let f = this.processMessage(message, seconds);
|
||||
if (f === false) return;
|
||||
|
||||
if (message_type === undefined) message_type = "error_message";
|
||||
|
||||
let toService = {
|
||||
id: this.project_id,
|
||||
ipAddresses: this.ipAddresses
|
||||
};
|
||||
|
||||
//js_error || error_message
|
||||
toService[message_type] = message;
|
||||
|
||||
console.log("ErrorToServiceHandler------------------------>send to service", toService);
|
||||
|
||||
RESTBuilder.make(function(builder) {
|
||||
builder.method('POST');
|
||||
builder.post(toService);
|
||||
builder.url('http://192.168.252.2:8004/sentmessage');
|
||||
|
||||
builder.callback(function(err, response, output) {
|
||||
console.log("process.on error send", err, response, output, toService);
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
const errorHandler = new ErrorToServiceHandler();
|
||||
|
||||
|
||||
module.exports = errorHandler;
|
||||
//module.exports = ErrorToServiceHandler;
|
||||
44
RVO37/flow/helper/db_helper.js
Executable file
44
RVO37/flow/helper/db_helper.js
Executable 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
|
||||
}
|
||||
30
RVO37/flow/helper/logger.js
Executable file
30
RVO37/flow/helper/logger.js
Executable file
|
|
@ -0,0 +1,30 @@
|
|||
//https://github.com/log4js-node/log4js-node/blob/master/examples/example.js
|
||||
//file: { type: 'file', filename: path.join(__dirname, 'log/file.log') }
|
||||
|
||||
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");
|
||||
|
||||
//USAGE
|
||||
//logger.debug("text")
|
||||
//monitor.info('info');
|
||||
//errLogger.error("some error");
|
||||
|
||||
module.exports = { errLogger, logger, monitor };
|
||||
5
RVO37/flow/helper/md5.js
Executable file
5
RVO37/flow/helper/md5.js
Executable 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
|
||||
}
|
||||
121
RVO37/flow/helper/notification_reporter.js
Executable file
121
RVO37/flow/helper/notification_reporter.js
Executable file
|
|
@ -0,0 +1,121 @@
|
|||
//key is device, value = message {}
|
||||
let sentValues = {};
|
||||
let notificationsData = null;
|
||||
let rvoName;
|
||||
|
||||
//sendNotification("CMD Manager: process cmd", SETTINGS.rvoTbName, "dimming_profile_was_successfully_received_by_node", { node: node }, "", SEND_TO.tb, instance);
|
||||
|
||||
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]);
|
||||
|
||||
|
||||
function initNotification() {
|
||||
notificationsData = FLOW.GLOBALS.notificationsData;
|
||||
rvoName = FLOW.GLOBALS.settings.rvo_name;
|
||||
}
|
||||
|
||||
|
||||
function sendNotification(func, device, key, params, extra, tb_output, instance, saveKey) {
|
||||
|
||||
let storeToSendValues = true;
|
||||
if (saveKey == undefined) storeToSendValues = false;
|
||||
|
||||
let weight = "";
|
||||
let message = {};
|
||||
|
||||
let notification = notificationsData[key];
|
||||
|
||||
if (notification) {
|
||||
weight = notification.weight.toLowerCase();
|
||||
|
||||
Object.keys(notification).forEach(item => {
|
||||
if (["en", "sk", "de", "cz", "it", "es"].includes(item)) {
|
||||
message[item] = rvoName + ": " + template(notification[item], params);
|
||||
}
|
||||
})
|
||||
}
|
||||
else {
|
||||
//console.error("sendNotification: Notifications: undefined key", key, func, notificationsData);
|
||||
console.error("sendNotification: Notifications: undefined key", key, func);
|
||||
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 (JSON.stringify(sentValues[saveKey]) == JSON.stringify(message)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (sentValues[saveKey] == undefined) {
|
||||
if (storeToSendValues) {
|
||||
//do not send - flow is was started
|
||||
sentValues[saveKey] = message;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (storeToSendValues) sentValues[saveKey] = message;
|
||||
|
||||
let content = {
|
||||
"type": weight,
|
||||
"status": "new",
|
||||
"source": {
|
||||
"func": func,
|
||||
"component": instance.id,
|
||||
"component_name": instance.name,
|
||||
"edge": device
|
||||
},
|
||||
"message": message,
|
||||
"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,
|
||||
ERRWEIGHT,
|
||||
initNotification
|
||||
}
|
||||
|
||||
144
RVO37/flow/helper/register.js
Executable file
144
RVO37/flow/helper/register.js
Executable 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
|
||||
}
|
||||
99
RVO37/flow/helper/serialport_helper.js
Executable file
99
RVO37/flow/helper/serialport_helper.js
Executable file
|
|
@ -0,0 +1,99 @@
|
|||
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) => {
|
||||
|
||||
// If first item in data array is 255, we just write broadcast command to rsPort
|
||||
// We wait 3 seconds and resolve(["broadcast"])
|
||||
// It is important to resolve with array
|
||||
if (data[0] == 255) {
|
||||
|
||||
port.write(Buffer.from(data), function(err) {
|
||||
if (err) {
|
||||
reject(err.message);
|
||||
}
|
||||
});
|
||||
|
||||
setTimeout(resolve, 3000, ["broadcast"]);
|
||||
return;
|
||||
}
|
||||
|
||||
//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 = [];
|
||||
|
||||
port.on('data', callback);
|
||||
|
||||
port.write(Buffer.from(data), function(err) {
|
||||
if (err) {
|
||||
port.removeListener('data', callback);
|
||||
reject(err.message);
|
||||
}
|
||||
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
openPort,
|
||||
runSyncExec,
|
||||
writeData
|
||||
}
|
||||
317
RVO37/flow/helper/suncalc.js
Executable file
317
RVO37/flow/helper/suncalc.js
Executable 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;
|
||||
|
||||
}());
|
||||
161
RVO37/flow/helper/utils.js
Executable file
161
RVO37/flow/helper/utils.js
Executable file
|
|
@ -0,0 +1,161 @@
|
|||
const fs = require('fs').promises;
|
||||
|
||||
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);
|
||||
|
||||
let result = 0;
|
||||
for (let i = 0; i < buffer.length; i++) {
|
||||
result = (result << 8) | buffer[i];
|
||||
}
|
||||
|
||||
return result >>> 0; //ensure it's an unsigned 32-bit number
|
||||
}
|
||||
|
||||
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 emptyJsObject(jsObject) {
|
||||
Object.keys(jsObject).forEach(key => delete jsObject[key]);
|
||||
}
|
||||
|
||||
function convertUTCDateToLocalDate(date) {
|
||||
var newDate = new Date(date);
|
||||
newDate.setMinutes(date.getMinutes() + date.getTimezoneOffset());
|
||||
return newDate;
|
||||
}
|
||||
|
||||
function addZeroBefore(n) {
|
||||
return (n < 10 ? '0' : '') + n;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Asynchronously writes data to a file.
|
||||
*
|
||||
* @param {string} filePath The path to the file.
|
||||
* @param {string} data The data to write to the file.
|
||||
* @param {boolean} [append=false] If true, appends the data to the file. If false, it overwrites the file.
|
||||
*/
|
||||
async function writeToFile(filePath, data, append = false) {
|
||||
if (typeof data !== 'string') data = JSON.stringify(data, null, 2);
|
||||
try {
|
||||
if (append) {
|
||||
// Append the data to the end of the file. This is the simplest way to append.
|
||||
await fs.appendFile(filePath, data, 'utf8');
|
||||
console.log(`Successfully appended data to ${filePath} using fs.appendFile.`);
|
||||
} else {
|
||||
// Overwrite the file with the new data.
|
||||
await fs.writeFile(filePath, data, 'utf8');
|
||||
console.log(`Successfully wrote (overwrote) data to ${filePath} using fs.writeFile.`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Error writing to file ${filePath}:`, error);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Checks if an item is present in an array and adds it if it's not.
|
||||
* * @param {Array} arr The array to check.
|
||||
* @param {*} item The item to add.
|
||||
* @returns {Array} The modified array.
|
||||
*/
|
||||
const addToArrayIfUnique = (arr, item) => {
|
||||
if (!arr.includes(item)) {
|
||||
arr.push(item);
|
||||
}
|
||||
return arr;
|
||||
};
|
||||
|
||||
|
||||
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,
|
||||
emptyJsObject,
|
||||
sleep,
|
||||
convertUTCDateToLocalDate,
|
||||
writeToFile,
|
||||
addToArrayIfUnique
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue