Daily reports - dimming and power combined results

This commit is contained in:
rasta5man 2025-09-27 23:53:39 +02:00
parent cf16481324
commit 7093d765ec
5 changed files with 433 additions and 86 deletions

View file

@ -30,6 +30,7 @@ const total_energy = {
47: 1100,
48: 1500,
50: 3200,
53: 1250,
55: 1000,
56: 5500
}

View file

@ -3,7 +3,7 @@ exports.title = 'CMD Manager';
exports.group = 'Worksys';
exports.color = '#5D9CEC';
exports.version = '0.0.3';
exports.output = ['red', 'blue', 'yellow', 'blue', 'white'];
exports.output = ['red', 'blue', 'yellow', 'blue', 'white', 'green'];
exports.input = 3;
exports.icon = 'cloud-upload';
@ -34,7 +34,7 @@ exports.install = function(instance) {
const { exec } = require('child_process');
const { crc16 } = require('easy-crc');
const { runSyncExec, writeData } = require('./helper/serialport_helper');
const { bytesToInt, longToByteArray, addZeroBefore } = require('./helper/utils');
const { bytesToInt, longToByteArray, addZeroBefore, isEmptyObject, emptyJsObject, writeToFile, addToArrayIfUnique } = require('./helper/utils');
const bitwise = require('bitwise');
var SunCalc = require('./helper/suncalc');
@ -65,7 +65,8 @@ exports.install = function(instance) {
tb: 1,
http_response: 2,
dido_controller: 3,
infoSender: 4
infoSender: 4,
dailyReport: 5
}
const PRIORITY_TYPES = {
@ -139,12 +140,13 @@ exports.install = function(instance) {
let relaysData;
let nodesData;
// holds dusk, dawn (and more) values
let sunCalcResult;
let reportDuskDawn;
//helper container for counting resolved group of commands (commands related to set profile)
let cmdCounter = {};//key is node, value is counter
//TODO: is this set working?? According to previous checks, sets do not work
//if sending of profile to node fails, we send notification and push node into set, so we do not send notification twice
const nodeProfileSendFail = new Set();
@ -152,6 +154,22 @@ exports.install = function(instance) {
let temperatureInSenica = null;
let accelerometerInterval = null;
//NOTE: daily reports senica:
//rvo_is_on status, we monitor all nodes - if true, power and dimming should be not 0, if false, 24/7 nodes should be 0, other rvo should not respond
let rvo_is_on;
let previous_rvo_is_on_value;
let handleDailyReport; //setInterval for dailyReportHandler function
let dailyReport = {}; //data needed for daily report
let reportToSend = {}; //final report which we send to cloud
let breakerCounter = null; // status of breakers after flow starts is not in report
let rvoPeriod; // interval of checking dusk dawn and if rvo_is_on
let initialReportStatus = false;
const DAILY_REPORT_HANDLER_TIME = 3_600_000;
const SET_SUNCALC_RESULT_TIME = 3_600_000;
const SET_RVO_PERIOD_TIME = 300_000;
const ADD_NODE_TO_REPORT_TIME = 3_600_000;
//END OF VARIABLE SETTINGS
//--------------------------------
@ -172,24 +190,24 @@ exports.install = function(instance) {
sunCalcResult = calculateDuskDawn();
reportDuskDawn = {
dusk_time: sunCalcResult.dusk_time,
dawn_time: sunCalcResult.dawn_time,
dusk_time_reported: undefined,
dawn_time_reported: undefined
};
handleRsPort();
customTasksInterval = setInterval(function() {
reportEdgeDateTimeAndNumberOfLuminaires();
}, 120000);
reportEdgeDateTimeAndNumberOfLuminaires();
customTasksInterval = setInterval(reportEdgeDateTimeAndNumberOfLuminaires, 120_000);
setTimeout(reportEdgeDateTimeAndNumberOfLuminaires, 4000);
//dailyReport related
emptyReportToSend();
breakerCounter = Object.keys(relaysData).length - 1; // we get number of lines (breakers) except of line 0
rvoPeriod = setInterval(setRvoPeriod, SET_RVO_PERIOD_TIME);
setTimeout(setRvoPeriod, 3000);
setInterval(setSunCalcResult, SET_SUNCALC_RESULT_TIME);
handleDailyReport = setInterval(dailyReportHandler, DAILY_REPORT_HANDLER_TIME);
setCorrectTime = setInterval(setCorrectPlcTimeOnceADay, 60000 * 60); // 1 hour
setCorrectPlcTimeOnceADay();
sendNodeReadout = setInterval(sendNodesData, 150000);
sendNodeReadout = setInterval(sendNodesData, 150_000);
accelerometerInterval = setInterval(accelerometerData, 60000 * 30); //30 min
}
@ -792,6 +810,10 @@ exports.install = function(instance) {
info: info
};
//to assure, handleDailyReportFunction do not run before rvo_is_on variable changes. So after every line switch we reset the timer
clearInterval(handleDailyReport);
handleDailyReport = setInterval(dailyReportHandler, DAILY_REPORT_HANDLER_TIME);
//logger.debug("linia", line, obj);
instance.send(SEND_TO.dido_controller, obj);
}
@ -863,11 +885,10 @@ exports.install = function(instance) {
logger.debug("-->buildTasks clear tasks");
}
else {
processLineProfiles = false;
processLineProfiles = params.processLineProfiles;
processBroadcast = false;
processNodes = false;
processLineProfiles = params.processLineProfiles;
processLine = params.line;
}
@ -920,6 +941,13 @@ exports.install = function(instance) {
// if astro clock true, we remove all regular profile points
time_points = [];
//TODO: when astro clock == true, is offset calculated ???
//let duskAstroClockOffset = profile.dusk_astro_clock_offset;
//let dawnAstroClockOffset = profile.dawn_astro_clock_offset;
//console.log("line astro clock offsets dusk a dawn: ", duskAstroClockOffset, dawnAstroClockOffset);
// maybe add dusk dawn offset to calculateDuskDawn ?? what dusk dawn will be if dawn_lux_sensor == true??
//let sunCalcResult = calculateDuskDawn(new Date(), line, duskAstroClockOffset, dawnAstroClockOffset);
let sunCalcResult = calculateDuskDawn(new Date(), line);
// adding dusk dawn to timpoints
@ -1053,7 +1081,7 @@ exports.install = function(instance) {
let d = new Date();
let time = d.getTime();
let sunCalcResult = calculateDuskDawn();
//let sunCalcResult = calculateDuskDawn();
{
let params = getParams();
@ -1310,49 +1338,154 @@ exports.install = function(instance) {
}
function processDailyReport() {
const now = Date.now();
if (rvo_is_on) {
for (const [key, value] of Object.entries(dailyReport)) {
if (["name", "time", "dusk_and_dawn"].includes(key)) continue;
if (value.initialTs) {
if (value.initialTs + ADD_NODE_TO_REPORT_TIME < now) {
addToArrayIfUnique(reportToSend["night_no_data"], key);
console.log('report nedostava ziadne data uz hodinu', key);
value.initialTs = now;
}
}
if (value.dimmingAndPowerAreZeroTime) {
if (value.dimmingAndPowerAreZeroTime + ADD_NODE_TO_REPORT_TIME < now) {
addToArrayIfUnique(reportToSend["night_dimming=0"], key);
console.log("report node dimming je 0", key);
value.dimmingAndPowerAreZeroTime = now;
}
}
}
} else {
for (const [key, value] of Object.entries(dailyReport)) {
if (["name", "time", "dusk_and_dawn"].includes(key)) continue;
let nodeIsOnLine = dailyReport[key].line;
let contactorStatus = relaysData[nodeIsOnLine].contactor;
if (contactorStatus === 1) {
if (value.initialTs) {
if (value.initialTs + ADD_NODE_TO_REPORT_TIME < now) {
addToArrayIfUnique(reportToSend["day_24/7_no_data"], key);
console.log('node je na 24/7 ale nedostava ziadne data uz hodinu', key);
value.initialTs = now;
}
}
if (value.nodeIsOnButShouldBeOffTime) {
if (value.nodeIsOnButShouldBeOffTime + ADD_NODE_TO_REPORT_TIME < now) {
addToArrayIfUnique(reportToSend["day_24/7_dimming>0"], key);
console.log("report nema svietit ale svieti viac ako hodinu", key);
value.nodeIsOnButShouldBeOffTime = now;
}
}
}
}
}
let report = {};
report["name"] = SETTINGS.rvo_name;
report["time"] = new Date();
report["report"] = reportToSend;
writeToFile(F.path.root("report_data.log"), report, true);
instance.send(SEND_TO.dailyReport, report);
}
function dailyReportHandler() {
// after dawn we empty reportToSend and start to get data for a new day
const date = new Date();
const hour = date.getHours();
const minute = date.getMinutes();
console.log("now: ", hour, minute, "suncalc: ", sunCalcResult.dawn_hours, sunCalcResult.dawn_minutes);
if (hour === sunCalcResult.dawn_hours) {
//NOTE: ak je este pred usvitom, spracujeme report a posleme na cloud, ak uz je po usvite, resetujeme report plnime data noveho dna
if (minute >= sunCalcResult.dawn_minutes - 2) {
emptyReportToSend();
emptyDailyReport();
console.log("Podmienka 1 v dailyReport handler");
} else {
processDailyReport();
emptyReportToSend();
emptyDailyReport();
console.log("Podmienka 2 v dailyReport handler");
}
initialReportStatus = true;
// ak sa funkcia spusti o hodinu alebo 2 neskor, ako je usvit (moze sa to stat, kedze kazde zapnutie/vypnutie linii odznova spusti casovac.
} else if (hour === sunCalcResult.dawn_hours + 1 || hour === sunCalcResult.dawn_hours + 2) {
if (!initialReportStatus) {
emptyReportToSend();
emptyDailyReport();
initialReportStatus = true;
console.log("Podmienka 3 v dailyReport handler");
} else {
processDailyReport();
initialReportStatus = true;
console.log("Podmienka 4 v dailyReport handler");
}
} else {
processDailyReport();
initialReportStatus = false;
console.log("Podmienka 5 v dailyReport handler");
}
console.log("initialReportStatus: ", initialReportStatus);
}
function emptyReportToSend() {
emptyJsObject(reportToSend);
reportToSend["contactor"] = { off: [], on: [] };
reportToSend["night_no_data"] = [];
reportToSend["night_dimming=0"] = [];
reportToSend["day_24/7_no_data"] = [];
reportToSend["day_24/7_dimming>0"] = [];
//console.log(`je ${sunCalcResult.dawn_hours}:${sunCalcResult.dawn_minutes}, resetuje sa reportToSend: `, reportToSend);
console.log(`resetuje sa reportToSend`);
}
//NOTE: ked je initialTs stale rovnaky a zistime ze linie su vypnute (relaysData.line.contactor) - zistim, ci je node na tej linii. Vieme, ze ak je linia vypnuta je to v poriadku lebo nie je na 24/7 linii
//ak je na 24/7 linii, reportujeme, ze neprijima data
function emptyDailyReport() {
const ts = Date.now();
emptyJsObject(dailyReport);
//NOTE: do dailyReport dame vsetky nody a pravidelne kontrolujeme ci maju data
//ked nastane sumrak/usvit a svetla maju zacat/prestat svietit, dailyReport spravime nanovo:
for (const [key, value] of Object.entries(nodesData)) {
dailyReport[value.node] = { line: value.line, initialTs: ts };
}
console.log("dailyReport: ", dailyReport);
}
async function runTasks() {
clearInterval(interval);
let currentTimestamp = Date.now();
//report dusk, dawn---------------------------------
if (reportDuskDawn.dusk_time < currentTimestamp) {
//vyreportuj iba ak nie je velky rozdiel napr. 60 sekund
if ((currentTimestamp - reportDuskDawn.dusk_time) < 60 * 1000) {
//reportovali sme?
if (reportDuskDawn.dusk_time_reported != sunCalcResult.dusk_time) {
//sendNotification("Cmd-mngr: calculated Time of dusk", SETTINGS.rvoTbName, "dusk_has_occured", { value: sunCalcResult["dusk"] }, "", SEND_TO.tb, instance);
reportDuskDawn.dusk_time_reported = sunCalcResult.dusk_time;
}
}
var nextDay = new Date();
nextDay.setDate(nextDay.getDate() + 1);
sunCalcResult = calculateDuskDawn(nextDay);
reportDuskDawn.dusk_time = sunCalcResult.dusk_time;
}
if (reportDuskDawn.dawn_time < currentTimestamp) {
//vyreportuj iba ak nie je velky rozdiel napr. 60 sekund
if ((currentTimestamp - reportDuskDawn.dawn_time) < 60 * 1000) {
//reportovali sme?
if (reportDuskDawn.dawn_time_reported != sunCalcResult.dawn_time) {
//sendNotification(": calculated Time of dawn", SETTINGS.rvoTbName, "dawn_has_occured", { value: sunCalcResult["dawn"] }, "", SEND_TO.tb, instance);
reportDuskDawn.dawn_time_reported = sunCalcResult.dawn_time;
}
}
var nextDay = new Date();
nextDay.setDate(nextDay.getDate() + 1);
sunCalcResult = calculateDuskDawn(nextDay);
reportDuskDawn.dawn_time = sunCalcResult.dawn_time;
}
//--------------------------------------------------------
//sort tasks based on timestamp
tasks.sort(function(a, b) {
if (a.timestamp <= currentTimestamp && b.timestamp <= currentTimestamp) {
@ -1409,6 +1542,7 @@ exports.install = function(instance) {
}
//kontrola nespracovanych profilov nodov
//TODO: co ked niektore nody neprijimaju profily? kazdu hodinu zahltuju "tasks" array
if (type == "process_profiles") {
//na vsetky zapnutych liniach sa spracuju nespracovane profily nodov
loadRelaysData();
@ -1426,7 +1560,8 @@ exports.install = function(instance) {
date.setDate(date.getDate() + 1);//next day
let sunCalcResult;
if (timePointName) sunCalcResult = calculateDuskDawn(date, params.line);
if (timePointName) { sunCalcResult = calculateDuskDawn(date, params.line); console.log("typee-rellay: ", sunCalcResult.dawn_time, sunCalcResult.dusk_time); }
if (timePointName == "dawn") {
tasks[0].timestamp = sunCalcResult.dawn_time;
@ -1497,7 +1632,6 @@ exports.install = function(instance) {
if (register == 6 && params.recipient === 2) {
if (type != "cmd-terminal") {
let sunCalcResult = calculateDuskDawn();
params.byte1 = sunCalcResult["dusk_hours"];//h
params.byte2 = sunCalcResult["dusk_minutes"];//m
}
@ -1506,7 +1640,6 @@ exports.install = function(instance) {
//Time of dawn
if (register == 7 && params.recipient === 2) {
if (type != "cmd-terminal") {
let sunCalcResult = calculateDuskDawn();
params.byte1 = sunCalcResult["dawn_hours"];//h
params.byte2 = sunCalcResult["dawn_minutes"];//m
}
@ -1583,6 +1716,40 @@ exports.install = function(instance) {
values.comm_status = "OK";
values.status = "OK";
nodesData[node].readout = { ...nodesData[node].readout, ...values };
//TODO: co ak nedostavame odpovede z nodu ? Musime vyreportovat!!
//v dailyReport teda musi byt kompletny zoznam nodov a neustale kontrolovat, ci maju data, ak nie report node - neodpoveda
if (register === 1 || register === 76) {
let now = Date.now();
if (rvo_is_on === true) {
if ("nodeIsOnButShouldBeOffTime" in dailyReport[node]) delete dailyReport[node].nodeIsOnButShouldBeOffTime;
if (values.dimming > 0 || values.power > 0) {
if ("dimmingAndPowerAreZeroTime" in dailyReport[node]) delete dailyReport[node].dimmingAndPowerAreZeroTime;
dailyReport[node] = { ...dailyReport[node], initialTs: now };
} else {
if (!("dimmingAndPowerAreZeroTime" in dailyReport[node])) dailyReport[node] = { ...dailyReport[node], dimmingAndPowerAreZeroTime: now, initialTs: now };
else dailyReport[node] = { ...dailyReport[node], initialTs: now };
}
} else {
if ("dimmingAndPowerAreZeroTime" in dailyReport[node]) delete dailyReport[node].dimmingAndPowerAreZeroTime;
if (values.dimming > 0 || values.power > 0) {
if (!("nodeIsOnButShouldBeOffTime" in dailyReport[node])) dailyReport[node] = { ...dailyReport[node], nodeIsOnButShouldBeOffTime: now, initialTs: now };
else dailyReport[node] = { ...dailyReport[node], initialTs: now };
} else {
if ("nodeIsOnButShouldBeOffTime" in dailyReport[node]) delete dailyReport[node].nodeIsOnButShouldBeOffTime;
dailyReport[node] = { ...dailyReport[node], initialTs: now };
}
}
}
}
//master node
@ -1811,6 +1978,36 @@ exports.install = function(instance) {
}
function setSunCalcResult() {
//if next day, we get new dusk and dawn. To make sure, in local timezone 2:00 means 00:00 in utc (it means next day)
if (new Date().getHours() === 2) {
sunCalcResult = calculateDuskDawn();
console.log("Novy suncalc: ", sunCalcResult);
}
}
function setRvoPeriod() {
const ts = Date.now();
previous_rvo_is_on_value = rvo_is_on;
if (ts < sunCalcResult.dawn_time - 1_800_000) { // nodes should be on (00:00 -> 06:00 ( - pol hodina, lebo rvo vypina skor)
rvo_is_on = true;
} else if (sunCalcResult.dawn_time - 1_800_000 < ts && ts < sunCalcResult.dusk_time + 1_800_000) { // nodes should be off 06:00 -> 21:00
rvo_is_on = false;
} else if (sunCalcResult.dusk_time + 1_800_000 < ts) { // nodes should be on 21:00 -> 00:00
rvo_is_on = true;
}
if (previous_rvo_is_on_value !== rvo_is_on) {
emptyDailyReport();
console.log("rvo_is: ", rvo_is_on, previous_rvo_is_on_value);
}
}
function handleRsPort() {
if (rsPort) {
@ -1868,6 +2065,11 @@ exports.install = function(instance) {
main();
})
instance.on("2", _ => {
console.log("dailyReport, reportToSend, rvo_is_on", dailyReport, reportToSend, rvo_is_on, previous_rvo_is_on_value);
})
instance.on("1", async function(flowdata) {
//instance.send(SEND_TO.debug, "on Data");
@ -1987,6 +2189,9 @@ exports.install = function(instance) {
}
else if (cmd == "state_of_breaker") {
//istic linie
breakerCounter--;
let value = flowdata.data.value;
let line = parseInt(flowdata.data.line);
@ -2003,8 +2208,14 @@ exports.install = function(instance) {
if (relaysData.hasOwnProperty(line)) {
let tbname = relaysData[line].tbname;
if (value == "Off") sendNotification("Cmd-mngr: onData", tbname, "circuit_breaker_was_turned_off_line", { line: line }, "", SEND_TO.tb, instance, "circuit_breaker");
else sendNotification("Cmd-mngr: onData", tbname, "circuit_breaker_was_turned_on_line", { line: line }, "", SEND_TO.tb, instance, "circuit_breaker");
if (value == "Off") {
sendNotification("Cmd-mngr: onData", tbname, "circuit_breaker_was_turned_off_line", { line: line }, "", SEND_TO.tb, instance, "circuit_breaker");
if (breakerCounter < 0) reportToSend["contactor"]["off"].push({ [line]: Date.now(), maintenance_mode: SETTINGS.maintenance_mode });
}
else {
sendNotification("Cmd-mngr: onData", tbname, "circuit_breaker_was_turned_on_line", { line: line }, "", SEND_TO.tb, instance, "circuit_breaker");
if (breakerCounter < 0) reportToSend["contactor"]["on"].push({ [line]: Date.now(), maintenance_mode: SETTINGS.maintenance_mode });
}
//report status liniu
sendTelemetry({ status: status }, tbname)
@ -2276,8 +2487,14 @@ exports.install = function(instance) {
if (isObject(relayObject)) line = relayObject.line;
// v relaysData je contactor bud 0 alebo 1, ale z platformy prichadza true, false;
if (value == false) turnLine("off", line, "command received from platform");
else turnLine("on", line, "command received from platform");
if (value == false) {
turnLine("off", line, "command received from platform");
reportToSend["contactor"]["off"].push({ [line]: Date.now(), maintenance_mode: SETTINGS.maintenance_mode });
}
else {
turnLine("on", line, "command received from platform");
reportToSend["contactor"]["on"].push({ [line]: Date.now(), maintenance_mode: SETTINGS.maintenance_mode });
}
}
}
else {
@ -2472,13 +2689,11 @@ exports.install = function(instance) {
tbHandler.sendToTb(dataToTb, instance);
}
function calculateDuskDawn(date, line, duskOffset = 0, dawnOffset = 0) {
if (date === undefined) date = new Date();
//if(duskOffset === undefined) duskOffset = 0;
//if(dawnOffset === undefined) dawnOffset = 0;
//let line = keys[i];
let profilestr = "";
if (relaysData[line] != undefined) profilestr = relaysData[line].profile;
@ -2492,7 +2707,6 @@ exports.install = function(instance) {
//http://suncalc.net/#/48.5598,18.169,11/2021.04.07/11:06
//https://mapa.zoznam.sk/zisti-gps-suradnice-m6
let dusk_astro_clock_offset = duskOffset;//minutes
let dawn_astro_clock_offset = dawnOffset;//minutes
@ -2520,9 +2734,6 @@ exports.install = function(instance) {
}
//dusk - súmrak
//down, sunrise - svitanie
} catch (error) {
if (profilestr != "") {
logger.debug(profilestr);
@ -2741,10 +2952,12 @@ exports.install = function(instance) {
}
function getObjectByTbValue(object, tbname) {
return object[Object.keys(object).find(key => object[key].tbname === tbname)];
}
function isObject(item) {
return (typeof item === "object" && !Array.isArray(item) && item !== null);
}

View file

@ -759,6 +759,16 @@
"index": "0",
"id": "1635936391935"
}
],
"5": [
{
"index": "0",
"id": "1757006030239"
},
{
"index": "0",
"id": "1757006060377"
}
]
},
"disabledio": {
@ -1009,7 +1019,7 @@
"output": []
},
"state": {
"text": "840.05 MB / 985.68 MB",
"text": "858.06 MB / 985.68 MB",
"color": "gray"
},
"options": {
@ -1039,7 +1049,7 @@
"output": []
},
"state": {
"text": "5.78 GB / 7.26 GB",
"text": "5.69 GB / 7.26 GB",
"color": "gray"
},
"options": {
@ -1495,7 +1505,7 @@
"output": []
},
"state": {
"text": "2.4% / 74.33 MB",
"text": "13% / 74.17 MB",
"color": "gray"
},
"options": {
@ -2018,7 +2028,7 @@
"tag_on_include": "[{\"user_id\":\"U072JE5JUQG\", \"includes\":[\"Electrometer\", \"Twilight sensor\"]}]",
"message_includes": "[\"is responding again\", \"Flow has been restarted\", \"Node db has changed\"]",
"types": "[\"emergency\", \"critical\", \"error\", \"alert\"]",
"name": "rvo_senica_33_10.0.0.127"
"name": "rvo_senica_15_ip114"
},
"color": "#30E193",
"notes": ""
@ -2889,6 +2899,85 @@
"options": {},
"color": "#F6BB42",
"notes": ""
},
{
"id": "1757006030239",
"component": "httprequest",
"tab": "1615551125555",
"name": "192.168.252.2:8015/daily_report",
"x": 756.5666656494141,
"y": 715.4499969482422,
"connections": {
"0": [
{
"index": "0",
"id": "1757006045804"
}
]
},
"disabledio": {
"input": [],
"output": []
},
"state": {
"text": "",
"color": "gray"
},
"options": {
"url": "http://192.168.252.2:8015/daily_report",
"method": "POST",
"stringify": "json"
},
"color": "#5D9CEC",
"notes": ""
},
{
"id": "1757006045804",
"component": "debug",
"tab": "1615551125555",
"name": "ddd",
"x": 1091.566665649414,
"y": 711.4499969482422,
"connections": {},
"disabledio": {
"input": [],
"output": []
},
"state": {
"text": "Enabled",
"color": "gray"
},
"options": {
"type": "data",
"repository": false,
"enabled": true
},
"color": "#967ADC",
"notes": ""
},
{
"id": "1757006060377",
"component": "debug",
"tab": "1615551125555",
"name": "reportDebug",
"x": 749.5666656494141,
"y": 799.4499969482422,
"connections": {},
"disabledio": {
"input": [],
"output": []
},
"state": {
"text": "Enabled",
"color": "gray"
},
"options": {
"type": "data",
"repository": false,
"enabled": true
},
"color": "#967ADC",
"notes": ""
}
],
"version": 615

View file

@ -1,3 +1,5 @@
const fs = require('fs').promises;
function bytesToInt(bytes, numberOfBytes) {
let buffer = [];
if (Array.isArray(bytes)) {
@ -60,6 +62,10 @@ function isEmptyObject(obj) {
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());
@ -70,6 +76,46 @@ 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) {
@ -107,6 +153,9 @@ module.exports = {
addZeroBefore,
resizeArray,
isEmptyObject,
emptyJsObject,
sleep,
convertUTCDateToLocalDate
convertUTCDateToLocalDate,
writeToFile,
addToArrayIfUnique
}

View file

@ -1,15 +1,10 @@
[![Support](https://www.totaljs.com/img/button-support.png)](https://www.totaljs.com/support/)
# Total.js version 4 - Flow
- [__Live chat with professional support__](https://messenger.totaljs.com)
- [__HelpDesk with professional support__](https://helpdesk.totaljs.com)
- [Documentation](https://docs.totaljs.com)
- [Wiki](https://wiki.totaljs.com)
This is a version of citysys-flowserver, running on Debian12 OS.
It has the latest LTS version of nodejs and latest npm modules installed.
# Total.js: Empty Project - Flow
- download example
- open terminal / command-line
- open app directory
- install latest version of Total.js from NPM `$ npm install total.js`
- run `$ node debug.js`
- open browser `http://127.0.0.1:8000`
- run `$ npm install`
- run `$ node index.js`
- open browser `http://0.0.0.0:12345`