[ { "id": "b487e656e7a73c72", "type": "tab", "label": "VRM API", "disabled": false, "info": "", "env": [] }, { "id": "4aede9ec59461e66", "type": "tab", "label": "Victron Force Discharge ", "disabled": false, "info": "", "env": [] }, { "id": "57d9411237352b64", "type": "tab", "label": "Flow 1", "disabled": false, "info": "", "env": [] }, { "id": "92f743ea8d8588a4", "type": "subflow", "name": "Forecast Solar", "info": "This subflow uses the http request node to fetch solar forecasts for geographical positions, using the API from https://forecast.solar/. Please check their website and consider getting a paid account.\n\nDo note that, on a free account, you are limited in the number of requests to do. Also note that the data only gets updated once every 15 minutes, so there is no reason to query more often. There is rate limiting built in the subflow not to perform requests more than once every 15 minutes.\n\n# Configuration\n\nIt uses the parameters as described on: http://doc.forecast.solar/doku.php\n\n - `:apikey` - personal API key for registered users\n - `:lat` - latitude of location, -90 (south) … 90 (north); Internal precission is 0.0001 or abt. 10 m\n - `:lon` - longitude of location, -180 (west) … 180 (east); Internal precission is 0.0001 or abt. 10 m\n - `:dec` - plane declination, 0 (horizontal) … 90 (vertical); Internal precission is integer\n - `:az` - plane azimuth, -180 … 180 (-180 = north, -90 = east, 0 = south, 90 = west, 180 = north); Internal precission is integer\n - `:kwp` - installed modules power in kilo watt peak (kWp)\n\nYou can choose between 3 different type of requests. Note that only `estimate` is available on the free plan.\n\n- `estimate` - this is the forecasted estimate that your panels should produce (given the right parameter settings)\n- `history` - historical data showing the long term averages for the days to come. See [https://joint-research-centre.ec.europa.eu/pvgis-online-tool/pvgis-data-download/cm-saf-solar-radiation_en](https://joint-research-centre.ec.europa.eu/pvgis-online-tool/pvgis-data-download/cm-saf-solar-radiation_en) for where the data is fetched from.\n- `clear sky` - estimate given if there would be a clear sky tomorrow\n\nIn case of estimates, one of the following options can be selected:\n- `watts` - Watts (power) average for the period\n- `watt_hours_period` - Watt hours (energy) for the period\n- `watt_hours` - Watt hours (energy) summarized over the day\n- `watt_hours_day` - Watt hours (energy) summarized for each day\n\nFor the graph output there are some extra settings available:\n\n- _Output in kWh_ - when checked output can be set to kWh instead of Wh\n- _Show todays forecast_ - whether or not to include todays forecast\n- _Days to forecast_ - the number of days to forecast (excluding today). Note that you can not get more days forecasted than your API key allows.\n- _Widen graph_ - widen the graph to only show non-zero values\n\n# Input \n\nThe input is for triggering the solar forecast request. \nIt triggers when injecting a message into the node.\n\n# Output\n\nThere are two outputs. The first output is an object with the result and a status message stored into the `msg.payload`.\n\nMost important is the `msg.payload.result`, which contains the estimated production of the panels. E.g.:\n\n```\npayload: object\n result: object\n 2022-11-28: 23\n 2022-11-29: 35\n```\n\nThe `msg.payload.message` gives information on how successful the query was, the exitcode of the query and the status of the rate limit (how many queries you have left).\n\nThe **second** output can be directly linked to a line or a bar chart, quickly giving a once-glance overview for the predicted forecast.\n\n# Status\n\nInitially the status of the note will be a blue dot, showing \"_Unknown limit_\", as it is unaware of the set ratelmits. After the first request, the returned ratelimit will be put in the text in the form of `remaining/limit`. If more than half the limit is remaining, the dot will be green. If less then half the limit is remaining, the dot will be yellow. If no limit is left, the dot will turn red.\nPlease keep in mind that the ratelimit will be reset after one hour, so you can send a new request after that hour.\n\nIf something is wrong in the API request, the dot will turn red\nand the message will contain the msg.payload with the error. This\nhappens typically when the API is temporally down for maintenance.", "category": "", "in": [ { "x": 260, "y": 100, "wires": [ { "id": "311a5913bb9137dd" } ] } ], "out": [ { "x": 770, "y": 260, "wires": [ { "id": "cf98a2c0f2aa9b68", "port": 0 }, { "id": "82beba3b3ed086d0", "port": 0 } ] } ], "env": [ { "name": "latitude", "type": "num", "value": "51.3", "ui": { "icon": "font-awesome/fa-location-arrow", "type": "input", "opts": { "types": [ "num" ] } } }, { "name": "longitude", "type": "num", "value": "5.6", "ui": { "icon": "font-awesome/fa-location-arrow", "type": "input", "opts": { "types": [ "num" ] } } }, { "name": "declination", "type": "num", "value": "37", "ui": { "icon": "font-awesome/fa-chevron-up", "type": "input", "opts": { "types": [ "num" ] } } }, { "name": "azimuth", "type": "num", "value": "0", "ui": { "icon": "font-awesome/fa-compass", "type": "spinner", "opts": { "min": -180, "max": 180 } } }, { "name": "modules power", "type": "num", "value": "1", "ui": { "icon": "font-awesome/fa-power-off", "type": "input", "opts": { "types": [ "num" ] } } }, { "name": "apikey", "type": "cred", "ui": { "icon": "font-awesome/fa-key", "type": "input", "opts": { "types": [ "cred" ] } } }, { "name": "type", "type": "str", "value": "estimate", "ui": { "label": { "en-US": "type" }, "type": "select", "opts": { "opts": [ { "l": { "en-US": "Estimate" }, "v": "estimate" }, { "l": { "en-US": "History" }, "v": "history" }, { "l": { "en-US": "Clear sky" }, "v": "clearsky" } ] } } }, { "name": "watt", "type": "str", "value": "watts", "ui": { "icon": "font-awesome/fa-question-circle-o", "type": "select", "opts": { "opts": [ { "l": { "en-US": "Watts (power) average for the period" }, "v": "watts" }, { "l": { "en-US": "Watt hours (energy) for the period" }, "v": "watt_hours_period" }, { "l": { "en-US": "Watt hours (energy) summarized over the day" }, "v": "watt_hours" }, { "l": { "en-US": "Watt hours (energy) summarized for each day" }, "v": "watt_hours_day" } ] } } }, { "name": "kwhoutput", "type": "bool", "value": "true", "ui": { "label": { "en-US": "Output in kWh (in the graph)" }, "type": "checkbox" } }, { "name": "showtoday", "type": "bool", "value": "false", "ui": { "label": { "en-US": "Show todays forecast" }, "type": "checkbox" } }, { "name": "daystoforecast", "type": "str", "value": "-1", "ui": { "label": { "en-US": "Days to forecast" }, "type": "select", "opts": { "opts": [ { "l": { "en-US": "Max" }, "v": "-1" }, { "l": { "en-US": "0" }, "v": "0" }, { "l": { "en-US": "1" }, "v": "1" }, { "l": { "en-US": "2" }, "v": "2" }, { "l": { "en-US": "3" }, "v": "3" }, { "l": { "en-US": "4" }, "v": "4" }, { "l": { "en-US": "5" }, "v": "5" }, { "l": { "en-US": "6" }, "v": "6" } ] } } }, { "name": "widengraph", "type": "bool", "value": "true", "ui": { "label": { "en-US": "Widen graph" }, "type": "checkbox" } } ], "meta": { "module": "Solar Forecast", "version": "0.0.9", "author": "dfaber@victronenergy.com", "desc": "Get solar forecasting per location", "keywords": "solar,forecast,api", "license": "GPL-3.0" }, "color": "#FFCC66", "inputLabels": [ "trigger" ], "outputLabels": [ "output" ], "icon": "font-awesome/fa-sun-o", "status": { "x": 740, "y": 520, "wires": [ { "id": "97d5d27c71bcac18", "port": 0 }, { "id": "01769e7ff28b30bb", "port": 0 } ] } }, { "id": "671ca7014a331f3d", "type": "subflow", "name": "Solcast API", "info": "", "category": "", "in": [ { "x": 100, "y": 220, "wires": [ { "id": "a82e28fd38b6e4c6" } ] } ], "out": [ { "x": 1040, "y": 220, "wires": [ { "id": "8b4be0e8d54525bb", "port": 0 } ] }, { "x": 1040, "y": 440, "wires": [ { "id": "0bb1602bc0e85e74", "port": 0 } ] } ], "env": [], "meta": {}, "color": "#F3B567", "icon": "node-red/cog.svg" }, { "id": "d70dfb5177478915", "type": "group", "z": "4aede9ec59461e66", "name": "Dashboard", "style": { "label": true }, "nodes": [ "1633bb19a9ddd729", "1c5c5da971b5e512", "c0519c134b096a6a", "c1df7a1b18181138", "c7c8322cefc4a7f2", "11de7f2b239686be", "ae94d037e45ed09b", "07a1a9088b1dfd5a", "2e0f46abf287daa1" ], "x": 14, "y": 19, "w": 1052, "h": 142 }, { "id": "11c0695b7819894f", "type": "group", "z": "4aede9ec59461e66", "name": "Store battery capacity", "style": { "label": true }, "nodes": [ "e9a9bebc9c4732d0", "b48a8f507e14330a", "b68ffdbbf4152cf3", "8d723ea6a3f644bc" ], "x": 114, "y": 1839, "w": 1092, "h": 82 }, { "id": "39e068921febf967", "type": "group", "z": "57d9411237352b64", "name": "PV Forecasting", "style": { "stroke": "#000000", "label": true, "fill": "#e3f3d3", "color": "#000000" }, "nodes": [ "1c0269248b30d14c", "622417c86656a55a", "a0639ff12d6cc588", "68fab40506af3cc1", "a645d5888e08d5a5", "034ffd0a4563878a", "e4f221e6fe2b838d", "d3a0054f46f35e67", "6d8285772aea9b8e", "cdb6839d04f6eeed", "f62a70f909344197" ], "x": 34, "y": 599 }, { "id": "454f7fa49c474ab0", "type": "group", "z": "b487e656e7a73c72", "name": "Dashboard", "style": { "fill": "#e3f3d3", "label": true, "stroke": "#000000", "color": "#000000" }, "nodes": [ "b12a29d37dcb9823", "bcf0ef37dbcace29", "f7fbc445f2a3b97a", "0538dae11f8d94dc", "9533da7a28706c10", "625aa6af09d5d508", "6a8df52e3fa889d6", "cc808f1a5e7b5ba8", "9ca4b1ff316c16e8", "ea6673a5ca27409c", "b6e7343e07e4b5b7", "c8863be5f66fcf43", "ddd0674644eefabe", "6c3738f109bc43b4", "1fb63f47d8e19d29", "1b0e82fd3f491877", "02bf8f19109ba869", "6ceb28f176111651", "31017ed0963a7a33", "012a840d5df4c706", "cb3ca506ca71a6d3", "eda69ab7c0ade129", "34474ccad4271429", "e9b3b9c4c32b6905", "2a39dd455c8874a1", "afd85275d425e413", "6b227c0d5b75267f", "c05a89834ef25dd5", "18331e9d57b59d23", "96bf10f8470faf10", "1993a6b5a7c879c2", "2d2d498eaca5e516", "44dbc068be2d210e", "86e39d66a68a5b8d", "288573ae480982b1", "10377da50a6c2ecc", "6599b4ccbe0caa01", "d7e703090b6b41a5", "f37c11c76b719632", "72e8c98817dd1ce1", "47a75f78cf9aa491", "c137024f68a4da6e" ], "x": 14, "y": 19, "w": 1432, "h": 782 }, { "id": "962183d94e9de23f", "type": "group", "z": "b487e656e7a73c72", "style": { "stroke": "#999999", "stroke-opacity": "1", "fill": "none", "fill-opacity": "1", "label": true, "label-position": "nw", "color": "#a4a4a4" }, "nodes": [ "88264821ad6e4168", "97a7294932188d5a", "0876362380c2567a", "7619e4de107c6191", "cb0ed53e03157c8d", "56acb48fc4816208", "cb7803ac9c74a7da", "7419e489a9a180b1", "831eba8ead987193", "30725da530d0fda2", "6eb3409f7e11d8f7", "b401a2ec46369c51", "539441bb6033dc3f", "cd496b55a73ce86e", "53103870fd4c2fc8" ], "x": 54, "y": 1599, "w": 1292, "h": 342 }, { "id": "a7193393a3cf36da", "type": "ui_tab", "name": "Victron", "icon": "dashboard", "disabled": false, "hidden": false }, { "id": "5330c2827c3734fa", "type": "ui_base", "theme": { "name": "theme-custom", "lightTheme": { "default": "#0094CE", "baseColor": "#0094CE", "baseFont": "-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif", "edited": true, "reset": false }, "darkTheme": { "default": "#097479", "baseColor": "#097479", "baseFont": "-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif", "edited": false }, "customTheme": { "name": "Untitled Theme 1", "default": "#4B7930", "baseColor": "#4B7930", "baseFont": "-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif", "reset": false }, "themeState": { "base-color": { "default": "#4B7930", "value": "#4B7930", "edited": false }, "page-titlebar-backgroundColor": { "value": "#4B7930", "edited": false }, "page-backgroundColor": { "value": "#111111", "edited": false }, "page-sidebar-backgroundColor": { "value": "#333333", "edited": false }, "group-textColor": { "value": "#6db046", "edited": false }, "group-borderColor": { "value": "#24c65a", "edited": true }, "group-backgroundColor": { "value": "#333333", "edited": false }, "widget-textColor": { "value": "#eeeeee", "edited": false }, "widget-backgroundColor": { "value": "#4b7930", "edited": false }, "widget-borderColor": { "value": "#333333", "edited": false }, "base-font": { "value": "-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif" } }, "angularTheme": { "primary": "indigo", "accents": "blue", "warn": "red", "background": "grey", "palette": "light" } }, "site": { "name": "Node-RED Dashboard", "hideToolbar": "false", "allowSwipe": "false", "lockMenu": "false", "allowTempTheme": "true", "dateFormat": "DD/MM/YYYY", "sizes": { "sx": 48, "sy": 48, "gx": 6, "gy": 6, "cx": 6, "cy": 6, "px": 0, "py": 0 } } }, { "id": "4c71a0775513569d", "type": "ui_group", "name": "Multiplus II - GX", "tab": "a7193393a3cf36da", "order": 1, "disp": true, "width": "6", "collapse": false, "className": "" }, { "id": "victron-client-id", "type": "victron-client" }, { "id": "162676fcf8b309cf", "type": "ui_group", "name": "Manual Control", "tab": "4b4a645c282da09b", "order": 1, "disp": true, "width": "6", "collapse": false, "className": "" }, { "id": "28736f50ce51e6e2", "type": "ui_group", "name": "On a schedule", "tab": "64ce07714bed8ca0", "order": 1, "disp": true, "width": 7, "collapse": false, "className": "" }, { "id": "5ede56129287c339", "type": "mqtt-broker", "name": "HA MQTT", "broker": "localhost", "port": "1883", "clientid": "", "autoConnect": true, "usetls": false, "protocolVersion": "4", "keepalive": "60", "cleansession": true, "birthTopic": "", "birthQos": "0", "birthPayload": "", "birthMsg": {}, "closeTopic": "", "closeQos": "0", "closePayload": "", "closeMsg": {}, "willTopic": "", "willQos": "0", "willPayload": "", "willMsg": {}, "userProps": "", "sessionExpiry": "" }, { "id": "090ee97a3f04aab9", "type": "ui_group", "name": "Gauges", "tab": "64ce07714bed8ca0", "order": 2, "disp": true, "width": 7, "collapse": false, "className": "" }, { "id": "40ac04dcdbac9081", "type": "ui_group", "name": "Gauges - Battery", "tab": "64ce07714bed8ca0", "order": 3, "disp": true, "width": 7, "collapse": false, "className": "" }, { "id": "f2a1e3f054cae718", "type": "ui_group", "name": "Graph", "tab": "64ce07714bed8ca0", "order": 5, "disp": true, "width": "21", "collapse": false, "className": "" }, { "id": "4b4a645c282da09b", "type": "ui_tab", "d": true, "name": "Manual Control", "icon": "fa-bolt", "order": 4, "disabled": false, "hidden": false }, { "id": "64ce07714bed8ca0", "type": "ui_tab", "d": true, "name": "Scheduled Discharge", "icon": "fa-clock-o", "order": 1, "disabled": false, "hidden": false }, { "id": "d92c8c036277db16", "type": "ui_group", "name": "Battery", "tab": "a7193393a3cf36da", "order": 2, "disp": true, "width": "6", "collapse": false, "className": "" }, { "id": "5fcd0bce74e72cb7", "type": "config-vrm-api", "name": "VRM", "token": "XXXXXX" }, { "id": "87c32be49619e588", "type": "config-vrm-api", "name": "VRM", "token": "c0619ab2a0f0" }, { "id": "9b0bae12a2d227fe", "type": "ui_group", "name": "Smart Charging.", "tab": "a7193393a3cf36da", "order": 3, "disp": true, "width": "7", "collapse": false, "className": "" }, { "id": "eaf8c4fa5129659c", "type": "ui_tab", "name": "Home", "icon": "dashboard", "disabled": false, "hidden": false }, { "id": "a2610400bb587574", "type": "ui_tab", "name": "Summary", "icon": "dashboard", "order": 1, "disabled": false, "hidden": false }, { "id": "73cab65a46420bcf", "type": "ui_tab", "name": "Home", "icon": "dashboard", "disabled": false, "hidden": false }, { "id": "a113d73127054160", "type": "ui_tab", "name": "Summary", "icon": "dashboard", "order": 1, "disabled": false, "hidden": false }, { "id": "8f7cf18b3d82937c", "type": "ui_tab", "name": "Home", "icon": "dashboard", "disabled": false, "hidden": false }, { "id": "386169c7abaac84b", "type": "ui_tab", "name": "Summary", "icon": "dashboard", "order": 1, "disabled": false, "hidden": false }, { "id": "3f45129e911695f7", "type": "ui_tab", "name": "Home", "icon": "dashboard", "disabled": false, "hidden": false }, { "id": "bfbbcb5d1d531b95", "type": "ui_tab", "name": "Summary", "icon": "dashboard", "order": 1, "disabled": false, "hidden": false }, { "id": "d75ca3c9f6dc4a63", "type": "position-config", "name": "GJW Sun Position", "isValide": "true", "angleType": "deg", "timeZoneOffset": 99, "timeZoneDST": 0, "stateTimeFormat": "3", "stateDateFormat": "12", "contextStore": "" }, { "id": "bdf7c4a.9ca6c38", "type": "position-config", "name": "", "longitude": "13.71587", "latitude": "51.01732", "angleType": "deg" }, { "id": "028a2db8cabbdb0e", "type": "ui_group", "name": "Smart Charging Stats.", "tab": "a7193393a3cf36da", "order": 4, "disp": true, "width": "7", "collapse": false, "className": "" }, { "id": "6bbde287553c0324", "type": "mqtt-broker", "name": "", "broker": "192.168.1.221", "port": "1883", "clientid": "", "autoConnect": true, "usetls": false, "protocolVersion": "4", "keepalive": "60", "cleansession": true, "birthTopic": "", "birthQos": "0", "birthPayload": "", "birthMsg": {}, "closeTopic": "", "closeQos": "0", "closePayload": "", "closeMsg": {}, "willTopic": "", "willQos": "0", "willPayload": "", "willMsg": {}, "userProps": "", "sessionExpiry": "" }, { "id": "b644206e3a5cde22", "type": "ui_group", "name": "Smart Meter readings:", "tab": "a7193393a3cf36da", "order": 5, "disp": true, "width": "6", "collapse": false, "className": "" }, { "id": "d8696860006cf5b9", "type": "http request", "z": "92f743ea8d8588a4", "name": "Forecast Solar", "method": "GET", "ret": "txt", "paytoqs": "ignore", "url": "", "tls": "", "persist": false, "proxy": "", "insecureHTTPParser": false, "authType": "", "senderr": false, "headers": [], "x": 400, "y": 180, "wires": [ [ "9b8fe902f595487e" ] ] }, { "id": "311a5913bb9137dd", "type": "function", "z": "92f743ea8d8588a4", "name": "create forecast.solar url", "func": "msg.url = 'https://api.forecast.solar/';\n\nif (env.get('apikey')) {\n msg.url += env.get('apikey') + '/';\n }\n\nmsg.url += env.get('type') + '/';\n\nmsg.url += env.get('watt') + '/';\n\nmsg.url += env.get('latitude') + '/' +\n env.get('longitude') + '/' +\n env.get('declination') + '/' +\n env.get('azimuth') + '/' +\n env.get('modules power');\n\nmsg.topic = 'solar forecast: '+(env.get('type') || '');\nmsg.topic += (' '+env.get('watt') || '');\nif (env.get('kwhoutput')) {\n msg.topic += ' (kWh)';\n}\nreturn msg;", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 630, "y": 100, "wires": [ [ "146b0c960400c71b" ] ] }, { "id": "9b8fe902f595487e", "type": "json", "z": "92f743ea8d8588a4", "name": "Convert to json", "property": "payload", "action": "", "pretty": false, "x": 660, "y": 180, "wires": [ [ "0b3ece368887a94f" ] ] }, { "id": "c8cb0f89a96084b1", "type": "function", "z": "92f743ea8d8588a4", "name": "update ratelimit", "func": "var remaining = msg.payload.message.ratelimit.remaining || 0;\nvar limit = msg.payload.message.ratelimit.limit;\n\nflow.set('forecast.solar.ratelimit.remaining', remaining)\nflow.set('forecast.solar.ratelimit.limit', limit)\n\nreturn msg;", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 580, "y": 440, "wires": [ [ "ec3d0ccfe4d4cc9b" ] ] }, { "id": "0b3ece368887a94f", "type": "link out", "z": "92f743ea8d8588a4", "name": "link out 1", "mode": "link", "links": [ "12245237bc264f8d", "588a38db7cd46f1c" ], "x": 815, "y": 180, "wires": [] }, { "id": "12245237bc264f8d", "type": "link in", "z": "92f743ea8d8588a4", "name": "link in 1", "links": [ "0b3ece368887a94f" ], "x": 445, "y": 440, "wires": [ [ "c8cb0f89a96084b1" ] ] }, { "id": "588a38db7cd46f1c", "type": "link in", "z": "92f743ea8d8588a4", "name": "link in 2", "links": [ "0b3ece368887a94f" ], "x": 265, "y": 260, "wires": [ [ "82beba3b3ed086d0" ] ] }, { "id": "5f4938f9d64cc334", "type": "inject", "z": "92f743ea8d8588a4", "name": "", "props": [ { "p": "payload" }, { "p": "topic", "vt": "str" } ], "repeat": "", "crontab": "", "once": true, "onceDelay": 0.1, "topic": "", "payload": "", "payloadType": "date", "x": 590, "y": 400, "wires": [ [ "ec3d0ccfe4d4cc9b" ] ] }, { "id": "97d5d27c71bcac18", "type": "function", "z": "92f743ea8d8588a4", "name": "update status", "func": "var remaining = flow.get('forecast.solar.ratelimit.remaining') || -1;\nvar limit = flow.get('forecast.solar.ratelimit.limit') || -1\n\nvar text = remaining.toString() + '/' + limit.toString();\nvar fill = \"green\";\n\nif (remaining == 0) {\n fill = \"red\";\n text = \"Limit used\";\n}\n\nif (remaining > 0 && remaining < limit / 2) {\n fill = \"yellow\"\n}\n\nif (remaining == -1 ) {\n fill = \"blue\"\n text = \"Limits unknown\"\n}\n\nmsg.payload = ({ fill: fill, text: text });\n\nreturn msg;", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 580, "y": 540, "wires": [ [] ] }, { "id": "146b0c960400c71b", "type": "link out", "z": "92f743ea8d8588a4", "name": "link out 7", "mode": "link", "links": [ "36909573691c12a9" ], "x": 815, "y": 100, "wires": [] }, { "id": "36909573691c12a9", "type": "link in", "z": "92f743ea8d8588a4", "name": "link in 18", "links": [ "146b0c960400c71b" ], "x": 265, "y": 180, "wires": [ [ "d8696860006cf5b9" ] ] }, { "id": "dc97c298bff51b4e", "type": "catch", "z": "92f743ea8d8588a4", "name": "", "scope": null, "uncaught": false, "x": 320, "y": 400, "wires": [ [ "d7667dfe2df7f6ed" ] ] }, { "id": "ec3d0ccfe4d4cc9b", "type": "link out", "z": "92f743ea8d8588a4", "name": "link out 8", "mode": "link", "links": [ "9c927642c4b44a6f" ], "x": 745, "y": 440, "wires": [] }, { "id": "9c927642c4b44a6f", "type": "link in", "z": "92f743ea8d8588a4", "name": "link in 19", "links": [ "ec3d0ccfe4d4cc9b" ], "x": 445, "y": 540, "wires": [ [ "97d5d27c71bcac18" ] ] }, { "id": "d7667dfe2df7f6ed", "type": "link out", "z": "92f743ea8d8588a4", "name": "link out 9", "mode": "link", "links": [ "7675adbf030a4c7e", "cf98a2c0f2aa9b68" ], "x": 445, "y": 400, "wires": [] }, { "id": "7675adbf030a4c7e", "type": "link in", "z": "92f743ea8d8588a4", "name": "link in 20", "links": [ "d7667dfe2df7f6ed" ], "x": 445, "y": 500, "wires": [ [ "01769e7ff28b30bb" ] ] }, { "id": "01769e7ff28b30bb", "type": "function", "z": "92f743ea8d8588a4", "name": "Set error status", "func": "node.warn(msg.payload)\nmsg.payload = ({ fill: \"red\", text: msg.payload });\n\nreturn msg;", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 580, "y": 500, "wires": [ [] ] }, { "id": "cf98a2c0f2aa9b68", "type": "link in", "z": "92f743ea8d8588a4", "name": "link in 21", "links": [ "d7667dfe2df7f6ed" ], "x": 605, "y": 320, "wires": [ [] ] }, { "id": "82beba3b3ed086d0", "type": "function", "z": "92f743ea8d8588a4", "name": "Processed info", "func": "msg.resolution = 60;\nmsg.days = 1;\nmsg.type = env.get('type');\nmsg.watt = env.get('watt');\nmsg.kwhoutput = env.get('kwhoutput');\n\nvar key1 = Object.keys(msg.payload.result)[1];\nvar key2 = Object.keys(msg.payload.result)[2];\nvar key3 = Object.keys(msg.payload.result)[Object.keys(msg.payload.result).length-1];\n\nvar d1 = new Date(key1);\nvar d2 = new Date(key2); \nvar d3 = new Date(key3);\n\nmsg.resolution = 3600000 / (d2.getTime() - d1.getTime());\n\nmsg.days = Math.floor((d3.getTime() - d1.getTime()) / (1000 * 3600 * 24));\n\nif (msg.watt === 'watt_hours_day') {\n msg.resolution = null;\n}\n\nreturn msg;", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 400, "y": 260, "wires": [ [] ], "info": "Function to process the result from forecast.solar to add\nextra information, which is handy for either graphing or\nto store in a database.\n\n\nThe extra values added:\n- `msg.resolution` - The number of measurements per hour. If\nno API key is used, this will be 1. Other values may be 2 or 4.\n- `msg.days` - The number of days in the forcast. If no API\n- key is used this will be 1. Other values may be 3 or 6." }, { "id": "a82e28fd38b6e4c6", "type": "http request", "z": "671ca7014a331f3d", "name": "Solcast ", "method": "GET", "ret": "obj", "paytoqs": "ignore", "url": "https://api.solcast.com.au/rooftop_sites/3404-1032-c059-2b50/forecasts?format=json", "tls": "", "persist": false, "proxy": "", "insecureHTTPParser": false, "authType": "basic", "senderr": false, "headers": [], "x": 240, "y": 220, "wires": [ [ "c37ba46200d80bb2", "77ea5382b7eb830e" ] ] }, { "id": "c37ba46200d80bb2", "type": "function", "z": "671ca7014a331f3d", "name": "Extract All", "func": "// add up all the values:\nfor (var i in msg.payload.forecasts) {\n msg.payload.forecasts[i] = Number(msg.payload.forecasts[i].pv_estimate);\n }\n msg.payload.pvtotal = msg.payload.forecasts.reduce(function(a, b){\n return a + b;\n }, 0);\n// halve the value due to a reading every 30 minutes:\nmsg.payload.pvtotal = msg.payload.pvtotal/2;\nreturn msg;", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 480, "y": 120, "wires": [ [ "c007053cc6666ae4", "739842bc0c762cba", "442a40a96c925093" ] ] }, { "id": "c007053cc6666ae4", "type": "change", "z": "671ca7014a331f3d", "name": "PVForecast to global", "rules": [ { "t": "set", "p": "pvforecast", "pt": "global", "to": "payload.pvtotal", "tot": "msg" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 820, "y": 120, "wires": [ [] ] }, { "id": "739842bc0c762cba", "type": "change", "z": "671ca7014a331f3d", "name": "Write forecasts array to global", "rules": [ { "t": "set", "p": "individualforecast", "pt": "global", "to": "payload.forecasts", "tot": "msg" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 850, "y": 80, "wires": [ [] ] }, { "id": "3d48298713f14499", "type": "function", "z": "671ca7014a331f3d", "name": "Extract Daily Total", "func": "// add up all the values:\nvar pvtotal = 0\nvar x = -1\nvar zeroday = 0\nvar forecasts = []\nvar dailypv = []\nfor (var i in msg.payload) {\n if (msg.payload[i]==0) {\n zeroday = 0;\n } else if (zeroday==1) {\n dailypv[x] = dailypv[x] + msg.payload[i]/2;\n }else{\n zeroday = 1\n x = x + 1\n dailypv[x] = 0\n dailypv[x] = dailypv[x] + msg.payload[i]/2;\n}}\nmsg.payload = dailypv;\nreturn msg;", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 510, "y": 220, "wires": [ [ "8b4be0e8d54525bb" ] ] }, { "id": "8b4be0e8d54525bb", "type": "change", "z": "671ca7014a331f3d", "name": "Set Daily Total to Global", "rules": [ { "t": "set", "p": "DailyTotal", "pt": "global", "to": "payload", "tot": "msg" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 830, "y": 220, "wires": [ [] ] }, { "id": "fb663192b353b0e3", "type": "function", "z": "671ca7014a331f3d", "name": "Extract DailyP10 Total", "func": "// add up all the values:\nvar pvtotal = 0\nvar x = -1\nvar zeroday = 0\nvar forecasts = []\nvar dailypv = []\nfor (var i in msg.payload) {\n if (msg.payload[i]==0) {\n zeroday = 0;\n } else if (zeroday==1) {\n dailypv[x] = dailypv[x] + msg.payload[i]/2;\n }else{\n zeroday = 1\n x = x + 1\n dailypv[x] = 0\n dailypv[x] = dailypv[x] + msg.payload[i]/2;\n}}\nmsg.payload = dailypv;\nreturn msg;", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 520, "y": 440, "wires": [ [ "0bb1602bc0e85e74" ] ] }, { "id": "0bb1602bc0e85e74", "type": "change", "z": "671ca7014a331f3d", "name": "Set Daily Total to Global", "rules": [ { "t": "set", "p": "DailyTotalP10", "pt": "global", "to": "payload", "tot": "msg" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 830, "y": 440, "wires": [ [] ] }, { "id": "d4f080c20839ea2e", "type": "change", "z": "671ca7014a331f3d", "name": "PVForecast to global", "rules": [ { "t": "set", "p": "pvforecastP10", "pt": "global", "to": "payload.pvtotal", "tot": "msg" }, { "t": "set", "p": "payload", "pt": "msg", "to": "", "tot": "str" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 820, "y": 340, "wires": [ [] ] }, { "id": "7902deb955182a5b", "type": "change", "z": "671ca7014a331f3d", "name": "Write forecasts array to global", "rules": [ { "t": "set", "p": "individualforecastP10", "pt": "global", "to": "payload.forecasts", "tot": "msg" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 850, "y": 300, "wires": [ [] ] }, { "id": "77ea5382b7eb830e", "type": "function", "z": "671ca7014a331f3d", "name": "Extract All P10", "func": "// add up all the values:\nfor (var i in msg.payload.forecasts) {\n msg.payload.forecasts[i] = Number(msg.payload.forecasts[i].pv_estimate10);\n }\n msg.payload.pvtotal = msg.payload.forecasts.reduce(function(a, b){\n return a + b;\n }, 0);\n// halve the value due to a reading every 30 minutes:\nmsg.payload.pvtotal = msg.payload.pvtotal/2;\nreturn msg;", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 500, "y": 340, "wires": [ [ "d4f080c20839ea2e", "7902deb955182a5b", "c2dba2aa43ea364a" ] ] }, { "id": "442a40a96c925093", "type": "change", "z": "671ca7014a331f3d", "name": "Change for total", "rules": [ { "t": "set", "p": "payload", "pt": "msg", "to": "individualforecast", "tot": "global" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 800, "y": 160, "wires": [ [ "3d48298713f14499" ] ] }, { "id": "c2dba2aa43ea364a", "type": "change", "z": "671ca7014a331f3d", "name": "Change for P10 total", "rules": [ { "t": "set", "p": "payload", "pt": "msg", "to": "individualforecastP10", "tot": "global" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 820, "y": 380, "wires": [ [ "fb663192b353b0e3" ] ] }, { "id": "b12a29d37dcb9823", "type": "inject", "z": "b487e656e7a73c72", "g": "454f7fa49c474ab0", "name": "% accuracy of forecast", "props": [ { "p": "payload" } ], "repeat": "", "crontab": "", "once": true, "onceDelay": 0.1, "topic": "", "payload": "80", "payloadType": "num", "x": 160, "y": 60, "wires": [ [ "ddd0674644eefabe" ] ] }, { "id": "bcf0ef37dbcace29", "type": "ui_slider", "z": "b487e656e7a73c72", "g": "454f7fa49c474ab0", "name": "Accuracy", "label": "Accuracy of forecast (%):", "tooltip": "", "group": "9b0bae12a2d227fe", "order": 7, "width": 0, "height": 0, "passthru": true, "outs": "end", "topic": "Accuracy", "topicType": "str", "min": 0, "max": "100", "step": "5", "className": "", "x": 560, "y": 60, "wires": [ [ "31017ed0963a7a33" ] ] }, { "id": "f7fbc445f2a3b97a", "type": "ui_numeric", "z": "b487e656e7a73c72", "g": "454f7fa49c474ab0", "name": "Days", "label": "Days to look back:", "tooltip": "", "group": "9b0bae12a2d227fe", "order": 1, "width": 0, "height": 0, "wrap": false, "passthru": true, "topic": "Days", "topicType": "str", "format": "{{value}}", "min": 0, "max": "31", "step": 1, "className": "", "x": 550, "y": 160, "wires": [ [ "012a840d5df4c706" ] ] }, { "id": "0538dae11f8d94dc", "type": "inject", "z": "b487e656e7a73c72", "g": "454f7fa49c474ab0", "name": "Days to look back", "props": [ { "p": "payload" } ], "repeat": "", "crontab": "", "once": true, "onceDelay": 0.1, "topic": "", "payload": "30", "payloadType": "num", "x": 150, "y": 160, "wires": [ [ "6c3738f109bc43b4" ] ] }, { "id": "9533da7a28706c10", "type": "inject", "z": "b487e656e7a73c72", "g": "454f7fa49c474ab0", "name": "ESS capacity", "props": [ { "p": "payload" } ], "repeat": "", "crontab": "", "once": true, "onceDelay": 0.1, "topic": "", "payload": "14.4", "payloadType": "num", "x": 140, "y": 240, "wires": [ [ "1fb63f47d8e19d29" ] ] }, { "id": "625aa6af09d5d508", "type": "ui_slider", "z": "b487e656e7a73c72", "g": "454f7fa49c474ab0", "name": "", "label": "ESS capacity (KW):", "tooltip": "", "group": "9b0bae12a2d227fe", "order": 6, "width": 0, "height": 0, "passthru": true, "outs": "end", "topic": "ESS capacity", "topicType": "str", "min": 0, "max": "45", "step": ".1", "className": "", "x": 590, "y": 240, "wires": [ [ "cb3ca506ca71a6d3" ] ] }, { "id": "6a8df52e3fa889d6", "type": "inject", "z": "b487e656e7a73c72", "g": "454f7fa49c474ab0", "name": "Lowest SOC for ESS", "props": [ { "p": "payload" } ], "repeat": "", "crontab": "", "once": true, "onceDelay": 0.1, "topic": "", "payload": "15", "payloadType": "num", "x": 160, "y": 340, "wires": [ [ "1b0e82fd3f491877" ] ] }, { "id": "cc808f1a5e7b5ba8", "type": "ui_slider", "z": "b487e656e7a73c72", "g": "454f7fa49c474ab0", "name": "", "label": "Lowest SOC for ESS (%):", "tooltip": "", "group": "9b0bae12a2d227fe", "order": 2, "width": 0, "height": 0, "passthru": true, "outs": "end", "topic": "Lowest SOC", "topicType": "str", "min": "15", "max": "100", "step": 1, "className": "", "x": 610, "y": 340, "wires": [ [ "eda69ab7c0ade129" ] ] }, { "id": "9ca4b1ff316c16e8", "type": "ui_text_input", "z": "b487e656e7a73c72", "g": "454f7fa49c474ab0", "name": "", "label": "Start of cheap electricity:", "tooltip": "", "group": "9b0bae12a2d227fe", "order": 4, "width": 0, "height": 0, "passthru": true, "mode": "time", "delay": "0", "topic": "cheap electricity", "sendOnBlur": true, "className": "", "topicType": "str", "x": 850, "y": 440, "wires": [ [ "34474ccad4271429" ] ] }, { "id": "ea6673a5ca27409c", "type": "inject", "z": "b487e656e7a73c72", "g": "454f7fa49c474ab0", "name": "Start of cheap Electricity", "props": [ { "p": "payload" } ], "repeat": "", "crontab": "", "once": true, "onceDelay": 0.1, "topic": "", "payload": "3600000", "payloadType": "num", "x": 170, "y": 440, "wires": [ [ "02bf8f19109ba869" ] ] }, { "id": "b6e7343e07e4b5b7", "type": "ui_text_input", "z": "b487e656e7a73c72", "g": "454f7fa49c474ab0", "name": "", "label": "Start of premium exporting:", "tooltip": "", "group": "9b0bae12a2d227fe", "order": 5, "width": 0, "height": 0, "passthru": true, "mode": "time", "delay": "0", "topic": "premium exporting", "sendOnBlur": true, "className": "", "topicType": "str", "x": 860, "y": 540, "wires": [ [ "e9b3b9c4c32b6905" ] ] }, { "id": "c8863be5f66fcf43", "type": "inject", "z": "b487e656e7a73c72", "g": "454f7fa49c474ab0", "name": "Start of Premium exporting:", "props": [ { "p": "payload" } ], "repeat": "", "crontab": "", "once": true, "onceDelay": 0.1, "topic": "", "payload": "54000000", "payloadType": "num", "x": 180, "y": 540, "wires": [ [ "6ceb28f176111651" ] ] }, { "id": "ddd0674644eefabe", "type": "file in", "z": "b487e656e7a73c72", "g": "454f7fa49c474ab0", "name": "Load Accuracy", "filename": "/data/home/nodered/Accuracy.txt", "filenameType": "str", "format": "utf8", "chunk": false, "sendError": false, "encoding": "none", "allProps": false, "x": 380, "y": 60, "wires": [ [ "bcf0ef37dbcace29", "2a39dd455c8874a1" ] ] }, { "id": "6c3738f109bc43b4", "type": "file in", "z": "b487e656e7a73c72", "g": "454f7fa49c474ab0", "name": "Load Days", "filename": "/data/home/nodered/Days.txt", "filenameType": "str", "format": "utf8", "chunk": false, "sendError": false, "encoding": "none", "allProps": false, "x": 370, "y": 160, "wires": [ [ "f7fbc445f2a3b97a", "afd85275d425e413" ] ] }, { "id": "1fb63f47d8e19d29", "type": "file in", "z": "b487e656e7a73c72", "g": "454f7fa49c474ab0", "name": "Load ESS Capacity", "filename": "/data/home/nodered/ESSCapacity.txt", "filenameType": "str", "format": "utf8", "chunk": false, "sendError": false, "encoding": "none", "allProps": false, "x": 370, "y": 240, "wires": [ [ "625aa6af09d5d508", "6b227c0d5b75267f" ] ] }, { "id": "1b0e82fd3f491877", "type": "file in", "z": "b487e656e7a73c72", "g": "454f7fa49c474ab0", "name": "Load Lowest SOC", "filename": "/data/home/nodered/LowestSOC.txt", "filenameType": "str", "format": "utf8", "chunk": false, "sendError": false, "encoding": "none", "allProps": false, "x": 390, "y": 340, "wires": [ [ "cc808f1a5e7b5ba8", "c05a89834ef25dd5" ] ] }, { "id": "02bf8f19109ba869", "type": "file in", "z": "b487e656e7a73c72", "g": "454f7fa49c474ab0", "name": "Load Cheap Electricity time", "filename": "/data/home/nodered/Cheaptime.txt", "filenameType": "str", "format": "utf8", "chunk": false, "sendError": false, "encoding": "none", "allProps": false, "x": 440, "y": 440, "wires": [ [ "1993a6b5a7c879c2" ] ] }, { "id": "6ceb28f176111651", "type": "file in", "z": "b487e656e7a73c72", "g": "454f7fa49c474ab0", "name": "Load Premium Export time", "filename": "/data/home/nodered/Premiumexport.txt", "filenameType": "str", "format": "utf8", "chunk": false, "sendError": false, "encoding": "none", "allProps": false, "x": 440, "y": 540, "wires": [ [ "2d2d498eaca5e516" ] ] }, { "id": "31017ed0963a7a33", "type": "file", "z": "b487e656e7a73c72", "g": "454f7fa49c474ab0", "name": "Save Accuracy", "filename": "/data/home/nodered/Accuracy.txt", "filenameType": "str", "appendNewline": false, "createDir": false, "overwriteFile": "true", "encoding": "none", "x": 760, "y": 60, "wires": [ [ "2a39dd455c8874a1" ] ] }, { "id": "012a840d5df4c706", "type": "file", "z": "b487e656e7a73c72", "g": "454f7fa49c474ab0", "name": "Save Days", "filename": "/data/home/nodered/Days.txt", "filenameType": "str", "appendNewline": false, "createDir": false, "overwriteFile": "true", "encoding": "none", "x": 710, "y": 160, "wires": [ [ "afd85275d425e413" ] ] }, { "id": "cb3ca506ca71a6d3", "type": "file", "z": "b487e656e7a73c72", "g": "454f7fa49c474ab0", "name": "Save ESS Capacity", "filename": "/data/home/nodered/ESSCapacity.txt", "filenameType": "str", "appendNewline": false, "createDir": false, "overwriteFile": "true", "encoding": "none", "x": 830, "y": 240, "wires": [ [ "6b227c0d5b75267f" ] ] }, { "id": "eda69ab7c0ade129", "type": "file", "z": "b487e656e7a73c72", "g": "454f7fa49c474ab0", "name": "Save Lowest SOC", "filename": "/data/home/nodered/LowestSOC.txt", "filenameType": "str", "appendNewline": false, "createDir": false, "overwriteFile": "true", "encoding": "none", "x": 890, "y": 340, "wires": [ [ "c05a89834ef25dd5" ] ] }, { "id": "34474ccad4271429", "type": "file", "z": "b487e656e7a73c72", "g": "454f7fa49c474ab0", "name": "Save Cheap Electricty time", "filename": "/data/home/nodered/Cheaptime.txt", "filenameType": "str", "appendNewline": false, "createDir": false, "overwriteFile": "true", "encoding": "none", "x": 1120, "y": 440, "wires": [ [ "18331e9d57b59d23" ] ] }, { "id": "e9b3b9c4c32b6905", "type": "file", "z": "b487e656e7a73c72", "g": "454f7fa49c474ab0", "name": "Save Premium Export time", "filename": "/data/home/nodered/Premiumexport.txt", "filenameType": "str", "appendNewline": false, "createDir": false, "overwriteFile": "true", "encoding": "none", "x": 1120, "y": 540, "wires": [ [ "96bf10f8470faf10" ] ] }, { "id": "2a39dd455c8874a1", "type": "function", "z": "b487e656e7a73c72", "g": "454f7fa49c474ab0", "name": "Set Global Accuracy variable", "func": "var Accuracy = flow.get(\"Accuracy\") || 0;\n\nAccuracy = msg.payload;\nflow.set(\"Accuracy\", Accuracy);\n\n\nreturn msg;", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 720, "y": 100, "wires": [ [] ] }, { "id": "afd85275d425e413", "type": "function", "z": "b487e656e7a73c72", "g": "454f7fa49c474ab0", "name": "Set Global Days variable", "func": "var Days = flow.get(\"Days\") || 0;\n\nDays = msg.payload;\nflow.set(\"Days\", Days);\n\n//node.warn(msg);\n\nreturn msg;", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 670, "y": 200, "wires": [ [] ] }, { "id": "35414432ac1601c3", "type": "function", "z": "b487e656e7a73c72", "name": "Download Historical Daily Hourly stats", "func": "var Days = flow.get(\"Days\") || 0;\nvar SimplePushFlag = flow.get(\"SimplePushFlag\") || false;\nvar SimplePushCount = flow.get(\"SimplePushCount\") || 0;\n\nSimplePushCount = 0;\nflow.set(\"SimplePushCount\", SimplePushCount);\nSimplePushFlag = false;\nflow.set(\"SimplePushFlag\", SimplePushFlag);\n\n\n//node.warn(Days);\n\nmsg.headers = {};\nsitenumber = \"999999\";\n\nvar d = new Date();\n\nvar day=d.getDate();\nvar month=d.getMonth();\nvar year=d.getFullYear();\nday = day-1;\n\nvar previousday = new Date(year,month,day);\nvar numberofdaysback = new Date(year,month,day-Days);\n\n// gets the unix time in second format\nvar unixendtime = previousday.getTime()/1000;\nvar unixstarttime = numberofdaysback.getTime()/1000;\n\nvar starttime = unixstarttime.toString();\nvar endtime = unixendtime.toString();\n\nmsg.headers = {\n \"X-Authorization\" : \"Token XXXXXX\",\n 'Content-Type': 'application/json'\n };\nmsg.httpRequestTimeout = 60000;\nmsg.method = \"GET\";\nmsg.url = \"https://vrmapi.victronenergy.com/v2/installations/\" + sitenumber + \"/stats?start=\" + starttime + \"&end=\" + endtime + \"&type=kwh&interval=hours\";\nmsg.payload = {};\nreturn msg;", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 470, "y": 880, "wires": [ [ "d21a89df1a53f9fe" ] ] }, { "id": "d21a89df1a53f9fe", "type": "http request", "z": "b487e656e7a73c72", "name": "Victron VRM API", "method": "use", "ret": "obj", "paytoqs": "ignore", "url": "", "tls": "", "persist": false, "proxy": "", "insecureHTTPParser": false, "authType": "", "senderr": false, "headers": [], "x": 750, "y": 880, "wires": [ [ "14d81de10b4bf9db" ] ] }, { "id": "14d81de10b4bf9db", "type": "function", "z": "b487e656e7a73c72", "name": "Combine Historical Daily Stats to Hourly only", "func": "\n\n\nvar Days = flow.get(\"Days\") || 0;\nvar Messageheadings = Object.keys(msg.payload.records);\n//node.warn(Days);\n\n//const Headings = [\"Bc\",\"Gc\",\"Gb\",\"Bg\",\"Pc\",\"Pb\",\"Pg\"];\n//var temparray = new Array(parseFloat(0),parseFloat(0));\n//node.warn(temparray);\n//var thirtydayhourly = [];\n\n\nvar Hourlyaveragedoverdays = {};\n\n//for (const xx in Messageheadings)\n//{\n// Hourlyaveragedoverdays[Messageheadings[xx]] = new Array([0]);\n// for (x=0 ;x<24; x++)\n// {\n// Hourlyaveragedoverdays[Messageheadings[xx]].push(0);\n// }\n//}\n\n// set all array values for the individaul hours to 0\nfor (const xx of Messageheadings)\n{\n Hourlyaveragedoverdays[xx] = new Array([]);\n for (x=0 ;x<24; x++)\n {\n Hourlyaveragedoverdays[xx].push(new Array(parseFloat(0),parseFloat(0)));\n }\n}\n\n//node.warn(Hourlyaveragedoverdays);\n\n//Hourlyaveragedoverdays[Messageheadings[0]] = new Array([0]);\n//Hourlyaveragedoverdays[Messageheadings[1]] = new Array([0]);\n\n//var qqq = [];\n\n\n//var thirtydayhourly = RED.util.cloneMessage(msg.payload.records);\n//node.warn(thirtydayhourly);\n\n//var unixtime = msg.payload.records.Bg[0][0];\n//var date = new Date(unixtime);\n//var hour = date.getHours();\n\nvar unixtime;\nvar date;\nvar hour;\n\nvar valuekwh;\n\n//var record = thirtydayhourly;\n//var record = msg.payload.slice();\n//node.warn(record);\n\n//thirtydayhourly.Bc.splice(0);\n//node.warn(thirtydayhourly);\n//node.warn(thirtydayhourly.Bc.length);\n\n//record.Bg.splice(0); \n//record.Bc.splice(0);\n\n//node.warn(Object.keys(thirtydayhourly));\n//node.warn(Messageheadings);\n//node.warn(Messageheadings[0]);\n\n\n//for (x = 0; x< msg.payload.records.Bg.length; x ++)\n\n// Sum the corresponding hours together for each day to give a single total for each hour\n// var heading;\nfor (const heading of Messageheadings)\n{\n\n// for (x = 0; x< 5; x ++)\n for (x = 0; x< msg.payload.records[heading].length; x ++)\n {\n unixtime = msg.payload.records[heading][x][0]; \n date = new Date(unixtime);\n hour = date.getHours();\n// node.warn(hour); \n\n\n\n valuekwh = msg.payload.records[heading][x][1];\n//valuekwh = msg.payload.records.Bc[x][1];\n// node.warn(valuekwh);\n//node.warn(Hourlyaveragedoverdays[yy][hour+1]);\n Hourlyaveragedoverdays[heading][hour+1][0] = Hourlyaveragedoverdays[heading][hour+1][0] + valuekwh;\n }\n//put it here\n}\n\n//node.warn(Hourlyaveragedoverdays);\n\n\n// Get the average of the hourly usage over the number of Days sample.\nvar answer;\nfor (const heading of Messageheadings)\n{\n// node.warn(heading);\n for (x = 1; x< Hourlyaveragedoverdays[heading].length; x ++)\n {\n answer = parseFloat((Hourlyaveragedoverdays[heading][x][0] / Days).toFixed(4));\n \n// Hourlyaveragedoverdays[heading][x][1] = (Hourlyaveragedoverdays[heading][x][0] / Days); \n Hourlyaveragedoverdays[heading][x][1] = answer; \n }\n// node.warn(\"rounded answer\");\n// node.warn(answer);\n}\n\n//}\n\n//node.warn(msg);\n//node.warn(Hourlyaveragedoverdays);\nmsg.topic = \"Historical Averaged Hourly stats\";\n\n\nmsg.payload = Hourlyaveragedoverdays;\n//node.warn(msg);\n\nreturn msg;", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 830, "y": 940, "wires": [ [ "4b61fe1633367595" ] ] }, { "id": "6b227c0d5b75267f", "type": "function", "z": "b487e656e7a73c72", "g": "454f7fa49c474ab0", "name": "Set Global ESSCapacity variable", "func": "var ESSCapacity = flow.get(\"ESSCapacity\") || 0;\n\nESSCapacity = msg.payload;\nflow.set(\"ESSCapacity\", ESSCapacity);\n\n//node.warn(msg);\n\nreturn msg;", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 840, "y": 280, "wires": [ [] ] }, { "id": "c05a89834ef25dd5", "type": "function", "z": "b487e656e7a73c72", "g": "454f7fa49c474ab0", "name": "Set Global LowestSOC variable", "func": "var LowestSOC = flow.get(\"LowestSOC\") || 0;\n\nLowestSOC = msg.payload;\nflow.set(\"LowestSOC\", LowestSOC);\n\n//node.warn(msg);\n\nreturn msg;", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 890, "y": 380, "wires": [ [] ] }, { "id": "18331e9d57b59d23", "type": "function", "z": "b487e656e7a73c72", "g": "454f7fa49c474ab0", "name": "Set Global Cheaptimevariable", "func": "var Cheaptime = flow.get(\"Cheaptime\") || 0;\n\nvar time = new Date(msg.payload);\nvar hour = time.getHours();\n\n//node.warn(hour);\nCheaptime = hour;\n\nflow.set(\"Cheaptime\", Cheaptime);\n\n//node.warn(msg);\n\nreturn msg;", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 1290, "y": 500, "wires": [ [] ] }, { "id": "96bf10f8470faf10", "type": "function", "z": "b487e656e7a73c72", "g": "454f7fa49c474ab0", "name": "Set Global PremiumExport variable", "func": "var PremiumExport = flow.get(\"PremiumExport\") || 0;\n\nvar d = new Date(msg.payload);\nvar Premium = d.getHours();\n\n//node.warn(\"Prem hours\");\n//node.warn(Premium);\n\nPremiumExport = Premium;\nflow.set(\"PremiumExport\", PremiumExport);\n\n//node.warn(msg);\n\nreturn msg;", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 1200, "y": 600, "wires": [ [] ] }, { "id": "1993a6b5a7c879c2", "type": "function", "z": "b487e656e7a73c72", "g": "454f7fa49c474ab0", "name": "Make to init", "func": "msg.payload = parseInt(msg.payload);\n\n\nreturn msg;", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 650, "y": 440, "wires": [ [ "9ca4b1ff316c16e8", "18331e9d57b59d23" ] ] }, { "id": "2d2d498eaca5e516", "type": "function", "z": "b487e656e7a73c72", "g": "454f7fa49c474ab0", "name": "Make to init", "func": "msg.payload = parseInt(msg.payload);\n\n\nreturn msg;", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 650, "y": 540, "wires": [ [ "b6e7343e07e4b5b7", "96bf10f8470faf10" ] ] }, { "id": "9d72ed6fd8d1ea23", "type": "debug", "z": "b487e656e7a73c72", "name": "debug 23", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "true", "targetType": "full", "statusVal": "", "statusType": "auto", "x": 740, "y": 1080, "wires": [] }, { "id": "4b61fe1633367595", "type": "join", "z": "b487e656e7a73c72", "name": "", "mode": "custom", "build": "array", "property": "payload", "propertyType": "msg", "key": "topic", "joiner": "\\n", "joinerType": "str", "accumulate": false, "timeout": "", "count": "2", "reduceRight": false, "reduceExp": "", "reduceInit": "", "reduceInitType": "", "reduceFixup": "", "x": 1090, "y": 960, "wires": [ [ "cbd0694956a0bb41" ] ] }, { "id": "4f933258d4b2a53f", "type": "vrm-api", "z": "b487e656e7a73c72", "vrm": "5fcd0bce74e72cb7", "name": "Victron VRM API PV forecast", "idSite": "999999", "installations": "stats", "attribute": "vrm_pv_inverter_yield_fc", "stats_interval": "hours", "stats_start": "0", "stats_end": "86400", "verbose": false, "x": 440, "y": 960, "wires": [ [ "81e068a0a0edb052" ] ] }, { "id": "cbd0694956a0bb41", "type": "function", "z": "b487e656e7a73c72", "name": "Calculate new SOC", "func": "var Accuracy = flow.get(\"Accuracy\") || 0;\nvar Days = flow.get(\"Days\") || 0;\nvar ESSCapacity = flow.get(\"ESSCapacity\") || 0;\nvar LowestSOC = flow.get(\"LowestSOC\") || 0;\nvar Cheaptime = flow.get(\"Cheaptime\") || 0;\nvar PremiumExport = flow.get(\"PremiumExport\") || 0;\nvar Discharge_stop_SOC = flow.get(\"Discharge_stop_SOC\") || 0;\nvar Padding = flow.get(\"Padding\") || 0;\nvar CurrentSOC = global.get(\"CurrentSOC\") || 0;\n\n\nvar NewBatterySOCPercent = 0;\n\nvar keys0 = Object.keys(msg.payload[0]);\nvar keys1 = Object.keys(msg.payload[1]);\n\n//node.warn(keys1);\n\n// 31/10/2023 - GJW\n\n// if keys length is 1 then we are looking at VRM_pv yield forecast.\n// if keys length is 8 then we are looking at the historical data.\n// First letter if device from second letter is device to\n// Bg - means Battery to Grid, Pb means Photovoltaic to battery etc.\n// In vrm array the index counts from 1 to 24 inclusive, with index 1 meaning the time finishing\n// at 01:00, 2 finishing at 02:00 etc. upto 24 with the time finishing at 24:00\n// the first element is the start time of the period the second is the wh value forecast.\n\n// In the Bg arrays the index counts from 1 to 24 inclusive, with index 1 meaning the time finishing\n// at 01:00, 2 finishing at 02:00 etc. upto 24 with the time finishing at 24:00\n// the first element is the total Kwh over the x Days sample, the second element is the \n// average of those amounts (over Days).\n\n// Loop from start of cheap electricy time to start of premium export time\n// and add the production and (Accuracy * forecast), less consumption, for each\n// hour, noting the lowest value achieved.\n\nvar vrm_pv;\nvar vrm_pv_key;\nvar historical;\nvar cummulativeKwh = 0;\nvar ForecastPV = 0;\nvar lowestKwh = 0;\n\nif (keys0.length == 1)\n{\n vrm_pv_key = keys0;\n vrm_pv = 0;\n historical = 1;\n}\nelse \n{\n vrm_pv_key = keys1;\n vrm_pv = 1\n historical = 0;\n}\n\n\n// currently just check up to the premium export time\n// but might need to move to Sunset (ish) say 20:00 to get all the \n// summer solar.\n\nfor (loop = Cheaptime; loop < PremiumExport + 1; loop++ )\n//for (loop = 8; loop <= 10; loop++ )\n{\n// node.warn(\"loop\");\n// node.warn(loop);\n cummulativeKwh = cummulativeKwh - msg.payload[historical][\"Gc\"][loop][1] - \n msg.payload[historical][\"Bc\"][loop][1] +\n ((msg.payload[vrm_pv][vrm_pv_key][loop][1]/1000)* (Accuracy/100));\n\n ForecastPV = ForecastPV + ((msg.payload[vrm_pv][vrm_pv_key][loop][1]/1000)* (Accuracy/100));\n\n// node.warn(loop);\n// node.warn(cummulativeKwh);\n// node.warn(\"cummulativeKwh\");\n// node.warn(msg.payload[historical][\"Pc\"][loop][1]);\n// node.warn(msg.payload[historical][\"Gc\"][loop][1]);\n// node.warn(msg.payload[historical][\"Bc\"][loop][1]);\n// node.warn(msg.payload[vrm_pv][vrm_pv_key][loop][1]);\n \n\n \n if (cummulativeKwh < lowestKwh)\n { \n lowestKwh = cummulativeKwh;\n }\n \n// node.warn(\"lowestKwh\");\n\n//node.warn(lowestKwh);\n \n}\n//node.warn(\"cumm\");\n//node.warn(cummulativeKwh);\n//node.warn(\"lowestKwh\");\n\n//node.warn(lowestKwh);\nvar thresholdused = \"No\";\nvar abslowestKwh = Math.abs(lowestKwh);\n//node.warn(lowestKwh);\n\n//NewBatterySOCPercent = ((LowestSOC/100) * ESSCapacity);\n//node.warn(NewBatterySOCPercent);\n\nif (cummulativeKwh > 0)\n{\n NewBatterySOCPercent = parseInt((parseFloat(LowestSOC) + ((abslowestKwh/ESSCapacity) * 100)).toFixed());\n var MinimumthresholdPercent = parseInt((parseFloat(NewBatterySOCPercent) + ((cummulativeKwh/ESSCapacity) *100)).toFixed());\n node.warn(\"MinimumthresholdPercent\");\n node.warn(MinimumthresholdPercent);\n// node.warn(Discharge_stop_SOC);\n thresholdused = thresholdused + \", plus +ve cummlative.\";\n\n if (MinimumthresholdPercent < Discharge_stop_SOC)\n {\n thresholdused = \"Yes\";\n NewBatterySOCPercent = parseInt((parseFloat(Discharge_stop_SOC) - ((cummulativeKwh/ESSCapacity) * 100)).toFixed());\n }\n// Need to figure out if we need to have a minimum SOC level at the beginning of the day\n// e.g. Discharge_stop_SOC. So even if the cummulative Kwh's is positive it might not be enough to \n// take the battery charge from the minimum level to \n\n\n}\nelse\n{\n NewBatterySOCPercent = parseInt((parseFloat(Discharge_stop_SOC) + ((abslowestKwh/ESSCapacity) * 100)).toFixed());\n thresholdused = thresholdused + \", -ve cummlative.\";\n\n}\n\n//node.warn(NewBatterySOCPercent);\n\n// padding figure for New Battery SOC\n// currently set as a flat 10% but should be settable from a Dashboard figure\n\nNewBatterySOCPercent = NewBatterySOCPercent + parseInt(Padding);\nif (NewBatterySOCPercent > 96 )\n{\n NewBatterySOCPercent = 100;\n}\nelse \n{\n NewBatterySOCPercent = parseInt(NewBatterySOCPercent/5)*5 + 5\n}\n\nif (NewBatterySOCPercent < 100)\n{\n if ((((ForecastPV/ESSCapacity) * 100) + CurrentSOC) < 100)\n {\n NewBatterySOCPercent = 100;\n// node.warn(CurrentSOC);\n }\n \n}\n\n\nmsg.lowest = ((lowestKwh).toFixed(4)).toString() + \" kWh, \" + (((lowestKwh/ESSCapacity) * 100).toFixed()).toString() + \"%\";\n//node.warn(msg.lowest);\nmsg.cumm = ((cummulativeKwh).toFixed(4)).toString() + \" kWh, \" + (((cummulativeKwh/ESSCapacity) * 100).toFixed()).toString() + \"%\";\n//node.warn(msg.cumm);\nmsg.payload = NewBatterySOCPercent;\nmsg.threshold = thresholdused;\nmsg.Padding = Padding;\nmsg.Pushvalue = NewBatterySOCPercent;\n\n//node.warn(\"ForecastPV\");\n//node.warn(ForecastPV);\n\n\n\nreturn msg;", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 310, "y": 1100, "wires": [ [ "6934e88e0f09dce6", "51eaac72c1236654", "fd7020be4401adce", "6ee28581867480a7", "f5475049a72c81d3", "14c351954c541acd", "b559735f679d6344", "b3a08de90bb4f4e2", "746f72acd519509e" ] ] }, { "id": "81e068a0a0edb052", "type": "function", "z": "b487e656e7a73c72", "name": "Split to be in same format as Historical data", "func": "\nvar Messageheadings = Object.keys(msg.payload.records);\n\n//node.warn(Messageheadings);\n\nvar ForecastHourly = {};\n\nfor (const xx of Messageheadings)\n{\n ForecastHourly[xx] = new Array([]);\n for (x=0 ;x<24; x++)\n {\n ForecastHourly[xx].push(new Array(parseFloat(0),parseFloat(0)));\n }\n}\n\nvar heading;\nfor (heading of Messageheadings)\n{\n\n// for (x = 0; x< 5; x ++)\n for (x = 0; x< msg.payload.records[heading].length; x ++)\n {\n unixtime = msg.payload.records[heading][x][0]; \n date = new Date(unixtime);\n hour = date.getHours();\n ForecastHourly[heading][hour+1] = msg.payload.records[heading][x];\n }\n}\nmsg.topic = \"999999:stats\"\n\n\nmsg.payload = ForecastHourly;\n//node.warn(msg);\n//node.warn(ForecastHourly);\n\nreturn msg;", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 830, "y": 980, "wires": [ [ "4b61fe1633367595" ] ] }, { "id": "6934e88e0f09dce6", "type": "ui_gauge", "z": "b487e656e7a73c72", "name": "", "group": "9b0bae12a2d227fe", "order": 8, "width": 0, "height": 0, "gtype": "gage", "title": "Suggested next Battery SOC (%)", "label": "%", "format": "{{value}}", "min": 0, "max": "100", "colors": [ "#ca3838", "#e6e600", "#00b500" ], "seg1": "", "seg2": "", "diff": false, "className": "", "x": 820, "y": 1120, "wires": [] }, { "id": "caa963420b78f6c1", "type": "time-inject", "z": "b487e656e7a73c72", "name": "Aintree Sun", "nameInt": "⏲ sunset end = timestamp", "positionConfig": "d75ca3c9f6dc4a63", "props": [ { "p": "", "pt": "msgPayload", "v": "", "vt": "date", "o": "", "oT": "none", "oM": "1000", "f": 0, "fS": 0, "fT": "UNIX timestamp (ms)", "fI": "0", "next": true, "days": "*", "months": "*", "onlyOddDays": false, "onlyEvenDays": false, "onlyOddWeeks": false, "onlyEvenWeeks": false }, { "p": "", "pt": "msgTopic", "v": "", "vt": "str", "o": "", "oT": "none", "oM": "60000", "f": 0, "fS": 0, "fT": "UNIX timestamp (ms)", "fI": "0", "next": false, "days": "*", "months": "*", "onlyOddDays": false, "onlyEvenDays": false, "onlyOddWeeks": false, "onlyEvenWeeks": false } ], "injectTypeSelect": "time", "intervalCount": 1, "intervalCountType": "num", "intervalCountMultiplier": 60000, "cron": "", "cronType": "cronexpr", "time": "sunsetEnd", "timeType": "pdsTime", "offset": 0, "offsetType": "none", "offsetMultiplier": 60000, "timeEnd": "", "timeEndType": "entered", "timeEndOffset": 0, "timeEndOffsetType": "none", "timeEndOffsetMultiplier": 60000, "timeDays": "*", "timeOnlyOddDays": false, "timeOnlyEvenDays": false, "timeOnlyOddWeeks": false, "timeOnlyEvenWeeks": false, "timeMonths": "*", "timedatestart": "", "timedateend": "", "property": "", "propertyType": "none", "propertyCompare": "true", "propertyThreshold": "", "propertyThresholdType": "num", "timeAlt": "", "timeAltType": "entered", "timeAltDays": "*", "timeAltOnlyOddDays": false, "timeAltOnlyEvenDays": false, "timeAltOnlyOddWeeks": false, "timeAltOnlyEvenWeeks": false, "timeAltMonths": "*", "timeAltOffset": 0, "timeAltOffsetType": "none", "timeAltOffsetMultiplier": 60000, "once": false, "onceDelay": 0.1, "recalcTime": 2, "x": 130, "y": 880, "wires": [ [ "35414432ac1601c3", "4f933258d4b2a53f" ] ] }, { "id": "239d56ab2e8dc3a1", "type": "simplepush", "z": "b487e656e7a73c72", "key": "nk5GfE", "title": "", "message": "", "event": "", "actions": "", "actionTimeout": 180, "password": "", "salt": "", "name": "", "outputs": 1, "x": 970, "y": 1260, "wires": [ [] ] }, { "id": "fd7020be4401adce", "type": "function", "z": "b487e656e7a73c72", "name": "Format push message", "func": "var value = msg.Pushvalue;\n \nvar SimplePushFlag = flow.get(\"SimplePushFlag\");\nvar SimplePushCount = flow.get(\"SimplePushCount\");\n \n \nvar d = new Date();\n\nvar dformat = [('0' + d.getDate()).slice(-2),\n ('0' + (d.getMonth()+1)).slice(-2),\n d.getFullYear()].join('/')+' @ '+\n [('0' + d.getHours()).slice(-2),\n ('0' + d.getMinutes()).slice(-2)].join(':');\n\n//\nnode.warn(SimplePushFlag);\nnode.warn(SimplePushCount);\n\n\nSimplePushCount = SimplePushCount + 1;\nflow.set(\"SimplePushCount\", SimplePushCount);\n\nif(SimplePushFlag == false)\n{\nmsg.title = \"From Victron:\";\nmsg.payload = \"New Battery SOC = \" + value.toString() + \"%, set on \" + dformat + \".\";\nSimplePushFlag = true;\nflow.set(\"SimplePushFlag\", SimplePushFlag);\nnode.warn(SimplePushFlag);\nnode.warn(SimplePushCount);\nreturn msg;\n}\nelse\n{\nSimplePushFlag = false;\nflow.set(\"SimplePushFlag\", SimplePushFlag);\nnode.warn(SimplePushFlag);\nnode.warn(SimplePushCount);\n}\n\n\n", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 780, "y": 1260, "wires": [ [ "239d56ab2e8dc3a1", "b2467cd8289a773f" ] ] }, { "id": "b3a08de90bb4f4e2", "type": "victron-output-ess", "z": "b487e656e7a73c72", "service": "com.victronenergy.settings", "path": "/Settings/CGwacs/BatteryLife/Schedule/Charge/0/Soc", "serviceObj": { "service": "com.victronenergy.settings", "name": "Venus settings" }, "pathObj": { "path": "/Settings/CGwacs/BatteryLife/Schedule/Charge/0/Soc", "type": "integer", "name": "Schedule 1: State of charge (%)", "writable": true }, "name": "Schedule 1 SOC", "onlyChanges": false, "x": 770, "y": 1200, "wires": [] }, { "id": "e59028b2799e28b2", "type": "inject", "z": "b487e656e7a73c72", "name": "", "props": [ { "p": "payload" }, { "p": "topic", "vt": "str" } ], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "100", "payloadType": "num", "x": 350, "y": 1200, "wires": [ [ "b3a08de90bb4f4e2" ] ] }, { "id": "9ba736ff462388dc", "type": "ui_text", "z": "b487e656e7a73c72", "group": "028a2db8cabbdb0e", "order": 9, "width": 0, "height": 0, "name": "", "label": "Last Updated:", "format": "{{msg.payload}}", "layout": "row-spread", "className": "", "style": false, "font": "", "fontSize": 16, "color": "#000000", "x": 980, "y": 1300, "wires": [] }, { "id": "51eaac72c1236654", "type": "function", "z": "b487e656e7a73c72", "name": "Date", "func": "\nvar d = new Date();\n\nvar dformat = [('0' + d.getDate()).slice(-2),\n ('0' + (d.getMonth()+1)).slice(-2),\n d.getFullYear()].join('/')+' @ '+\n [('0' + d.getHours()).slice(-2),\n ('0' + d.getMinutes()).slice(-2)].join(':');\n\n//node.warn(dformat);\nmsg.payload = dformat;\nreturn msg;", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 730, "y": 1300, "wires": [ [ "9ba736ff462388dc" ] ] }, { "id": "8732a512ad6178ad", "type": "ui_text", "z": "b487e656e7a73c72", "group": "028a2db8cabbdb0e", "order": 10, "width": 0, "height": 0, "name": "", "label": "Cummulative:", "format": "{{msg.payload}}", "layout": "row-spread", "className": "", "style": false, "font": "", "fontSize": 16, "color": "#000000", "x": 980, "y": 1340, "wires": [] }, { "id": "6ee28581867480a7", "type": "function", "z": "b487e656e7a73c72", "name": "Cummulative", "func": "var cumm = msg.cumm;\n\n//msg.payload = cumm.toFixed(4) + \" KWh.\";\n\nmsg.payload = cumm;\n\nreturn msg;", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 750, "y": 1340, "wires": [ [ "8732a512ad6178ad" ] ] }, { "id": "dc1db7a64d15586b", "type": "ui_text", "z": "b487e656e7a73c72", "group": "028a2db8cabbdb0e", "order": 11, "width": 0, "height": 0, "name": "", "label": "Lowest:", "format": "{{msg.payload}}", "layout": "row-spread", "className": "", "style": false, "font": "", "fontSize": 16, "color": "#000000", "x": 960, "y": 1380, "wires": [] }, { "id": "f5475049a72c81d3", "type": "function", "z": "b487e656e7a73c72", "name": "Lowest", "func": "var lowest = msg.lowest;\n\n//msg.payload = lowest.toFixed(4) + \" KWh.\";\n\nmsg.payload = lowest;\n\nreturn msg;", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 740, "y": 1380, "wires": [ [ "dc1db7a64d15586b" ] ] }, { "id": "10377da50a6c2ecc", "type": "ui_slider", "z": "b487e656e7a73c72", "g": "454f7fa49c474ab0", "name": "", "label": "SOC Stop Discharging value (%):", "tooltip": "", "group": "9b0bae12a2d227fe", "order": 3, "width": 0, "height": 0, "passthru": true, "outs": "end", "topic": "SOC_stop_value", "topicType": "msg", "min": "15", "max": "100", "step": "5", "className": "", "x": 660, "y": 640, "wires": [ [ "86e39d66a68a5b8d" ] ] }, { "id": "44dbc068be2d210e", "type": "function", "z": "b487e656e7a73c72", "g": "454f7fa49c474ab0", "name": "Discharge stop SOC", "func": "var Discharge_stop_SOC = flow.get(\"Discharge_stop_SOC\") || 0;\n\nDischarge_stop_SOC = msg.payload;\nflow.set(\"Discharge_stop_SOC\", Discharge_stop_SOC);\n\nmsg.Discharge_stop_SOC = Discharge_stop_SOC;\n//node.warn(Discharge_stop_SOC);\n\nreturn msg;", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 1140, "y": 680, "wires": [ [] ] }, { "id": "86e39d66a68a5b8d", "type": "file", "z": "b487e656e7a73c72", "g": "454f7fa49c474ab0", "name": "Save Stop SOC", "filename": "/data/home/nodered/StopSOC.txt", "filenameType": "str", "appendNewline": true, "createDir": true, "overwriteFile": "true", "encoding": "none", "x": 920, "y": 640, "wires": [ [ "44dbc068be2d210e" ] ] }, { "id": "288573ae480982b1", "type": "file in", "z": "b487e656e7a73c72", "g": "454f7fa49c474ab0", "name": "Load Stop SOC", "filename": "/data/home/nodered/StopSOC.txt", "filenameType": "str", "format": "utf8", "chunk": false, "sendError": false, "encoding": "none", "allProps": false, "x": 400, "y": 640, "wires": [ [ "10377da50a6c2ecc", "44dbc068be2d210e" ] ] }, { "id": "6599b4ccbe0caa01", "type": "inject", "z": "b487e656e7a73c72", "g": "454f7fa49c474ab0", "name": "SOC Stop value", "props": [ { "p": "payload" } ], "repeat": "", "crontab": "", "once": true, "onceDelay": 0.1, "topic": "", "payload": "40", "payloadType": "num", "x": 140, "y": 640, "wires": [ [ "288573ae480982b1" ] ] }, { "id": "14c351954c541acd", "type": "function", "z": "b487e656e7a73c72", "name": "Threshold", "func": "var threshold = msg.threshold;\n\n//msg.payload = lowest.toFixed(4) + \" Kwh.\";\n\nmsg.payload = threshold;\n\nreturn msg;", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 740, "y": 1420, "wires": [ [ "24b6528fbf265a3b" ] ] }, { "id": "24b6528fbf265a3b", "type": "ui_text", "z": "b487e656e7a73c72", "group": "028a2db8cabbdb0e", "order": 11, "width": 0, "height": 0, "name": "", "label": "Threshold used:", "format": "{{msg.payload}}", "layout": "row-spread", "className": "", "style": false, "font": "", "fontSize": 16, "color": "#000000", "x": 980, "y": 1420, "wires": [] }, { "id": "1493274219adaaae", "type": "ui_text", "z": "b487e656e7a73c72", "group": "028a2db8cabbdb0e", "order": 4, "width": 0, "height": 0, "name": "", "label": "Next Battery SOC:", "format": "{{msg.payload}}", "layout": "row-spread", "className": "", "style": false, "font": "", "fontSize": 16, "color": "#000000", "x": 990, "y": 1160, "wires": [] }, { "id": "b559735f679d6344", "type": "function", "z": "b487e656e7a73c72", "name": "Next Battery SOC", "func": "Padding = msg.Padding;\nmsg.payload = msg.payload + \"% (with \" + Padding + \"% padding).\";\n\n\nreturn msg;", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 770, "y": 1160, "wires": [ [ "1493274219adaaae" ] ] }, { "id": "f85124c756404b49", "type": "victron-input-ess", "z": "b487e656e7a73c72", "service": "com.victronenergy.settings", "path": "/Settings/CGwacs/BatteryLife/Schedule/Charge/0/Soc", "serviceObj": { "service": "com.victronenergy.settings", "name": "Venus settings" }, "pathObj": { "path": "/Settings/CGwacs/BatteryLife/Schedule/Charge/0/Soc", "type": "integer", "name": "Schedule 1: State of charge (%)" }, "initial": "", "name": "", "onlyChanges": false, "x": 240, "y": 1520, "wires": [ [ "073e39d8a4df6d3f" ] ] }, { "id": "073e39d8a4df6d3f", "type": "ui_gauge", "z": "b487e656e7a73c72", "name": "", "group": "028a2db8cabbdb0e", "order": 8, "width": 0, "height": 0, "gtype": "gage", "title": "Current Schedule SOC.", "label": "%", "format": "{{value}}", "min": 0, "max": "100", "colors": [ "#ca3838", "#e6e600", "#00b500" ], "seg1": "", "seg2": "", "diff": false, "className": "", "x": 1010, "y": 1520, "wires": [] }, { "id": "d7e703090b6b41a5", "type": "ui_numeric", "z": "b487e656e7a73c72", "g": "454f7fa49c474ab0", "name": "Padding", "label": "Padding amount (%):", "tooltip": "", "group": "9b0bae12a2d227fe", "order": 1, "width": 0, "height": 0, "wrap": false, "passthru": true, "topic": "Padding", "topicType": "str", "format": "", "min": 0, "max": "20", "step": 1, "className": "", "x": 580, "y": 720, "wires": [ [ "f37c11c76b719632" ] ] }, { "id": "47a75f78cf9aa491", "type": "inject", "z": "b487e656e7a73c72", "g": "454f7fa49c474ab0", "name": "Padding Percentage", "props": [ { "p": "payload" } ], "repeat": "", "crontab": "", "once": true, "onceDelay": 0.1, "topic": "", "payload": "10", "payloadType": "num", "x": 160, "y": 720, "wires": [ [ "c137024f68a4da6e" ] ] }, { "id": "c137024f68a4da6e", "type": "file in", "z": "b487e656e7a73c72", "g": "454f7fa49c474ab0", "name": "Load Padding", "filename": "/data/home/nodered/Padding.txt", "filenameType": "str", "format": "utf8", "chunk": false, "sendError": false, "encoding": "none", "allProps": false, "x": 380, "y": 720, "wires": [ [ "d7e703090b6b41a5", "72e8c98817dd1ce1" ] ] }, { "id": "f37c11c76b719632", "type": "file", "z": "b487e656e7a73c72", "g": "454f7fa49c474ab0", "name": "Save Padding", "filename": "/data/home/nodered/Padding.txt", "filenameType": "str", "appendNewline": false, "createDir": false, "overwriteFile": "true", "encoding": "none", "x": 760, "y": 720, "wires": [ [ "72e8c98817dd1ce1" ] ] }, { "id": "72e8c98817dd1ce1", "type": "function", "z": "b487e656e7a73c72", "g": "454f7fa49c474ab0", "name": "Set Global Padding variable", "func": "var Padding = flow.get(\"Padding\") || 0;\n\nPadding = msg.payload;\nflow.set(\"Padding\", Padding);\n\n//node.warn(msg);\n\nreturn msg;", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 1020, "y": 760, "wires": [ [] ] }, { "id": "746f72acd519509e", "type": "function", "z": "b487e656e7a73c72", "name": "Assemble MQTT message", "func": "value = msg.payload;\n\nvar d = new Date();\n\nvar dformat = [('0' + d.getDate()).slice(-2),\n ('0' + (d.getMonth()+1)).slice(-2),\n d.getFullYear()].join('/')+' @ '+\n [('0' + d.getHours()).slice(-2),\n ('0' + d.getMinutes()).slice(-2)].join(':');\n\n//\n\nmsg.payload = {};\n\nmsg.topic = \"Victron_Forecast_SOC\";\n\nmsg.payload[\"Cummulative\"] = msg.cumm;\nmsg.payload[\"Lowest\"] = msg.lowest;\nmsg.payload[\"SOC\"] = value;\nmsg.payload[\"Date\"] = dformat;\n\n\nreturn msg;\n\n", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 700, "y": 1460, "wires": [ [ "40170b251dc624f2" ] ] }, { "id": "40170b251dc624f2", "type": "mqtt out", "z": "b487e656e7a73c72", "name": "Victron MQTT to HA", "topic": "", "qos": "", "retain": "", "respTopic": "", "contentType": "", "userProps": "", "correl": "", "expiry": "", "broker": "5ede56129287c339", "x": 1000, "y": 1460, "wires": [] }, { "id": "b2467cd8289a773f", "type": "debug", "z": "b487e656e7a73c72", "name": "debug 25", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "true", "targetType": "full", "statusVal": "", "statusType": "auto", "x": 960, "y": 1220, "wires": [] }, { "id": "88264821ad6e4168", "type": "function", "z": "b487e656e7a73c72", "g": "962183d94e9de23f", "name": "Download Historical 2 Day 15 mins stats", "func": "var Days = flow.get(\"Days\") || 0;\n\n//node.warn(Days);\n\nmsg.headers = {};\nsitenumber = \"999999\";\n\nvar d = new Date();\n\nvar day=d.getDate();\nvar month=d.getMonth();\nvar year=d.getFullYear();\nday = day+1;\n\n//node.warn(day);\n\nvar previousday = new Date(year,month,day);\nvar numberofdaysback = new Date(year,month,day-2);\n\n// gets the unix time in second format\nvar unixendtime = previousday.getTime()/1000;\nvar unixstarttime = numberofdaysback.getTime()/1000;\n\nvar starttime = unixstarttime.toString();\nvar endtime = unixendtime.toString();\n\n//node.warn(unixstarttime);\n//node.warn(unixendtime);\n\nmsg.headers = {\n \"X-Authorization\" : \"Token XXXXXX\",\n 'Content-Type': 'application/json'\n };\nmsg.httpRequestTimeout = 60000;\nmsg.method = \"GET\";\nmsg.url = \"https://vrmapi.victronenergy.com/v2/installations/\" + sitenumber + \"/stats?start=\" + starttime + \"&end=\" + endtime + \"&type=kwh&interval=15mins\";\nmsg.payload = {};\nreturn msg;", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 500, "y": 1640, "wires": [ [ "97a7294932188d5a" ] ] }, { "id": "97a7294932188d5a", "type": "http request", "z": "b487e656e7a73c72", "g": "962183d94e9de23f", "name": "Victron VRM API", "method": "use", "ret": "obj", "paytoqs": "ignore", "url": "", "tls": "", "persist": false, "proxy": "", "insecureHTTPParser": false, "authType": "", "senderr": false, "headers": [], "x": 770, "y": 1640, "wires": [ [ "0876362380c2567a" ] ] }, { "id": "0876362380c2567a", "type": "function", "z": "b487e656e7a73c72", "g": "962183d94e9de23f", "name": "Get Offpeak power usage", "func": "var LastCheapImport = flow.get(\"LastCheapImport\") || 0;\n\nvar Days = flow.get(\"Days\") || 0;\nvar Messageheadings = Object.keys(msg.payload.records);\n//node.warn(Days);\n\n//const Headings = [\"Bc\",\"Gc\",\"Gb\",\"Bg\",\"Pc\",\"Pb\",\"Pg\"];\n//var temparray = new Array(parseFloat(0),parseFloat(0));\n//node.warn(temparray);\n//var thirtydayhourly = [];\nnode.warn(msg);\n\nvar unixtime;\nvar date;\nvar hour;\nvar minute;\n\nvar Hourlyaveragedoverdays = {};\n\nvar d = new Date();\n\nvar day=d.getDate();\nvar month=d.getMonth();\nvar year=d.getFullYear();\nd.setHours(23);\nendhours = 5;\nd.setMinutes(30);\nd.setSeconds(0);\nd.setDate(day-1);\n\nvar Startday = new Date(d);\nd.setDate(day);\nd.setHours(5);\n\nvar Endday = new Date(d);\n\nnode.warn(Startday);\nnode.warn(Endday);\n\nvar totalkWh = 0;\nvar valuekwh = 0;\n for (x = 0; x< msg.payload.records['Gb'].length; x ++)\n {\n unixtime = msg.payload.records['Gb'][x][0]; \n\n\n if ((unixtime > Startday) && (unixtime <= Endday))\n {\n// node.warn(unixtime);\n valuekwh = parseFloat(msg.payload.records['Gb'][x][1]);\n// node.warn(valuekwh);\n totalkWh = totalkWh + valuekwh;\n//\n }\n }\n\nLastCheapImport = totalkWh.toFixed(3);\n\n//node.warn(LastCheapImport);\nmsg.topic = \"LastCheapImport\";\nmsg.payload = parseFloat(LastCheapImport);\n\nflow.set(\"LastCheapImport\", LastCheapImport);\n\nreturn msg;", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 990, "y": 1640, "wires": [ [ "7419e489a9a180b1", "539441bb6033dc3f" ] ] }, { "id": "7619e4de107c6191", "type": "mqtt in", "z": "b487e656e7a73c72", "g": "962183d94e9de23f", "name": "MQTT IHD meter", "topic": "glowaintree/84CCA8544CC4/SENSOR/electricitymeter", "qos": "2", "datatype": "auto-detect", "broker": "6bbde287553c0324", "nl": false, "rap": true, "rh": 0, "inputs": 0, "x": 160, "y": 1720, "wires": [ [ "56acb48fc4816208" ] ] }, { "id": "cb0ed53e03157c8d", "type": "debug", "z": "b487e656e7a73c72", "g": "962183d94e9de23f", "name": "debug 26", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "true", "targetType": "full", "statusVal": "", "statusType": "auto", "x": 1000, "y": 1780, "wires": [] }, { "id": "56acb48fc4816208", "type": "function", "z": "b487e656e7a73c72", "g": "962183d94e9de23f", "name": "Get Export meter value", "func": "var LatestExportValue = flow.get(\"LatestExportValue\") || 0;\n\nvar cumulative = msg.payload.electricitymeter.energy.export.cumulative;\nvar units = msg.payload.electricitymeter.energy.export.units;\n\n//node.warn(cumulative);\n\nmsg.payload = cumulative;\nLatestExportValue = cumulative;\nflow.set(\"LatestExportValue\", LatestExportValue);\n\nreturn msg;\n\n", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 370, "y": 1720, "wires": [ [ "cb7803ac9c74a7da", "539441bb6033dc3f" ] ] }, { "id": "cb7803ac9c74a7da", "type": "ui_numeric", "z": "b487e656e7a73c72", "g": "962183d94e9de23f", "name": "", "label": "Export Value:", "tooltip": "", "group": "b644206e3a5cde22", "order": 8, "width": 0, "height": 0, "wrap": false, "passthru": false, "topic": "topic", "topicType": "msg", "format": "{{value}}", "min": 0, "max": "100000", "step": ".001", "className": "", "x": 630, "y": 1720, "wires": [ [] ] }, { "id": "7419e489a9a180b1", "type": "ui_gauge", "z": "b487e656e7a73c72", "d": true, "g": "962183d94e9de23f", "name": "", "group": "b644206e3a5cde22", "order": 1, "width": 0, "height": 0, "gtype": "gage", "title": "last cheap import", "label": "kWh", "format": "{{value}}", "min": 0, "max": "40", "colors": [ "#00b500", "#e6e600", "#ca3838" ], "seg1": "", "seg2": "", "diff": false, "className": "", "x": 1230, "y": 1640, "wires": [] }, { "id": "831eba8ead987193", "type": "function", "z": "b487e656e7a73c72", "g": "962183d94e9de23f", "name": "function 13", "func": "var d = new Date();\n\nvar hour = d.getHours();\nvar CurrentSOC = (msg.payload[\"Venus system - Battery State of Charge (%)\"]);\nvar Export = (msg.payload[\"glowaintree/84CCA8544CC4/SENSOR/electricitymeter\"]);\nvar LastCheapImport = (msg.payload[\"LastCheapImport\"]);\nvar Timeset = new Date(msg.payload[\"Timeset\"]);\n\n\n//node.warn(CurrentSOC);\n//node.warn(Export);\n//node.warn(Timeset);\n\nvar hours = Timeset.getHours();\n//node.warn(hours);\n\nvar NewExportValue = parseInt(LastCheapImport/2);\n\n//payload[\"Venus system - Battery State of Charge (%)\"]\n//payload[\"glowaintree/84CCA8544CC4/SENSOR/electricitymeter\"]\n\n\nif ((hours >= 16) && (CurrentSOC > 40))\n{\n node.warn(\"We should be Exporting\")\n}\n\n\nreturn msg;", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 1010, "y": 1820, "wires": [ [] ] }, { "id": "30725da530d0fda2", "type": "victron-input-system", "z": "b487e656e7a73c72", "d": true, "g": "962183d94e9de23f", "service": "com.victronenergy.system/0", "path": "/Dc/Battery/Soc", "serviceObj": { "service": "com.victronenergy.system/0", "name": "Venus system" }, "pathObj": { "path": "/Dc/Battery/Soc", "type": "float", "name": "Battery State of Charge (%)" }, "name": "", "onlyChanges": false, "x": 250, "y": 1900, "wires": [ [ "b401a2ec46369c51" ] ] }, { "id": "6eb3409f7e11d8f7", "type": "ui_gauge", "z": "b487e656e7a73c72", "d": true, "g": "962183d94e9de23f", "name": "", "group": "b644206e3a5cde22", "order": 1, "width": 0, "height": 0, "gtype": "gage", "title": "Battery SOC (%)", "label": "%", "format": "{{value}}", "min": 0, "max": "100", "colors": [ "#ca3838", "#e6e600", "#00b500" ], "seg1": "", "seg2": "", "diff": false, "className": "", "x": 770, "y": 1900, "wires": [] }, { "id": "b401a2ec46369c51", "type": "function", "z": "b487e656e7a73c72", "g": "962183d94e9de23f", "name": "Current SOC", "func": "var CurrentSOC = global.get(\"CurrentSOC\") || 0;\n\nCurrentSOC = msg.payload;\n\nmsg.payload = CurrentSOC;\n//node.warn(CurrentSOC);\nglobal.set(\"CurrentSOC\", CurrentSOC);\n\nreturn msg;", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 550, "y": 1900, "wires": [ [ "539441bb6033dc3f", "6eb3409f7e11d8f7" ] ] }, { "id": "539441bb6033dc3f", "type": "join", "z": "b487e656e7a73c72", "g": "962183d94e9de23f", "name": "", "mode": "custom", "build": "object", "property": "payload", "propertyType": "msg", "key": "topic", "joiner": "\\n", "joinerType": "str", "accumulate": true, "timeout": "", "count": "2", "reduceRight": false, "reduceExp": "", "reduceInit": "", "reduceInitType": "num", "reduceFixup": "", "x": 730, "y": 1820, "wires": [ [ "831eba8ead987193" ] ] }, { "id": "cd496b55a73ce86e", "type": "time-inject", "z": "b487e656e7a73c72", "d": true, "g": "962183d94e9de23f", "name": "", "nameInt": "⏲ 16:00 = timestamp", "positionConfig": "d75ca3c9f6dc4a63", "props": [ { "p": "", "pt": "msgPayload", "v": "", "vt": "date", "o": "", "oT": "none", "oM": "60000", "f": 0, "fS": 0, "fT": "UNIX timestamp (ms)", "fI": "0", "next": true, "days": "*", "months": "*", "onlyOddDays": false, "onlyEvenDays": false, "onlyOddWeeks": false, "onlyEvenWeeks": false }, { "p": "", "pt": "msgTopic", "v": "Timeset", "vt": "str", "o": "", "oT": "none", "oM": "60000", "f": 0, "fS": 0, "fT": "UNIX timestamp (ms)", "fI": "0", "next": false, "days": "*", "months": "*", "onlyOddDays": false, "onlyEvenDays": false, "onlyOddWeeks": false, "onlyEvenWeeks": false } ], "injectTypeSelect": "time", "intervalCount": 1, "intervalCountType": "num", "intervalCountMultiplier": 60000, "cron": "", "cronType": "cronexpr", "time": "16:00", "timeType": "entered", "offset": 0, "offsetType": "none", "offsetMultiplier": 60000, "timeEnd": "", "timeEndType": "entered", "timeEndOffset": 0, "timeEndOffsetType": "none", "timeEndOffsetMultiplier": 60000, "timeDays": "*", "timeOnlyOddDays": false, "timeOnlyEvenDays": false, "timeOnlyOddWeeks": false, "timeOnlyEvenWeeks": false, "timeMonths": "*", "timedatestart": "", "timedateend": "", "property": "", "propertyType": "none", "propertyCompare": "true", "propertyThreshold": "", "propertyThresholdType": "num", "timeAlt": "", "timeAltType": "entered", "timeAltDays": "*", "timeAltOnlyOddDays": false, "timeAltOnlyEvenDays": false, "timeAltOnlyOddWeeks": false, "timeAltOnlyEvenWeeks": false, "timeAltMonths": "*", "timeAltOffset": 0, "timeAltOffsetType": "none", "timeAltOffsetMultiplier": 60000, "once": false, "onceDelay": 0.1, "recalcTime": 2, "x": 200, "y": 1820, "wires": [ [ "539441bb6033dc3f" ] ] }, { "id": "53103870fd4c2fc8", "type": "time-inject", "z": "b487e656e7a73c72", "d": true, "g": "962183d94e9de23f", "name": "", "nameInt": "⏲ 15:50 = timestamp", "positionConfig": "d75ca3c9f6dc4a63", "props": [ { "p": "", "pt": "msgPayload", "v": "", "vt": "date", "o": "", "oT": "none", "oM": "60000", "f": 0, "fS": 0, "fT": "UNIX timestamp (ms)", "fI": "0", "next": true, "days": "*", "months": "*", "onlyOddDays": false, "onlyEvenDays": false, "onlyOddWeeks": false, "onlyEvenWeeks": false }, { "p": "", "pt": "msgTopic", "v": "Timeset", "vt": "str", "o": "", "oT": "none", "oM": "60000", "f": 0, "fS": 0, "fT": "UNIX timestamp (ms)", "fI": "0", "next": false, "days": "*", "months": "*", "onlyOddDays": false, "onlyEvenDays": false, "onlyOddWeeks": false, "onlyEvenWeeks": false } ], "injectTypeSelect": "time", "intervalCount": 1, "intervalCountType": "num", "intervalCountMultiplier": 60000, "cron": "", "cronType": "cronexpr", "time": "15:50", "timeType": "entered", "offset": 0, "offsetType": "none", "offsetMultiplier": 60000, "timeEnd": "", "timeEndType": "entered", "timeEndOffset": 0, "timeEndOffsetType": "none", "timeEndOffsetMultiplier": 60000, "timeDays": "*", "timeOnlyOddDays": false, "timeOnlyEvenDays": false, "timeOnlyOddWeeks": false, "timeOnlyEvenWeeks": false, "timeMonths": "*", "timedatestart": "", "timedateend": "", "property": "", "propertyType": "none", "propertyCompare": "true", "propertyThreshold": "", "propertyThresholdType": "num", "timeAlt": "", "timeAltType": "entered", "timeAltDays": "*", "timeAltOnlyOddDays": false, "timeAltOnlyEvenDays": false, "timeAltOnlyOddWeeks": false, "timeAltOnlyEvenWeeks": false, "timeAltMonths": "*", "timeAltOffset": 0, "timeAltOffsetType": "none", "timeAltOffsetMultiplier": 60000, "once": false, "onceDelay": 0.1, "recalcTime": 2, "x": 200, "y": 1640, "wires": [ [ "88264821ad6e4168" ] ] }, { "id": "b7b6220170daa9d1", "type": "victron-input-system", "z": "4aede9ec59461e66", "service": "com.victronenergy.system/0", "path": "/Dc/Battery/Soc", "serviceObj": { "service": "com.victronenergy.system/0", "name": "Venus system" }, "pathObj": { "path": "/Dc/Battery/Soc", "type": "float", "name": "Battery State of Charge (%)" }, "name": "", "onlyChanges": false, "x": 190, "y": 700, "wires": [ [ "a8f8befa5c55d231" ] ] }, { "id": "6361612f92f64910", "type": "ui_gauge", "z": "4aede9ec59461e66", "name": "", "group": "4c71a0775513569d", "order": 1, "width": 0, "height": 0, "gtype": "gage", "title": "Battery SOC (%)", "label": "%", "format": "{{value}}", "min": 0, "max": "100", "colors": [ "#ca3838", "#e6e600", "#00b500" ], "seg1": "", "seg2": "", "diff": false, "className": "", "x": 690, "y": 700, "wires": [] }, { "id": "2ab93f3a19e4f329", "type": "victron-input-system", "z": "4aede9ec59461e66", "service": "com.victronenergy.system/0", "path": "/Dc/Battery/State", "serviceObj": { "service": "com.victronenergy.system/0", "name": "Venus system" }, "pathObj": { "path": "/Dc/Battery/State", "type": "enum", "name": "Battery state", "enum": { "0": "idle", "1": "charging", "2": "discharging" } }, "initial": "", "name": "", "onlyChanges": false, "x": 140, "y": 760, "wires": [ [ "f44526857211bf5b" ] ] }, { "id": "12f3a92b504bf0b0", "type": "victron-input-ess", "z": "4aede9ec59461e66", "service": "com.victronenergy.settings", "path": "/Settings/CGwacs/AcPowerSetPoint", "serviceObj": { "service": "com.victronenergy.settings", "name": "Venus settings" }, "pathObj": { "path": "/Settings/CGwacs/AcPowerSetPoint", "type": "integer", "name": "Grid set-point (W)" }, "initial": "", "name": "", "onlyChanges": false, "x": 160, "y": 640, "wires": [ [ "19eae0562a18c196", "d896bd120607ef9c" ] ] }, { "id": "19eae0562a18c196", "type": "ui_slider", "z": "4aede9ec59461e66", "name": "", "label": "Grid Set Point (W):", "tooltip": "", "group": "4c71a0775513569d", "order": 5, "width": 0, "height": 0, "passthru": true, "outs": "end", "topic": "GridSetPoint", "topicType": "msg", "min": "-5500", "max": "100", "step": "100", "className": "", "x": 650, "y": 640, "wires": [ [] ] }, { "id": "ae5dabb1f398b507", "type": "ui_text", "z": "4aede9ec59461e66", "group": "4c71a0775513569d", "order": 4, "width": 0, "height": 0, "name": "", "label": "Charging state:", "format": "{{msg.payload}}", "layout": "row-spread", "className": "", "style": false, "font": "", "fontSize": 16, "color": "#000000", "x": 660, "y": 760, "wires": [] }, { "id": "f44526857211bf5b", "type": "function", "z": "4aede9ec59461e66", "name": "Charging State", "func": "switch(msg.payload)\n{\n case 0:\n {\n msg.payload = \"Idle\";\n break;\n }\n case 1:\n {\n msg.payload = \"Charging\";\n break;\n }\n case 2:\n {\n msg.payload = \"Discharging\";\n break;\n }\n default:\n {\n msg.payload = \"Error!!\";\n break;\n }\n} \nreturn msg;\n", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 400, "y": 760, "wires": [ [ "ae5dabb1f398b507" ] ] }, { "id": "1633bb19a9ddd729", "type": "ui_slider", "z": "4aede9ec59461e66", "g": "d70dfb5177478915", "name": "", "label": "SOC Start value (%):", "tooltip": "", "group": "4c71a0775513569d", "order": 6, "width": 0, "height": 0, "passthru": true, "outs": "end", "topic": "SOC_start_value", "topicType": "msg", "min": 0, "max": "100", "step": "5", "className": "", "x": 500, "y": 60, "wires": [ [ "11de7f2b239686be" ] ] }, { "id": "1c5c5da971b5e512", "type": "ui_slider", "z": "4aede9ec59461e66", "g": "d70dfb5177478915", "name": "", "label": "SOC Stop value (%):", "tooltip": "", "group": "4c71a0775513569d", "order": 7, "width": 0, "height": 0, "passthru": true, "outs": "end", "topic": "SOC_stop_value", "topicType": "msg", "min": "20", "max": "100", "step": "5", "className": "", "x": 500, "y": 120, "wires": [ [ "ae94d037e45ed09b" ] ] }, { "id": "cb3b7580851b4dcf", "type": "ui_switch", "z": "4aede9ec59461e66", "name": "", "label": "Force Discharge:", "tooltip": "", "group": "4c71a0775513569d", "order": 3, "width": 0, "height": 0, "passthru": true, "decouple": "false", "topic": "GridSetPoint", "topicType": "msg", "style": "", "onvalue": "true", "onvalueType": "bool", "onicon": "", "oncolor": "", "offvalue": "false", "offvalueType": "bool", "officon": "", "offcolor": "", "animate": false, "className": "", "x": 650, "y": 580, "wires": [ [ "e24d8020656549e2" ] ] }, { "id": "c0519c134b096a6a", "type": "inject", "z": "4aede9ec59461e66", "g": "d70dfb5177478915", "name": "", "props": [ { "p": "topic", "vt": "str" } ], "repeat": "", "crontab": "", "once": true, "onceDelay": 0.1, "topic": "", "x": 110, "y": 60, "wires": [ [ "07a1a9088b1dfd5a", "2e0f46abf287daa1" ] ] }, { "id": "338b44cbb51a40dd", "type": "debug", "z": "4aede9ec59461e66", "name": "debug 2", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "true", "targetType": "full", "statusVal": "", "statusType": "auto", "x": 980, "y": 260, "wires": [] }, { "id": "c1df7a1b18181138", "type": "function", "z": "4aede9ec59461e66", "g": "d70dfb5177478915", "name": "Discharge start SOC", "func": "var Discharge_start_SOC = flow.get(\"Discharge_start_SOC\") || 0;\n\nDischarge_start_SOC = msg.payload;\nflow.set(\"Discharge_start_SOC\", Discharge_start_SOC);\n\nmsg.Discharge_start_SOC = Discharge_start_SOC;\nnode.warn(Discharge_start_SOC);\n\nreturn msg;", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 940, "y": 60, "wires": [ [] ] }, { "id": "c7c8322cefc4a7f2", "type": "function", "z": "4aede9ec59461e66", "g": "d70dfb5177478915", "name": "Discharge stop SOC", "func": "var Discharge_stop_SOC = flow.get(\"Discharge_stop_SOC\") || 0;\n\nDischarge_stop_SOC = msg.payload;\nflow.set(\"Discharge_stop_SOC\", Discharge_stop_SOC);\n\nmsg.Discharge_stop_SOC = Discharge_stop_SOC;\nnode.warn(Discharge_stop_SOC);\n\nreturn msg;", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 940, "y": 120, "wires": [ [] ] }, { "id": "d896bd120607ef9c", "type": "function", "z": "4aede9ec59461e66", "name": "Check on Force discharge", "func": "var GridSetPoint = flow.get(\"GridSetPoint\") || 0;\nvar ForceDischarge = flow.get(\"ForceDischarge\") || false;\n\nif (msg.payload < -1000)\n{\n msg.payload = true;\n ForceDischarge = true;\n}\nelse\n{\n msg.payload = false;\n ForceDischarge = false;\n}\n//node.warn(msg);\nGridSetPoint = msg.payload;\nflow.set(\"GridSetPoint\", GridSetPoint);\nflow.set(\"ForceDischarge\", ForceDischarge);\nreturn msg;\n\n", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 430, "y": 580, "wires": [ [ "cb3b7580851b4dcf" ] ] }, { "id": "14d1903a0e842b64", "type": "ui_time_scheduler", "z": "4aede9ec59461e66", "group": "4c71a0775513569d", "name": "Peak Discharge time", "startDay": 0, "refresh": 60, "devices": [ "Discharge Victron:" ], "singleOff": false, "onlySendChange": false, "customPayload": false, "eventMode": false, "eventOptions": [], "sendTopic": true, "lat": "", "lon": "", "customContextStore": "", "outputs": 2, "order": 8, "width": 0, "height": 0, "x": 520, "y": 220, "wires": [ [ "154028142638a122" ], [ "1a784dd4b7d1a580" ] ] }, { "id": "1a784dd4b7d1a580", "type": "function", "z": "4aede9ec59461e66", "name": "Force Discharge", "func": "var Discharge_start_SOC = flow.get(\"Discharge_start_SOC\") || 0;\nvar GridSetPoint = flow.get(\"GridSetPoint\") || 0;\nvar CurrentSOC = global.get(\"CurrentSOC\") || 0;\nvar ForceDischarge = flow.get(\"ForceDischarge\") || false;\nvar Discharge_stop_SOC = flow.get(\"Discharge_stop_SOC\") || 0;\n\n//node.warn(msg);\n//node.warn(ForceDischarge);\n\nif (msg.payload)\n{\n//node.warn(\"true\");\n switch(ForceDischarge)\n {\n case false:\n {\n if (CurrentSOC >= Discharge_start_SOC)\n {\n// node.warn(msg);\n msg.payload = -5000;\n ForceDischarge = true;\n }\n else\n {\n msg.payload = 0;\n ForceDischarge = false; \n }\n break;\n }\n case true:\n {\n// node.warn(CurrentSOC);\n// node.warn(Discharge_stop_SOC);\n if (CurrentSOC <= Discharge_stop_SOC)\n {\n// node.warn(msg);\n msg.payload = 0;\n ForceDischarge = false;\n }\n else\n {\n msg.payload = -5000;\n ForceDischarge = true; \n }\n break;\n }\n default:\n {\n break;\n }\n }\n flow.set(\"ForceDischarge\", ForceDischarge);\n// node.warn(\"we are here\");\n// msg.payload = 0;\n// node.warn(msg.payload);\n// return msg;\n}\nelse\n{\n msg.payload = 0;\n}\n//node.warn(msg);\nreturn msg;\n\n \n\n\n\n", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 780, "y": 260, "wires": [ [ "d75a037c1cf40229" ] ] }, { "id": "a8f8befa5c55d231", "type": "function", "z": "4aede9ec59461e66", "name": "Current SOC", "func": "var CurrentSOC = global.get(\"CurrentSOC\") || 0;\n\nCurrentSOC = msg.payload;\n//node.warn(CurrentSOC);\nglobal.set(\"CurrentSOC\", CurrentSOC);\n\nreturn msg;", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 450, "y": 700, "wires": [ [ "6361612f92f64910" ] ] }, { "id": "d75a037c1cf40229", "type": "victron-output-ess", "z": "4aede9ec59461e66", "service": "com.victronenergy.settings", "path": "/Settings/CGwacs/AcPowerSetPoint", "serviceObj": { "service": "com.victronenergy.settings", "name": "Venus settings" }, "pathObj": { "path": "/Settings/CGwacs/AcPowerSetPoint", "type": "integer", "name": "Grid set-point (W)", "writable": true }, "name": "", "onlyChanges": false, "x": 1060, "y": 340, "wires": [] }, { "id": "154028142638a122", "type": "file", "z": "4aede9ec59461e66", "name": "Save Default Timer", "filename": "/data/home/nodered/Defaulttimer.txt", "filenameType": "str", "appendNewline": false, "createDir": true, "overwriteFile": "true", "encoding": "none", "x": 790, "y": 220, "wires": [ [] ] }, { "id": "0cf103e63023ebdb", "type": "file in", "z": "4aede9ec59461e66", "name": "Load Default Timer", "filename": "/data/home/nodered/Defaulttimer.txt", "filenameType": "str", "format": "utf8", "chunk": false, "sendError": false, "encoding": "none", "allProps": false, "x": 310, "y": 220, "wires": [ [ "14d1903a0e842b64" ] ] }, { "id": "684e0263737eb0ce", "type": "inject", "z": "4aede9ec59461e66", "name": "", "props": [ { "p": "payload" }, { "p": "topic", "vt": "str" } ], "repeat": "", "crontab": "", "once": true, "onceDelay": 0.1, "topic": "", "payload": "", "payloadType": "date", "x": 110, "y": 220, "wires": [ [ "0cf103e63023ebdb" ] ] }, { "id": "444a22cb4b18ced1", "type": "inject", "z": "4aede9ec59461e66", "name": "Force discharge - On", "props": [ { "p": "payload" } ], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "-5000", "payloadType": "num", "x": 140, "y": 300, "wires": [ [ "d75a037c1cf40229" ] ] }, { "id": "c659f76dc59131c7", "type": "inject", "z": "4aede9ec59461e66", "name": "Force discharge - Off", "props": [ { "p": "payload" } ], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "0", "payloadType": "num", "x": 140, "y": 340, "wires": [ [ "d75a037c1cf40229" ] ] }, { "id": "b618980be2f80433", "type": "simplepush", "z": "4aede9ec59461e66", "key": "nk5GfE", "title": "", "message": "", "event": "", "actions": "", "actionTimeout": 180, "password": "", "salt": "", "name": "", "outputs": 1, "x": 1250, "y": 540, "wires": [ [] ] }, { "id": "e24d8020656549e2", "type": "function", "z": "4aede9ec59461e66", "name": "Send message on 'Change of State'", "func": "var previous_switch_value = flow.get(\"previous_switch_value\") || false;\nvar CurrentSOC = global.get(\"CurrentSOC\") || 0;\nvar dt = new Date();\nvar hours = dt.getHours();\nvar minutes = dt.getMinutes();\nvar Batteryitem = \"\";\n\nif (hours <= 9)\n{\n hours = \"0\" + hours;\n}\n\nif (minutes <= 9)\n{\n minutes = \"0\" + minutes;\n}\n\nif (CurrentSOC < 95)\n{\n Batteryitem = \" Battery @ \" + CurrentSOC + \"%.\";\n}\n\nvar dtime = hours + \":\" + minutes + \".\";\nmsg.title = \"From Victron:\";\n\n//node.warn(msg);\n\nif (msg.payload != previous_switch_value)\n{\n switch (msg.payload)\n {\n case true:\n {\n previous_switch_value = msg.payload; \n msg.payload = \"Starting \";\n break;\n }\n case false:\n {\n previous_switch_value = msg.payload;\n msg.payload = \"Stopping \";\n break;\n }\n default:\n {\n break;\n }\n }\n flow.set(\"previous_switch_value\", previous_switch_value);\n msg.payload = msg.payload + \"Forced Discharge @ \" + dtime + Batteryitem;\n return msg;\n}\n", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 1000, "y": 540, "wires": [ [ "b618980be2f80433" ] ] }, { "id": "354298a0134bacbc", "type": "inject", "z": "4aede9ec59461e66", "name": "reset previous switch value", "props": [ { "p": "payload" }, { "p": "topic", "vt": "str" } ], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "", "payloadType": "date", "x": 490, "y": 520, "wires": [ [ "3c9bd6bc16e9c18d" ] ] }, { "id": "3c9bd6bc16e9c18d", "type": "function", "z": "4aede9ec59461e66", "name": "function 2", "func": "var previous_switch_value = flow.get(\"previous_switch_value\");\n\nprevious_switch_value = !previous_switch_value;\nflow.set(\"previous_switch_value\",previous_switch_value);\nreturn msg;", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 680, "y": 520, "wires": [ [ "e24d8020656549e2" ] ] }, { "id": "210c51015ba0f699", "type": "victron-input-battery", "z": "4aede9ec59461e66", "service": "com.victronenergy.battery/512", "path": "/Alarms/InternalFailure", "serviceObj": { "service": "com.victronenergy.battery/512", "name": "Pylontech battery" }, "pathObj": { "path": "/Alarms/InternalFailure", "type": "enum", "name": "Internal error alarm", "enum": { "0": "No alarm", "1": "Warning", "2": "Alarm" } }, "initial": "", "name": "", "onlyChanges": false, "x": 170, "y": 460, "wires": [ [ "5722f5088bc0a52d" ] ] }, { "id": "ae6730d0bd3c3b76", "type": "ui_switch", "z": "4aede9ec59461e66", "name": "", "label": "Battery Alarm:", "tooltip": "", "group": "4c71a0775513569d", "order": 2, "width": 0, "height": 0, "passthru": true, "decouple": "false", "topic": "topic", "topicType": "msg", "style": "", "onvalue": "true", "onvalueType": "bool", "onicon": "", "oncolor": "", "offvalue": "false", "offvalueType": "bool", "officon": "", "offcolor": "", "animate": false, "className": "", "x": 660, "y": 460, "wires": [ [ "7d7cf93c83e8b145" ] ] }, { "id": "5722f5088bc0a52d", "type": "function", "z": "4aede9ec59461e66", "name": "function 3", "func": "switch(msg.paylod)\n{\n case 0:\n {\n msg.payload = false;\n break;\n }\n case 1:\n {\n msg.payload = true;\n break;\n } \n case 2:\n {\n msg.payload = true;\n break;\n } \n default:\n {\n break;\n } \n}\n\nreturn msg;", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 420, "y": 460, "wires": [ [ "ae6730d0bd3c3b76" ] ] }, { "id": "7d7cf93c83e8b145", "type": "function", "z": "4aede9ec59461e66", "name": "Send message on Battery Alarm", "func": "var dt = new Date();\nvar hours = dt.getHours();\nvar minutes = dt.getMinutes();\n\nif (hours <= 9)\n{\n hours = \"0\" + hours;\n}\n\nif (minutes <= 9)\n{\n minutes = \"0\" + minutes;\n}\n\nvar dtime = hours + \":\" + minutes + \".\";\nmsg.title = \"From Victron:\";\n\nnode.warn(msg);\n switch (msg.payload)\n {\n case true:\n {\n msg.payload = \"Battery Alarm triggered @ \" + dtime;\n break;\n }\n case false:\n {\n break;\n }\n default:\n {\n break;\n }\n }\nreturn msg;\n\n", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 990, "y": 460, "wires": [ [ "b618980be2f80433" ] ] }, { "id": "c80b0ff75dfebf02", "type": "inject", "z": "4aede9ec59461e66", "name": "", "props": [ { "p": "payload" }, { "p": "topic", "vt": "str" } ], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "true", "payloadType": "bool", "x": 690, "y": 420, "wires": [ [ "7d7cf93c83e8b145" ] ] }, { "id": "11de7f2b239686be", "type": "file", "z": "4aede9ec59461e66", "g": "d70dfb5177478915", "name": "Save Start SOC", "filename": "/data/home/nodered/StartSOC.txt", "filenameType": "str", "appendNewline": false, "createDir": true, "overwriteFile": "true", "encoding": "none", "x": 720, "y": 60, "wires": [ [ "c1df7a1b18181138" ] ] }, { "id": "ae94d037e45ed09b", "type": "file", "z": "4aede9ec59461e66", "g": "d70dfb5177478915", "name": "Save Stop SOC", "filename": "/data/home/nodered/StopSOC.txt", "filenameType": "str", "appendNewline": false, "createDir": true, "overwriteFile": "true", "encoding": "none", "x": 720, "y": 120, "wires": [ [ "c7c8322cefc4a7f2" ] ] }, { "id": "07a1a9088b1dfd5a", "type": "file in", "z": "4aede9ec59461e66", "g": "d70dfb5177478915", "name": "Load Start SOC", "filename": "/data/home/nodered/StartSOC.txt", "filenameType": "str", "format": "utf8", "chunk": false, "sendError": false, "encoding": "none", "allProps": false, "x": 280, "y": 60, "wires": [ [ "1633bb19a9ddd729" ] ] }, { "id": "2e0f46abf287daa1", "type": "file in", "z": "4aede9ec59461e66", "g": "d70dfb5177478915", "name": "Load Stop SOC", "filename": "/data/home/nodered/StopSOC.txt", "filenameType": "str", "format": "utf8", "chunk": false, "sendError": false, "encoding": "none", "allProps": false, "x": 280, "y": 120, "wires": [ [ "1c5c5da971b5e512" ] ] }, { "id": "e9a9bebc9c4732d0", "type": "change", "z": "4aede9ec59461e66", "g": "11c0695b7819894f", "name": "battery capacity", "rules": [ { "t": "set", "p": "payload", "pt": "msg", "to": "dess.options.b_max", "tot": "flow" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 320, "y": 1880, "wires": [ [ "b68ffdbbf4152cf3" ] ] }, { "id": "b48a8f507e14330a", "type": "victron-output-custom", "z": "4aede9ec59461e66", "g": "11c0695b7819894f", "service": "com.victronenergy.settings", "path": "/Settings/DynamicEss/BatteryCapacity", "serviceObj": { "service": "com.victronenergy.settings", "name": "com.victronenergy.settings" }, "pathObj": { "path": "/Settings/DynamicEss/BatteryCapacity", "name": "/Settings/DynamicEss/BatteryCapacity", "type": "number" }, "name": "", "onlyChanges": false, "x": 940, "y": 1880, "wires": [] }, { "id": "b68ffdbbf4152cf3", "type": "change", "z": "4aede9ec59461e66", "g": "11c0695b7819894f", "name": "to number", "rules": [ { "t": "set", "p": "payload", "pt": "msg", "to": "$number(payload)", "tot": "jsonata" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 510, "y": 1880, "wires": [ [ "b48a8f507e14330a" ] ] }, { "id": "8d723ea6a3f644bc", "type": "link in", "z": "4aede9ec59461e66", "g": "11c0695b7819894f", "name": "link in 1", "links": [ "0a258a4a88409834", "fa866313f9c8bebf" ], "x": 155, "y": 1880, "wires": [ [ "e9a9bebc9c4732d0" ] ] }, { "id": "10c4208410261312", "type": "file in", "z": "4aede9ec59461e66", "name": "", "filename": "", "filenameType": "str", "format": "utf8", "chunk": false, "sendError": false, "encoding": "none", "allProps": false, "x": 1040, "y": 700, "wires": [ [] ] }, { "id": "0d2647a790e9005e", "type": "inject", "z": "57d9411237352b64", "name": "inject", "props": [ { "p": "payload" }, { "p": "topic", "vt": "str" } ], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "", "payloadType": "date", "x": 110, "y": 100, "wires": [ [ "aae41bc8d4579755" ] ] }, { "id": "aae41bc8d4579755", "type": "function", "z": "57d9411237352b64", "name": "Data Download for day", "func": "msg.headers = {};\nsitenumber = \"999999\";\n\nvar d = new Date();\n\nvar day=d.getDate();\nvar month=d.getMonth();\nvar year=d.getFullYear();\nday = day-1;\n\nvar previousday = new Date(year,month,day);\n// gets the unix time in second format\nvar unixtimemidnight = previousday.getTime()/1000;\nvar unixtime2345 = unixtimemidnight + 85500;\nvar starttime = unixtimemidnight.toString();\nvar endtime = unixtime2345.toString();\n\nmsg.headers = {\n \"X-Authorization\" : \"Token XXXXXX\",\n 'Content-Type': 'application/json'\n };\nmsg.httpRequestTimeout = 60000;\nmsg.method = \"GET\";\nmsg.url = \"https://vrmapi.victronenergy.com/v2/installations/\" + sitenumber + \"/data-download?start=\" + starttime + \"&end=\" + endtime + \"&datatype=kwh&format=csv\";\nmsg.payload = {};\nreturn msg;", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 320, "y": 100, "wires": [ [ "f4d27b879cfef6a4" ] ] }, { "id": "6822054c6a5ff970", "type": "function", "z": "57d9411237352b64", "name": "Put Daily data in 15 minute array", "func": "var data=msg.payload;\nvar temp=data.split(\"\\n\");\n//node.warn(temp);\n\nnode.warn(temp.length);\n\nvar Fifteenminutearray = [];\nvar minutedata = \"\";\n\nvar Gridtobattery = 0;\nvar Gridtoconsumer = 0;\nminutedata= temp[2].split(\",\");\n//node.warn(minutedata);\n\nvar temp2 = (minutedata[7]);\ntemp2 = temp2.substr(1,temp2.length-2);\n//node.warn(temp2);\n\n\n\nvar temp3 = parseFloat(temp2);\n//node.warn(temp3);\nvar value;\nvar valuefloat =0.0;\n\n//node.warn(minutedata);\nfor (let x = 2; x< temp.length; x ++)\n//\n{\n var temparray = [];\n minutedata = temp[x].split(\",\");\n// node.warn(minutedata);\n for (let y = 0; y0)\n {\n value = parseFloat(value);\n if(isNaN(value))\n value = 0;\n }\n temparray.push(value); \n }\n// node.warn(temparray);\n// Gridtobattery = parseFloat(minutedata[2]);\n// node.warn(Gridtobattery);\n Fifteenminutearray[x-2] = temparray;\n//node.warn(minutedata[2]);\n}\n//\n\n//node.warn(Fifteenminutearray);\nmsg.payload = Fifteenminutearray;\nreturn msg;", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 870, "y": 480, "wires": [ [ "775913279513ccfb" ] ] }, { "id": "775913279513ccfb", "type": "function", "z": "57d9411237352b64", "name": "Convert 15 minute array to hourly", "func": "var Fifteenminutearray = msg.payload;\nvar Hourlyarray = [];\n\nvar value1 = 0;\nvar value2 = 0;\nvar value3 = 0;\nvar value4 = 0;\n\n//node.warn(Fifteenminutearray);\n\nfor(let x = 0; x < Fifteenminutearray.length; x +4)\n{\n Hourlyarray[x] = Fifteenminutearray[x];\n node.warn(Hourlyarray[x][7]);\n node.warn(Hourlyarray[x].length);\n for (let y = 1; y < Hourlyarray[x].length; y++)\n {\n node.warn(y);\n node.warn(x);\n// node.warn(Hourlyarray[x][y]);\n value1 = Hourlyarray[x][y];\n// value2 = Hourlyarray[x+1][y];\n// value3 = Hourlyarray[x+2][y];\n// value4 = Hourlyarray[x+3][y];\n \n node.warn(value1);\n// node.warn(value2);\n// node.warn(value3);\n// node.warn(value4);\n \n \n// Hourlyarray[x][y] = value1 + value2 + value3 + value4;\n }\n}\nnode.warn(Hourlyarray);\n\nreturn msg;\n\n", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 860, "y": 540, "wires": [ [ "8b9f5098b7c836f1" ] ] }, { "id": "e4e8c1369b3db954", "type": "debug", "z": "57d9411237352b64", "name": "debug 11", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "true", "targetType": "full", "statusVal": "", "statusType": "auto", "x": 740, "y": 440, "wires": [] }, { "id": "1c0269248b30d14c", "type": "subflow:92f743ea8d8588a4", "z": "57d9411237352b64", "g": "39e068921febf967", "name": "Graham's Forecast Solar ", "env": [ { "name": "latitude", "value": "51.425962", "type": "num" }, { "name": "longitude", "value": ".369632", "type": "num" }, { "name": "declination", "value": "32", "type": "num" }, { "name": "modules power", "value": "6.55", "type": "num" }, { "name": "apikey", "type": "cred" }, { "name": "watt", "value": "watt_hours_period", "type": "str" }, { "name": "kwhoutput", "type": "bool", "value": "false" }, { "name": "daystoforecast", "value": "1", "type": "str" }, { "name": "widengraph", "type": "bool", "value": "false" } ], "x": 350, "y": 640, "wires": [ [ "d3a0054f46f35e67" ] ] }, { "id": "622417c86656a55a", "type": "inject", "z": "57d9411237352b64", "g": "39e068921febf967", "name": "", "props": [ { "p": "payload" }, { "p": "topic", "vt": "str" } ], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "", "payloadType": "date", "x": 140, "y": 700, "wires": [ [] ] }, { "id": "a0639ff12d6cc588", "type": "function", "z": "57d9411237352b64", "g": "39e068921febf967", "name": "Forecast.Solar", "func": "flow.set('Forecast.Solar', msg.payload);\nreturn msg;", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 700, "y": 680, "wires": [ [] ], "icon": "node-red/file-in.svg" }, { "id": "68fab40506af3cc1", "type": "vrm-api", "z": "57d9411237352b64", "g": "39e068921febf967", "vrm": "5fcd0bce74e72cb7", "name": "Victron VRM API PV forecast", "idSite": "999999", "installations": "stats", "attribute": "vrm_pv_inverter_yield_fc", "stats_interval": "hours", "stats_start": "0", "stats_end": "86400", "verbose": true, "x": 380, "y": 740, "wires": [ [ "e4f221e6fe2b838d", "cdb6839d04f6eeed" ] ] }, { "id": "a645d5888e08d5a5", "type": "http request", "z": "57d9411237352b64", "g": "39e068921febf967", "name": "Solcast ", "method": "GET", "ret": "obj", "paytoqs": "ignore", "url": "https://api.solcast.com.au/rooftop_sites/3404-1032-c059-2b50/forecasts?format=json", "tls": "", "persist": false, "proxy": "", "insecureHTTPParser": false, "authType": "basic", "senderr": false, "headers": [], "x": 300, "y": 860, "wires": [ [ "034ffd0a4563878a" ] ] }, { "id": "034ffd0a4563878a", "type": "debug", "z": "57d9411237352b64", "g": "39e068921febf967", "name": "debug 19", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "true", "targetType": "full", "statusVal": "", "statusType": "auto", "x": 480, "y": 860, "wires": [] }, { "id": "e4f221e6fe2b838d", "type": "debug", "z": "57d9411237352b64", "g": "39e068921febf967", "name": "debug 20", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "false", "statusVal": "", "statusType": "auto", "x": 700, "y": 740, "wires": [] }, { "id": "d3a0054f46f35e67", "type": "debug", "z": "57d9411237352b64", "g": "39e068921febf967", "name": "debug 21", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "false", "statusVal": "", "statusType": "auto", "x": 580, "y": 640, "wires": [] }, { "id": "6d8285772aea9b8e", "type": "function", "z": "57d9411237352b64", "g": "39e068921febf967", "name": "function 12", "func": "\nreturn msg;", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 570, "y": 780, "wires": [ [] ] }, { "id": "cdb6839d04f6eeed", "type": "link out", "z": "57d9411237352b64", "g": "39e068921febf967", "name": "link out 11", "mode": "link", "links": [ "5807c3c729663294" ], "x": 565, "y": 700, "wires": [] }, { "id": "f62a70f909344197", "type": "link in", "z": "57d9411237352b64", "g": "39e068921febf967", "name": "link in 23", "links": [ "0b03709b13ba8140" ], "x": 215, "y": 740, "wires": [ [ "68fab40506af3cc1" ] ] } ]