Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- [
- {
- "id": "9c5e9d61.1f5fe",
- "type": "subflow",
- "name": "database stats",
- "info": "",
- "category": "",
- "in": [
- {
- "x": 540,
- "y": 220,
- "wires": [
- {
- "id": "cff83da3.a7ea1"
- }
- ]
- }
- ],
- "out": [
- {
- "x": 1214.0000171661377,
- "y": 226.00000190734863,
- "wires": [
- {
- "id": "5988a52b493c9716",
- "port": 0
- }
- ]
- }
- ]
- },
- {
- "id": "cff83da3.a7ea1",
- "type": "function",
- "z": "9c5e9d61.1f5fe",
- "name": "",
- "func": "if (!msg.stats.where) {\n msg.stats.where = '1 == 1';\n}\n\nlet sql = `\n SELECT timestamp, ${msg.stats.agregateFunction}(value) as value FROM (\n SELECT\n UNIX_TIMESTAMP(DATE_FORMAT(${msg.stats.column_date}, '%Y-%m-%d-%H:%i:00')) * 1000 as \\`timestamp\\`,\n ${msg.stats.column_value} as value\n FROM\n ${msg.stats.table}\n WHERE\n ${msg.stats.column_date} > NOW() - INTERVAL ${msg.stats.interval}\n AND ${msg.stats.where}\n ) ss\n GROUP BY\n \\`timestamp\\`\n`;\nmsg.payload = []\nmsg.topic = sql;\n//node.warn(sql);\nreturn msg;\n",
- "outputs": 1,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 670,
- "y": 220,
- "wires": [
- [
- "6e210fc3.ed7a1"
- ]
- ]
- },
- {
- "id": "6e210fc3.ed7a1",
- "type": "mysql",
- "z": "9c5e9d61.1f5fe",
- "mydb": "76a2023f.8c254c",
- "name": "",
- "x": 830.9999771118164,
- "y": 219,
- "wires": [
- [
- "5988a52b493c9716"
- ]
- ]
- },
- {
- "id": "a9df1a10.6311e8",
- "type": "function",
- "z": "9c5e9d61.1f5fe",
- "d": true,
- "name": "dashboard v2.x",
- "func": "let data = [];\n\nmsg.payload.forEach((v, k) => {\n data.push([\n v.timestamp,\n v.value\n ]);\n});\n\nmsg.payload = [\n {\n \"key\": `${msg.stats.column_value}`,\n \"values\": data\n }\n]\n\nreturn msg;",
- "outputs": 1,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 1054.000114440918,
- "y": 284.00000381469727,
- "wires": [
- []
- ]
- },
- {
- "id": "5988a52b493c9716",
- "type": "function",
- "z": "9c5e9d61.1f5fe",
- "name": "dashboard v3.x",
- "func": "let data = [];\n\nmsg.payload.forEach((v, k) => {\n data.push({\n x:v.timestamp,\n y:v.value\n });\n});\n\nmsg.payload = [\n {\n \"series\": [\"value\"],\n \"data\": [data],\n \"labels\": [\"\"]\n }\n]\n\nreturn msg;",
- "outputs": 1,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 1049.8000144958496,
- "y": 225.00000381469727,
- "wires": [
- []
- ]
- },
- {
- "id": "303c9862.ddfff8",
- "type": "tab",
- "label": "FVE",
- "disabled": false,
- "info": ""
- },
- {
- "id": "f0ca0f93933a6266",
- "type": "junction",
- "z": "303c9862.ddfff8",
- "x": 549.8600784540176,
- "y": 657.4985766410828,
- "wires": [
- [
- "5d07132555535339",
- "0f816f3ad14dd816",
- "0d35bbeb61b3425d"
- ]
- ]
- },
- {
- "id": "2c54ae5b8ba85505",
- "type": "junction",
- "z": "303c9862.ddfff8",
- "x": 1522.2407758235931,
- "y": 3605.2983433380723,
- "wires": [
- [
- "8e3f2accc4d47cf1",
- "d0c51b4e08b32eb2",
- "535ea969ba5e5c16",
- "5f18183f56309951",
- "dd5dd723ead7dd78",
- "8d0de0a23b20e624",
- "656b1803a57a159b",
- "b562397f4dc61e83",
- "7ba79850621f4c7b"
- ]
- ]
- },
- {
- "id": "c4597790.33e678",
- "type": "function",
- "z": "303c9862.ddfff8",
- "name": "",
- "func": "for (const record of msg.payload.forecasts) {\n const endDate = record.period_end.substr(0, 19).replace('T', ' ');\n msg.payload = [\n endDate,\n endDate,\n msg.rooftopId,\n record.pv_estimate,\n record.pv_estimate10,\n record.pv_estimate90,\n ];\n msg.topic = `INSERT INTO pv_forecast SET\n request_date = NOW(),\n forecast_from_date = CONVERT_TZ(?, '+00:00', 'SYSTEM') - INTERVAL 30 MINUTE,\n forecast_to_date = CONVERT_TZ(?, '+00:00', 'SYSTEM'),\n pv_rooftop_id = ?,\n kilowatts = ?,\n kilowatts_min = ?,\n kilowatts_max = ?\n `;\n node.send(msg);\n}\n",
- "outputs": 1,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 1061.0001182556152,
- "y": 368.00000381469727,
- "wires": [
- [
- "d069bd08.9ae74",
- "12df0984d0ecf73c"
- ]
- ]
- },
- {
- "id": "d069bd08.9ae74",
- "type": "mysql",
- "z": "303c9862.ddfff8",
- "mydb": "76a2023f.8c254c",
- "name": "",
- "x": 1269.0001220703125,
- "y": 368.00000381469727,
- "wires": [
- []
- ]
- },
- {
- "id": "e2033b47.3c6a98",
- "type": "comment",
- "z": "303c9862.ddfff8",
- "name": "solcast DB",
- "info": "",
- "x": 327,
- "y": 307.99997091293335,
- "wires": []
- },
- {
- "id": "54dfb091.cc0db",
- "type": "http in",
- "z": "303c9862.ddfff8",
- "name": "",
- "url": "/goodwe-pv-inverter-record",
- "method": "post",
- "upload": false,
- "swaggerDoc": "",
- "x": 463.8952331542969,
- "y": 1345.3619434833527,
- "wires": [
- [
- "d2bc7cbb.1c069",
- "962e1edb.38107",
- "dd943cb8.da362",
- "c3f6137434653aca"
- ]
- ]
- },
- {
- "id": "d2bc7cbb.1c069",
- "type": "debug",
- "z": "303c9862.ddfff8",
- "name": "",
- "active": false,
- "tosidebar": true,
- "console": false,
- "tostatus": false,
- "complete": "true",
- "targetType": "full",
- "statusVal": "",
- "statusType": "auto",
- "x": 719.0952606201172,
- "y": 1292.7619869709015,
- "wires": []
- },
- {
- "id": "b40fcb52.2ad378",
- "type": "http response",
- "z": "303c9862.ddfff8",
- "name": "",
- "statusCode": "",
- "headers": {},
- "x": 898.0952587127686,
- "y": 1365.7619888782501,
- "wires": []
- },
- {
- "id": "962e1edb.38107",
- "type": "function",
- "z": "303c9862.ddfff8",
- "name": "",
- "func": "msg.payload = {status: 200}\nreturn msg;",
- "outputs": 1,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [
- {
- "var": "fs",
- "module": "fs"
- }
- ],
- "x": 723.0952529907227,
- "y": 1357.7619888782501,
- "wires": [
- [
- "b40fcb52.2ad378"
- ]
- ]
- },
- {
- "id": "38713333.c0669c",
- "type": "comment",
- "z": "303c9862.ddfff8",
- "name": "logger",
- "info": "",
- "x": 242.09523010253906,
- "y": 1261.3619244098663,
- "wires": []
- },
- {
- "id": "dd943cb8.da362",
- "type": "function",
- "z": "303c9862.ddfff8",
- "name": "",
- "func": "const columns = Object.keys(msg.payload).map((column) => `${column} = ?`).join(', ');\n\nmsg.topic = `INSERT INTO pv_inverter_record SET log_date = NOW(), ${columns}`;\nmsg.payload = Object.values(msg.payload);\n\nreturn msg;\n",
- "outputs": 1,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 860.0952301025391,
- "y": 1449.3619244098663,
- "wires": [
- [
- "3adb4230412c1917"
- ]
- ]
- },
- {
- "id": "94c83d02.02f7c",
- "type": "debug",
- "z": "303c9862.ddfff8",
- "name": "",
- "active": false,
- "tosidebar": true,
- "console": false,
- "tostatus": false,
- "complete": "false",
- "statusVal": "",
- "statusType": "auto",
- "x": 1280.095230102539,
- "y": 1418.3619244098663,
- "wires": []
- },
- {
- "id": "1f2bf028.4ec1c",
- "type": "ui_text",
- "z": "303c9862.ddfff8",
- "group": "312b72db.d7629e",
- "order": 2,
- "width": 0,
- "height": 0,
- "name": "",
- "label": "House Consumption",
- "format": "{{msg.payload.ac_house_consumption_maxof}}W ({{msg.payload.ac_house_consumption}}W)",
- "layout": "row-spread",
- "x": 1379.0952320098877,
- "y": 1610.5620663166046,
- "wires": []
- },
- {
- "id": "efdc183d.d80958",
- "type": "function",
- "z": "303c9862.ddfff8",
- "name": "",
- "func": "/*node.warn({\n ac_load_p1: msg.payload.ac_load_p1,\n ac_pgrid1: msg.payload.ac_pgrid1,\n backup_p1: msg.payload.backup_p1,\n});*/\n\nmsg.payload.lastUpdateTime = dateformat(new Date(), \"yyyy-mm-dd HH:MM:ss\");\n\n// Pokud je to ostrovni rezim, tak hodnoty pro ac_load chodi stejny jako pro backup\n// Ale v normalnim rezimu On-Grid, je to rozdelene - na backup chodi jen to co je na backupu a na ac_load jen to co je v normalni siti\n// Takze v ostrovnim rezimu se chceme tvarit jako ze ac_load je nulovy\nif (msg.payload.work_mode_label == \"Normal (Off-Grid)\") {\n msg.payload.ac_load_p1 = 0;\n msg.payload.ac_load_p2 = 0;\n msg.payload.ac_load_p3 = 0;\n}\n\n// spotreba domu vzit jako max z reportovane spotreby domu a souctu vystupu na backupu a vystupu do site\nmsg.payload.ac_house_consumption_maxof = Math.max(\n msg.payload.ac_house_consumption,\n (msg.payload.ac_load_p1+msg.payload.ac_load_p2+msg.payload.ac_load_p3) + (msg.payload.backup_p1+msg.payload.backup_p2+msg.payload.backup_p3)\n);\n\n// spocitat volne dostupnou energii\n// ta je jako soucet toho co se exportuje do gridu a do baterie\nconst batteryRecord = flow.get('batteryRecord');\nmsg.payload.freeAvailableEnergy = \n msg.payload.grid_active_power\n +\n batteryRecord.batteryPower\n;\n\nmsg.payload.pv_ppv_percent1 = Math.round(100 * (msg.payload.pv_ppv1/1000) / flow.get('pv_rooftop_power1'));\nmsg.payload.pv_ppv_percent2 = Math.round(100 * (msg.payload.pv_ppv2 / 1000) / flow.get('pv_rooftop_power2'));\n\nflow.set('pvInverterRecord', msg.payload);\n\nreturn msg;",
- "outputs": 1,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [
- {
- "var": "dateformat",
- "module": "dateformat"
- }
- ],
- "x": 963.0953235626221,
- "y": 1706.562043428421,
- "wires": [
- [
- "8f66dcf7.548df",
- "54170f47.5f04d",
- "86b20f44.38068",
- "8485efb6.66136",
- "3163b2fe.f1ff5e",
- "75307869.913298",
- "74496f57.36c2a",
- "118f534d.d832bd",
- "d2264ec6.39eaa",
- "203e54fa.eef5ac",
- "ab490cf4.8d57c",
- "811c3f65.b4f79",
- "1f2bf028.4ec1c",
- "7a1b5a43ecb17018",
- "24aa274ef9f69f21",
- "1c6d03dba19e8225",
- "e0c76b9c8b0a812d",
- "5b12492d69e13db2",
- "dc5ecd1673d5073d",
- "c94a357adb066e7e"
- ]
- ]
- },
- {
- "id": "8f66dcf7.548df",
- "type": "ui_text",
- "z": "303c9862.ddfff8",
- "group": "312b72db.d7629e",
- "order": 1,
- "width": 0,
- "height": 0,
- "name": "",
- "label": "PV",
- "format": "{{msg.payload.pv_ppv}}W ({{msg.payload.pv_ppv1}}+{{msg.payload.pv_ppv2}})",
- "layout": "row-spread",
- "className": "",
- "x": 1326.0952529907227,
- "y": 1657.5620243549347,
- "wires": []
- },
- {
- "id": "54170f47.5f04d",
- "type": "ui_text",
- "z": "303c9862.ddfff8",
- "d": true,
- "group": "312b72db.d7629e",
- "order": 3,
- "width": 0,
- "height": 0,
- "name": "",
- "label": "Battery",
- "format": "{{msg.payload.battery_pbattery1*-1}}W",
- "layout": "row-spread",
- "x": 1338.095230102539,
- "y": 1699.5619976520538,
- "wires": []
- },
- {
- "id": "83d4257e.51d728",
- "type": "ui_text",
- "z": "303c9862.ddfff8",
- "group": "312b72db.d7629e",
- "order": 5,
- "width": 0,
- "height": 0,
- "name": "Grid",
- "label": "Grid ({{msg.payload.grid_direction}})",
- "format": "{{msg.payload.grid_active_power}}W ({{msg.payload.grid_meter_active_power1 >= 0 ? \"+\"+msg.payload.grid_meter_active_power1 : msg.payload.grid_meter_active_power1}}{{msg.payload.grid_meter_active_power2 >= 0 ? \"+\"+msg.payload.grid_meter_active_power2 : msg.payload.grid_meter_active_power2}}{{msg.payload.grid_meter_active_power3 >= 0 ? \"+\"+msg.payload.grid_meter_active_power3 : msg.payload.grid_meter_active_power3}})",
- "layout": "row-spread",
- "x": 1387.095266342163,
- "y": 1751.5619661808014,
- "wires": []
- },
- {
- "id": "86b20f44.38068",
- "type": "ui_text",
- "z": "303c9862.ddfff8",
- "group": "b55f633.0a700a",
- "order": 0,
- "width": 0,
- "height": 0,
- "name": "",
- "label": "SOC",
- "format": "{{msg.payload.battery_soc}}%",
- "layout": "row-spread",
- "x": 1327.095230102539,
- "y": 1844.1619732379913,
- "wires": []
- },
- {
- "id": "8485efb6.66136",
- "type": "ui_text",
- "z": "303c9862.ddfff8",
- "group": "b55f633.0a700a",
- "order": 0,
- "width": 0,
- "height": 0,
- "name": "",
- "label": "Mode",
- "format": "{{msg.payload.battery_mode_label}}",
- "layout": "row-spread",
- "x": 1330.0952281951904,
- "y": 1879.1620209217072,
- "wires": []
- },
- {
- "id": "4d42466c.cea3e8",
- "type": "inject",
- "z": "303c9862.ddfff8",
- "name": "",
- "props": [
- {
- "p": "payload"
- },
- {
- "p": "topic",
- "vt": "str"
- }
- ],
- "repeat": "600",
- "crontab": "",
- "once": true,
- "onceDelay": 0.1,
- "topic": "",
- "payload": "",
- "payloadType": "date",
- "x": 478.6667289733887,
- "y": 860.3333446979523,
- "wires": [
- [
- "bbd40e52.e5e28"
- ]
- ]
- },
- {
- "id": "bbd40e52.e5e28",
- "type": "function",
- "z": "303c9862.ddfff8",
- "name": "",
- "func": "const af = global.get('actionflows');\n\nconst resMsg = await af.invoke('core.db.query', {\n database: 'smarthouse',\n query: \"SELECT * FROM pv_rooftop\",\n values: [],\n});\n\nlet totalPower = 0;\n\nfor (const rooftop of resMsg.payload) {\n const resMsg2 = await af.invoke('core.db.query', {\n database: 'smarthouse',\n query: `\n SELECT * FROM pv_forecast\n \tWHERE pv_rooftop_id = ? AND forecast_from_date >= NOW()\n \tORDER by forecast_from_date ASC, request_date DESC LIMIT 1\n \t`,\n values: [rooftop.id],\n });\n \n if (resMsg2.payload.length) {\n totalPower += resMsg2.payload[0].kilowatts * rooftop.power;\n }\n}\n\nmsg.payload = Math.round(totalPower * 1000);\nreturn msg;",
- "outputs": 1,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 660.6667289733887,
- "y": 865.3333446979523,
- "wires": [
- [
- "194df1a8.097f6e",
- "3a31dfb9.55bf9"
- ]
- ]
- },
- {
- "id": "3a31dfb9.55bf9",
- "type": "debug",
- "z": "303c9862.ddfff8",
- "name": "",
- "active": false,
- "tosidebar": true,
- "console": false,
- "tostatus": false,
- "complete": "false",
- "statusVal": "",
- "statusType": "auto",
- "x": 892.666748046875,
- "y": 851.9333031177521,
- "wires": []
- },
- {
- "id": "194df1a8.097f6e",
- "type": "ui_text",
- "z": "303c9862.ddfff8",
- "group": "d9bbfe4e.3d039",
- "order": 1,
- "width": 0,
- "height": 0,
- "name": "",
- "label": "Now",
- "format": "{{msg.payload}}W",
- "layout": "row-spread",
- "className": "",
- "x": 881.666748046875,
- "y": 902.333377122879,
- "wires": []
- },
- {
- "id": "e136e96b.2dbfe8",
- "type": "function",
- "z": "303c9862.ddfff8",
- "name": "",
- "func": "//msg.topic = `select UNIX_TIMESTAMP(forecast_from_date) as forecast_from_date, UNIX_TIMESTAMP(forecast_to_date) as forecast_to_date, roof_name, kilowatts from pv_solcast_forecast where request_date = (SELECT request_date FROM pv_solcast_forecast WHERE forecast_from_date >= NOW() ORDER BY forecast_from_date, request_date DESC LIMIT 1) AND forecast_from_date >= NOW() AND forecast_to_date < DATE(NOW())+interval 1 day order by forecast_from_date`;\nmsg.topic = `\n WITH\n \tpv_forecast_ranked_1 AS (\n \t\tselect\n \t\t\tpv_forecast.forecast_to_date, pv_forecast.kilowatts*pv_rooftop.power AS rooftop_kilowatts, ROW_NUMBER() OVER (PARTITION BY forecast_from_date ORDER BY request_date DESC) AS rn\n \t\tfrom\n \t\t\tpv_forecast\n \t\tJOIN pv_rooftop ON pv_rooftop.id = pv_rooftop_id\n \t\twhere\n \t\t\tDATE(NOW() + INTERVAL ${msg.todayOffset} DAY) = DATE(forecast_to_date)\n \t\t\tand pv_rooftop_id = 1\n \t\torder by forecast_to_date, request_date\n \t),\n \tpv_forecast_ranked_2 AS (\n \t\tselect\n \t\t\tpv_forecast.forecast_to_date, pv_forecast.kilowatts*pv_rooftop.power AS rooftop_kilowatts, ROW_NUMBER() OVER (PARTITION BY forecast_from_date ORDER BY request_date DESC) AS rn\n \t\tfrom\n \t\t\tpv_forecast\n\t\t\tJOIN pv_rooftop ON pv_rooftop.id = pv_rooftop_id\n \t\twhere\n \t\t\tDATE(NOW() + INTERVAL ${msg.todayOffset} DAY) = DATE(forecast_to_date)\n \t\t\tand pv_rooftop_id = 2\n \t\torder by forecast_to_date, request_date\n \t)\n \n SELECT * FROM (\n \tSELECT time, total_power1 AS forecast_rest_power1, total_power2 AS forecast_rest_power2 FROM (\n \t\tSELECT time, @curr1:=(string1)*(ABS(IF(@prevTime IS NULL, 0, time-@prevTime))/3600) as kwh1, @curr2:=(string2)*(ABS(IF(@prevTime IS NULL, 0, time-@prevTime))/3600) as kwh2, @e1:=@e1+@curr1 AS total_power1, @e2:=@e2+@curr2 AS total_power2, @prevTime:=time FROM (\n \t\t\tSELECT\n \t\t\tUNIX_TIMESTAMP(pv_forecast_ranked_1.forecast_to_date) AS \"time\",\n \t\t\tpv_forecast_ranked_1.rooftop_kilowatts AS string1, IFNULL(pv_forecast_ranked_2.rooftop_kilowatts, 0) AS string2\n \t\t\tFROM\n \t\t\tpv_forecast_ranked_1\n\t\t\t\tLEFT JOIN pv_forecast_ranked_2 ON pv_forecast_ranked_1.forecast_to_date = pv_forecast_ranked_2.forecast_to_date AND pv_forecast_ranked_2.rn = 1\n \t\t\tWHERE\n \t\t\tpv_forecast_ranked_1.rn = 1\n \t\t\tORDER BY time DESC\n \t\t) forecast, (SELECT@e1:=0)e1, (SELECT@e2:=0)e2, (SELECT@prevTime:=NULL)prevTime\n \t) forecast2\n \tORDER BY time ASC\n ) forecast3\n`;\nmsg.payload = [];\n\nreturn msg;\n",
- "outputs": 1,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 636.66672706604,
- "y": 1044.1333572864532,
- "wires": [
- [
- "67449735.a106e8"
- ]
- ]
- },
- {
- "id": "67449735.a106e8",
- "type": "mysql",
- "z": "303c9862.ddfff8",
- "mydb": "76a2023f.8c254c",
- "name": "",
- "x": 807.6667461395264,
- "y": 1039.13338971138,
- "wires": [
- [
- "f59eeb5f.e41d88",
- "c97e520.1152db"
- ]
- ]
- },
- {
- "id": "adf8461f.01e548",
- "type": "ui_text",
- "z": "303c9862.ddfff8",
- "group": "d9bbfe4e.3d039",
- "order": 3,
- "width": 0,
- "height": 0,
- "name": "",
- "label": "Power Today",
- "format": "{{msg.payload.total}}kWh ({{msg.payload.total1}}+{{msg.payload.total2}})",
- "layout": "row-spread",
- "className": "",
- "x": 1178.6668167114258,
- "y": 1075.1334142684937,
- "wires": []
- },
- {
- "id": "a0f2c0a1.2d959",
- "type": "inject",
- "z": "303c9862.ddfff8",
- "name": "",
- "props": [
- {
- "p": "payload"
- },
- {
- "p": "todayOffset",
- "v": "0",
- "vt": "str"
- }
- ],
- "repeat": "600",
- "crontab": "",
- "once": true,
- "onceDelay": 0.1,
- "topic": "",
- "payload": "",
- "payloadType": "date",
- "x": 483.66673469543457,
- "y": 1027.1333782672882,
- "wires": [
- [
- "e136e96b.2dbfe8"
- ]
- ]
- },
- {
- "id": "f59eeb5f.e41d88",
- "type": "debug",
- "z": "303c9862.ddfff8",
- "name": "",
- "active": false,
- "tosidebar": true,
- "console": false,
- "tostatus": false,
- "complete": "false",
- "statusVal": "",
- "statusType": "auto",
- "x": 978.6667442321777,
- "y": 992.1333782672882,
- "wires": []
- },
- {
- "id": "bb805d7.6002ea",
- "type": "ui_gauge",
- "z": "303c9862.ddfff8",
- "name": "Battery SOC",
- "group": "819686be.5e6a58",
- "order": 6,
- "width": 0,
- "height": 0,
- "gtype": "wave",
- "title": "Battery SOC ({{msg.batteryChangeSpeedText}})",
- "label": "%",
- "format": "{{value}}",
- "min": 0,
- "max": "100",
- "colors": [
- "#00b500",
- "#e6e600",
- "#ca3838"
- ],
- "seg1": "",
- "seg2": "",
- "x": 1392.0952644348145,
- "y": 2367.561976671219,
- "wires": []
- },
- {
- "id": "3163b2fe.f1ff5e",
- "type": "function",
- "z": "303c9862.ddfff8",
- "name": "",
- "func": "msg.batteryChangeSpeedText = flow.get('batteryRecord').batteryChangeSpeedText;\nmsg.payload = msg.payload.battery_soc;\nreturn msg;",
- "outputs": 1,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 1231.0952682495117,
- "y": 2364.5619747638702,
- "wires": [
- [
- "bb805d7.6002ea"
- ]
- ]
- },
- {
- "id": "75307869.913298",
- "type": "function",
- "z": "303c9862.ddfff8",
- "name": "",
- "func": "msg.payload = msg.payload.pv_ppv;\nreturn msg;",
- "outputs": 1,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "x": 1234.0952682495117,
- "y": 2252.5620715618134,
- "wires": [
- [
- "9b497417b6425c53"
- ]
- ]
- },
- {
- "id": "bb2004f2.959448",
- "type": "ui_gauge",
- "z": "303c9862.ddfff8",
- "d": true,
- "name": "Battery",
- "group": "819686be.5e6a58",
- "order": 3,
- "width": 0,
- "height": 0,
- "gtype": "gage",
- "title": "Battery - {{msg.batteryMode}}",
- "label": "W",
- "format": "{{value}}",
- "min": "-8000",
- "max": "8000",
- "colors": [
- "#b30000",
- "#ffffff",
- "#36cc00"
- ],
- "seg1": "",
- "seg2": "",
- "x": 1394.0952682495117,
- "y": 2316.561976671219,
- "wires": []
- },
- {
- "id": "74496f57.36c2a",
- "type": "function",
- "z": "303c9862.ddfff8",
- "name": "",
- "func": "let batteryPower = msg.payload.battery_pbattery1*-1;\nlet batteryMode = msg.payload.battery_mode_label; \n\nif (batteryMode == \"Discharge\" && batteryPower >= 0) {\n batteryPower = 0;\n if (msg.payload.battery_soc >= 100) {\n batteryMode = \"Fully Charged\";\n }else {\n batteryMode = \"Standby\";\n }\n}\n\nmsg.batteryMode = batteryMode;\nmsg.payload = batteryPower;\nreturn msg;",
- "outputs": 1,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 1227.0952682495117,
- "y": 2314.561976671219,
- "wires": [
- [
- "bb2004f2.959448"
- ]
- ]
- },
- {
- "id": "3aab581b.326c98",
- "type": "function",
- "z": "303c9862.ddfff8",
- "name": "Zatížení fází",
- "func": "const phasesLoad = [\n Math.round(100 * msg.payload.backup_p1 / 3300),\n Math.round(100 * msg.payload.backup_p2 / 3300),\n Math.round(100 * msg.payload.backup_p3 / 3300),\n];\n\nfunction notifyLoad(phase, currentLoad)\n{\n const lastNotifiedTime = flow.get(`lastNotifiedBackupLoadTime_${phase}`) || 0;\n if (Date.now() - lastNotifiedTime > 5*1000) {\n flow.set(`lastNotifiedBackupLoadTime_${phase}`, Date.now());\n \n const lastNotifiedBackupLoad = flow.get(`lastNotifiedBackupLoadValue_${phase}`) || 0;\n const diff = Math.abs(currentLoad - lastNotifiedBackupLoad);\n \n // notifikovat pokud je laod vetsi nez 95 popr. pokud se zvednul o dalsich 10\n // nebo pokud byl load > 95 a uz je pod 70\n const upperThreshold = 110;\n const lowerThreshold = 70;\n if ((currentLoad > upperThreshold && currentLoad > lastNotifiedBackupLoad + 10) || (lastNotifiedBackupLoad > upperThreshold && currentLoad <= lowerThreshold)) {\n flow.set(`lastNotifiedBackupLoadValue_${phase}`, currentLoad);\n \n node.warn(`Load changed (phase: ${phase}, current load: ${currentLoad}, previousLoad: ${lastNotifiedBackupLoad})`);\n msg.payload = {\"title\" : `Zatížení fáze L${phase}. ${currentLoad}%`, \"text\" : \"\", \"event\" : \"speech\", \"options\" : {\"telegram\" : false}}\n node.send(msg);\n }\n }\n}\n\nnotifyLoad(1, phasesLoad[0]);\nnotifyLoad(2, phasesLoad[1]);\nnotifyLoad(3, phasesLoad[2]);\n",
- "outputs": 1,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 873.0953063964844,
- "y": 2677.7623703479767,
- "wires": [
- [
- "bddab30d.0dddc"
- ]
- ]
- },
- {
- "id": "bddab30d.0dddc",
- "type": "actionflows",
- "z": "303c9862.ddfff8",
- "info": "Describe your action API here.",
- "untilproptype": "num",
- "proptype": "msg",
- "name": "notify",
- "prop": "loop",
- "untilprop": 0,
- "until": "gt",
- "loop": "none",
- "scope": "global",
- "perf": false,
- "seq": false,
- "x": 1037.0953063964844,
- "y": 2679.7623703479767,
- "wires": [
- []
- ]
- },
- {
- "id": "d2f463e9.b9a6",
- "type": "ui_text",
- "z": "303c9862.ddfff8",
- "group": "d1547785.b0eb48",
- "order": 0,
- "width": 0,
- "height": 0,
- "name": "",
- "label": "L1",
- "format": "{{msg.payload.phasesLoad[0].ac+msg.payload.phasesLoad[0].backup}}W({{msg.payload.phasesLoad[0].ac}}+{{msg.payload.phasesLoad[0].backup}}) [{{msg.payload.phasesLoad[0].percent}}%]",
- "layout": "row-spread",
- "x": 1387.0952892303467,
- "y": 2538.1618225574493,
- "wires": []
- },
- {
- "id": "118f534d.d832bd",
- "type": "function",
- "z": "303c9862.ddfff8",
- "name": "Phases Load",
- "func": "const phasesLoad = [\n {percent: Math.round(100 * (msg.payload.backup_p1+msg.payload.ac_load_p1) / 3300), backup: msg.payload.backup_p1, ac: msg.payload.ac_load_p1},\n {percent: Math.round(100 * (msg.payload.backup_p2+msg.payload.ac_load_p2) / 3300), backup: msg.payload.backup_p2, ac: msg.payload.ac_load_p2},\n {percent: Math.round(100 * (msg.payload.backup_p3+msg.payload.ac_load_p3) / 3300), backup: msg.payload.backup_p3, ac: msg.payload.ac_load_p3},\n];\n\nmsg.payload = {\n phasesLoad,\n};\n\nreturn msg;",
- "outputs": 1,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 1225.0952281951904,
- "y": 2539.161930322647,
- "wires": [
- [
- "d2f463e9.b9a6",
- "eb45726.34fae9",
- "ead65c60.5d7af"
- ]
- ]
- },
- {
- "id": "eb45726.34fae9",
- "type": "ui_text",
- "z": "303c9862.ddfff8",
- "group": "d1547785.b0eb48",
- "order": 0,
- "width": 0,
- "height": 0,
- "name": "",
- "label": "L2",
- "format": "{{msg.payload.phasesLoad[1].ac+msg.payload.phasesLoad[1].backup}}W({{msg.payload.phasesLoad[1].ac}}+{{msg.payload.phasesLoad[1].backup}}) [{{msg.payload.phasesLoad[1].percent}}%]",
- "layout": "row-spread",
- "x": 1387.095266342163,
- "y": 2576.1617834568024,
- "wires": []
- },
- {
- "id": "ead65c60.5d7af",
- "type": "ui_text",
- "z": "303c9862.ddfff8",
- "group": "d1547785.b0eb48",
- "order": 0,
- "width": 0,
- "height": 0,
- "name": "",
- "label": "L3",
- "format": "{{msg.payload.phasesLoad[2].ac+msg.payload.phasesLoad[2].backup}}W({{msg.payload.phasesLoad[2].ac}}+{{msg.payload.phasesLoad[2].backup}}) [{{msg.payload.phasesLoad[2].percent}}%]",
- "layout": "row-spread",
- "x": 1390.095266342163,
- "y": 2612.1617834568024,
- "wires": []
- },
- {
- "id": "9c95fb95.b18c28",
- "type": "function",
- "z": "303c9862.ddfff8",
- "name": "Stav FVE",
- "func": "const lastNotifiedInverterStatus = flow.get(`lastNotifiedInverterStatus`);\n\nlet currentInverterStatus = `Změna stavu fotovoltaiky ${msg.payload.work_mode_label}. Stav sítě ${msg.payload.grid_mode_label}`;\n\nif (currentInverterStatus != lastNotifiedInverterStatus) {\n flow.set(`lastNotifiedInverterStatus`, currentInverterStatus);\n \n msg.payload = {\"title\" : currentInverterStatus, \"text\" : \"\", \"event\" : \"speech\"}\n node.send(msg);\n}\n",
- "outputs": 1,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 858.0952453613281,
- "y": 2932.3623485565186,
- "wires": [
- [
- "6a08531c.173c0c"
- ]
- ]
- },
- {
- "id": "6a08531c.173c0c",
- "type": "actionflows",
- "z": "303c9862.ddfff8",
- "info": "Describe your action API here.",
- "untilproptype": "num",
- "proptype": "msg",
- "name": "notify",
- "prop": "loop",
- "untilprop": 0,
- "until": "gt",
- "loop": "none",
- "scope": "global",
- "perf": false,
- "seq": false,
- "x": 1036.0953674316406,
- "y": 2930.3623485565186,
- "wires": [
- []
- ]
- },
- {
- "id": "4dad62b3.f306fc",
- "type": "function",
- "z": "303c9862.ddfff8",
- "name": "SOC Baterie",
- "func": "const lastNotifiedSOC = flow.get(`lastNotifiedSOC`) || 0;\n\nlet currentSOC = msg.payload.battery_soc;\n\nif (\n currentSOC % 5 == 0 /*stav baterie musi byt delitelny 5*/\n &&\n (\n (currentSOC > 50 && Math.abs(currentSOC - lastNotifiedSOC) >= 10)\n || \n (currentSOC <= 50 && Math.abs(currentSOC - lastNotifiedSOC) >= 5)\n )\n) {\n flow.set(`lastNotifiedSOC`, currentSOC);\n \n msg.payload = {\"title\" : currentSOC > lastNotifiedSOC ? `Baterie se dobila na ${currentSOC}%` : `Baterie se vybila na ${currentSOC}%`, \"text\" : \"\", \"event\" : \"speech\"}\n node.send(msg);\n}\n",
- "outputs": 1,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 855.0952415466309,
- "y": 3052.162185907364,
- "wires": [
- [
- "d87a2bdcc3f484b0"
- ]
- ]
- },
- {
- "id": "e6a603d9.ee064",
- "type": "actionflows",
- "z": "303c9862.ddfff8",
- "info": "Describe your action API here.",
- "untilproptype": "num",
- "proptype": "msg",
- "name": "notify",
- "prop": "loop",
- "untilprop": 0,
- "until": "gt",
- "loop": "none",
- "scope": "global",
- "perf": false,
- "seq": false,
- "x": 1276.0953102111816,
- "y": 3050.162399291992,
- "wires": [
- []
- ]
- },
- {
- "id": "c97e520.1152db",
- "type": "function",
- "z": "303c9862.ddfff8",
- "name": "",
- "func": "const msgs = [null, null];\n\nlet total1 = null;\nlet total2 = null;\nlet rest1 = null;\nlet rest2 = null;\n\nfor (const row of msg.payload) {\n if (total1 === null) {\n total1 = row.forecast_rest_power1;\n }\n if (total2 === null) {\n total2 = row.forecast_rest_power2;\n }\n if (rest1 === null && row.time*1000 >= Date.now()) {\n rest1 = row.forecast_rest_power1;\n rest2 = row.forecast_rest_power2;\n }\n}\n\nmsgs[msg.todayOffset] = {\n payload: {\n total: Math.round((total1 + total2) * 10) / 10,\n total1: Math.round(total1 * 10) / 10,\n total2: Math.round(total2 * 10) / 10,\n rest: Math.round((rest1 + rest2) * 10) / 10,\n rest1: Math.round(rest1 * 10) / 10,\n rest2: Math.round(rest2 * 10) / 10,\n },\n}\n\nreturn msgs;",
- "outputs": 2,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 991.6667423248291,
- "y": 1090.3333303928375,
- "wires": [
- [
- "adf8461f.01e548",
- "bc31c91c29d3fac8"
- ],
- [
- "cbd97cf7.6245b"
- ]
- ]
- },
- {
- "id": "cbd97cf7.6245b",
- "type": "ui_text",
- "z": "303c9862.ddfff8",
- "group": "d9bbfe4e.3d039",
- "order": 4,
- "width": 0,
- "height": 0,
- "name": "",
- "label": "Power Tomorrow",
- "format": "{{msg.payload.total}}kWh ({{msg.payload.total1}}+{{msg.payload.total2}})",
- "layout": "row-spread",
- "className": "",
- "x": 1187.6668167114258,
- "y": 1119.3332195281982,
- "wires": []
- },
- {
- "id": "2bc43a60.d2e196",
- "type": "inject",
- "z": "303c9862.ddfff8",
- "name": "",
- "props": [
- {
- "p": "payload"
- },
- {
- "p": "todayOffset",
- "v": "1",
- "vt": "str"
- }
- ],
- "repeat": "600",
- "crontab": "",
- "once": true,
- "onceDelay": 0.1,
- "topic": "",
- "payload": "",
- "payloadType": "date",
- "x": 482.66673851013184,
- "y": 1082.3333790302277,
- "wires": [
- [
- "e136e96b.2dbfe8"
- ]
- ]
- },
- {
- "id": "d2264ec6.39eaa",
- "type": "ui_text",
- "z": "303c9862.ddfff8",
- "group": "e7d46503.f3f4b8",
- "order": 1,
- "width": 0,
- "height": 0,
- "name": "",
- "label": "PV String 1",
- "format": "{{msg.payload.pv_vpv1}}V {{msg.payload.pv_ipv1}}A ({{msg.payload.pv_ppv1}}W~{{msg.payload.pv_ppv_percent1}}%)",
- "layout": "row-spread",
- "className": "",
- "x": 1348.0952072143555,
- "y": 2008.762088060379,
- "wires": []
- },
- {
- "id": "203e54fa.eef5ac",
- "type": "ui_text",
- "z": "303c9862.ddfff8",
- "group": "e7d46503.f3f4b8",
- "order": 2,
- "width": 0,
- "height": 0,
- "name": "",
- "label": "PV String 2",
- "format": "{{msg.payload.pv_vpv2}}V {{msg.payload.pv_ipv2}}A ({{msg.payload.pv_ppv2}}W~{{msg.payload.pv_ppv_percent2}}%)",
- "layout": "row-spread",
- "className": "",
- "x": 1351.0952072143555,
- "y": 2043.161990404129,
- "wires": []
- },
- {
- "id": "ab490cf4.8d57c",
- "type": "ui_text",
- "z": "303c9862.ddfff8",
- "group": "e7d46503.f3f4b8",
- "order": 3,
- "width": 0,
- "height": 0,
- "name": "",
- "label": "Battery",
- "format": "{{msg.payload.battery_vbattery1}}V {{msg.payload.battery_ibattery1*-1}}A",
- "layout": "row-spread",
- "x": 1342.0952281951904,
- "y": 2081.1620247364044,
- "wires": []
- },
- {
- "id": "811c3f65.b4f79",
- "type": "ui_text",
- "z": "303c9862.ddfff8",
- "group": "b55f633.0a700a",
- "order": 0,
- "width": 0,
- "height": 0,
- "name": "",
- "label": "Limit Charge/Discharge",
- "format": "{{msg.payload.battery_charge_limit}}A/{{msg.payload.battery_discharge_limit}}A",
- "layout": "row-spread",
- "x": 1396.095209121704,
- "y": 1913.7619888782501,
- "wires": []
- },
- {
- "id": "c14f51cd.0afad",
- "type": "comment",
- "z": "303c9862.ddfff8",
- "name": "predikce stavu baterie",
- "info": "",
- "x": 342.45230865478516,
- "y": 3139.7619268894196,
- "wires": []
- },
- {
- "id": "8452501d.15a64",
- "type": "ui_button",
- "z": "303c9862.ddfff8",
- "d": true,
- "name": "",
- "group": "d1c39829.3ee0e8",
- "order": 0,
- "width": 0,
- "height": 0,
- "passthru": false,
- "label": "Calculate",
- "tooltip": "",
- "color": "",
- "bgcolor": "",
- "icon": "",
- "payload": "",
- "payloadType": "str",
- "topic": "",
- "x": 487.9523239135742,
- "y": 3192.761799097061,
- "wires": [
- [
- "81a374d23a95621c"
- ]
- ]
- },
- {
- "id": "7fab9dfb.9b56e4",
- "type": "inject",
- "z": "303c9862.ddfff8",
- "name": "",
- "props": [
- {
- "p": "payload"
- },
- {
- "p": "topic",
- "vt": "str"
- }
- ],
- "repeat": "1800",
- "crontab": "",
- "once": true,
- "onceDelay": 0.1,
- "topic": "",
- "payload": "",
- "payloadType": "date",
- "x": 469.9522933959961,
- "y": 3245.761799097061,
- "wires": [
- [
- "81a374d23a95621c"
- ]
- ]
- },
- {
- "id": "2b8e5315.f38d9c",
- "type": "function",
- "z": "303c9862.ddfff8",
- "name": "compute",
- "func": "const batteryCapacity = 14.21;\nconst predictionHours = 36;\n\n\n//-------------------------------------------------------------------------------------\nconst af = global.get('actionflows');\n\nconst batterySocPredictionEngine = (await af.invoke('core.npm.require', {payload: {\n module: flow.get('battery_soc_prediction_module_path'),\n cached: false,\n}})).payload;\n\nconst predictionDateFrom = batterySocPredictionEngine.getPredictionDateFrom('now');\n//node.warn(predictionDateFrom);\n\nconst dbConnection = {\n async query(query, values) {\n const resMsg = await af.invoke('core.db.query', {\n database: 'smarthouse',\n query,\n values,\n });\n return resMsg.payload;\n }\n};\nconst batterySOCPrediction = await batterySocPredictionEngine.computeBatterySOCPrediction(predictionDateFrom, predictionHours, batteryCapacity, {\n\tpvForecast: dbConnection,\n\tpvInverter: dbConnection,\n});\n\nmsg.payload = batterySOCPrediction;\n\nawait batterySocPredictionEngine.saveBatterySOCPrediction(batterySOCPrediction, predictionDateFrom, dbConnection);\n\nreturn msg;\n",
- "outputs": 1,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 845.9522972106934,
- "y": 3235.7618000507355,
- "wires": [
- [
- "bf878c79.f3a24",
- "d799d8e48807dbf8"
- ]
- ]
- },
- {
- "id": "bf878c79.f3a24",
- "type": "debug",
- "z": "303c9862.ddfff8",
- "name": "",
- "active": false,
- "tosidebar": true,
- "console": false,
- "tostatus": false,
- "complete": "false",
- "statusVal": "",
- "statusType": "auto",
- "x": 908.9522819519043,
- "y": 3155.7618000507355,
- "wires": []
- },
- {
- "id": "3adb4230412c1917",
- "type": "mysql",
- "z": "303c9862.ddfff8",
- "mydb": "76a2023f.8c254c",
- "name": "",
- "x": 1061.0952320098877,
- "y": 1429.562061548233,
- "wires": [
- [
- "94c83d02.02f7c"
- ]
- ]
- },
- {
- "id": "f681de4bd9af482d",
- "type": "inject",
- "z": "303c9862.ddfff8",
- "name": "",
- "props": [
- {
- "p": "payload"
- },
- {
- "p": "topic",
- "vt": "str"
- }
- ],
- "repeat": "3600",
- "crontab": "",
- "once": false,
- "onceDelay": 0.1,
- "topic": "",
- "payload": "",
- "payloadType": "date",
- "x": 521.0000228881836,
- "y": 361.9999599456787,
- "wires": [
- [
- "c9e1512f88fd2f65"
- ]
- ]
- },
- {
- "id": "c9e1512f88fd2f65",
- "type": "function",
- "z": "303c9862.ddfff8",
- "name": "",
- "func": "const af = global.get('actionflows');\n\nconst resMsg = await af.invoke('core.db.query', {\n database: 'smarthouse',\n query: \"SELECT * FROM pv_rooftop\",\n payload: [],\n});\n\nfor (const rooftop of resMsg.payload) {\n node.send({\n rooftopId: rooftop.id,\n url: `https://api.solcast.com.au/rooftop_sites/${rooftop.solcast_rooftop_id}/forecasts?format=json&api_key=${flow.get('solcast_api_key')}`,\n payload: null,\n });\n}\n",
- "outputs": 1,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 674.0000228881836,
- "y": 365.9999599456787,
- "wires": [
- [
- "bb1882e1d266048b",
- "1bd4c55a0c9e9a52"
- ]
- ]
- },
- {
- "id": "bb1882e1d266048b",
- "type": "debug",
- "z": "303c9862.ddfff8",
- "name": "",
- "active": false,
- "tosidebar": true,
- "console": false,
- "tostatus": false,
- "complete": "true",
- "targetType": "full",
- "statusVal": "",
- "statusType": "auto",
- "x": 858.0000190734863,
- "y": 320.99995470046997,
- "wires": []
- },
- {
- "id": "e462500714e8288d",
- "type": "inject",
- "z": "303c9862.ddfff8",
- "name": "",
- "props": [
- {
- "p": "payload"
- },
- {
- "p": "topic",
- "vt": "str"
- }
- ],
- "repeat": "",
- "crontab": "",
- "once": true,
- "onceDelay": 0.1,
- "topic": "",
- "payload": "",
- "payloadType": "date",
- "x": 558.0000877380371,
- "y": 144.00000286102295,
- "wires": [
- [
- "ebdacb6214e094e7"
- ]
- ]
- },
- {
- "id": "ebdacb6214e094e7",
- "type": "function",
- "z": "303c9862.ddfff8",
- "name": "solcast API key",
- "func": "flow.set('solcast_api_key', '-A6JkZ-k_chTjbJxux9ATGFNT5GMAb7T')\nreturn msg;",
- "outputs": 1,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 775.0000915527344,
- "y": 149.00000286102295,
- "wires": [
- []
- ]
- },
- {
- "id": "1bd4c55a0c9e9a52",
- "type": "http request",
- "z": "303c9862.ddfff8",
- "name": "",
- "method": "GET",
- "ret": "obj",
- "paytoqs": "ignore",
- "url": "",
- "tls": "",
- "persist": false,
- "proxy": "",
- "authType": "",
- "senderr": false,
- "x": 871.0000190734863,
- "y": 366.99995613098145,
- "wires": [
- [
- "b7d2296ea2d6e9e1",
- "c4597790.33e678"
- ]
- ]
- },
- {
- "id": "b7d2296ea2d6e9e1",
- "type": "debug",
- "z": "303c9862.ddfff8",
- "name": "",
- "active": false,
- "tosidebar": true,
- "console": false,
- "tostatus": false,
- "complete": "true",
- "targetType": "full",
- "statusVal": "",
- "statusType": "auto",
- "x": 1050.0000228881836,
- "y": 320.99995517730713,
- "wires": []
- },
- {
- "id": "12df0984d0ecf73c",
- "type": "debug",
- "z": "303c9862.ddfff8",
- "name": "",
- "active": false,
- "tosidebar": true,
- "console": false,
- "tostatus": false,
- "complete": "true",
- "targetType": "full",
- "statusVal": "",
- "statusType": "auto",
- "x": 1255.0000228881836,
- "y": 327.9999542236328,
- "wires": []
- },
- {
- "id": "77d073a993526f05",
- "type": "comment",
- "z": "303c9862.ddfff8",
- "name": "forecast UI",
- "info": "",
- "x": 271.6666603088379,
- "y": 803.1333267688751,
- "wires": []
- },
- {
- "id": "b4e9aadd8bfac91b",
- "type": "function",
- "z": "303c9862.ddfff8",
- "name": "stats",
- "func": "msg.stats = {\n table: 'pv_inverter_battery_soc_prediction',\n column_date: 'log_date',\n column_value: 'soc',\n interval: '0 HOUR',\n agregateFunction: 'AVG',\n where: `1`,\n}\nreturn msg;",
- "outputs": 1,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 1547.6666259765625,
- "y": 3258.333241701126,
- "wires": [
- [
- "d124319fb087e0e4"
- ]
- ]
- },
- {
- "id": "d124319fb087e0e4",
- "type": "subflow:9c5e9d61.1f5fe",
- "z": "303c9862.ddfff8",
- "name": "",
- "env": [],
- "x": 1722.6665420532227,
- "y": 3258.3332846164703,
- "wires": [
- [
- "a0bc64c52698e9d4",
- "e19475402f3c5f96"
- ]
- ]
- },
- {
- "id": "8ce17d64b220885e",
- "type": "ui_chart",
- "z": "303c9862.ddfff8",
- "name": "",
- "group": "d1c39829.3ee0e8",
- "order": 8,
- "width": 0,
- "height": 0,
- "label": "Previous 12 / Next 36 Hours",
- "chartType": "line",
- "legend": "false",
- "xformat": "HH:mm:ss",
- "interpolate": "bezier",
- "nodata": "",
- "dot": false,
- "ymin": "0",
- "ymax": "100",
- "removeOlder": "1",
- "removeOlderPoints": "",
- "removeOlderUnit": "86400",
- "cutout": 0,
- "useOneColor": false,
- "useUTC": false,
- "colors": [
- "#00a1d6",
- "#ffcd42",
- "#ff7f0e",
- "#2ca02c",
- "#98df8a",
- "#d62728",
- "#ff9896",
- "#9467bd",
- "#c5b0d5"
- ],
- "outputs": 1,
- "x": 2306.666175842285,
- "y": 3353.3332788944244,
- "wires": [
- []
- ]
- },
- {
- "id": "a0bc64c52698e9d4",
- "type": "debug",
- "z": "303c9862.ddfff8",
- "name": "",
- "active": false,
- "tosidebar": true,
- "console": false,
- "tostatus": false,
- "complete": "false",
- "statusVal": "",
- "statusType": "auto",
- "x": 1810.666633605957,
- "y": 3150.333283662796,
- "wires": []
- },
- {
- "id": "d799d8e48807dbf8",
- "type": "function",
- "z": "303c9862.ddfff8",
- "name": "stats",
- "func": "msg.stats = {\n table: 'pv_inverter_record',\n column_date: 'log_date',\n column_value: 'battery_soc',\n interval: '12 HOUR',\n agregateFunction: 'AVG',\n where: `1`,\n}\nreturn msg;",
- "outputs": 1,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 1014.6666259765625,
- "y": 3234.733243227005,
- "wires": [
- [
- "2f129c7156b55337"
- ]
- ]
- },
- {
- "id": "2f129c7156b55337",
- "type": "subflow:9c5e9d61.1f5fe",
- "z": "303c9862.ddfff8",
- "name": "",
- "env": [],
- "x": 1189.6665420532227,
- "y": 3234.7332861423492,
- "wires": [
- [
- "4763f74abca7dfc6",
- "275ea24681bc6eba"
- ]
- ]
- },
- {
- "id": "5a2e9bf1bddbfbb7",
- "type": "inject",
- "z": "303c9862.ddfff8",
- "name": "",
- "props": [
- {
- "p": "payload"
- },
- {
- "p": "topic",
- "vt": "str"
- }
- ],
- "repeat": "",
- "crontab": "",
- "once": false,
- "onceDelay": 0.1,
- "topic": "",
- "payload": "",
- "payloadType": "date",
- "x": 889.666618347168,
- "y": 3316.7332422733307,
- "wires": [
- [
- "d799d8e48807dbf8"
- ]
- ]
- },
- {
- "id": "4763f74abca7dfc6",
- "type": "debug",
- "z": "303c9862.ddfff8",
- "name": "",
- "active": false,
- "tosidebar": true,
- "console": false,
- "tostatus": false,
- "complete": "false",
- "statusVal": "",
- "statusType": "auto",
- "x": 1385.6666374206543,
- "y": 3197.7332842350006,
- "wires": []
- },
- {
- "id": "275ea24681bc6eba",
- "type": "function",
- "z": "303c9862.ddfff8",
- "name": "",
- "func": "msg.stats1 = msg.payload;\nreturn msg;",
- "outputs": 1,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 1384.6666374206543,
- "y": 3273.733285188675,
- "wires": [
- [
- "b4e9aadd8bfac91b"
- ]
- ]
- },
- {
- "id": "50a7249feade58d6",
- "type": "http in",
- "z": "303c9862.ddfff8",
- "name": "",
- "url": "/pylon-pv-battery-state-record",
- "method": "post",
- "upload": false,
- "swaggerDoc": "",
- "x": 502.66661071777344,
- "y": 3595.333428621292,
- "wires": [
- [
- "e9349d108908ac06",
- "da499acd5b31d569",
- "1c67febfe1ce1abd",
- "2c54ae5b8ba85505"
- ]
- ]
- },
- {
- "id": "e9349d108908ac06",
- "type": "debug",
- "z": "303c9862.ddfff8",
- "name": "",
- "active": false,
- "tosidebar": true,
- "console": false,
- "tostatus": false,
- "complete": "false",
- "statusVal": "",
- "statusType": "auto",
- "x": 863.8666381835938,
- "y": 3537.733472108841,
- "wires": []
- },
- {
- "id": "da499acd5b31d569",
- "type": "function",
- "z": "303c9862.ddfff8",
- "name": "",
- "func": "msg.payload = {status: 200}\nreturn msg;",
- "outputs": 1,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [
- {
- "var": "fs",
- "module": "fs"
- }
- ],
- "x": 847.8666305541992,
- "y": 3602.7334740161896,
- "wires": [
- [
- "e0665fb2fd857050"
- ]
- ]
- },
- {
- "id": "e0665fb2fd857050",
- "type": "http response",
- "z": "303c9862.ddfff8",
- "name": "",
- "statusCode": "",
- "headers": {},
- "x": 1022.8666362762451,
- "y": 3610.7334740161896,
- "wires": []
- },
- {
- "id": "5f18183f56309951",
- "type": "function",
- "z": "303c9862.ddfff8",
- "name": "disp_pwr",
- "func": "if (msg.payload.type == \"disp_pwr\") {\n msg.payload = msg.payload.data;\n \n const columns = Object.keys(msg.payload).map((column) => `${column} = ?`).join(', ');\n\n msg.topic = `INSERT INTO pv_battery_state_record SET log_date = NOW(), ${columns}`;\n msg.payload = Object.values(msg.payload);\n\n return msg;\n}\n",
- "outputs": 1,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 1640.8665504455566,
- "y": 3551.3337955474854,
- "wires": [
- [
- "d21bbf6f218abd58"
- ]
- ]
- },
- {
- "id": "d21bbf6f218abd58",
- "type": "mysql",
- "z": "303c9862.ddfff8",
- "mydb": "76a2023f.8c254c",
- "name": "",
- "x": 1800.8665618896484,
- "y": 3547.5339879989624,
- "wires": [
- [
- "d7de585efcc764fc"
- ]
- ]
- },
- {
- "id": "412378114f768b4a",
- "type": "comment",
- "z": "303c9862.ddfff8",
- "name": "pylon logger",
- "info": "",
- "x": 301.1666145324707,
- "y": 3486.333427667618,
- "wires": []
- },
- {
- "id": "403733106671b049",
- "type": "function",
- "z": "303c9862.ddfff8",
- "name": "",
- "func": "msg.batteryMode = msg.payload.batteryMode;\nmsg.payload = msg.payload.batteryPower;\nmsg.topic = msg.batteryMode;\n\nreturn msg;",
- "outputs": 1,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 1212.6666259765625,
- "y": 3857.333382844925,
- "wires": [
- [
- "8c7b70b7d47684f3",
- "d971f7c5cdcd8c7e",
- "189adeb07b8246d6"
- ]
- ]
- },
- {
- "id": "8c7b70b7d47684f3",
- "type": "ui_gauge",
- "z": "303c9862.ddfff8",
- "d": true,
- "name": "Battery",
- "group": "819686be.5e6a58",
- "order": 4,
- "width": 0,
- "height": 0,
- "gtype": "gage",
- "title": "BMS Battery - {{msg.batteryMode}}",
- "label": "W",
- "format": "{{value}}",
- "min": "-8000",
- "max": "8000",
- "colors": [
- "#b30000",
- "#ffffff",
- "#36cc00"
- ],
- "seg1": "",
- "seg2": "",
- "x": 1438.6666526794434,
- "y": 3791.333286523819,
- "wires": []
- },
- {
- "id": "be5efd648227638b",
- "type": "function",
- "z": "303c9862.ddfff8",
- "name": "no data timeout",
- "func": "const timeout = 30000;\n\nconst timer = context.get('timer');\n\nif (timer) {\n clearTimeout(timer);\n}\n\ncontext.set('timer', setTimeout(() => {\n node.send({\n bmsDataTimedout: true,\n payload: {},\n })\n}, timeout));\n\nnode.send(msg);",
- "outputs": 1,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 981.6666259765625,
- "y": 3802.733381509781,
- "wires": [
- [
- "6e138e18de8b9465"
- ]
- ]
- },
- {
- "id": "c3f6137434653aca",
- "type": "function",
- "z": "303c9862.ddfff8",
- "name": "no data timeout",
- "func": "const timeout = 30000;\n\nconst timer = context.get('timer');\n\nif (timer) {\n clearTimeout(timer);\n}\n\ncontext.set('timer', setTimeout(() => {\n node.send({\n inverterDataTimedout: true,\n payload: {},\n })\n}, timeout));\n\nnode.send(msg);",
- "outputs": 1,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 701.6666450500488,
- "y": 1563.7333748340607,
- "wires": [
- [
- "efdc183d.d80958",
- "4dad62b3.f306fc",
- "9c95fb95.b18c28",
- "3aab581b.326c98",
- "a599f9f6a477953a",
- "d886e6cc2138ed94",
- "6e138e18de8b9465",
- "f2911eb919633a36"
- ]
- ]
- },
- {
- "id": "fe9df8fcb1931c40",
- "type": "function",
- "z": "303c9862.ddfff8",
- "name": "siren beep",
- "func": "msg.payload = [\"smarthouse-controller-siren\", \"pin.siren.pulse.start\", {\n \"sequence\" : \"beep\",\n}]\n\nreturn msg;",
- "outputs": 1,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 1279.6666984558105,
- "y": 2749.9334642887115,
- "wires": [
- [
- "d085d90cf23540f8"
- ]
- ]
- },
- {
- "id": "d085d90cf23540f8",
- "type": "jsonrpc-call",
- "z": "303c9862.ddfff8",
- "name": "",
- "method": "rpc.proxy",
- "client": "36ca1673.3376ea",
- "x": 1443.6666564941406,
- "y": 2749.9333679676056,
- "wires": [
- [
- "7b2db10fc138600d"
- ]
- ]
- },
- {
- "id": "11b3b99f4f114d05",
- "type": "inject",
- "z": "303c9862.ddfff8",
- "name": "",
- "props": [
- {
- "p": "payload"
- },
- {
- "p": "topic",
- "vt": "str"
- }
- ],
- "repeat": "",
- "crontab": "",
- "once": false,
- "onceDelay": 0.1,
- "topic": "",
- "payload": "",
- "payloadType": "date",
- "x": 1115.6668395996094,
- "y": 2787.9336347579956,
- "wires": [
- [
- "fe9df8fcb1931c40"
- ]
- ]
- },
- {
- "id": "7b2db10fc138600d",
- "type": "debug",
- "z": "303c9862.ddfff8",
- "name": "",
- "active": false,
- "tosidebar": true,
- "console": false,
- "tostatus": false,
- "complete": "false",
- "statusVal": "",
- "statusType": "auto",
- "x": 1607.4666557312012,
- "y": 2751.933173418045,
- "wires": []
- },
- {
- "id": "a599f9f6a477953a",
- "type": "function",
- "z": "303c9862.ddfff8",
- "name": "Přetížení fáze siréna",
- "func": "const phasesLoad = [\n Math.round(100 * msg.payload.backup_p1 / 3300),\n Math.round(100 * msg.payload.backup_p2 / 3300),\n Math.round(100 * msg.payload.backup_p3 / 3300),\n];\n\nconst maxLoad = 120;\n\nif (phasesLoad[0] >= maxLoad || phasesLoad[1] >= maxLoad || phasesLoad[2] >= maxLoad) {\n msg.payload = phasesLoad;\n return msg;\n}\n",
- "outputs": 1,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 903.6666946411133,
- "y": 2716.9332687854767,
- "wires": [
- [
- "e7e97e769bab9c97"
- ]
- ]
- },
- {
- "id": "e7e97e769bab9c97",
- "type": "throttle",
- "z": "303c9862.ddfff8",
- "name": "",
- "throttleType": "time",
- "timeLimit": "5",
- "timeLimitType": "seconds",
- "countLimit": 0,
- "blockSize": 0,
- "locked": false,
- "x": 1114.6666946411133,
- "y": 2720.7336599826813,
- "wires": [
- [
- "fe9df8fcb1931c40",
- "42545386709df21d"
- ]
- ]
- },
- {
- "id": "42545386709df21d",
- "type": "debug",
- "z": "303c9862.ddfff8",
- "name": "",
- "active": false,
- "tosidebar": true,
- "console": false,
- "tostatus": false,
- "complete": "false",
- "statusVal": "",
- "statusType": "auto",
- "x": 1292.666696548462,
- "y": 2683.733462572098,
- "wires": []
- },
- {
- "id": "a99792fb08391c11",
- "type": "function",
- "z": "303c9862.ddfff8",
- "name": "clear",
- "func": "msg.payload = [];\nreturn msg;",
- "outputs": 1,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 1456.2666206359863,
- "y": 3349.7332861423492,
- "wires": [
- [
- "8ce17d64b220885e"
- ]
- ]
- },
- {
- "id": "81a374d23a95621c",
- "type": "function",
- "z": "303c9862.ddfff8",
- "name": "",
- "func": "\nreturn msg;",
- "outputs": 1,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 649.2666015625,
- "y": 3217.73328435421,
- "wires": [
- [
- "2b8e5315.f38d9c",
- "a99792fb08391c11"
- ]
- ]
- },
- {
- "id": "d886e6cc2138ed94",
- "type": "function",
- "z": "303c9862.ddfff8",
- "name": "Příliž nízký stav baterie",
- "func": "const soc = msg.payload.battery_soc;\nlet lastNotifiedLowBatterySOC = flow.get(`lastNotifiedLowBatterySOC`) || 100;\n\nconst pvInverterRecord = flow.get('pvInverterRecord');\n\nif (pvInverterRecord.grid_mode_label != \"Connected to grid\") {\n if (soc <= 15) {\n // pokud klesnul stav baterie tak pipnout\n if (soc < lastNotifiedLowBatterySOC) {\n node.send(msg);\n }\n }\n}\n\nflow.set(`lastNotifiedLowBatterySOC`, soc);\n",
- "outputs": 1,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 916.6666564941406,
- "y": 2760.13334274292,
- "wires": [
- [
- "fe9df8fcb1931c40"
- ]
- ]
- },
- {
- "id": "d707a23a58a83b39",
- "type": "ui_chart",
- "z": "303c9862.ddfff8",
- "name": "House Consumption",
- "group": "819686be.5e6a58",
- "order": 2,
- "width": 0,
- "height": 0,
- "label": "House Consumption: {{msg.payload}}W",
- "chartType": "line",
- "legend": "false",
- "xformat": "HH:mm:ss",
- "interpolate": "linear",
- "nodata": "",
- "dot": false,
- "ymin": "0",
- "ymax": "",
- "removeOlder": "5",
- "removeOlderPoints": "",
- "removeOlderUnit": "60",
- "cutout": 0,
- "useOneColor": false,
- "useUTC": false,
- "colors": [
- "#1f77b4",
- "#aec7e8",
- "#ff7f0e",
- "#2ca02c",
- "#98df8a",
- "#d62728",
- "#ff9896",
- "#9467bd",
- "#c5b0d5"
- ],
- "outputs": 1,
- "x": 1420.6666564941406,
- "y": 2197.933350801468,
- "wires": [
- []
- ]
- },
- {
- "id": "7a1b5a43ecb17018",
- "type": "function",
- "z": "303c9862.ddfff8",
- "name": "",
- "func": "msg.payload = msg.payload.ac_house_consumption_maxof;\nreturn msg;",
- "outputs": 1,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 1233.666633605957,
- "y": 2201.333331346512,
- "wires": [
- [
- "d707a23a58a83b39"
- ]
- ]
- },
- {
- "id": "d971f7c5cdcd8c7e",
- "type": "ui_text",
- "z": "303c9862.ddfff8",
- "group": "312b72db.d7629e",
- "order": 4,
- "width": 0,
- "height": 0,
- "name": "Battery",
- "label": "Battery ({{msg.batteryMode}})",
- "format": "{{msg.payload}}W",
- "layout": "row-spread",
- "className": "",
- "x": 1452.6666564941406,
- "y": 3933.133287668228,
- "wires": []
- },
- {
- "id": "b3a8bf6e77ec851a",
- "type": "inject",
- "z": "303c9862.ddfff8",
- "name": "",
- "props": [
- {
- "p": "payload"
- },
- {
- "p": "todayOffset",
- "v": "0",
- "vt": "str"
- }
- ],
- "repeat": "600",
- "crontab": "",
- "once": true,
- "onceDelay": 0.1,
- "topic": "",
- "payload": "",
- "payloadType": "date",
- "x": 481.66664123535156,
- "y": 4236.133440256119,
- "wires": [
- [
- "d96eb2fb252d9ecc"
- ]
- ]
- },
- {
- "id": "d96eb2fb252d9ecc",
- "type": "function",
- "z": "303c9862.ddfff8",
- "name": "",
- "func": "const af = global.get('actionflows');\n\nnode.status({text: `Start`});\n\nconst resDb = await af.invoke('core.db.query', {\n database: 'smarthouse',\n query: `\n SELECT MAX(pv_harvested_kwh1) AS kwh1, MAX(pv_harvested_kwh2) AS kwh2 FROM (\n SELECT time, total_ws1/1000/3600 AS pv_harvested_kwh1, total_ws2/1000/3600 AS pv_harvested_kwh2 FROM (\n \tSELECT time, @curr1:=power_value1*(IF(@prevT IS NULL, 0, time-@prevT)), @curr2:=power_value2*(IF(@prevT IS NULL, 0, time-@prevT)) as ws, @e1:=@e1+@curr1 AS total_ws1, @e2:=@e2+@curr2 AS total_ws2, @prevT:=time FROM (\n \t\tSELECT\n \t\tUNIX_TIMESTAMP(log_date) AS \"time\",\n \t\tpv_ppv1 AS power_value1,\n\t\t\t\t\tpv_ppv2 AS power_value2\n \t\tFROM pv_inverter_record\n \t\tWHERE\n \t\tlog_date BETWEEN DATE(NOW() - INTERVAL ${msg.todayOffset} DAY) AND DATE(NOW() - INTERVAL ${msg.todayOffset} DAY) + INTERVAL 1 DAY\n \t\tORDER BY log_date\n \t)r1, (SELECT@e1:=0)e1, (SELECT@e2:=0)e2, (SELECT@prevT:=NULL)prevT\n )r2\n )r3\n `,\n values: [],\n});\n\nnode.status({text: `Done`});\n\nmsg.payload = resDb.payload[0];\n\nmsg.dailyStats = {\n\tpv1: msg.payload.kwh1,\n\tpv2: msg.payload.kwh2,\n\tpv: msg.payload.kwh1 + msg.payload.kwh2,\n};\n\nreturn msg;\n",
- "outputs": 1,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 634.666633605957,
- "y": 4253.133419275284,
- "wires": [
- [
- "6a115fdb62bf4b36",
- "3e1392c885cd773c",
- "ce47cc5f7bbcaeed"
- ]
- ]
- },
- {
- "id": "3e1392c885cd773c",
- "type": "debug",
- "z": "303c9862.ddfff8",
- "name": "",
- "active": false,
- "tosidebar": true,
- "console": false,
- "tostatus": false,
- "complete": "false",
- "statusVal": "",
- "statusType": "auto",
- "x": 830.6666450500488,
- "y": 4221.1332924366,
- "wires": []
- },
- {
- "id": "8c846f474c9fbc76",
- "type": "ui_text",
- "z": "303c9862.ddfff8",
- "group": "802549dc0ec48149",
- "order": 1,
- "width": 0,
- "height": 0,
- "name": "",
- "label": "Harvested Today",
- "format": "{{msg.payload.total}}kWh ({{msg.payload.total1}}+{{msg.payload.total2}})",
- "layout": "row-spread",
- "className": "",
- "x": 1184.6666526794434,
- "y": 4273.133440256119,
- "wires": []
- },
- {
- "id": "61bba1d29f469c59",
- "type": "comment",
- "z": "303c9862.ddfff8",
- "name": "stats",
- "info": "",
- "x": 271.4666519165039,
- "y": 4097.133380174637,
- "wires": []
- },
- {
- "id": "6a115fdb62bf4b36",
- "type": "function",
- "z": "303c9862.ddfff8",
- "name": "",
- "func": "const msgs = [null, null];\n\nmsgs[msg.todayOffset] = {\n payload: {\n total: Math.round((msg.payload.kwh1 + msg.payload.kwh2) * 10) / 10,\n total1: Math.round(msg.payload.kwh1 * 10) / 10,\n total2: Math.round(msg.payload.kwh2 * 10) / 10,\n }\n}\n\nreturn msgs;",
- "outputs": 2,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 990.6666488647461,
- "y": 4275.9334881305695,
- "wires": [
- [
- "8c846f474c9fbc76"
- ],
- [
- "078d27b844fc3fae"
- ]
- ]
- },
- {
- "id": "51ab74349f8c4265",
- "type": "ui_text",
- "z": "303c9862.ddfff8",
- "group": "802549dc0ec48149",
- "order": 2,
- "width": 0,
- "height": 0,
- "name": "",
- "label": "Consumed Today",
- "format": "{{msg.payload}}kWh",
- "layout": "row-spread",
- "x": 1197.666648864746,
- "y": 4499.733881235123,
- "wires": []
- },
- {
- "id": "078d27b844fc3fae",
- "type": "ui_text",
- "z": "303c9862.ddfff8",
- "group": "802549dc0ec48149",
- "order": 3,
- "width": 0,
- "height": 0,
- "name": "",
- "label": "Harvested Yesterday",
- "format": "{{msg.payload.total}}kWh ({{msg.payload.total1}}+{{msg.payload.total2}})",
- "layout": "row-spread",
- "className": "",
- "x": 1190.666633605957,
- "y": 4310.733233690262,
- "wires": []
- },
- {
- "id": "9718c4e32e7b3791",
- "type": "inject",
- "z": "303c9862.ddfff8",
- "name": "",
- "props": [
- {
- "p": "payload"
- },
- {
- "p": "todayOffset",
- "v": "1",
- "vt": "str"
- }
- ],
- "repeat": "600",
- "crontab": "",
- "once": true,
- "onceDelay": 0.1,
- "topic": "",
- "payload": "",
- "payloadType": "date",
- "x": 478.66664123535156,
- "y": 4290.3333904743195,
- "wires": [
- [
- "d96eb2fb252d9ecc"
- ]
- ]
- },
- {
- "id": "f71446e6f06a56d9",
- "type": "inject",
- "z": "303c9862.ddfff8",
- "name": "",
- "props": [
- {
- "p": "payload"
- },
- {
- "p": "todayOffset",
- "v": "0",
- "vt": "str"
- }
- ],
- "repeat": "600",
- "crontab": "",
- "once": true,
- "onceDelay": 0.1,
- "topic": "",
- "payload": "",
- "payloadType": "date",
- "x": 475.66663360595703,
- "y": 4461.933429002762,
- "wires": [
- [
- "478f152e86f5bbaa"
- ]
- ]
- },
- {
- "id": "3b778125dfe6d052",
- "type": "inject",
- "z": "303c9862.ddfff8",
- "name": "",
- "props": [
- {
- "p": "payload"
- },
- {
- "p": "todayOffset",
- "v": "1",
- "vt": "str"
- }
- ],
- "repeat": "600",
- "crontab": "",
- "once": true,
- "onceDelay": 0.1,
- "topic": "",
- "payload": "",
- "payloadType": "date",
- "x": 472.66663360595703,
- "y": 4516.1333792209625,
- "wires": [
- [
- "478f152e86f5bbaa"
- ]
- ]
- },
- {
- "id": "478f152e86f5bbaa",
- "type": "function",
- "z": "303c9862.ddfff8",
- "name": "",
- "func": "const af = global.get('actionflows');\n\nnode.status({text: `Start`});\n\nconst resDb = await af.invoke('core.db.query', {\n database: 'smarthouse',\n query: `\n SELECT MAX(house_consumption_kwh) AS kwh FROM (\n SELECT time, total_ws/1000/3600 AS house_consumption_kwh FROM (\n \tSELECT time, @curr:=power_value*(IF(@prevT IS NULL, 0, time-@prevT)) as ws, @e:=@e+@curr AS total_ws, @prevT:=time FROM (\n \t\tSELECT\n \t\tUNIX_TIMESTAMP(log_date) AS \"time\",\n \t\tGREATEST((IF(work_mode_label = \"Normal (On-Grid)\", ac_load_p1, 0)+IF(work_mode_label = \"Normal (On-Grid)\", ac_load_p2, 0)+IF(work_mode_label = \"Normal (On-Grid)\", ac_load_p3, 0)) + (backup_p1+backup_p2+backup_p3), ac_house_consumption) AS power_value\n \t\tFROM pv_inverter_record\n \t\tWHERE\n \t\tlog_date BETWEEN DATE(NOW() - INTERVAL ${msg.todayOffset} DAY) AND DATE(NOW() - INTERVAL ${msg.todayOffset} DAY) + INTERVAL 1 DAY\n \t\tORDER BY log_date\n \t)r1, (SELECT@e:=0)e, (SELECT@prevT:=NULL)prevT\n )r2\n )r3\n `,\n values: [],\n});\n\nnode.status({text: `Done`});\n\nmsg.payload = resDb.payload[0];\n\nmsg.dailyStats = {\n\tconsumption: msg.payload.kwh,\n};\n\nreturn msg;\n",
- "outputs": 1,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 628.6666259765625,
- "y": 4478.933408021927,
- "wires": [
- [
- "c7903419f60f94d9",
- "53758c5d3182e479",
- "ce47cc5f7bbcaeed"
- ]
- ]
- },
- {
- "id": "53758c5d3182e479",
- "type": "function",
- "z": "303c9862.ddfff8",
- "name": "",
- "func": "const msgs = [null, null];\n\nmsgs[msg.todayOffset] = {\n payload: Math.round(msg.payload.kwh * 10) / 10,\n}\n\nreturn msgs;",
- "outputs": 2,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 984.6666412353516,
- "y": 4501.7334768772125,
- "wires": [
- [
- "51ab74349f8c4265"
- ],
- [
- "9454cd1b9fc64d0a"
- ]
- ]
- },
- {
- "id": "c7903419f60f94d9",
- "type": "debug",
- "z": "303c9862.ddfff8",
- "name": "",
- "active": false,
- "tosidebar": true,
- "console": false,
- "tostatus": false,
- "complete": "false",
- "statusVal": "",
- "statusType": "auto",
- "x": 831.6666488647461,
- "y": 4451.9332954883575,
- "wires": []
- },
- {
- "id": "9454cd1b9fc64d0a",
- "type": "ui_text",
- "z": "303c9862.ddfff8",
- "group": "802549dc0ec48149",
- "order": 4,
- "width": 0,
- "height": 0,
- "name": "",
- "label": "Consumed Yesterday",
- "format": "{{msg.payload}}kWh",
- "layout": "row-spread",
- "x": 1208.666633605957,
- "y": 4548.933429002762,
- "wires": []
- },
- {
- "id": "9b497417b6425c53",
- "type": "ui_chart",
- "z": "303c9862.ddfff8",
- "name": "PV Power",
- "group": "819686be.5e6a58",
- "order": 1,
- "width": 0,
- "height": 0,
- "label": "PV Power: {{msg.payload}}W",
- "chartType": "line",
- "legend": "false",
- "xformat": "HH:mm:ss",
- "interpolate": "linear",
- "nodata": "",
- "dot": false,
- "ymin": "0",
- "ymax": "12600",
- "removeOlder": "5",
- "removeOlderPoints": "",
- "removeOlderUnit": "60",
- "cutout": 0,
- "useOneColor": false,
- "useUTC": false,
- "colors": [
- "#fff700",
- "#aec7e8",
- "#ff7f0e",
- "#2ca02c",
- "#98df8a",
- "#d62728",
- "#ff9896",
- "#9467bd",
- "#c5b0d5"
- ],
- "outputs": 1,
- "useDifferentColor": false,
- "className": "",
- "x": 1381.6666564941406,
- "y": 2257.933335542679,
- "wires": [
- []
- ]
- },
- {
- "id": "71d63e751b4c8b6c",
- "type": "ui_chart",
- "z": "303c9862.ddfff8",
- "name": "Battery",
- "group": "819686be.5e6a58",
- "order": 5,
- "width": 0,
- "height": 0,
- "label": "Battery: {{msg.batteryMode}} {{msg.payload}}W",
- "chartType": "line",
- "legend": "false",
- "xformat": "HH:mm:ss",
- "interpolate": "step",
- "nodata": "",
- "dot": false,
- "ymin": "-8000",
- "ymax": "8000",
- "removeOlder": "5",
- "removeOlderPoints": "1000",
- "removeOlderUnit": "60",
- "cutout": 0,
- "useOneColor": false,
- "useUTC": false,
- "colors": [
- "#000000",
- "#bd0000",
- "#32bd00",
- "#bababa",
- "#98df8a",
- "#d62728",
- "#ff9896",
- "#9467bd",
- "#c5b0d5"
- ],
- "outputs": 1,
- "x": 1535.0666542053223,
- "y": 3893.7332870960236,
- "wires": [
- []
- ]
- },
- {
- "id": "4773c89f3226d39a",
- "type": "inject",
- "z": "303c9862.ddfff8",
- "name": "Charging",
- "props": [
- {
- "p": "payload"
- },
- {
- "p": "topic",
- "vt": "str"
- }
- ],
- "repeat": "",
- "crontab": "",
- "once": true,
- "onceDelay": 0.1,
- "topic": "",
- "payload": "100",
- "payloadType": "num",
- "x": 891.0666465759277,
- "y": 3881.7332870960236,
- "wires": [
- [
- "e74acd960ab80b51"
- ]
- ]
- },
- {
- "id": "3d982f3496db6194",
- "type": "function",
- "z": "303c9862.ddfff8",
- "name": "",
- "func": "function sleep(ms) {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nnode.send({\n topic: '',\n payload: [],\n});\n\nfor (const mode of ['Zero', 'Discharge', 'Charge', 'Idle']) {\n await sleep(100);\n node.send({\n topic: mode,\n payload: 0,\n });\n}\n",
- "outputs": 1,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 1281.066650390625,
- "y": 3941.7332870960236,
- "wires": [
- [
- "71d63e751b4c8b6c"
- ]
- ]
- },
- {
- "id": "e74acd960ab80b51",
- "type": "function",
- "z": "303c9862.ddfff8",
- "name": "rand",
- "func": "if (msg.payload > 0) {\n msg.payload = {\"voltage\":400, \"current\":Math.random()*10, \"base_state_label\" : \"Charge\"};\n}else if (msg.payload < 0) {\n msg.payload = { \"voltage\": 400, \"current\": -Math.random() * 10, \"base_state_label\": \"Discharge\"};\n}else {\n msg.payload = {\"voltage\":400, \"current\":0, \"base_state_label\" : \"Idle\"};\n}\n\nreturn msg;",
- "outputs": 1,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 1039.666648864746,
- "y": 3894.7332870960236,
- "wires": [
- [
- "403733106671b049"
- ]
- ]
- },
- {
- "id": "0f89590bb278d274",
- "type": "inject",
- "z": "303c9862.ddfff8",
- "name": "Discharging",
- "props": [
- {
- "p": "payload"
- },
- {
- "p": "topic",
- "vt": "str"
- }
- ],
- "repeat": "",
- "crontab": "",
- "once": true,
- "onceDelay": 0.1,
- "topic": "",
- "payload": "-100",
- "payloadType": "num",
- "x": 896.666633605957,
- "y": 3919.733233690262,
- "wires": [
- [
- "e74acd960ab80b51"
- ]
- ]
- },
- {
- "id": "8cb4808ea8445ed5",
- "type": "inject",
- "z": "303c9862.ddfff8",
- "name": "Idle",
- "props": [
- {
- "p": "payload"
- },
- {
- "p": "topic",
- "vt": "str"
- }
- ],
- "repeat": "",
- "crontab": "",
- "once": true,
- "onceDelay": 0.1,
- "topic": "",
- "payload": "0",
- "payloadType": "num",
- "x": 876.666633605957,
- "y": 3957.733233690262,
- "wires": [
- [
- "e74acd960ab80b51"
- ]
- ]
- },
- {
- "id": "189adeb07b8246d6",
- "type": "function",
- "z": "303c9862.ddfff8",
- "name": "multiplex",
- "func": "const modes = ['Discharge', 'Charge', 'Idle'].filter((v) => v != msg.batteryMode);\n//node.warn(modes);\n\nsetTimeout(() => {\n node.send({\n topic: 'Zero',\n payload: 0,\n });\n}, 1);\n\nfor (const mode of modes) {\n setTimeout(() => {\n node.send({\n topic: mode,\n payload: 0,\n });\n }, 1);\n}\n\nsetTimeout(() => {\n node.send(msg);\n}, 1);\n",
- "outputs": 1,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 1386.6666564941406,
- "y": 3869.7332870960236,
- "wires": [
- [
- "71d63e751b4c8b6c"
- ]
- ]
- },
- {
- "id": "f9b0870b92c91650",
- "type": "inject",
- "z": "303c9862.ddfff8",
- "name": "Clear",
- "props": [
- {
- "p": "payload"
- },
- {
- "p": "topic",
- "vt": "str"
- }
- ],
- "repeat": "",
- "crontab": "",
- "once": true,
- "onceDelay": 0.1,
- "topic": "",
- "payload": "[]",
- "payloadType": "json",
- "x": 1153.666648864746,
- "y": 3943.733289003372,
- "wires": [
- [
- "3d982f3496db6194"
- ]
- ]
- },
- {
- "id": "f794bbd0e4d0db3d",
- "type": "ui_text",
- "z": "303c9862.ddfff8",
- "group": "802549dc0ec48149",
- "order": 5,
- "width": 0,
- "height": 0,
- "name": "",
- "label": "Import/Export Today",
- "format": "{{msg.payload.import}}/{{msg.payload.export}}kWh",
- "layout": "row-spread",
- "x": 1204.666648864746,
- "y": 4717.733233690262,
- "wires": []
- },
- {
- "id": "961ebfcec704e4ed",
- "type": "inject",
- "z": "303c9862.ddfff8",
- "name": "",
- "props": [
- {
- "p": "payload"
- },
- {
- "p": "todayOffset",
- "v": "0",
- "vt": "str"
- }
- ],
- "repeat": "600",
- "crontab": "",
- "once": true,
- "onceDelay": 0.1,
- "topic": "",
- "payload": "",
- "payloadType": "date",
- "x": 472.66663360595703,
- "y": 4679.932781457901,
- "wires": [
- [
- "df2ff145fbb01179"
- ]
- ]
- },
- {
- "id": "21155122bda9ae7b",
- "type": "inject",
- "z": "303c9862.ddfff8",
- "name": "",
- "props": [
- {
- "p": "payload"
- },
- {
- "p": "todayOffset",
- "v": "1",
- "vt": "str"
- }
- ],
- "repeat": "600",
- "crontab": "",
- "once": true,
- "onceDelay": 0.1,
- "topic": "",
- "payload": "",
- "payloadType": "date",
- "x": 469.66663360595703,
- "y": 4734.132731676102,
- "wires": [
- [
- "df2ff145fbb01179"
- ]
- ]
- },
- {
- "id": "df2ff145fbb01179",
- "type": "function",
- "z": "303c9862.ddfff8",
- "name": "",
- "func": "const af = global.get('actionflows');\n\nnode.status({text: `Start`});\nconst resMsgExport = await af.invoke('core.db.query', {\n database: 'smarthouse',\n query: `\n SELECT MAX(grid_export_kwh) AS kwh FROM (\n SELECT time, total_ws/1000/3600 AS grid_export_kwh FROM (\n \tSELECT time, @curr:=power_value*(IF(@prevT IS NULL, 0, time-@prevT)) as ws, @e:=@e+@curr AS total_ws, @prevT:=time FROM (\n \t\tSELECT\n \t\tUNIX_TIMESTAMP(log_date) AS \"time\",\n \t\tIF(grid_meter_active_power1 > 0, grid_meter_active_power1, 0) + IF(grid_meter_active_power2 > 0, grid_meter_active_power2, 0) + IF(grid_meter_active_power3 > 0, grid_meter_active_power3, 0) AS power_value\n \t\tFROM pv_inverter_record\n \t\tWHERE\n \t\tlog_date BETWEEN DATE(NOW() - INTERVAL ${msg.todayOffset} DAY) AND DATE(NOW() - INTERVAL ${msg.todayOffset} DAY) + INTERVAL 1 DAY\n \t\tORDER BY log_date\n \t)r1, (SELECT@e:=0)e, (SELECT@prevT:=NULL)prevT\n )r2\n )r3\n `,\n values: [],\n});\nnode.status({text: `${JSON.stringify({'export': resMsgExport.payload[0]})}`});\n//node.warn(resMsgExport);\n\nconst resMsgImport = await af.invoke('core.db.query', {\n database: 'smarthouse',\n query: `\n SELECT MAX(grid_export_kwh) AS kwh FROM (\n SELECT time, total_ws/1000/3600 AS grid_export_kwh FROM (\n \tSELECT time, @curr:=power_value*(IF(@prevT IS NULL, 0, time-@prevT)) as ws, @e:=@e+@curr AS total_ws, @prevT:=time FROM (\n \t\tSELECT\n \t\tUNIX_TIMESTAMP(log_date) AS \"time\",\n \t\t-1*(IF(grid_meter_active_power1 < 0, grid_meter_active_power1, 0) + IF(grid_meter_active_power2 < 0, grid_meter_active_power2, 0) + IF(grid_meter_active_power3 < 0, grid_meter_active_power3, 0)) AS power_value\n \t\tFROM pv_inverter_record\n \t\tWHERE\n \t\tlog_date BETWEEN DATE(NOW() - INTERVAL ${msg.todayOffset} DAY) AND DATE(NOW() - INTERVAL ${msg.todayOffset} DAY) + INTERVAL 1 DAY\n \t\tORDER BY log_date\n \t)r1, (SELECT@e:=0)e, (SELECT@prevT:=NULL)prevT\n )r2\n )r3\n `,\n values: [],\n});\nnode.status({text: `${JSON.stringify({'import': resMsgImport.payload[0]})}`});\n//node.warn(resMsgImport);\n\nmsg.payload = {\n export: Math.round(resMsgExport.payload[0].kwh*100)/100,\n import: Math.round(resMsgImport.payload[0].kwh*100)/100,\n}\n\nnode.status({text: `Done`});\n\nmsg.dailyStats = {\n imported: msg.payload.import,\n exported: msg.payload.export,\n};\n\nreturn msg;\n",
- "outputs": 1,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 625.6666259765625,
- "y": 4696.932760477066,
- "wires": [
- [
- "2d6ede508a243d40",
- "19230393a6fe7743",
- "ce47cc5f7bbcaeed"
- ]
- ]
- },
- {
- "id": "2d6ede508a243d40",
- "type": "function",
- "z": "303c9862.ddfff8",
- "name": "",
- "func": "const msgs = [null, null];\n\nmsgs[msg.todayOffset] = {\n payload: msg.payload,\n}\n\nreturn msgs;",
- "outputs": 2,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 981.6666412353516,
- "y": 4719.732829332352,
- "wires": [
- [
- "f794bbd0e4d0db3d"
- ],
- [
- "571a46d3d6a3d41e"
- ]
- ]
- },
- {
- "id": "19230393a6fe7743",
- "type": "debug",
- "z": "303c9862.ddfff8",
- "name": "",
- "active": false,
- "tosidebar": true,
- "console": false,
- "tostatus": false,
- "complete": "false",
- "statusVal": "",
- "statusType": "auto",
- "x": 851.6666450500488,
- "y": 4676.932908296585,
- "wires": []
- },
- {
- "id": "571a46d3d6a3d41e",
- "type": "ui_text",
- "z": "303c9862.ddfff8",
- "group": "802549dc0ec48149",
- "order": 6,
- "width": 0,
- "height": 0,
- "name": "",
- "label": "Import/Export Yesterday",
- "format": "{{msg.payload.import}}/{{msg.payload.export}}kWh",
- "layout": "row-spread",
- "x": 1215.666633605957,
- "y": 4766.932781457901,
- "wires": []
- },
- {
- "id": "24aa274ef9f69f21",
- "type": "function",
- "z": "303c9862.ddfff8",
- "name": "",
- "func": "msg.payload.grid_direction = msg.payload.grid_active_power > 0 ? \"Exporting\" : \"Importing\";\nreturn msg;",
- "outputs": 1,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 1221.6666564941406,
- "y": 1736.3333532810211,
- "wires": [
- [
- "83d4257e.51d728"
- ]
- ]
- },
- {
- "id": "1c6d03dba19e8225",
- "type": "ui_text",
- "z": "303c9862.ddfff8",
- "group": "9a78c351d1914ac8",
- "order": 2,
- "width": 0,
- "height": 0,
- "name": "",
- "label": "Work Mode",
- "format": "{{msg.payload.work_mode_label}}",
- "layout": "row-spread",
- "x": 1256.666648864746,
- "y": 1513.1333992481232,
- "wires": []
- },
- {
- "id": "e0c76b9c8b0a812d",
- "type": "ui_text",
- "z": "303c9862.ddfff8",
- "group": "9a78c351d1914ac8",
- "order": 3,
- "width": 0,
- "height": 0,
- "name": "",
- "label": "Grid Mode",
- "format": "{{msg.payload.grid_mode_label}}",
- "layout": "row-spread",
- "x": 1254.666633605957,
- "y": 1552.1333801746368,
- "wires": []
- },
- {
- "id": "5b12492d69e13db2",
- "type": "pub",
- "z": "303c9862.ddfff8",
- "name": "",
- "topic": "pv.inverter.record",
- "message": "",
- "x": 1060.666648864746,
- "y": 1534.3333494663239,
- "wires": []
- },
- {
- "id": "e19475402f3c5f96",
- "type": "function",
- "z": "303c9862.ddfff8",
- "name": "merge history+forecast",
- "func": "msg.stats2 = msg.payload;\n\nmsg.payload = msg.stats1;\nmsg.payload[0].data.push(msg.stats2[0].data[0]);\nreturn msg;",
- "outputs": 1,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 1988.0667114257812,
- "y": 3250.9334251880646,
- "wires": [
- [
- "8ce17d64b220885e"
- ]
- ]
- },
- {
- "id": "dba82e589e0e36eb",
- "type": "inject",
- "z": "303c9862.ddfff8",
- "name": "",
- "props": [
- {
- "p": "payload"
- },
- {
- "p": "todayOffset",
- "v": "0",
- "vt": "str"
- }
- ],
- "repeat": "3600",
- "crontab": "",
- "once": true,
- "onceDelay": 0.1,
- "topic": "",
- "payload": "",
- "payloadType": "date",
- "x": 467.66670989990234,
- "y": 4860.732670783997,
- "wires": [
- [
- "98b35784bd592816"
- ]
- ]
- },
- {
- "id": "98b35784bd592816",
- "type": "function",
- "z": "303c9862.ddfff8",
- "name": "",
- "func": "const af = global.get('actionflows');\n\nconst BILLING_PERIOD_DATE_FROM = flow.get('billing_period_date_from');\n\nconst resMsgGridStats = await af.invoke('core.db.query', {\n database: 'smarthouse',\n query: `\n SELECT SUM(imported) AS imported_kwh, SUM(exported) AS exported_kwh\n FROM pv_daily_stats\n WHERE log_date >= IF(STR_TO_DATE(CONCAT('${BILLING_PERIOD_DATE_FROM}', YEAR(NOW())),'%d.%m.%Y') < NOW(), STR_TO_DATE(CONCAT('${BILLING_PERIOD_DATE_FROM}', YEAR(NOW())),'%d.%m.%Y'), STR_TO_DATE(CONCAT('${BILLING_PERIOD_DATE_FROM}', YEAR(NOW())-1),'%d.%m.%Y'))\n `,\n values: [],\n});\n//node.warn(resMsgGridStats);\n\nmsg.payload = {\n import: Math.round(resMsgGridStats.payload[0].imported_kwh),\n export: Math.round(resMsgGridStats.payload[0].exported_kwh),\n}\n\nflow.set('billing_period_imported_kwh', msg.payload.import);\nflow.set('billing_period_exported_kwh', msg.payload.export);\n\nreturn msg;\n",
- "outputs": 1,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 656.6667175292969,
- "y": 4860.732739448547,
- "wires": [
- [
- "6303ff5d796f71a2",
- "904a6ce028e46aca"
- ]
- ]
- },
- {
- "id": "6303ff5d796f71a2",
- "type": "ui_text",
- "z": "303c9862.ddfff8",
- "group": "802549dc0ec48149",
- "order": 8,
- "width": 0,
- "height": 0,
- "name": "",
- "label": "Import/Export Billing Period",
- "format": "{{msg.payload.import}}/{{msg.payload.export}}kWh",
- "layout": "row-spread",
- "className": "",
- "x": 918.6667175292969,
- "y": 4869.732739448547,
- "wires": []
- },
- {
- "id": "6e138e18de8b9465",
- "type": "function",
- "z": "303c9862.ddfff8",
- "name": "Battery record",
- "func": "const lastBatteryRecord = flow.get('batteryRecord');\n\nif (msg.payload) {\n let recordType;\n\n let batteryRecord;\n\n if ('battery_vbattery1' in msg.payload) {\n // je to zaznam z invertoru\n recordType = 'inverter';\n batteryRecord = {\n voltage: msg.payload.battery_vbattery1,\n current: -msg.payload.battery_ibattery1,\n base_state_label: msg.payload.battery_mode_label,\n };\n } else if ('base_state_label' in msg.payload) {\n // je to zaznam z pylon bms\n recordType = 'bms';\n batteryRecord = msg.payload;\n if (batteryRecord.base_state_label == 'Dischg') {\n batteryRecord.base_state_label = 'Discharge';\n }\n } else if ('bmsDataTimedout' in msg) {\n recordType = undefined;\n batteryRecord = {\n voltage: undefined,\n current: undefined,\n base_state_label: undefined,\n };\n }else {\n return;\n }\n\n const batteryPower = Math.round(batteryRecord.voltage * batteryRecord.current);\n const batteryMode = batteryRecord.base_state_label;\n\n const batteryChangeSpeedText = `${batteryPower > 0 ? '+' : ''}${Math.round(100 * batteryPower / 14200 / 60 * 100) / 100}%/m`;\n\n batteryRecord.recordType = recordType;\n batteryRecord.batteryPower = batteryPower;\n batteryRecord.batteryMode = batteryMode;\n batteryRecord.batteryChangeSpeedText = batteryChangeSpeedText;\n\n // ulozit zaznam jen pokud tam predchozi neni, nebo je to z bms, ktera prebije zaznam z invertoru\n if (!lastBatteryRecord || lastBatteryRecord.recordType == undefined || recordType == 'bms' || recordType === undefined || lastBatteryRecord.recordType == 'inverter') {\n flow.set('batteryRecord', batteryRecord);\n }else {\n return;\n }\n\n msg.payload = batteryRecord;\n}else {\n msg.payload = {};\n}\n\nreturn msg;\n",
- "outputs": 1,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 1191.666648864746,
- "y": 3803.1334335803986,
- "wires": [
- [
- "403733106671b049",
- "e592cce1a0844c89",
- "47897d4254f965d1"
- ]
- ]
- },
- {
- "id": "71cfbe3f9fd15264",
- "type": "actionflows",
- "z": "303c9862.ddfff8",
- "info": "Describe your action API here.",
- "untilproptype": "num",
- "proptype": "msg",
- "name": "notify",
- "prop": "loop",
- "untilprop": 0,
- "until": "gt",
- "loop": "none",
- "scope": "global",
- "perf": false,
- "seq": false,
- "x": 1358.666633605957,
- "y": 4050.933429002762,
- "wires": [
- []
- ]
- },
- {
- "id": "e592cce1a0844c89",
- "type": "function",
- "z": "303c9862.ddfff8",
- "name": "Stav",
- "func": "const lastNotifiedBatteryMonitoringStatus = flow.get('lastNotifiedBatteryMonitoringStatus');\nconst lastBatteryRecord = flow.get('batteryRecord');\n\nlet currentBatteryMonitoringStatus = `Změna stavu monitoringu baterie. Typ ${lastBatteryRecord.recordType}`;\n\nif (lastNotifiedBatteryMonitoringStatus != currentBatteryMonitoringStatus) {\n flow.set(`lastNotifiedBatteryMonitoringStatus`, currentBatteryMonitoringStatus);\n \n msg.payload = { \"title\": currentBatteryMonitoringStatus, \"text\" : \"\", \"event\" : \"speech\"}\n node.send(msg);\n}\n",
- "outputs": 1,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 1166.6666145324707,
- "y": 4055.933435678482,
- "wires": [
- [
- "71cfbe3f9fd15264"
- ]
- ]
- },
- {
- "id": "0d6d756a53f49305",
- "type": "inject",
- "z": "303c9862.ddfff8",
- "name": "",
- "props": [
- {
- "p": "payload"
- },
- {
- "p": "topic",
- "vt": "str"
- }
- ],
- "repeat": "",
- "crontab": "",
- "once": false,
- "onceDelay": 0.1,
- "topic": "",
- "payload": "{}",
- "payloadType": "json",
- "x": 867.6666488647461,
- "y": 4052.733290910721,
- "wires": [
- [
- "6e138e18de8b9465"
- ]
- ]
- },
- {
- "id": "47897d4254f965d1",
- "type": "debug",
- "z": "303c9862.ddfff8",
- "name": "debug 4",
- "active": false,
- "tosidebar": true,
- "console": false,
- "tostatus": false,
- "complete": "false",
- "statusVal": "",
- "statusType": "auto",
- "x": 1427.6666526794434,
- "y": 3731.333382844925,
- "wires": []
- },
- {
- "id": "abe985189bbbc2f7",
- "type": "comment",
- "z": "303c9862.ddfff8",
- "name": "Grid Mode",
- "info": "",
- "x": 274,
- "y": 506.00000762939453,
- "wires": []
- },
- {
- "id": "12633529c3bef7ba",
- "type": "ui_switch",
- "z": "303c9862.ddfff8",
- "name": "",
- "label": "Group 1 - {{msg.title}}",
- "tooltip": "",
- "group": "cf60b551c034e51c",
- "order": 0,
- "width": 0,
- "height": 0,
- "passthru": false,
- "decouple": "true",
- "topic": "topic",
- "topicType": "msg",
- "style": "",
- "onvalue": "true",
- "onvalueType": "bool",
- "onicon": "",
- "oncolor": "",
- "offvalue": "false",
- "offvalueType": "bool",
- "officon": "",
- "offcolor": "",
- "animate": false,
- "className": "",
- "x": 832.0000114440918,
- "y": 594.0000066757202,
- "wires": [
- [
- "6a2792bcd7be5504"
- ]
- ]
- },
- {
- "id": "5d07132555535339",
- "type": "function",
- "z": "303c9862.ddfff8",
- "name": "function 2",
- "func": "const mode = flow.get(\"gridMode1\") || \"backup\";\n\nmsg.payload = mode == \"backup\";\nmsg.title = mode == \"backup\" ? \"Backup\" : \"On-Grid\";\n\nreturn msg;",
- "outputs": 1,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 660.0000114440918,
- "y": 595.0000076293945,
- "wires": [
- [
- "12633529c3bef7ba"
- ]
- ]
- },
- {
- "id": "52ae9fae03f4bc34",
- "type": "inject",
- "z": "303c9862.ddfff8",
- "name": "",
- "props": [
- {
- "p": "payload"
- },
- {
- "p": "topic",
- "vt": "str"
- }
- ],
- "repeat": "",
- "crontab": "",
- "once": true,
- "onceDelay": 0.1,
- "topic": "",
- "payload": "",
- "payloadType": "date",
- "x": 295.0000305175781,
- "y": 576.0000085830688,
- "wires": [
- [
- "a1ae3e28769e2e30"
- ]
- ]
- },
- {
- "id": "6a2792bcd7be5504",
- "type": "function",
- "z": "303c9862.ddfff8",
- "name": "function 3",
- "func": "flow.set(\"gridMode1\", msg.payload ? \"backup\" : \"on-grid\");\n\nreturn msg;",
- "outputs": 1,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 997.0000152587891,
- "y": 594.0000085830688,
- "wires": [
- [
- "ce83228501fc0f0d"
- ]
- ]
- },
- {
- "id": "ce83228501fc0f0d",
- "type": "pub",
- "z": "303c9862.ddfff8",
- "name": "pvInverter.gridMode.changed",
- "topic": "pvInverter.gridMode.changed",
- "message": "",
- "x": 1237.8000183105469,
- "y": 635.6000576019287,
- "wires": []
- },
- {
- "id": "e1e261af6c103750",
- "type": "sub",
- "z": "303c9862.ddfff8",
- "name": "pvInverter.gridMode.changed",
- "topic": "pvInverter.gridMode.changed",
- "x": 359.8000030517578,
- "y": 658.600058555603,
- "wires": [
- [
- "f0ca0f93933a6266"
- ]
- ]
- },
- {
- "id": "8067ee3aaceec109",
- "type": "ui_switch",
- "z": "303c9862.ddfff8",
- "name": "",
- "label": "Group 2 - {{msg.title}}",
- "tooltip": "",
- "group": "cf60b551c034e51c",
- "order": 0,
- "width": 0,
- "height": 0,
- "passthru": false,
- "decouple": "true",
- "topic": "topic",
- "topicType": "msg",
- "style": "",
- "onvalue": "true",
- "onvalueType": "bool",
- "onicon": "",
- "oncolor": "",
- "offvalue": "false",
- "offvalueType": "bool",
- "officon": "",
- "offcolor": "",
- "animate": false,
- "className": "",
- "x": 837,
- "y": 661,
- "wires": [
- [
- "2e3f12d075e20f69"
- ]
- ]
- },
- {
- "id": "0f816f3ad14dd816",
- "type": "function",
- "z": "303c9862.ddfff8",
- "name": "function 4",
- "func": "const mode = flow.get(\"gridMode2\") || \"backup\";\n\nmsg.payload = mode == \"backup\";\nmsg.title = mode == \"backup\" ? \"Backup\" : \"On-Grid\";\n\nreturn msg;",
- "outputs": 1,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 665,
- "y": 662.0000009536743,
- "wires": [
- [
- "8067ee3aaceec109"
- ]
- ]
- },
- {
- "id": "2e3f12d075e20f69",
- "type": "function",
- "z": "303c9862.ddfff8",
- "name": "function 5",
- "func": "flow.set(\"gridMode2\", msg.payload ? \"backup\" : \"on-grid\");\n\nreturn msg;",
- "outputs": 1,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 1002.0000038146973,
- "y": 661.0000019073486,
- "wires": [
- [
- "ce83228501fc0f0d"
- ]
- ]
- },
- {
- "id": "61aa086381ef6356",
- "type": "ui_switch",
- "z": "303c9862.ddfff8",
- "name": "",
- "label": "Group 3 - {{msg.title}}",
- "tooltip": "",
- "group": "cf60b551c034e51c",
- "order": 0,
- "width": 0,
- "height": 0,
- "passthru": false,
- "decouple": "true",
- "topic": "topic",
- "topicType": "msg",
- "style": "",
- "onvalue": "true",
- "onvalueType": "bool",
- "onicon": "",
- "oncolor": "",
- "offvalue": "false",
- "offvalueType": "bool",
- "officon": "",
- "offcolor": "",
- "animate": false,
- "className": "",
- "x": 844,
- "y": 718,
- "wires": [
- [
- "bfa0fbad4541e98c"
- ]
- ]
- },
- {
- "id": "0d35bbeb61b3425d",
- "type": "function",
- "z": "303c9862.ddfff8",
- "name": "function 6",
- "func": "const mode = flow.get(\"gridMode3\") || \"backup\";\n\nmsg.payload = mode == \"backup\";\nmsg.title = mode == \"backup\" ? \"Backup\" : \"On-Grid\";\n\nreturn msg;",
- "outputs": 1,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 672,
- "y": 719.0000009536743,
- "wires": [
- [
- "61aa086381ef6356"
- ]
- ]
- },
- {
- "id": "bfa0fbad4541e98c",
- "type": "function",
- "z": "303c9862.ddfff8",
- "name": "function 7",
- "func": "flow.set(\"gridMode3\", msg.payload ? \"backup\" : \"on-grid\");\n\nreturn msg;",
- "outputs": 1,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 1009.0000038146973,
- "y": 718.0000019073486,
- "wires": [
- [
- "ce83228501fc0f0d"
- ]
- ]
- },
- {
- "id": "a1ae3e28769e2e30",
- "type": "function",
- "z": "303c9862.ddfff8",
- "name": "function 8",
- "func": "// defaultne je okruh 3 na backupu a okruh 1 a 2 na gridu\nflow.set(\"gridMode1\", flow.get(\"gridMode1\") || \"on-grid\");\nflow.set(\"gridMode2\", flow.get(\"gridMode2\") || \"on-grid\");\nflow.set(\"gridMode3\", flow.get(\"gridMode3\") || \"backup\");\n\nreturn msg;",
- "outputs": 1,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 479.00000762939453,
- "y": 597.0000085830688,
- "wires": [
- [
- "f0ca0f93933a6266"
- ]
- ]
- },
- {
- "id": "dc5ecd1673d5073d",
- "type": "ui_text",
- "z": "303c9862.ddfff8",
- "group": "9a78c351d1914ac8",
- "order": 1,
- "width": 0,
- "height": 0,
- "name": "",
- "label": "Last Update Time",
- "format": "{{msg.payload.lastUpdateTime}}",
- "layout": "row-spread",
- "className": "",
- "x": 1284,
- "y": 1474,
- "wires": []
- },
- {
- "id": "3cb62769caf4a4cb",
- "type": "inject",
- "z": "303c9862.ddfff8",
- "name": "",
- "props": [
- {
- "p": "payload"
- },
- {
- "p": "todayOffset",
- "v": "0",
- "vt": "str"
- }
- ],
- "repeat": "3600",
- "crontab": "",
- "once": true,
- "onceDelay": 0.1,
- "topic": "",
- "payload": "",
- "payloadType": "date",
- "x": 468.0001449584961,
- "y": 4797.999757766724,
- "wires": [
- [
- "4a267efb39b5bc07"
- ]
- ]
- },
- {
- "id": "4a267efb39b5bc07",
- "type": "function",
- "z": "303c9862.ddfff8",
- "name": "",
- "func": "const af = global.get('actionflows');\n\nconst resMsgGridStats = await af.invoke('core.db.query', {\n database: 'smarthouse',\n query: `\n SELECT SUM(imported) AS imported_kwh, SUM(exported) AS exported_kwh FROM pv_daily_stats\n `,\n values: [],\n});\n//node.warn(resMsgGridStats);\n\nmsg.payload = {\n import: Math.round(resMsgGridStats.payload[0].imported_kwh),\n export: Math.round(resMsgGridStats.payload[0].exported_kwh),\n}\n\nreturn msg;\n",
- "outputs": 1,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 657.0001525878906,
- "y": 4797.999826431274,
- "wires": [
- [
- "730fbcb2a8b18234"
- ]
- ]
- },
- {
- "id": "730fbcb2a8b18234",
- "type": "ui_text",
- "z": "303c9862.ddfff8",
- "group": "802549dc0ec48149",
- "order": 7,
- "width": 0,
- "height": 0,
- "name": "",
- "label": "Import/Export Total",
- "format": "{{msg.payload.import}}/{{msg.payload.export}}kWh",
- "layout": "row-spread",
- "x": 889.0001525878906,
- "y": 4806.999826431274,
- "wires": []
- },
- {
- "id": "4b25455cea161d4f",
- "type": "inject",
- "z": "303c9862.ddfff8",
- "name": "",
- "props": [
- {
- "p": "payload"
- },
- {
- "p": "topic",
- "vt": "str"
- }
- ],
- "repeat": "",
- "crontab": "",
- "once": true,
- "onceDelay": 0.1,
- "topic": "",
- "payload": "",
- "payloadType": "date",
- "x": 594.0000228881836,
- "y": 90.00000190734863,
- "wires": [
- [
- "00e399cab5f30c62"
- ]
- ]
- },
- {
- "id": "00e399cab5f30c62",
- "type": "function",
- "z": "303c9862.ddfff8",
- "name": "Billing Period",
- "func": "flow.set('billing_period_date_from', '1.1.')\nreturn msg;",
- "outputs": 1,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 785.0000267028809,
- "y": 94.00000190734863,
- "wires": [
- []
- ]
- },
- {
- "id": "33bd738d8d0650a4",
- "type": "comment",
- "z": "303c9862.ddfff8",
- "name": "Billing Period",
- "info": "",
- "x": 398.8000259399414,
- "y": 81,
- "wires": []
- },
- {
- "id": "bc31c91c29d3fac8",
- "type": "ui_text",
- "z": "303c9862.ddfff8",
- "group": "d9bbfe4e.3d039",
- "order": 2,
- "width": 0,
- "height": 0,
- "name": "",
- "label": "Rest Power Today",
- "format": "{{msg.payload.rest}}kWh ({{msg.payload.rest1}}+{{msg.payload.rest2}})",
- "layout": "row-spread",
- "className": "",
- "x": 1189,
- "y": 1027,
- "wires": []
- },
- {
- "id": "3c0f0981be58e691",
- "type": "sun-position",
- "z": "303c9862.ddfff8",
- "name": "",
- "positionConfig": "347876e0a6d5c1b0",
- "rules": [],
- "onlyOnChange": "true",
- "topic": "",
- "outputs": 1,
- "start": "",
- "startType": "none",
- "startOffset": 0,
- "startOffsetType": "none",
- "startOffsetMultiplier": 60000,
- "end": "",
- "endType": "none",
- "endOffset": 0,
- "endOffsetType": "none",
- "endOffsetMultiplier": 60000,
- "x": 2008.2000350952148,
- "y": 265.19997119903564,
- "wires": [
- [
- "befbe07cb3745cb5",
- "c82062ebc86dc60c",
- "5b26781b33a634d7",
- "e162b0ea29fdf26f",
- "889fe2593fed52ab",
- "d91fb2ef78f1148b"
- ]
- ]
- },
- {
- "id": "4fa5989c1f3111d8",
- "type": "inject",
- "z": "303c9862.ddfff8",
- "name": "",
- "props": [
- {
- "p": "payload"
- },
- {
- "p": "topic",
- "vt": "str"
- }
- ],
- "repeat": "60",
- "crontab": "",
- "once": false,
- "onceDelay": 0.1,
- "topic": "",
- "payload": "",
- "payloadType": "date",
- "x": 1847.2000350952148,
- "y": 273.19997119903564,
- "wires": [
- [
- "3c0f0981be58e691"
- ]
- ]
- },
- {
- "id": "befbe07cb3745cb5",
- "type": "debug",
- "z": "303c9862.ddfff8",
- "name": "debug 9",
- "active": false,
- "tosidebar": true,
- "console": false,
- "tostatus": false,
- "complete": "false",
- "statusVal": "",
- "statusType": "auto",
- "x": 2209.200168609619,
- "y": 185.19998359680176,
- "wires": []
- },
- {
- "id": "2046a24e0c2fdc92",
- "type": "ui_template",
- "z": "303c9862.ddfff8",
- "group": "45ecb2bfdd21bc90",
- "name": "",
- "order": 2,
- "width": 0,
- "height": 0,
- "format": "<div class=\"sun-position\">\n <img class=\"dum\" src=\"/img/dum.webp\">\n <div class=\"center\">\n <div class=\"line sunrise\" style=\"{{msg.payload.sunPosition.sunrise.azimuthTransform}}\"></div>\n <div class=\"line sunset\" style=\"{{msg.payload.sunPosition.sunset.azimuthTransform}}\"></div>\n <div class=\"line sun\" style=\"{{msg.payload.sunPosition.now.azimuthTransform}}\"></div>\n <div class=\"dot\"></div>\n </div>\n</div>\n\n\n<style>\n.sun-position {\n height: 272px;\n display: grid;\n grid-template-columns: 1fr;\n grid-template-rows: 1fr;\n grid-template-areas: \"content\";\n justify-items: center;\n align-items: center;\n overflow: hidden;\n}\n.sun-position .dum {\n grid-area: content;\n border: 2px solid rgb(0, 218, 0);\n object-fit: contain;\n width: 100%; /* or any custom size */\n height: 100%;\n}\n.sun-position .center {\n grid-area: content;\n height: 1px;\n width: 1px;\n position: relative;\n left: -0.5px;\n bottom: -0.5px;\n}\n.sun-position .dot {\n position: absolute;\n left: -4px;\n bottom: -4px;\n background-color: rgb(210 92 1);\n border-radius: 50%;\n height: 8px;\n width: 8px;\n}\n.sun-position .line {\n position: absolute;\n left: -2px;\n bottom: -2px;\n height: 200px;\n width: 4px;\n border-radius: 4px;\n transform-origin: 2px calc(100% - 2px);\n}\n.sun-position .sun {\n background-color: rgb(238 238 24 / 90%);\n}\n.sun-position .sunrise, .sun-position .sunset {\n background-color: rgb(174 174 174 / 80%);\n width: 2px;\n}\n</style>",
- "storeOutMessages": true,
- "fwdInMessages": true,
- "resendOnRefresh": true,
- "templateScope": "local",
- "className": "sun-position-widget",
- "x": 2250.2001037597656,
- "y": 681.2000370025635,
- "wires": [
- []
- ]
- },
- {
- "id": "c82062ebc86dc60c",
- "type": "function",
- "z": "303c9862.ddfff8",
- "name": "function 16",
- "func": "flow.set('sunPositionNow', msg.payload);\n\n",
- "outputs": 1,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 2211.199924468994,
- "y": 235.1999855041504,
- "wires": [
- []
- ]
- },
- {
- "id": "2defc3ce36d57aa7",
- "type": "comment",
- "z": "303c9862.ddfff8",
- "name": "sun",
- "info": "",
- "x": 1734.199951171875,
- "y": 169.1999969482422,
- "wires": []
- },
- {
- "id": "5b26781b33a634d7",
- "type": "within-time-switch",
- "z": "303c9862.ddfff8",
- "name": "",
- "nameInt": "",
- "positionConfig": "347876e0a6d5c1b0",
- "startTime": "0:00",
- "startTimeType": "entered",
- "startOffset": 0,
- "startOffsetType": "none",
- "startOffsetMultiplier": 60000,
- "endTime": "0:00",
- "endTimeType": "entered",
- "endOffset": 0,
- "endOffsetType": "none",
- "endOffsetMultiplier": 60000,
- "timeRestrictions": 0,
- "timeRestrictionsType": "none",
- "timeDays": "*",
- "timeOnlyOddDays": false,
- "timeOnlyEvenDays": false,
- "timeOnlyOddWeeks": false,
- "timeOnlyEvenWeeks": false,
- "timeMonths": "*",
- "timedatestart": "",
- "timedateend": "",
- "propertyStart": "",
- "propertyStartType": "none",
- "propertyStartCompare": "true",
- "propertyStartThreshold": "",
- "propertyStartThresholdType": "num",
- "startTimeAlt": "",
- "startTimeAltType": "entered",
- "startOffsetAlt": 0,
- "startOffsetAltType": "none",
- "startOffsetAltMultiplier": 60000,
- "propertyEnd": "",
- "propertyEndType": "none",
- "propertyEndCompare": "true",
- "propertyEndThreshold": "",
- "propertyEndThresholdType": "num",
- "endTimeAlt": "",
- "endTimeAltType": "entered",
- "endOffsetAlt": 0,
- "endOffsetAltType": "none",
- "endOffsetAltMultiplier": 60000,
- "withinTimeValue": "$getSunCalc(payload.times.sunrise.ts, true, true)",
- "withinTimeValueType": "jsonata",
- "outOfTimeValue": "false",
- "outOfTimeValueType": "msgInput",
- "tsCompare": "0",
- "x": 2265.1999015808105,
- "y": 328.1999912261963,
- "wires": [
- [
- "e901bc4cc16319a1",
- "0f4de5abbd27c721"
- ],
- []
- ]
- },
- {
- "id": "e901bc4cc16319a1",
- "type": "debug",
- "z": "303c9862.ddfff8",
- "name": "debug 13",
- "active": false,
- "tosidebar": true,
- "console": false,
- "tostatus": false,
- "complete": "false",
- "statusVal": "",
- "statusType": "auto",
- "x": 2455.199903488159,
- "y": 301.19996070861816,
- "wires": []
- },
- {
- "id": "e162b0ea29fdf26f",
- "type": "within-time-switch",
- "z": "303c9862.ddfff8",
- "name": "",
- "nameInt": "",
- "positionConfig": "347876e0a6d5c1b0",
- "startTime": "0:00",
- "startTimeType": "entered",
- "startOffset": 0,
- "startOffsetType": "none",
- "startOffsetMultiplier": 60000,
- "endTime": "0:00",
- "endTimeType": "entered",
- "endOffset": 0,
- "endOffsetType": "none",
- "endOffsetMultiplier": 60000,
- "timeRestrictions": 0,
- "timeRestrictionsType": "none",
- "timeDays": "*",
- "timeOnlyOddDays": false,
- "timeOnlyEvenDays": false,
- "timeOnlyOddWeeks": false,
- "timeOnlyEvenWeeks": false,
- "timeMonths": "*",
- "timedatestart": "",
- "timedateend": "",
- "propertyStart": "",
- "propertyStartType": "none",
- "propertyStartCompare": "true",
- "propertyStartThreshold": "",
- "propertyStartThresholdType": "num",
- "startTimeAlt": "",
- "startTimeAltType": "entered",
- "startOffsetAlt": 0,
- "startOffsetAltType": "none",
- "startOffsetAltMultiplier": 60000,
- "propertyEnd": "",
- "propertyEndType": "none",
- "propertyEndCompare": "true",
- "propertyEndThreshold": "",
- "propertyEndThresholdType": "num",
- "endTimeAlt": "",
- "endTimeAltType": "entered",
- "endOffsetAlt": 0,
- "endOffsetAltType": "none",
- "endOffsetAltMultiplier": 60000,
- "withinTimeValue": "$getSunCalc(payload.times.sunset.ts, true, true)",
- "withinTimeValueType": "jsonata",
- "outOfTimeValue": "false",
- "outOfTimeValueType": "msgInput",
- "tsCompare": "0",
- "x": 2267.199920654297,
- "y": 451.19997215270996,
- "wires": [
- [
- "fe3237283aa29bb5",
- "d959b85c0443d3cd"
- ],
- []
- ]
- },
- {
- "id": "fe3237283aa29bb5",
- "type": "debug",
- "z": "303c9862.ddfff8",
- "name": "debug 14",
- "active": false,
- "tosidebar": true,
- "console": false,
- "tostatus": false,
- "complete": "false",
- "statusVal": "",
- "statusType": "auto",
- "x": 2444.1998958587646,
- "y": 437.1999626159668,
- "wires": []
- },
- {
- "id": "0f4de5abbd27c721",
- "type": "function",
- "z": "303c9862.ddfff8",
- "name": "function 17",
- "func": "flow.set('sunPositionSunrise', msg.payload);\n",
- "outputs": 1,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 2462.199926376343,
- "y": 341.19997215270996,
- "wires": [
- []
- ]
- },
- {
- "id": "d959b85c0443d3cd",
- "type": "function",
- "z": "303c9862.ddfff8",
- "name": "function 18",
- "func": "flow.set('sunPositionSunset', msg.payload);\n",
- "outputs": 1,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 2456.199926376343,
- "y": 482.20000410079956,
- "wires": [
- []
- ]
- },
- {
- "id": "e1f413b8747a3e23",
- "type": "function",
- "z": "303c9862.ddfff8",
- "name": "function 19",
- "func": "const sunPositionNow = flow.get('sunPositionNow');\nconst sunPositionSunrise = flow.get('sunPositionSunrise');\nconst sunPositionSunset = flow.get('sunPositionSunset');\n\nsunPositionNow.azimuthTransform = `transform: rotateZ(${sunPositionNow.azimuthDegrees}deg)`;\nsunPositionSunrise.azimuthTransform = `transform: rotateZ(${sunPositionSunrise.azimuthDegrees}deg)`;\nsunPositionSunset.azimuthTransform = `transform: rotateZ(${sunPositionSunset.azimuthDegrees}deg)`;\n\n\nmsg.payload = {\n sunPosition: {\n now: sunPositionNow,\n sunrise: sunPositionSunrise,\n sunset: sunPositionSunset,\n }\n}\nreturn msg;",
- "outputs": 1,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 2077.199981689453,
- "y": 679.2000350952148,
- "wires": [
- [
- "2046a24e0c2fdc92"
- ]
- ]
- },
- {
- "id": "685cf8222df25623",
- "type": "inject",
- "z": "303c9862.ddfff8",
- "name": "",
- "props": [
- {
- "p": "payload"
- },
- {
- "p": "topic",
- "vt": "str"
- }
- ],
- "repeat": "60",
- "crontab": "",
- "once": false,
- "onceDelay": 0.1,
- "topic": "",
- "payload": "",
- "payloadType": "date",
- "x": 1894.1999740600586,
- "y": 677.2000350952148,
- "wires": [
- [
- "e1f413b8747a3e23"
- ]
- ]
- },
- {
- "id": "1c67febfe1ce1abd",
- "type": "function",
- "z": "303c9862.ddfff8",
- "name": "disp_pwr",
- "func": "if (msg.payload.type == \"disp_pwr\") {\n msg.payload = msg.payload.data;\n return msg;\n}",
- "outputs": 1,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 757.2000350952148,
- "y": 3687.200006365776,
- "wires": [
- [
- "be5efd648227638b"
- ]
- ]
- },
- {
- "id": "c94a357adb066e7e",
- "type": "function",
- "z": "303c9862.ddfff8",
- "name": "",
- "func": "msg.recordType = flow.get('batteryRecord').recordType;\nreturn msg;",
- "outputs": 1,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 1345.2000465393066,
- "y": 1951.5998821258545,
- "wires": [
- [
- "b3e26726cf0f4701"
- ]
- ]
- },
- {
- "id": "b3e26726cf0f4701",
- "type": "ui_text",
- "z": "303c9862.ddfff8",
- "group": "b55f633.0a700a",
- "order": 0,
- "width": 0,
- "height": 0,
- "name": "",
- "label": "Record Type",
- "format": "{{msg.recordType}}",
- "layout": "row-spread",
- "className": "",
- "x": 1496.200050354004,
- "y": 1949.600004196167,
- "wires": []
- },
- {
- "id": "d0c51b4e08b32eb2",
- "type": "function",
- "z": "303c9862.ddfff8",
- "name": "stat",
- "func": "if (msg.payload.type == \"stat\") {\n msg.payload = msg.payload.data;\n\n const columns = Object.keys(msg.payload).map((column) => `\\`${column}\\` = ?`).join(', ');\n\n msg.topic = `INSERT INTO pv_battery_stat SET log_date = NOW(), ${columns}`;\n msg.payload = Object.values(msg.payload);\n\n return msg;\n}",
- "outputs": 1,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 1631.199951171875,
- "y": 3588.400146484375,
- "wires": [
- [
- "782e5b5ab3f03abb"
- ]
- ]
- },
- {
- "id": "782e5b5ab3f03abb",
- "type": "mysql",
- "z": "303c9862.ddfff8",
- "mydb": "76a2023f.8c254c",
- "name": "",
- "x": 1799.866554260254,
- "y": 3587.7336959838867,
- "wires": [
- [
- "d7de585efcc764fc"
- ]
- ]
- },
- {
- "id": "d7de585efcc764fc",
- "type": "debug",
- "z": "303c9862.ddfff8",
- "name": "debug 15",
- "active": false,
- "tosidebar": true,
- "console": false,
- "tostatus": false,
- "complete": "false",
- "statusVal": "",
- "statusType": "auto",
- "x": 1960.2000579833984,
- "y": 3605.4001998901367,
- "wires": []
- },
- {
- "id": "8e3f2accc4d47cf1",
- "type": "function",
- "z": "303c9862.ddfff8",
- "name": "sysinfo",
- "func": "if (msg.payload.type == \"sysinfo\") {\n msg.payload = msg.payload.data;\n\n const columns = Object.keys(msg.payload).map((column) => `\\`${column}\\` = ?`).join(', ');\n\n msg.topic = `INSERT INTO pv_battery_sysinfo SET log_date = NOW(), ${columns}`;\n msg.payload = Object.values(msg.payload);\n\n return msg;\n}",
- "outputs": 1,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 1643.199951171875,
- "y": 3630.400146484375,
- "wires": [
- [
- "bcc98baeb30e95b9"
- ]
- ]
- },
- {
- "id": "bcc98baeb30e95b9",
- "type": "mysql",
- "z": "303c9862.ddfff8",
- "mydb": "76a2023f.8c254c",
- "name": "",
- "x": 1799.866554260254,
- "y": 3629.7336959838867,
- "wires": [
- [
- "d7de585efcc764fc"
- ]
- ]
- },
- {
- "id": "535ea969ba5e5c16",
- "type": "function",
- "z": "303c9862.ddfff8",
- "name": "bat",
- "func": "if (msg.payload.type == \"bat\") {\n const dataBatteries = msg.payload.data.batteries;\n\n msg.payload = msg.payload.data.columnValues;\n\n delete msg.payload.batteries;\n\n const columns = Object.keys(msg.payload).map((column) => `\\`${column}\\` = ?`).join(', ');\n\n node.send({\n topic: `INSERT INTO pv_battery_bat SET log_date = NOW(), ${columns}`,\n payload: Object.values(msg.payload),\n });\n\n for (const dataBattery of dataBatteries) {\n const columns = Object.keys(dataBattery).map((column) => `\\`${column}\\` = ?`).join(', ');\n\n node.send({\n topic: `INSERT INTO pv_battery_bat_battery SET ${columns}`,\n payload: Object.values(dataBattery),\n });\n }\n}",
- "outputs": 1,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 1637.199951171875,
- "y": 3672.400146484375,
- "wires": [
- [
- "1fd6a0a74c46a2a6"
- ]
- ]
- },
- {
- "id": "1fd6a0a74c46a2a6",
- "type": "mysql",
- "z": "303c9862.ddfff8",
- "mydb": "76a2023f.8c254c",
- "name": "",
- "x": 1803.866554260254,
- "y": 3671.7336959838867,
- "wires": [
- [
- "d7de585efcc764fc"
- ]
- ]
- },
- {
- "id": "dd5dd723ead7dd78",
- "type": "function",
- "z": "303c9862.ddfff8",
- "name": "soh",
- "func": "if (msg.payload.type == \"soh\") {\n const dataBatteries = msg.payload.data.batteries;\n\n msg.payload = msg.payload.data.columnValues;\n\n delete msg.payload.batteries;\n\n const columns = Object.keys(msg.payload).map((column) => `\\`${column}\\` = ?`).join(', ');\n\n node.send({\n topic: `INSERT INTO pv_battery_soh SET log_date = NOW(), ${columns}`,\n payload: Object.values(msg.payload),\n });\n\n for (const dataBattery of dataBatteries) {\n const columns = Object.keys(dataBattery).map((column) => `\\`${column}\\` = ?`).join(', ');\n\n node.send({\n topic: `INSERT INTO pv_battery_soh_battery SET ${columns}`,\n payload: Object.values(dataBattery),\n });\n }\n}",
- "outputs": 1,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 1634.199951171875,
- "y": 3714.199951171875,
- "wires": [
- [
- "9d612173b6f1a17d"
- ]
- ]
- },
- {
- "id": "9d612173b6f1a17d",
- "type": "mysql",
- "z": "303c9862.ddfff8",
- "mydb": "76a2023f.8c254c",
- "name": "",
- "x": 1800.866554260254,
- "y": 3713.5335006713867,
- "wires": [
- [
- "d7de585efcc764fc"
- ]
- ]
- },
- {
- "id": "8d0de0a23b20e624",
- "type": "function",
- "z": "303c9862.ddfff8",
- "name": "log",
- "func": "if (msg.payload.type == \"log\") {\n const dataRecords = msg.payload.data;\n\n for (const dataRecord of dataRecords) {\n const columns = Object.keys(dataRecord).map((column) => `\\`${column}\\` = ?`).join(', ');\n\n node.send({\n topic: `INSERT INTO pv_battery_log SET log_date = NOW(), ${columns} ON DUPLICATE KEY UPDATE uuid=uuid`,\n payload: Object.values(dataRecord),\n });\n }\n}",
- "outputs": 1,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 1638.199951171875,
- "y": 3754.199951171875,
- "wires": [
- [
- "341ca86f121477a6"
- ]
- ]
- },
- {
- "id": "341ca86f121477a6",
- "type": "mysql",
- "z": "303c9862.ddfff8",
- "mydb": "76a2023f.8c254c",
- "name": "",
- "x": 1804.866554260254,
- "y": 3753.5335006713867,
- "wires": [
- [
- "d7de585efcc764fc"
- ]
- ]
- },
- {
- "id": "656b1803a57a159b",
- "type": "function",
- "z": "303c9862.ddfff8",
- "name": "data event",
- "func": "if (msg.payload.type == \"data event\") {\n const dataBatteries = msg.payload.data.batteries;\n const dataUnits = msg.payload.data.units;\n\n msg.payload = msg.payload.data.columnValues;\n\n delete msg.payload.batteries;\n\n const columns = Object.keys(msg.payload).map((column) => `\\`${column}\\` = ?`).join(', ');\n\n node.send({\n topic: `INSERT INTO pv_battery_data_event SET log_date = NOW(), ${columns} ON DUPLICATE KEY UPDATE uuid=uuid`,\n payload: Object.values(msg.payload),\n });\n\n for (const dataBattery of dataBatteries) {\n const columns = Object.keys(dataBattery).map((column) => `\\`${column}\\` = ?`).join(', ');\n\n node.send({\n topic: `INSERT INTO pv_battery_data_event_battery SET ${columns} ON DUPLICATE KEY UPDATE parent_uuid=parent_uuid`,\n payload: Object.values(dataBattery),\n });\n }\n\n for (const dataUnit of dataUnits) {\n const columns = Object.keys(dataUnit).map((column) => `\\`${column}\\` = ?`).join(', ');\n\n node.send({\n topic: `INSERT INTO pv_battery_data_event_unit SET ${columns} ON DUPLICATE KEY UPDATE parent_uuid=parent_uuid`,\n payload: Object.values(dataUnit),\n });\n }\n}",
- "outputs": 1,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 1660.199951171875,
- "y": 3794.199951171875,
- "wires": [
- [
- "a1610872c8680840"
- ]
- ]
- },
- {
- "id": "a1610872c8680840",
- "type": "mysql",
- "z": "303c9862.ddfff8",
- "mydb": "76a2023f.8c254c",
- "name": "",
- "x": 1806.866554260254,
- "y": 3793.5335006713867,
- "wires": [
- []
- ]
- },
- {
- "id": "b562397f4dc61e83",
- "type": "function",
- "z": "303c9862.ddfff8",
- "name": "data history",
- "func": "if (msg.payload.type == \"data history\") {\n const dataBatteries = msg.payload.data.batteries;\n const dataUnits = msg.payload.data.units;\n\n msg.payload = msg.payload.data.columnValues;\n\n delete msg.payload.batteries;\n\n const columns = Object.keys(msg.payload).map((column) => `\\`${column}\\` = ?`).join(', ');\n\n node.send({\n topic: `INSERT INTO pv_battery_data_history SET log_date = NOW(), ${columns} ON DUPLICATE KEY UPDATE uuid=uuid`,\n payload: Object.values(msg.payload),\n });\n\n for (const dataBattery of dataBatteries) {\n const columns = Object.keys(dataBattery).map((column) => `\\`${column}\\` = ?`).join(', ');\n\n node.send({\n topic: `INSERT INTO pv_battery_data_history_battery SET ${columns} ON DUPLICATE KEY UPDATE parent_uuid=parent_uuid`,\n payload: Object.values(dataBattery),\n });\n }\n\n for (const dataUnit of dataUnits) {\n const columns = Object.keys(dataUnit).map((column) => `\\`${column}\\` = ?`).join(', ');\n\n node.send({\n topic: `INSERT INTO pv_battery_data_history_unit SET ${columns} ON DUPLICATE KEY UPDATE parent_uuid=parent_uuid`,\n payload: Object.values(dataUnit),\n });\n }\n}",
- "outputs": 1,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 1660.199951171875,
- "y": 3828.199951171875,
- "wires": [
- [
- "0573d01071f92415"
- ]
- ]
- },
- {
- "id": "0573d01071f92415",
- "type": "mysql",
- "z": "303c9862.ddfff8",
- "mydb": "76a2023f.8c254c",
- "name": "",
- "x": 1806.866554260254,
- "y": 3827.5335006713867,
- "wires": [
- []
- ]
- },
- {
- "id": "7ba79850621f4c7b",
- "type": "function",
- "z": "303c9862.ddfff8",
- "name": "data misc",
- "func": "if (msg.payload.type == \"data misc\") {\n const dataBatteries = msg.payload.data.batteries;\n const dataUnits = msg.payload.data.units;\n\n msg.payload = msg.payload.data.columnValues;\n\n delete msg.payload.batteries;\n\n const columns = Object.keys(msg.payload).map((column) => `\\`${column}\\` = ?`).join(', ');\n\n node.send({\n topic: `INSERT INTO pv_battery_data_misc SET log_date = NOW(), ${columns} ON DUPLICATE KEY UPDATE uuid=uuid`,\n payload: Object.values(msg.payload),\n });\n\n for (const dataBattery of dataBatteries) {\n const columns = Object.keys(dataBattery).map((column) => `\\`${column}\\` = ?`).join(', ');\n\n node.send({\n topic: `INSERT INTO pv_battery_data_misc_battery SET ${columns} ON DUPLICATE KEY UPDATE parent_uuid=parent_uuid`,\n payload: Object.values(dataBattery),\n });\n }\n\n for (const dataUnit of dataUnits) {\n const columns = Object.keys(dataUnit).map((column) => `\\`${column}\\` = ?`).join(', ');\n\n node.send({\n topic: `INSERT INTO pv_battery_data_misc_unit SET ${columns} ON DUPLICATE KEY UPDATE parent_uuid=parent_uuid`,\n payload: Object.values(dataUnit),\n });\n }\n}",
- "outputs": 1,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 1655.199951171875,
- "y": 3864.199951171875,
- "wires": [
- [
- "12e5b0aece5a3d30"
- ]
- ]
- },
- {
- "id": "12e5b0aece5a3d30",
- "type": "mysql",
- "z": "303c9862.ddfff8",
- "mydb": "76a2023f.8c254c",
- "name": "",
- "x": 1811.866554260254,
- "y": 3863.5335006713867,
- "wires": [
- []
- ]
- },
- {
- "id": "5d943b18bc939561",
- "type": "inject",
- "z": "303c9862.ddfff8",
- "name": "",
- "props": [
- {
- "p": "payload"
- },
- {
- "p": "topic",
- "vt": "str"
- }
- ],
- "repeat": "",
- "crontab": "",
- "once": true,
- "onceDelay": "5",
- "topic": "",
- "payload": "",
- "payloadType": "date",
- "x": 525.2000160217285,
- "y": 431.199990272522,
- "wires": [
- [
- "841afa9422f1d270"
- ]
- ]
- },
- {
- "id": "841afa9422f1d270",
- "type": "function",
- "z": "303c9862.ddfff8",
- "name": "",
- "func": "const af = global.get('actionflows');\n\nconst resMsg = await af.invoke('core.db.query', {\n database: 'smarthouse',\n query: \"SELECT * FROM pv_rooftop\",\n values: [],\n});\n\nfor (const rooftop of resMsg.payload) {\n flow.set(`pv_rooftop_power${rooftop.id}`, rooftop.power)\n}\n",
- "outputs": 1,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 691.2001113891602,
- "y": 431.1999988555908,
- "wires": [
- []
- ]
- },
- {
- "id": "78a4b4b587a2cc69",
- "type": "comment",
- "z": "303c9862.ddfff8",
- "name": "Configuration",
- "info": "",
- "x": 289.1999816894531,
- "y": 42.19999694824219,
- "wires": []
- },
- {
- "id": "34d36175b8acdfbf",
- "type": "comment",
- "z": "303c9862.ddfff8",
- "name": "Solcast",
- "info": "",
- "x": 380.1999855041504,
- "y": 135.1999969482422,
- "wires": []
- },
- {
- "id": "591c5614b4927551",
- "type": "comment",
- "z": "303c9862.ddfff8",
- "name": "strings power",
- "info": "",
- "x": 336.20001220703125,
- "y": 405.199990272522,
- "wires": []
- },
- {
- "id": "ad7b6572f85bdecc",
- "type": "ui_text",
- "z": "303c9862.ddfff8",
- "group": "45ecb2bfdd21bc90",
- "order": 1,
- "width": 0,
- "height": 0,
- "name": "",
- "label": "Sunrise",
- "format": "{{msg.payload}}",
- "layout": "row-spread",
- "className": "",
- "x": 2440.4000606536865,
- "y": 561.2000370025635,
- "wires": []
- },
- {
- "id": "889fe2593fed52ab",
- "type": "function",
- "z": "303c9862.ddfff8",
- "name": "function 21",
- "func": "const dt = new Date(msg.payload.times.sunrise.ts);\nmsg.payload = `${dt.getHours()}:${String(dt.getMinutes()).padStart(2, '0')}`;\nreturn msg;",
- "outputs": 1,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 2281.400058746338,
- "y": 562.2000360488892,
- "wires": [
- [
- "ad7b6572f85bdecc"
- ]
- ]
- },
- {
- "id": "d91fb2ef78f1148b",
- "type": "function",
- "z": "303c9862.ddfff8",
- "name": "function 22",
- "func": "const dt = new Date(msg.payload.times.sunset.ts);\nmsg.payload = `${dt.getHours()}:${String(dt.getMinutes()).padStart(2, '0')}`;\nreturn msg;",
- "outputs": 1,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 2285.39990234375,
- "y": 602.2000122070312,
- "wires": [
- [
- "030fdb239a77bcb1"
- ]
- ]
- },
- {
- "id": "030fdb239a77bcb1",
- "type": "ui_text",
- "z": "303c9862.ddfff8",
- "group": "45ecb2bfdd21bc90",
- "order": 1,
- "width": 0,
- "height": 0,
- "name": "",
- "label": "Sunset",
- "format": "{{msg.payload}}",
- "layout": "row-spread",
- "className": "",
- "x": 2444.3999042510986,
- "y": 601.2000131607056,
- "wires": []
- },
- {
- "id": "af9f1be217dafccc",
- "type": "http request",
- "z": "303c9862.ddfff8",
- "d": true,
- "name": "",
- "method": "POST",
- "ret": "txt",
- "paytoqs": "ignore",
- "url": "http://45.92.239.28:27009/fve-gibon",
- "tls": "",
- "persist": false,
- "proxy": "",
- "insecureHTTPParser": false,
- "authType": "",
- "senderr": false,
- "headers": [],
- "x": 2254.200183868408,
- "y": 922.4001140594482,
- "wires": [
- [
- "62a92fee9dced299"
- ]
- ]
- },
- {
- "id": "d26beecfc0830bfe",
- "type": "sub",
- "z": "303c9862.ddfff8",
- "d": true,
- "name": "pv.inverter.record",
- "topic": "pv.inverter.record",
- "x": 1697.200050354004,
- "y": 932.4000539779663,
- "wires": [
- [
- "7b32339e1d189737"
- ]
- ]
- },
- {
- "id": "7b32339e1d189737",
- "type": "function",
- "z": "303c9862.ddfff8",
- "d": true,
- "name": "function 24",
- "func": "msg.payload = {\n pvPowerPerWattPeak: {\n southEast: msg.payload.pv_ppv1 / 7200,\n southWest: msg.payload.pv_ppv2 / 5400,\n }\n};\nreturn msg;",
- "outputs": 1,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 1908.20015335083,
- "y": 929.4000844955444,
- "wires": [
- [
- "863414f1f720bfc1"
- ]
- ]
- },
- {
- "id": "62a92fee9dced299",
- "type": "debug",
- "z": "303c9862.ddfff8",
- "d": true,
- "name": "debug 22",
- "active": false,
- "tosidebar": true,
- "console": false,
- "tostatus": false,
- "complete": "false",
- "statusVal": "",
- "statusType": "auto",
- "x": 2394.199966430664,
- "y": 922.4000844955444,
- "wires": []
- },
- {
- "id": "54ee2ce5980e7fd8",
- "type": "comment",
- "z": "303c9862.ddfff8",
- "d": true,
- "name": "preposlani vykonu k otovi",
- "info": "",
- "x": 1679.200050354004,
- "y": 858.4000520706177,
- "wires": []
- },
- {
- "id": "863414f1f720bfc1",
- "type": "delay",
- "z": "303c9862.ddfff8",
- "d": true,
- "name": "",
- "pauseType": "rate",
- "timeout": "5",
- "timeoutUnits": "seconds",
- "rate": "1",
- "nbRateUnits": "10",
- "rateUnits": "second",
- "randomFirst": "1",
- "randomLast": "5",
- "randomUnits": "seconds",
- "drop": true,
- "allowrate": false,
- "outputs": 1,
- "x": 2085.2000579833984,
- "y": 923.4001140594482,
- "wires": [
- [
- "af9f1be217dafccc"
- ]
- ]
- },
- {
- "id": "6d168fe4f0603839",
- "type": "inject",
- "z": "303c9862.ddfff8",
- "name": "",
- "props": [
- {
- "p": "payload"
- },
- {
- "p": "topic",
- "vt": "str"
- }
- ],
- "repeat": "60",
- "crontab": "",
- "once": false,
- "onceDelay": 0.1,
- "topic": "",
- "payload": "",
- "payloadType": "date",
- "x": 1891.199951171875,
- "y": 736.2000122070312,
- "wires": [
- [
- "29a390381fb42140"
- ]
- ]
- },
- {
- "id": "29a390381fb42140",
- "type": "function",
- "z": "303c9862.ddfff8",
- "name": "function 28",
- "func": "const sunPositionNow = flow.get('sunPositionNow');\nconst sunPositionSunrise = flow.get('sunPositionSunrise');\nconst sunPositionSunset = flow.get('sunPositionSunset');\n\nmsg.payload = {\n altitude: sunPositionNow.altitudeDegrees,\n maxAltitude: sunPositionNow.positionAtSolarNoon.altitudeDegrees,\n afternoon: sunPositionNow.ts > (sunPositionSunset.ts + sunPositionSunrise.ts) / 2,\n}\nreturn msg;",
- "outputs": 1,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 2074.1999588012695,
- "y": 738.2000122070312,
- "wires": [
- [
- "a9c95c7334c170ae"
- ]
- ]
- },
- {
- "id": "a9c95c7334c170ae",
- "type": "ui_template",
- "z": "303c9862.ddfff8",
- "group": "45ecb2bfdd21bc90",
- "name": "",
- "order": 2,
- "width": 0,
- "height": 0,
- "format": "<div class=\"sun-path\">\n\t<canvas id=\"sunPathCanvas\" width=300 height=200></canvas>\n</div>\n\n<script>\n\t(function(scope) {\n\tscope.$watch('msg.payload', function(payload) {\n\t\tif (payload) {\n\t\t\tconsole.log(payload);\n\n\t\t\tclass SunPathUtils {\n\t\t\t\tstatic clearCanvas(ctx) {\n\t\t\t\t\tctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);\n\t\t\t\t}\n\n\t\t\t\tstatic drawAlignedText(ctx, text, x, y, align) {\n\t\t\t\t\tconst metrics = ctx.measureText(text);\n\t\t\t\t\tconst textWidth = metrics.width;\n\n\t\t\t\t\tif (align == 'center') {\n\t\t\t\t\t\tctx.fillText(text, x - (textWidth / 2), y);\n\t\t\t\t\t}else if (align == 'right') {\n\t\t\t\t\t\tctx.fillText(text, x - textWidth, y);\n\t\t\t\t\t}else {\n\t\t\t\t\t\tctx.fillText(text, x, y);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tstatic deg2rad(angle) {\n\t\t\t\t\treturn angle / 180 * Math.PI;\n\t\t\t\t}\n\n\t\t\t\tstatic getAngle(x1, y1, x2, y2) {\n\t\t\t\t\tconst dx = x2 - x1;\n\t\t\t\t\tconst dy = y2 - y1;\n\t\t\t\t\tconst radians = Math.atan2(dy, dx);\n\t\t\t\t\tconst angle = radians * 180 / Math.PI;\n\t\t\t\t\treturn angle;\n\t\t\t\t}\n\n\t\t\t\tstatic interceptCircleLine(circle, line) {\n\t\t\t\t\tlet a, b, c, d, u1, u2, ret, retP1, retP2, v1, v2;\n\t\t\t\t\tv1 = {};\n\t\t\t\t\tv2 = {};\n\t\t\t\t\tv1.x = line.p2.x - line.p1.x;\n\t\t\t\t\tv1.y = line.p2.y - line.p1.y;\n\t\t\t\t\tv2.x = line.p1.x - circle.center.x;\n\t\t\t\t\tv2.y = line.p1.y - circle.center.y;\n\t\t\t\t\tb = (v1.x * v2.x + v1.y * v2.y);\n\t\t\t\t\tc = 2 * (v1.x * v1.x + v1.y * v1.y);\n\t\t\t\t\tb *= -2;\n\t\t\t\t\td = Math.sqrt(b * b - 2 * c * (v2.x * v2.x + v2.y * v2.y - circle.radius * circle.radius));\n\t\t\t\t\tif(isNaN(d)){ // no intercept\n\t\t\t\t\t\treturn [];\n\t\t\t\t\t}\n\t\t\t\t\tu1 = (b - d) / c; // these represent the unit distance of point one and two on the line\n\t\t\t\t\tu2 = (b + d) / c; \n\t\t\t\t\tretP1 = {}; // return points\n\t\t\t\t\tretP2 = {} \n\t\t\t\t\tret = []; // return array\n\t\t\t\t\tif(u1 <= 1 && u1 >= 0){ // add point if on the line segment\n\t\t\t\t\t\tretP1.x = line.p1.x + v1.x * u1;\n\t\t\t\t\t\tretP1.y = line.p1.y + v1.y * u1;\n\t\t\t\t\t\tret[0] = retP1;\n\t\t\t\t\t}\n\t\t\t\t\tif(u2 <= 1 && u2 >= 0){ // second add point if on the line segment\n\t\t\t\t\t\tretP2.x = line.p1.x + v1.x * u2;\n\t\t\t\t\t\tretP2.y = line.p1.y + v1.y * u2;\n\t\t\t\t\t\tret[ret.length] = retP2;\n\t\t\t\t\t}\n\t\t\t\t\treturn ret;\n\t\t\t\t}\n\n\t\t\t\tstatic createLineByAngle(point, angle, length) {\n\t\t\t\t\tconst angleInRadians = angle * Math.PI / 180;\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\tp1: {\n\t\t\t\t\t\t\tx: point.x,\n\t\t\t\t\t\t\ty: point.y,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tp2: {\n\t\t\t\t\t\t\tx: point.x - length*Math.cos(angleInRadians),\n\t\t\t\t\t\t\ty: point.y - length*Math.sin(angleInRadians),\n\t\t\t\t\t\t},\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\tstatic getLineAngle(x1, y1, x2, y2) {\n\t\t\t\t\tconst dx = x2 - x1;\n\t\t\t\t\tconst dy = y2 - y1;\n\t\t\t\t\treturn Math.atan2(dy, dx) * 180 / Math.PI;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tclass SunPathVisualizer {\n\t\t\t\t// Set the ellipse parameters\n\t\t\t\tconfig = {\n\t\t\t\t\tcenterX: 170,\n\t\t\t\t\tcenterY: 250,\n\t\t\t\t\tradius: 250,\n\t\t\t\t};\n\n\t\t\t\tctx = null;\n\n\t\t\t\tconstructor(options, ctx) {\n\t\t\t\t\tthis.options = options;\n\t\t\t\t\tthis.ctx = ctx;\n\t\t\t\t\tthis.config = {\n\t\t\t\t\t\tcenterX: options.size / 2,\n\t\t\t\t\t\tcenterY: options.size,\n\t\t\t\t\t\tradius: options.size,\n\t\t\t\t\t};\n\n\t\t\t\t\tthis.azimuth = null;\n\t\t\t\t}\n\n\t\t\t\tcalcAngleOffsetByAltitude(altitude) {\n\t\t\t\t\t// vysku oblouku kruznice udelat pomerove vuci maximalni altitude.\n\t\t\t\t\t// Maximum je altitude 90° a v tom pripade se vykresli plny pulkruh\n\t\t\t\t\t// Pokud je altitude 45° tedy polovina z 90° tak vyska oblouku bude polovicni vuci pulkruhu\n\t\t\t\t\t//angleOffset = 90 * (altitude - 90) / 100;\n\t\t\t\t\tconst angleOffset = altitude;\n\n\t\t\t\t\treturn angleOffset;\n\t\t\t\t}\n\n\t\t\t\tdrawSunPath(ctx, maxAltitude) {\n\t\t\t\t\t// Begin drawing the ellipse path\n\t\t\t\t\tctx.beginPath();\n\n\t\t\t\t\tconst angleOffsetRad = SunPathUtils.deg2rad(this.calcAngleOffsetByAltitude(maxAltitude));\n\n\t\t\t\t\t// Draw the ellipse\n\t\t\t\t\tctx.ellipse(this.config.centerX, this.config.centerY, this.config.radius, this.config.radius, 0, Math.PI/2*3 - angleOffsetRad, Math.PI/2*3 + angleOffsetRad);\n\n\t\t\t\t\t// Set the stroke and fill styles\n\t\t\t\t\tctx.strokeStyle = \"black\";\n\t\t\t\t\tctx.lineWidth = 1;\n\t\t\t\t\tctx.fillStyle = \"lightblue\";\n\n\t\t\t\t\t// Fill and stroke the ellipse\n\t\t\t\t\tctx.fill();\n\t\t\t\t\tctx.stroke();\n\t\t\t\t}\n\n\t\t\t\tcalcPointByAzimuth(azimuth) {\n\t\t\t\t\tconst phi = 0;\n\n\t\t\t\t\tconst angle = azimuth - 90;\n\n\t\t\t\t\t// Calculate the angle between the X-axis and the point on the arc\n\t\t\t\t\tconst theta = (angle) * (Math.PI / 180);\n\n\t\t\t\t\t// Calculate the (x, y) position of the point on the arc\n\t\t\t\t\tconst x = this.config.centerX + this.config.radius * Math.cos(theta) * Math.cos(phi) - this.config.radius * Math.sin(theta) * Math.sin(phi);\n\t\t\t\t\tconst y = this.config.centerY + this.config.radius * Math.cos(theta) * Math.sin(phi) + this.config.radius * Math.sin(theta) * Math.cos(phi);\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\tx, y,\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tcalcGround(maxAltitude) {\n\t\t\t\t\t// potrebujeme zjistit, kde se nachazi zem\n\n\t\t\t\t\t// nejdrive podle altitude zjistime angle offset\n\t\t\t\t\tconst angleOffset = this.calcAngleOffsetByAltitude(maxAltitude);\n\t\t\t\t\t//console.log({angleOffset});\n\n\t\t\t\t\t// a podle angleOffset, ktery bude predstavovat azimuth, tak vypocitame pozici bodu\n\t\t\t\t\tconst point1 = this.calcPointByAzimuth(-angleOffset);\n\t\t\t\t\tconst point2 = this.calcPointByAzimuth(angleOffset);\n\n\t\t\t\t\t// vypocitame vysku oblouku\n\t\t\t\t\tconst arcHeight = this.config.radius - (this.config.centerY - point1.y);\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\tpoint1,\n\t\t\t\t\t\tpoint2,\n\t\t\t\t\t\tarcHeight,\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\tcalcGroundBasePoint(maxAltitude, afternoon) {\n\t\t\t\t\tconst ground = this.calcGround(maxAltitude);\n\n\t\t\t\t\t// zname vysku oblouku a uhel max altitude. Podle toho vypocitame do jakeho bodu to dopadne na zemi\n\t\t\t\t\tconst sideLengthRatio = Math.sin(SunPathUtils.deg2rad(90 - maxAltitude)) / Math.sin(SunPathUtils.deg2rad(maxAltitude));\n\t\t\t\t\tconst basePointOffsetFromCenter = ground.arcHeight * sideLengthRatio;\n\t\t\t\t\t//console.log({basePointOffsetFromCenter});\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\ty: ground.point1.y,\n\t\t\t\t\t\tx: afternoon ? this.config.centerX - basePointOffsetFromCenter : this.config.centerX + basePointOffsetFromCenter,\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\tdrawGround(ctx, maxAltitude, afternoon) {\n\t\t\t\t\tconst ground = this.calcGround(maxAltitude);\n\n\t\t\t\t\tctx.beginPath();\n\t\t\t\t\tctx.strokeStyle = \"black\";\n\t\t\t\t\tctx.lineWidth = 3;\n\t\t\t\t\tctx.moveTo(ground.point1.x, ground.point1.y);\n\t\t\t\t\tctx.lineTo(ground.point2.x, ground.point2.y);\n\t\t\t\t\tctx.stroke();\n\n\t\t\t\t\t// vykreslit bod\n\t\t\t\t\tconst groundBasePoint = this.calcGroundBasePoint(maxAltitude, afternoon);\n\t\t\t\t\tctx.beginPath();\n\t\t\t\t\tctx.arc(groundBasePoint.x, groundBasePoint.y, 5, 0, 2*Math.PI);\n\t\t\t\t\t// Set the fill color and fill the circle\n\t\t\t\t\tctx.fillStyle = \"#555\";\n\t\t\t\t\tctx.fill();\n\n\t\t\t\t\tctx.font = '13px Arial';\n\t\t\t\t\tctx.fillStyle = 'black';\n\t\t\t\t\tSunPathUtils.drawAlignedText(ctx, `sunset`, ground.point1.x, ground.point1.y + 15, 'left');\n\t\t\t\t\tSunPathUtils.drawAlignedText(ctx, `sunrise`, ground.point2.x, ground.point2.y + 15, 'right');\n\t\t\t\t}\n\n\t\t\t\tdrawSun(ctx, azimuth) {\n\t\t\t\t\tconst sunPosition = this.calcPointByAzimuth(azimuth);\n\n\t\t\t\t\tctx.beginPath();\n\t\t\t\t\tctx.arc(sunPosition.x, sunPosition.y, 10, 0, 2*Math.PI);\n\n\t\t\t\t\t// Set the fill color and fill the circle\n\t\t\t\t\tctx.fillStyle = \"yellow\";\n\t\t\t\t\tctx.fill();\n\t\t\t\t\tctx.stroke();\n\t\t\t\t}\n\n\t\t\t\tdrawSunAngle(ctx, maxAltitude, azimuth) {\n\t\t\t\t\t// zjistit, kde je base bod na zemi\n\t\t\t\t\tconst groundBasePoint = this.calcGroundBasePoint(maxAltitude, azimuth > 0);\n\n\t\t\t\t\t// zjistit bod na ceste slunce podle azimutu\n\t\t\t\t\tconst sunPosition = this.calcPointByAzimuth(azimuth);\n\n\t\t\t\t\tctx.beginPath();\n\t\t\t\t\tctx.setLineDash([2, 4]);\n\t\t\t\t\tctx.strokeStyle = \"#888\";\n\t\t\t\t\tctx.lineWidth = 1;\n\t\t\t\t\tctx.moveTo(groundBasePoint.x, groundBasePoint.y);\n\t\t\t\t\tctx.lineTo(sunPosition.x, sunPosition.y);\n\t\t\t\t\tctx.stroke();\n\t\t\t\t\tctx.setLineDash([]);\n\n\t\t\t\t\tconst angle = SunPathUtils.getAngle(Math.min(groundBasePoint.x, sunPosition.x), sunPosition.y, Math.max(groundBasePoint.x, sunPosition.x), groundBasePoint.y);\n\t\t\t\t\t//console.log({angle})\n\n\t\t\t\t\tctx.font = '15px Arial';\n\t\t\t\t\tctx.fillStyle = 'black';\n\t\t\t\t\tSunPathUtils.drawAlignedText(ctx, `${Math.round(angle)}°`, groundBasePoint.x, groundBasePoint.y - 15, 'center');\n\t\t\t\t}\n\n\t\t\t\tcalcSunPositionByAltitude(maxAltitude, altitude, afternoon) {\n\t\t\t\t\t// zjistit, kde je base bod na zemi\n\t\t\t\t\tconst groundBasePoint = this.calcGroundBasePoint(maxAltitude, afternoon);\n\n\t\t\t\t\t// zname bod na zemi a uhel smerem k oblouku kudy jde slunce\n\t\t\t\t\t// podle toho vypocitame pozici na oblouku\n\n\t\t\t\t\t// sestrojime usecku podle pozadovaneho uhlu\n\t\t\t\t\tconst line = SunPathUtils.createLineByAngle(groundBasePoint, afternoon ? 180 - altitude : altitude, 2*this.config.radius);\n\n\t\t\t\t\t// vypocitame prusecik\n\t\t\t\t\tconst intersections = SunPathUtils.interceptCircleLine({center: {x: this.config.centerX, y: this.config.centerY}, radius: this.config.radius}, line);\n\n\t\t\t\t\t//console.log(intersections);\n\n\t\t\t\t\tif (intersections.length > 0) {\n\t\t\t\t\t\t// for (const intersection of intersections) {\n\t\t\t\t\t\t// \tctx.beginPath();\n\t\t\t\t\t\t// \tctx.arc(intersection.x, intersection.y, 10, 0, 2*Math.PI);\n\n\t\t\t\t\t\t// \t// Set the fill color and fill the circle\n\t\t\t\t\t\t// \tctx.fillStyle = \"red\";\n\t\t\t\t\t\t// \tctx.fill();\n\t\t\t\t\t\t// }\n\n\t\t\t\t\t\tconst intersection = intersections[0];\n\n\t\t\t\t\t\t// zjistime jaky uhel svira stred kriznice a bod na ceste slunce\n\t\t\t\t\t\tconst angle = SunPathUtils.getLineAngle(intersection.x, intersection.y, this.config.centerX, this.config.centerY);\n\t\t\t\t\t\t//console.log(angle);\n\n\t\t\t\t\t\t// prepocitame na azimut\n\t\t\t\t\t\tthis.azimuth = -1*(90 - angle);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tcalcSizes(maxAltitude, azimuth, targetGroundWidth, targetGroundY) {\n\t\t\t\t\t// nahodit nejaky radius\n\t\t\t\t\tthis.config.radius = this.config.radius = 100;\n\t\t\t\t\tthis.config.centerY = 1000;\n\n\t\t\t\t\t// vypocitat polohu zeme\n\t\t\t\t\tlet ground = this.calcGround(maxAltitude, azimuth > 0);\n\t\t\t\t\tconst groundWidth = ground.point2.x - ground.point1.x;\n\n\t\t\t\t\t// podle vypoctene polohy zeme spocitat jak ma byt velky radius\n\t\t\t\t\tconst ratio = targetGroundWidth / groundWidth;\n\t\t\t\t\tconst radius = ratio * this.config.radius;\n\t\t\t\t\tthis.config.radius = this.config.radius = radius;\n\n\t\t\t\t\t// zjistit kam vychazi pozice zeme\n\t\t\t\t\tground = this.calcGround(maxAltitude, azimuth > 0);\n\t\t\t\t\t// soupnout stred kruhu podle pozadovane pozice zeme\n\t\t\t\t\tthis.config.centerY = 1000 + (targetGroundY - ground.point1.y);\n\t\t\t\t}\n\n\t\t\t\tdraw(maxAltitude, altitude, afternoon) {\n\t\t\t\t\tSunPathUtils.clearCanvas(this.ctx);\n\n\t\t\t\t\tthis.calcSizes(maxAltitude, 0, this.options.size - 2*10, this.options.size / 2);\n\n\t\t\t\t\tthis.calcSunPositionByAltitude(maxAltitude, altitude, afternoon);\n\n\t\t\t\t\tthis.azimuth = -this.azimuth;\n\n\t\t\t\t\tthis.drawSunPath(this.ctx, maxAltitude);\n\t\t\t\t\tthis.drawGround(this.ctx, maxAltitude, this.azimuth > 0);\n\t\t\t\t\tthis.drawSunAngle(this.ctx, maxAltitude, this.azimuth);\n\t\t\t\t\tthis.drawSun(this.ctx, this.azimuth);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t\n\t\t\t// Get the canvas element and its 2D drawing context\n\t\t\tconst sunPathCanvas = document.getElementById(\"sunPathCanvas\");\n\t\t\tconst sunPathCanvasCtx = sunPathCanvas.getContext(\"2d\");\n\t\t\tconst sunPathVisualizer = new SunPathVisualizer({size: 300}, sunPathCanvasCtx);\n\n\t\t\tsunPathVisualizer.draw(payload.maxAltitude, payload.altitude, payload.afternoon);\n\t\t}\n\t});\n})(scope);\n</script>\n\n<style>\n\t.sun-path {}\n\n\tcanvas {}\n</style>",
- "storeOutMessages": true,
- "fwdInMessages": true,
- "resendOnRefresh": true,
- "templateScope": "local",
- "className": "sun-path-widget",
- "x": 2247.200080871582,
- "y": 740.2000141143799,
- "wires": [
- []
- ]
- },
- {
- "id": "505d362ca3ebe622",
- "type": "inject",
- "z": "303c9862.ddfff8",
- "name": "",
- "props": [
- {
- "p": "payload"
- },
- {
- "p": "todayOffset",
- "v": "0",
- "vt": "str"
- }
- ],
- "repeat": "3600",
- "crontab": "",
- "once": true,
- "onceDelay": 0.1,
- "topic": "",
- "payload": "",
- "payloadType": "date",
- "x": 1187.1999626159668,
- "y": 4943.399903297424,
- "wires": [
- [
- "b62f4d1a7bf9b908"
- ]
- ]
- },
- {
- "id": "b62f4d1a7bf9b908",
- "type": "function",
- "z": "303c9862.ddfff8",
- "name": "",
- "func": "const af = global.get('actionflows');\n\nconst BILLING_PERIOD_DATE_FROM = flow.get('billing_period_date_from');\n\nlet q;\nconst resMsgGridStats = await af.invoke('core.db.query', {\n database: 'smarthouse',\n query: q=`\n SELECT date, ROUND(exported_kwh - imported_kwh) AS balance_kwh FROM (\n SELECT\n DATE(log_date) AS date,\n @running_total_imported := IFNULL(@running_total_imported, 0) + imported AS imported_kwh,\n @running_total_exported := IFNULL(@running_total_exported, 0) + exported AS exported_kwh\n FROM\n pv_daily_stats,\n (SELECT @running_total_imported := 0, @running_total_exported := 0) AS init_vars\n WHERE log_date >= IF(STR_TO_DATE(CONCAT('${BILLING_PERIOD_DATE_FROM}', YEAR(NOW())),'%d.%m.%Y') < NOW(), STR_TO_DATE(CONCAT('${BILLING_PERIOD_DATE_FROM}', YEAR(NOW())),'%d.%m.%Y'), STR_TO_DATE(CONCAT('${BILLING_PERIOD_DATE_FROM}', YEAR(NOW())-1),'%d.%m.%Y'))\n ) a\n `,\n values: [],\n});\n// node.warn(q);\n//node.warn(resMsgGridStats);\n\n// odhad do budoucna\n// zjistime zda-li je den zuctovani (resp. predchozi den) v budoucnosti\n// pokud je den v budoucnosti (napr. dnes je 1.9.2023 a ten den je 31.12.2023)\n// tak vezmeme z minulosti 2.9.2022-31.12.2022\nconst [day, month] = BILLING_PERIOD_DATE_FROM.split('.').map(Number);\nconst today = new Date();\nconst billingPeriodEndDate = new Date(today.getFullYear(), month - 1, day - 1);\n// opravit, aby to bylo tento rok, kdyby to nahodou preteklo do predchoziho\nbillingPeriodEndDate.setFullYear(today.getFullYear());\nconst billingPeriodEndDateInFuture = billingPeriodEndDate > today;\n\n\nconst resMsgEstimatedGridStats = await af.invoke('core.db.query', {\n database: 'smarthouse',\n query: `\n SELECT date, ROUND(exported_kwh - imported_kwh) AS balance_kwh FROM (\n SELECT\n DATE(log_date)+INTERVAL 1 YEAR AS date,\n @running_total_imported := IFNULL(@running_total_imported, 0) + imported AS imported_kwh,\n @running_total_exported := IFNULL(@running_total_exported, 0) + exported AS exported_kwh\n FROM\n pv_daily_stats,\n (SELECT @running_total_imported := 0, @running_total_exported := 0) AS init_vars\n WHERE\n log_date >= DATE(NOW()) + INTERVAL 1 DAY - INTERVAL 1 YEAR\n AND\n log_date <= STR_TO_DATE('${billingPeriodEndDate.getDate()}.${billingPeriodEndDate.getMonth() + 1}.${billingPeriodEndDateInFuture ? billingPeriodEndDate.getFullYear() - 1 : billingPeriodEndDate.getFullYear()}', '%d.%m.%Y')\n ) a\n `,\n values: [],\n});\n// node.warn(q);\nnode.warn(resMsgEstimatedGridStats);\n\n\n// zkombinovat\nmsg.payload = resMsgGridStats.payload;\n\nconst lastGridStatsRecord = resMsgGridStats.payload[resMsgGridStats.payload.length-1];\n// node.warn({ lastGridStatsRecord})\nfor (const record of resMsgEstimatedGridStats.payload) {\n msg.payload.push({\n date: record.date,\n estimated_balance_kwh: lastGridStatsRecord.balance_kwh + record.balance_kwh,\n });\n}\n\nreturn msg;\nmsg.payload = {\n import: Math.round(resMsgGridStats.payload[0].imported_kwh),\n export: Math.round(resMsgGridStats.payload[0].exported_kwh),\n}\n\nreturn msg;\n",
- "outputs": 1,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 1376.1999702453613,
- "y": 4943.399971961975,
- "wires": [
- [
- "32aefffe0f2a21de",
- "a29916e511733d1c"
- ]
- ]
- },
- {
- "id": "32aefffe0f2a21de",
- "type": "debug",
- "z": "303c9862.ddfff8",
- "name": "debug 25",
- "active": true,
- "tosidebar": true,
- "console": false,
- "tostatus": false,
- "complete": "false",
- "statusVal": "",
- "statusType": "auto",
- "x": 1562.2000617980957,
- "y": 4882.399729728699,
- "wires": []
- },
- {
- "id": "a29916e511733d1c",
- "type": "actionflows",
- "z": "303c9862.ddfff8",
- "info": "Describe your action API here.",
- "untilproptype": "num",
- "proptype": "msg",
- "name": "core.dashboard.graphize",
- "prop": "loop",
- "untilprop": 0,
- "until": "gt",
- "loop": "none",
- "scope": "global",
- "perf": false,
- "seq": false,
- "x": 1607.2000617980957,
- "y": 4934.399731636047,
- "wires": [
- [
- "f29f56da9f3fa0b7"
- ]
- ]
- },
- {
- "id": "f29f56da9f3fa0b7",
- "type": "ui_chart",
- "z": "303c9862.ddfff8",
- "name": "",
- "group": "802549dc0ec48149",
- "order": 9,
- "width": 0,
- "height": 0,
- "label": "I/E Balance (Billing Period) (kWh)",
- "chartType": "line",
- "legend": "false",
- "xformat": "D/M",
- "interpolate": "linear",
- "nodata": "",
- "dot": false,
- "ymin": "",
- "ymax": "",
- "removeOlder": "50",
- "removeOlderPoints": "",
- "removeOlderUnit": "604800",
- "cutout": 0,
- "useOneColor": false,
- "useUTC": false,
- "colors": [
- "#1f77b4",
- "#ffee2e",
- "#ff7f0e",
- "#2ca02c",
- "#98df8a",
- "#d62728",
- "#ff9896",
- "#9467bd",
- "#c5b0d5"
- ],
- "outputs": 1,
- "useDifferentColor": false,
- "className": "",
- "x": 1906.2000579833984,
- "y": 4929.399730682373,
- "wires": [
- []
- ]
- },
- {
- "id": "d87a2bdcc3f484b0",
- "type": "function",
- "z": "303c9862.ddfff8",
- "name": "on off-grid mode only",
- "func": "const pvInverterRecord = flow.get('pvInverterRecord');\n\nif (pvInverterRecord.grid_mode_label != \"Connected to grid\") {\n return msg;\n}",
- "outputs": 1,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 1101.2001037597656,
- "y": 3051.400192260742,
- "wires": [
- [
- "e6a603d9.ee064"
- ]
- ]
- },
- {
- "id": "f2911eb919633a36",
- "type": "function",
- "z": "303c9862.ddfff8",
- "name": "Stav Baterie",
- "func": "const lastNotifiedBatteryStatus = flow.get(`lastNotifiedBatteryStatus`);\n\nlet batteryMode = `${ msg.payload.battery_mode_label }`;\nif (batteryMode == \"Charge\" || batteryMode == \"Discharge\" || batteryMode == \"Standby\") {\n batteryMode = \"OK\";\n}\nlet currentBatteryStatus = `Změna stavu baterie: ${batteryMode}`;\n\nif (currentBatteryStatus != lastNotifiedBatteryStatus) {\n flow.set(`lastNotifiedBatteryStatus`, currentBatteryStatus);\n \n msg.payload = { \"title\": currentBatteryStatus, \"text\" : \"\", \"event\" : \"speech\"}\n node.send(msg);\n}\n",
- "outputs": 1,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 865.2000350952148,
- "y": 2987.400058746338,
- "wires": [
- [
- "d71589dd249da60c"
- ]
- ]
- },
- {
- "id": "d71589dd249da60c",
- "type": "actionflows",
- "z": "303c9862.ddfff8",
- "info": "Describe your action API here.",
- "untilproptype": "num",
- "proptype": "msg",
- "name": "notify",
- "prop": "loop",
- "untilprop": 0,
- "until": "gt",
- "loop": "none",
- "scope": "global",
- "perf": false,
- "seq": false,
- "x": 1042.2001037597656,
- "y": 2983.4001903533936,
- "wires": [
- []
- ]
- },
- {
- "id": "e0b28e1766b868d0",
- "type": "inject",
- "z": "303c9862.ddfff8",
- "name": "",
- "props": [
- {
- "p": "payload"
- },
- {
- "p": "todayOffset",
- "v": "0",
- "vt": "str"
- }
- ],
- "repeat": "600",
- "crontab": "",
- "once": true,
- "onceDelay": 0.1,
- "topic": "",
- "payload": "",
- "payloadType": "date",
- "x": 445.1999816894531,
- "y": 1191.4000244140625,
- "wires": [
- [
- "056ac2b68ca96547"
- ]
- ]
- },
- {
- "id": "056ac2b68ca96547",
- "type": "function",
- "z": "303c9862.ddfff8",
- "name": "",
- "func": "const af = global.get('actionflows');\n\nlet q;\nconst resMsgRows = await af.invoke('core.db.query', {\n database: 'smarthouse',\n query: q=`\n WITH\n pv_forecast_ranked_string1 AS (\n SELECT time*(30*60)*1000 AS time, rooftop_kilowatts FROM (\n SELECT\n FLOOR(UNIX_TIMESTAMP(forecast_from_date) / (30*60)) as \"time\",\n AVG(rooftop_kilowatts) AS \"rooftop_kilowatts\"\n FROM (\n select\n pv_forecast.forecast_from_date, pv_forecast.kilowatts*pv_rooftop.power AS rooftop_kilowatts, ROW_NUMBER() OVER (PARTITION BY forecast_from_date ORDER BY request_date DESC) AS rn\n from\n pv_forecast\n JOIN pv_rooftop ON pv_rooftop.id = pv_rooftop_id\n where\n forecast_from_date >= DATE(NOW()) AND forecast_to_date < DATE(NOW()) + INTERVAL 1 DAY\n and pv_rooftop_id = 1\n order by forecast_from_date, request_date\n ) t1\n WHERE\n rn = 1\n GROUP BY time\n ) t2\n ),\n pv_forecast_ranked_string2 AS (\n SELECT time*(30*60)*1000 AS time, rooftop_kilowatts FROM (\n SELECT\n FLOOR(UNIX_TIMESTAMP(forecast_from_date) / (30*60)) as \"time\",\n AVG(rooftop_kilowatts) AS \"rooftop_kilowatts\"\n FROM (\n select\n pv_forecast.forecast_from_date, pv_forecast.kilowatts*pv_rooftop.power AS rooftop_kilowatts, ROW_NUMBER() OVER (PARTITION BY forecast_from_date ORDER BY request_date DESC) AS rn\n from\n pv_forecast\n JOIN pv_rooftop ON pv_rooftop.id = pv_rooftop_id\n where\n forecast_from_date >= DATE(NOW()) AND forecast_to_date < DATE(NOW()) + INTERVAL 1 DAY\n and pv_rooftop_id = 2\n order by forecast_from_date, request_date\n ) t1\n WHERE\n rn = 1\n GROUP BY time\n ) t2\n ),\n pv_real_power AS (\n SELECT time*(30*60)*1000 AS time, pv_ppv FROM (\n SELECT\n FLOOR(UNIX_TIMESTAMP(log_date) / (30*60)) as time,\n AVG((pv_ppv)/1000) AS pv_ppv\n FROM pv_inverter_record\n WHERE\n log_date >= DATE(NOW()) AND log_date < DATE(NOW()) + INTERVAL 1 DAY\n GROUP BY time\n ) t1\n )\n\n SELECT\n pv_forecast_ranked_string1.time,\n pv_forecast_ranked_string1.rooftop_kilowatts + pv_forecast_ranked_string2.rooftop_kilowatts AS \"forecast\",\n pv_real_power.pv_ppv AS \"real\"\n FROM\n pv_forecast_ranked_string1\n JOIN pv_forecast_ranked_string2 ON pv_forecast_ranked_string2.time = pv_forecast_ranked_string1.time\n LEFT JOIN pv_real_power ON pv_real_power.time = pv_forecast_ranked_string1.time\n `,\n values: [],\n});\n//node.warn(q);\n//node.warn(resMsgRows);\n\nmsg.payload = resMsgRows.payload;\nreturn msg;\n",
- "outputs": 1,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 634.1999893188477,
- "y": 1191.4000930786133,
- "wires": [
- [
- "b401086f285896a2",
- "ae6cc39307a3438d"
- ]
- ]
- },
- {
- "id": "b401086f285896a2",
- "type": "debug",
- "z": "303c9862.ddfff8",
- "name": "debug 32",
- "active": false,
- "tosidebar": true,
- "console": false,
- "tostatus": false,
- "complete": "false",
- "statusVal": "",
- "statusType": "auto",
- "x": 820.200080871582,
- "y": 1130.399850845337,
- "wires": []
- },
- {
- "id": "ae6cc39307a3438d",
- "type": "actionflows",
- "z": "303c9862.ddfff8",
- "info": "Describe your action API here.",
- "untilproptype": "num",
- "proptype": "msg",
- "name": "core.dashboard.graphize",
- "prop": "loop",
- "untilprop": 0,
- "until": "gt",
- "loop": "none",
- "scope": "global",
- "perf": false,
- "seq": false,
- "x": 865.200080871582,
- "y": 1182.3998527526855,
- "wires": [
- [
- "4a1bea8e774f28cb"
- ]
- ]
- },
- {
- "id": "4a1bea8e774f28cb",
- "type": "ui_chart",
- "z": "303c9862.ddfff8",
- "name": "",
- "group": "d9bbfe4e.3d039",
- "order": 8,
- "width": 0,
- "height": 0,
- "label": "Power Today (kW)",
- "chartType": "line",
- "legend": "true",
- "xformat": "HH:mm",
- "interpolate": "linear",
- "nodata": "",
- "dot": false,
- "ymin": "",
- "ymax": "",
- "removeOlder": "24",
- "removeOlderPoints": "",
- "removeOlderUnit": "3600",
- "cutout": 0,
- "useOneColor": false,
- "useUTC": false,
- "colors": [
- "#6fb8ec",
- "#e6bf00",
- "#ff7f0e",
- "#2ca02c",
- "#98df8a",
- "#d62728",
- "#ff9896",
- "#9467bd",
- "#c5b0d5"
- ],
- "outputs": 1,
- "useDifferentColor": false,
- "className": "",
- "x": 1117.2000427246094,
- "y": 1182.3999347686768,
- "wires": [
- []
- ]
- },
- {
- "id": "904a6ce028e46aca",
- "type": "ui_text",
- "z": "303c9862.ddfff8",
- "group": "802549dc0ec48149",
- "order": 10,
- "width": 0,
- "height": 0,
- "name": "",
- "label": "Balance",
- "format": "{{msg.payload.export-msg.payload.import}}kWh",
- "layout": "row-spread",
- "className": "",
- "x": 858.0000762939453,
- "y": 4901.999437093735,
- "wires": []
- },
- {
- "id": "84d3387c34952bee",
- "type": "inject",
- "z": "303c9862.ddfff8",
- "name": "",
- "props": [
- {
- "p": "payload"
- },
- {
- "p": "todayOffset",
- "v": "0",
- "vt": "str"
- }
- ],
- "repeat": "3600",
- "crontab": "",
- "once": true,
- "onceDelay": 0.1,
- "topic": "",
- "payload": "",
- "payloadType": "date",
- "x": 458.1999816894531,
- "y": 4944.19970703125,
- "wires": [
- [
- "9bdbee1ef29576f4"
- ]
- ]
- },
- {
- "id": "9bdbee1ef29576f4",
- "type": "function",
- "z": "303c9862.ddfff8",
- "name": "",
- "func": "const af = global.get('actionflows');\n\nconst BILLING_PERIOD_DATE_FROM = flow.get('billing_period_date_from');\n\n// zjistime zda-li je den zuctovani (resp. predchozi den) v budoucnosti\n// pokud je den v budoucnosti (napr. dnes je 1.9.2023 a ten den je 31.12.2023)\n// tak vezmeme z minulosti 2.9.2022-31.12.2022\nconst [day, month] = BILLING_PERIOD_DATE_FROM.split('.').map(Number);\nconst today = new Date();\nconst billingPeriodEndDate = new Date(today.getFullYear(), month - 1, day - 1);\n// opravit, aby to bylo tento rok, kdyby to nahodou preteklo do predchoziho\nbillingPeriodEndDate.setFullYear(today.getFullYear());\nconst billingPeriodEndDateInFuture = billingPeriodEndDate > today;\n\n\nconst resMsgEstimatedGridStats = await af.invoke('core.db.query', {\n database: 'smarthouse',\n query: `\n SELECT SUM(imported) AS imported_kwh, SUM(exported) AS exported_kwh\n FROM pv_daily_stats\n WHERE\n log_date >= DATE(NOW()) + INTERVAL 1 DAY - INTERVAL 1 YEAR\n AND\n log_date <= STR_TO_DATE('${billingPeriodEndDate.getDate()}.${billingPeriodEndDate.getMonth() + 1}.${billingPeriodEndDateInFuture ? billingPeriodEndDate.getFullYear() - 1 : billingPeriodEndDate.getFullYear()}', '%d.%m.%Y')\n `,\n values: [],\n});\n// node.warn(q);\nnode.warn(resMsgEstimatedGridStats);\n\nmsg.payload = {\n import: Math.round(resMsgEstimatedGridStats.payload[0].imported_kwh),\n export: Math.round(resMsgEstimatedGridStats.payload[0].exported_kwh),\n}\n\nflow.set('estimated_rest_billing_period_imported_kwh', msg.payload.import);\nflow.set('estimated_rest_billing_period_exported_kwh', msg.payload.export);\n\nreturn msg;\n",
- "outputs": 1,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 647.1999893188477,
- "y": 4944.199775695801,
- "wires": [
- [
- "49535a063349de0f"
- ]
- ]
- },
- {
- "id": "49535a063349de0f",
- "type": "ui_text",
- "z": "303c9862.ddfff8",
- "group": "802549dc0ec48149",
- "order": 8,
- "width": 0,
- "height": 0,
- "name": "",
- "label": "Estimated I/E Rest Of Billing Period",
- "format": "{{msg.payload.import}}/{{msg.payload.export}}kWh",
- "layout": "row-spread",
- "className": "",
- "x": 939.1999893188477,
- "y": 4953.199775695801,
- "wires": []
- },
- {
- "id": "2187d4f8085d06b7",
- "type": "function",
- "z": "303c9862.ddfff8",
- "name": "",
- "func": "if (flow.get('billing_period_imported_kwh') && flow.get('estimated_rest_billing_period_imported_kwh')) {\n\n msg.payload = {\n export: flow.get('billing_period_exported_kwh') + flow.get('estimated_rest_billing_period_exported_kwh'),\n import: flow.get('billing_period_imported_kwh') + flow.get('estimated_rest_billing_period_imported_kwh'),\n }\n\n return msg;\n}",
- "outputs": 1,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 1411.2000484466553,
- "y": 4821.199534416199,
- "wires": [
- [
- "c316b5bc0610863e"
- ]
- ]
- },
- {
- "id": "c316b5bc0610863e",
- "type": "ui_text",
- "z": "303c9862.ddfff8",
- "group": "802549dc0ec48149",
- "order": 10,
- "width": 0,
- "height": 0,
- "name": "",
- "label": "Estimated Final Balance",
- "format": "{{msg.payload.export-msg.payload.import}}kWh",
- "layout": "row-spread",
- "className": "",
- "x": 1608.533302307129,
- "y": 4820.466135978699,
- "wires": []
- },
- {
- "id": "bb1a4f61dac0bb33",
- "type": "inject",
- "z": "303c9862.ddfff8",
- "name": "",
- "props": [
- {
- "p": "payload"
- },
- {
- "p": "todayOffset",
- "v": "0",
- "vt": "str"
- }
- ],
- "repeat": "3600",
- "crontab": "",
- "once": true,
- "onceDelay": 0.1,
- "topic": "",
- "payload": "",
- "payloadType": "date",
- "x": 1259.1999435424805,
- "y": 4823.199638366699,
- "wires": [
- [
- "2187d4f8085d06b7"
- ]
- ]
- },
- {
- "id": "ce47cc5f7bbcaeed",
- "type": "function",
- "z": "303c9862.ddfff8",
- "name": "save pv_daily_stats",
- "func": "const af = global.get('actionflows');\n\n// ulozit do db\nlet resMsgStats = await af.invoke('core.db.query', {\n database: 'smarthouse',\n query: `\n SELECT 1\n FROM pv_daily_stats\n\t\tWHERE\n\t\tDATE(NOW() - INTERVAL ${msg.todayOffset} DAY) = DATE(log_date)\n `,\n values: [],\n});\n\nif (resMsgStats.payload.length == 0) {\n resMsgStats = await af.invoke('core.db.query', {\n database: 'smarthouse',\n query: `\n INSERT INTO pv_daily_stats SET log_date = DATE(NOW() - INTERVAL ${msg.todayOffset} DAY)\n `\n });\n}\n\nfor (const [name, value] of Object.entries(msg.dailyStats)) {\n // node.warn(`${name} = ${value}`);\n resMsgStats = await af.invoke('core.db.query', {\n database: 'smarthouse',\n query: `\n UPDATE pv_daily_stats SET ${name} = ? WHERE log_date = DATE(NOW() - INTERVAL ${msg.todayOffset} DAY)\n `,\n values: [value],\n });\n}\n\n// node.warn(`Daily stats saved. todayOffset: ${msg.todayOffset}`);",
- "outputs": 1,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 1488.200050354004,
- "y": 4422.19952917099,
- "wires": [
- []
- ]
- },
- {
- "id": "32d82afdd0473074",
- "type": "inject",
- "z": "303c9862.ddfff8",
- "d": true,
- "name": "",
- "props": [
- {
- "p": "payload"
- },
- {
- "p": "topic",
- "vt": "str"
- }
- ],
- "repeat": "",
- "crontab": "",
- "once": false,
- "onceDelay": 0.1,
- "topic": "",
- "payload": "",
- "payloadType": "date",
- "x": 1343.1999492645264,
- "y": 4361.19970703125,
- "wires": [
- [
- "2a47ca02c3933ec6"
- ]
- ]
- },
- {
- "id": "2a47ca02c3933ec6",
- "type": "function",
- "z": "303c9862.ddfff8",
- "name": "recalc pv_daily_stats",
- "func": "async function sleep(ms) {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nfor (let todayOffset = 365; todayOffset <= 365+4*31; todayOffset++) {\n node.send({\n todayOffset,\n payload: {},\n });\n\n await sleep(1000);\n}",
- "outputs": 1,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 1530.200050354004,
- "y": 4356.1995277404785,
- "wires": [
- [
- "d96eb2fb252d9ecc",
- "478f152e86f5bbaa",
- "df2ff145fbb01179"
- ]
- ]
- },
- {
- "id": "23fce76ac4f7722e",
- "type": "comment",
- "z": "303c9862.ddfff8",
- "name": "Init",
- "info": "",
- "x": 270.1999816894531,
- "y": 264.1999702453613,
- "wires": []
- },
- {
- "id": "2e9be9117e4f9ba9",
- "type": "comment",
- "z": "303c9862.ddfff8",
- "name": "Battery SOC Prediction",
- "info": "",
- "x": 438.19996643066406,
- "y": 198.20000076293945,
- "wires": []
- },
- {
- "id": "abdb064dbd899fb8",
- "type": "inject",
- "z": "303c9862.ddfff8",
- "name": "",
- "props": [
- {
- "p": "payload"
- },
- {
- "p": "topic",
- "vt": "str"
- }
- ],
- "repeat": "",
- "crontab": "",
- "once": true,
- "onceDelay": 0.1,
- "topic": "",
- "payload": "",
- "payloadType": "date",
- "x": 661.0001449584961,
- "y": 206.00000381469727,
- "wires": [
- [
- "1bacfdafa261f61d"
- ]
- ]
- },
- {
- "id": "1bacfdafa261f61d",
- "type": "function",
- "z": "303c9862.ddfff8",
- "name": "Battery SOC Prediction JS Module",
- "func": "flow.set('battery_soc_prediction_module_path', '/home/gibo/dev/misc/pv/battery_soc_prediction/engine');\nreturn msg;",
- "outputs": 1,
- "noerr": 0,
- "initialize": "",
- "finalize": "",
- "libs": [],
- "x": 923.0001182556152,
- "y": 213.00000381469727,
- "wires": [
- []
- ]
- },
- {
- "id": "76a2023f.8c254c",
- "type": "MySQLdatabase",
- "name": "",
- "host": "mysql.smarthouse.vp.ip.kyrian.cz",
- "port": "3306",
- "db": "smarthouse",
- "tz": "",
- "charset": ""
- },
- {
- "id": "312b72db.d7629e",
- "type": "ui_group",
- "name": "Power",
- "tab": "7de7f9b4.9294a8",
- "order": 5,
- "disp": true,
- "width": "6",
- "collapse": false
- },
- {
- "id": "b55f633.0a700a",
- "type": "ui_group",
- "name": "Battery",
- "tab": "7de7f9b4.9294a8",
- "order": 6,
- "disp": true,
- "width": "6",
- "collapse": false
- },
- {
- "id": "d9bbfe4e.3d039",
- "type": "ui_group",
- "name": "Forecast",
- "tab": "7de7f9b4.9294a8",
- "order": 3,
- "disp": true,
- "width": "6",
- "collapse": false
- },
- {
- "id": "819686be.5e6a58",
- "type": "ui_group",
- "name": "Charts",
- "tab": "7de7f9b4.9294a8",
- "order": 4,
- "disp": true,
- "width": "6",
- "collapse": false
- },
- {
- "id": "d1547785.b0eb48",
- "type": "ui_group",
- "name": "Phases Load",
- "tab": "7de7f9b4.9294a8",
- "order": 7,
- "disp": true,
- "width": "6",
- "collapse": false
- },
- {
- "id": "e7d46503.f3f4b8",
- "type": "ui_group",
- "name": "Power Details",
- "tab": "7de7f9b4.9294a8",
- "order": 10,
- "disp": true,
- "width": "6",
- "collapse": false
- },
- {
- "id": "d1c39829.3ee0e8",
- "type": "ui_group",
- "name": "Battery SOC Prediction",
- "tab": "7de7f9b4.9294a8",
- "order": 9,
- "disp": true,
- "width": "6",
- "collapse": false
- },
- {
- "id": "36ca1673.3376ea",
- "type": "jsonrpc-client",
- "name": "smarthouse-core",
- "host": "vs-smarthouse",
- "port": "2004",
- "connection": "http"
- },
- {
- "id": "802549dc0ec48149",
- "type": "ui_group",
- "name": "Energy",
- "tab": "7de7f9b4.9294a8",
- "order": 8,
- "disp": true,
- "width": "6",
- "collapse": false
- },
- {
- "id": "9a78c351d1914ac8",
- "type": "ui_group",
- "name": "Status",
- "tab": "7de7f9b4.9294a8",
- "order": 1,
- "disp": true,
- "width": "6",
- "collapse": false
- },
- {
- "id": "cf60b551c034e51c",
- "type": "ui_group",
- "name": "Backup / On-Grid Mode",
- "tab": "7de7f9b4.9294a8",
- "order": 2,
- "disp": true,
- "width": "6",
- "collapse": false,
- "className": ""
- },
- {
- "id": "347876e0a6d5c1b0",
- "type": "position-config",
- "name": "",
- "isValide": "true",
- "angleType": "deg",
- "timeZoneOffset": 99,
- "timeZoneDST": 0,
- "stateTimeFormat": "3",
- "stateDateFormat": "12",
- "contextStore": ""
- },
- {
- "id": "45ecb2bfdd21bc90",
- "type": "ui_group",
- "name": "Sun",
- "tab": "7de7f9b4.9294a8",
- "order": 11,
- "disp": true,
- "width": "6",
- "collapse": false,
- "className": ""
- },
- {
- "id": "7de7f9b4.9294a8",
- "type": "ui_tab",
- "name": "FVE",
- "icon": "dashboard",
- "order": 17,
- "disabled": false,
- "hidden": false
- }
- ]
Advertisement
Add Comment
Please, Sign In to add comment