diff --git a/databases/total_energy.js b/databases/total_energy.js index cc8c018..dde340e 100644 --- a/databases/total_energy.js +++ b/databases/total_energy.js @@ -30,6 +30,7 @@ const total_energy = { 47: 1100, 48: 1500, 50: 3200, + 53: 1250, 55: 1000, 56: 5500 } diff --git a/flow/cmd_manager.js b/flow/cmd_manager.js index 07e12c6..c553e4c 100644 --- a/flow/cmd_manager.js +++ b/flow/cmd_manager.js @@ -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 } @@ -1529,7 +1662,7 @@ exports.install = function(instance) { // await keyword is important, otherwise incorrect data is returned! await writeData(rsPort, resp, readBytes, timeout).then(function(data) { - //sometimes happens, that status of node changes even if line was turned off and should be offline. To prevent this, we return if line contactor is 0: + //sometimes happens, that status of node changes to OK, NOK even if line was turned off and should be status OFFLINE. To prevent this, we return if line contactor is 0: if (itIsNodeCommand && line && relaysData[line].contactor !== 1) return; endTime = new Date(); @@ -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 @@ -1650,6 +1817,7 @@ exports.install = function(instance) { } + // if node does not respond to request, we repeat request 3 times: function repeatCommand(params) { params.repeatCounter++; if (params.repeatCounter < 4) { @@ -1810,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) { @@ -1867,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"); @@ -1986,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); @@ -2002,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) @@ -2275,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 { @@ -2471,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; @@ -2491,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 @@ -2519,9 +2734,6 @@ exports.install = function(instance) { } - //dusk - súmrak - //down, sunrise - svitanie - } catch (error) { if (profilestr != "") { logger.debug(profilestr); @@ -2740,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); } diff --git a/flow/db_init.js b/flow/db_init.js index 60a0510..a759465 100644 --- a/flow/db_init.js +++ b/flow/db_init.js @@ -50,7 +50,7 @@ exports.install = async function(instance) { Object.keys(dbs.nodesData).forEach(node => dbs.nodesData[node].readout = {}) dbs.settings = { - edge_fw_version: "2025-07-08", //rok-mesiac-den + edge_fw_version: "2025-08-08", //rok-mesiac-den language: responseSettings[0]["lang"], rvo_name: responseSettings[0]["rvo_name"], project_id: responseSettings[0]["project_id"], diff --git a/flow/designer.json b/flow/designer.json index 7565777..d757f87 100644 --- a/flow/designer.json +++ b/flow/designer.json @@ -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 diff --git a/flow/helper/utils.js b/flow/helper/utils.js index 9c054aa..dbffe45 100644 --- a/flow/helper/utils.js +++ b/flow/helper/utils.js @@ -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 } diff --git a/readme.md b/readme.md index f2e23d2..00a2146 100644 --- a/readme.md +++ b/readme.md @@ -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` \ No newline at end of file +- run `$ npm install` +- run `$ node index.js` +- open browser `http://0.0.0.0:12345`