-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathdata-view.flow
1 lines (1 loc) · 35.2 KB
/
data-view.flow
1
[{"id":"d13463e4.f8d44","type":"mqtt in","z":"c9203fa7.8d00a","name":"Grid Power","topic":"grid/power","qos":"2","broker":"3256e0e9.783578","x":130,"y":140,"wires":[["2a3ccf2e.c106"]]},{"id":"9d383893.2c69f8","type":"mqtt in","z":"c9203fa7.8d00a","name":"Grid Power In","topic":"grid/power_in","qos":"2","broker":"3256e0e9.783578","x":130,"y":340,"wires":[["d9f11fec.dd94f8"]]},{"id":"383cc75c.c55b8","type":"mqtt in","z":"c9203fa7.8d00a","name":"Grid Power Out","topic":"grid/power_out","qos":"2","broker":"3256e0e9.783578","x":140,"y":280,"wires":[["54c73114.f078d"]]},{"id":"54c73114.f078d","type":"function","z":"c9203fa7.8d00a","name":"Convert to Negative","func":"msg.payload = parseFloat(msg.payload) * -1\nif(msg.payload<0) return msg;","outputs":1,"noerr":0,"x":360,"y":280,"wires":[["d9f11fec.dd94f8"]]},{"id":"cd4d8f4f.965a28","type":"comment","z":"c9203fa7.8d00a","name":"Grid Power Flow For Two Separate Meters for Import/Export","info":"If meter can't provide negative values, two meters are needed.","x":280,"y":200,"wires":[]},{"id":"19f46c3.c3b5114","type":"comment","z":"c9203fa7.8d00a","name":"Grid Power for Meter That Can Provide Negative Values","info":"","x":260,"y":100,"wires":[]},{"id":"2a3ccf2e.c106","type":"function","z":"c9203fa7.8d00a","name":"Convert to Float and Save","func":"msg.payload = parseFloat(msg.payload)\nflow.set('grid_power',msg.payload)\nreturn msg;","outputs":1,"noerr":0,"x":370,"y":240,"wires":[[]]},{"id":"d0e7e4f8.ef28e","type":"function","z":"c9203fa7.8d00a","name":"Calculate Power","func":"const inverters = global.get('inverters')\nconst now = Date.now()\nconst roundToOne = n => Math.round(n*10)/10\nconst settings = global.get('settings')\nconst price = parseFloat(settings['price']||0)/1000\nconst cost = (w) => Math.round(price * w * 100)/100\n\n\nlet totalInverterPwr = 0\n \n\nfor(let id in inverters){\n const inverter = inverters[id]\n const inverterDataAge = now-inverter.lastUpdate\n if(inverter.active==='1' || inverterDataAge < 20000){\n totalInverterPwr += inverter.acPower\n }\n}\n\n\n\nconst unit = settings['monetary_unit'] || \"\"\nconst solarSaving = cost(totalInverterPwr)\n\nlet powerConsumption = 0\nconst gridPower = flow.get('grid_power')\nconst gridPowerOut = flow.get('grid_power_out')\n\nif(gridPower===0){\n powerConsumption += gridPowerOut\n}\nelse{\n powerConsumption += gridPower\n}\n\nconst gridCost = cost(gridPower)\n\npowerConsumption += totalInverterPwr\n\nreturn [\n {payload: roundToOne(powerConsumption)},\n {payload: roundToOne(gridPower>0||gridPower<0 ? gridPower : gridPowerOut),\n topic: `${gridCost} ${unit}/h`\n },\n {payload: roundToOne(totalInverterPwr),\n topic: `${solarSaving} ${unit}/h`\n }\n];","outputs":3,"noerr":0,"x":360,"y":440,"wires":[["8341050a.53aa78","3f124c79.77ffcc","e2b2995.63303e8"],["8954b9f9.affa6"],["89e60cea.ff7108","b0507b52.09ecc","a7dd587b.9eabd"]],"outputLabels":["Power Consumption","Grid Power","Solar Power"]},{"id":"ceab359e.29a568","type":"inject","z":"c9203fa7.8d00a","name":"Once a second","topic":"","payload":"","payloadType":"date","repeat":"1","crontab":"","once":true,"onceDelay":"5","x":160,"y":440,"wires":[["d0e7e4f8.ef28e"]]},{"id":"8341050a.53aa78","type":"ui_gauge","z":"c9203fa7.8d00a","name":"Consumption","group":"905ac2ff.0ef58","order":0,"width":"4","height":"4","gtype":"gage","title":"","label":"W","format":"{{value}}","min":0,"max":"7000","colors":["#00B500","#E6E600","#CA3838"],"seg1":"2500","seg2":"5000","x":620,"y":440,"wires":[]},{"id":"8954b9f9.affa6","type":"ui_gauge","z":"c9203fa7.8d00a","name":"Grid","group":"ed849b5e.f52f18","order":0,"width":"4","height":"4","gtype":"gage","title":"{{msg.topic}}","label":"W","format":"{{value}}","min":"-7000","max":"7000","colors":["#00B500","#E6E600","#CA3838"],"seg1":"0","seg2":"4000","x":590,"y":480,"wires":[]},{"id":"89e60cea.ff7108","type":"ui_gauge","z":"c9203fa7.8d00a","name":"Solar","group":"c82bdb5e.575a48","order":0,"width":"4","height":"4","gtype":"gage","title":"{{msg.topic}}","label":"W","format":"{{value}}","min":0,"max":"2400","colors":["#00b500","#e6e600","#ca3838"],"seg1":"800","seg2":"1600","x":590,"y":520,"wires":[]},{"id":"dc8c70a.d275a9","type":"inject","z":"c9203fa7.8d00a","name":"0","topic":"0","payload":"","payloadType":"num","repeat":"","crontab":"","once":true,"onceDelay":0.1,"x":130,"y":520,"wires":[["8954b9f9.affa6"]]},{"id":"e2b2995.63303e8","type":"function","z":"c9203fa7.8d00a","name":"Determine Power Limit","func":"const settings = global.get('settings') || {}\n\nconst inUse = settings.power_limit || \"true\"\nconst gridPower = flow.get('grid_power') || 0\nconst gridPowerOut = flow.get('grid_power_out') || 0\nlet consumptionAdjustment = context.get('consumption_adjustment') || 0\n\n//If we do not get a value for grid back feed we must adjust the assumed consumption until grid import is positive to prevent back feed.\nif(gridPower===0 && gridPowerOut===0){\n consumptionAdjustment += 10\n}else{\n consumptionAdjustment = 0\n}\n\nmsg.payload = msg.payload - consumptionAdjustment\nmsg.payload = msg.payload > 0 ? msg.payload : 200\n\ncontext.set('consumption_adjustment',consumptionAdjustment)\n\nif(inUse === 'true'){\n return msg\n}","outputs":1,"noerr":0,"x":400,"y":700,"wires":[["79a812ca.19b2b4"]]},{"id":"79a812ca.19b2b4","type":"mqtt out","z":"c9203fa7.8d00a","name":"Power Limit","topic":"powerLimit","qos":"","retain":"","broker":"3256e0e9.783578","x":810,"y":700,"wires":[]},{"id":"2a20b467.4ce7b4","type":"function","z":"c9203fa7.8d00a","name":"Reset Vars","func":"flow.set('grid_power',0)\nflow.set('grid_power_out',0)\nreturn msg;","outputs":1,"noerr":0,"x":290,"y":40,"wires":[["2436d9bc.58437e","e1860bbc.f6df98"]]},{"id":"94183320.b5e95","type":"comment","z":"c9203fa7.8d00a","name":"Settings","info":"","x":100,"y":1360,"wires":[]},{"id":"24126b63.0cebb4","type":"bigmongo in","z":"c9203fa7.8d00a","service":"_ext_","configNode":"e7706f11.1fe1c","name":"Find settings","collection":"settings","operation":"find.toArray","x":130,"y":1500,"wires":[["e71b3f0a.33ba48"],[]]},{"id":"915ed8.78a41128","type":"function","z":"c9203fa7.8d00a","name":"Inject {}","func":"msg.payload = {}\nreturn msg;","outputs":1,"noerr":0,"x":120,"y":1440,"wires":[["24126b63.0cebb4"]]},{"id":"e71b3f0a.33ba48","type":"function","z":"c9203fa7.8d00a","name":"Read Settings","func":"\nconst associated = {}\nfor(let i in msg.payload){\n associated[msg.payload[i].name] = msg.payload[i].value\n \n}\nmsg.payload = associated\nglobal.set('settings',msg.payload)\nreturn msg;","outputs":1,"noerr":0,"x":320,"y":1500,"wires":[["e8c91d5a.eb3a"]]},{"id":"38225d85.cce44a","type":"inject","z":"c9203fa7.8d00a","name":"At Startup","topic":"At Startup","payload":"","payloadType":"date","repeat":"","crontab":"","once":true,"onceDelay":"3","x":130,"y":1400,"wires":[["915ed8.78a41128"]]},{"id":"e8c91d5a.eb3a","type":"function","z":"c9203fa7.8d00a","name":"Init UI","func":"\nreturn [\n {payload: msg.payload.power_limit||'1'},\n {payload: msg.payload.price||0},\n {payload: msg.payload.monetary_unit||''}];","outputs":3,"noerr":0,"x":490,"y":1500,"wires":[["6ebbf65c.62ebe8"],["521893f1.525bfc"],["95a1e5af.59f0d8"]],"outputLabels":["Power Limit","Energy Price","Monetary Unit"]},{"id":"6ebbf65c.62ebe8","type":"ui_switch","z":"c9203fa7.8d00a","name":"Prevent Grid Backfeed","label":"Prevent Grid Backfeed","group":"65998117.00a648","order":0,"width":0,"height":0,"passthru":false,"decouple":"false","topic":"power_limit","style":"","onvalue":"true","onvalueType":"str","onicon":"","oncolor":"","offvalue":"false","offvalueType":"str","officon":"","offcolor":"","x":700,"y":1480,"wires":[["2b2b71c2.dc4e86"]]},{"id":"521893f1.525bfc","type":"ui_numeric","z":"c9203fa7.8d00a","name":"Price /kWh","label":"Price /kWh","group":"65998117.00a648","order":0,"width":0,"height":0,"passthru":false,"topic":"price","format":"{{value}}","min":0,"max":"100","step":"0.01","x":670,"y":1520,"wires":[["2b2b71c2.dc4e86"]]},{"id":"95a1e5af.59f0d8","type":"ui_text_input","z":"c9203fa7.8d00a","name":"Monetary Unit","label":"Monetary Unit","group":"65998117.00a648","order":0,"width":0,"height":0,"passthru":false,"mode":"text","delay":300,"topic":"monetary_unit","x":680,"y":1560,"wires":[["2b2b71c2.dc4e86"]]},{"id":"2b2b71c2.dc4e86","type":"function","z":"c9203fa7.8d00a","name":"Create Query","func":"\nconst query = [\n {'name':msg.topic},\n {'$set': {'value': msg.payload }},\n {'upsert': true}\n ]\nmsg.payload = query\nreturn msg;","outputs":1,"noerr":0,"x":670,"y":1640,"wires":[["163f937f.95905d"]]},{"id":"163f937f.95905d","type":"bigmongo in","z":"c9203fa7.8d00a","service":"_ext_","configNode":"e7706f11.1fe1c","name":"Save Settings","collection":"settings","operation":"findOneAndUpdate","x":680,"y":1700,"wires":[["cbc96e0d.42c24","915ed8.78a41128"],[]]},{"id":"cbc96e0d.42c24","type":"debug","z":"c9203fa7.8d00a","name":"Saved Settings","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","x":920,"y":1700,"wires":[]},{"id":"ed93e3.ad72142","type":"inject","z":"c9203fa7.8d00a","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":true,"onceDelay":"5","x":130,"y":40,"wires":[["2a20b467.4ce7b4"]]},{"id":"3f124c79.77ffcc","type":"mqtt out","z":"c9203fa7.8d00a","name":"Power Consumption","topic":"power_consumption","qos":"","retain":"","broker":"3256e0e9.783578","x":640,"y":580,"wires":[]},{"id":"b0507b52.09ecc","type":"mqtt out","z":"c9203fa7.8d00a","name":"Solar Power","topic":"solar_power","qos":"0","retain":"false","broker":"3256e0e9.783578","x":610,"y":640,"wires":[]},{"id":"beeae7fd.1ee508","type":"comment","z":"c9203fa7.8d00a","name":"Energy Recording","info":"","x":130,"y":720,"wires":[]},{"id":"2cc09eed.deaba2","type":"mqtt in","z":"c9203fa7.8d00a","name":"Solar Energy","topic":"solar/energy","qos":"2","broker":"3256e0e9.783578","x":110,"y":820,"wires":[["fc15c554.61035","1ae7da6b.fd3d2e"]]},{"id":"6bd1b3eb.09ae44","type":"mqtt in","z":"c9203fa7.8d00a","name":"Grid Energy","topic":"grid/energy","qos":"2","broker":"3256e0e9.783578","x":110,"y":880,"wires":[["fc15c554.61035","e380bdd7.a2844"]]},{"id":"fc15c554.61035","type":"function","z":"c9203fa7.8d00a","name":"Save","func":"const energyThisHour = flow.get('energyThisHour') || {}\nconst energyPreviousHour = flow.get('energyPreviousHour') || {}\nlet floatPayload = parseFloat(msg.payload)\nenergyThisHour[msg.topic] = isNaN(floatPayload) ? energyThisHour[msg.topic] || 0 : floatPayload;\n\n//Invalidate the previous hour reading if it looks like the totalizer has started from zero\n\nif(!isNaN(floatPayload)){\n \n if(energyPreviousHour[msg.topic] === 0){\n energyPreviousHour[msg.topic] = floatPayload\n }\n if( typeof energyPreviousHour[msg.topic] === 'undefined' ){\n energyPreviousHour[msg.topic] = 0\n }\n \n const fixedDoubleString = floatPayload.toFixed(4)\n if(fixedDoubleString===\"0.0000\"){\n energyPreviousHour[msg.topic] = 0\n }\n \n flow.set('energyPreviousHour',energyPreviousHour)\n}\n \n\nflow.set('energyThisHour',energyThisHour)\nmsg.payload = energyThisHour\nreturn [msg,{payload:energyPreviousHour,topic:msg.topic}];","outputs":2,"noerr":0,"x":390,"y":860,"wires":[["ff575d5d.ba0d58"],["8deffeb0.31252"]],"outputLabels":["energyThisHour","energyPreviousHour"]},{"id":"d24b9a24.51c89","type":"inject","z":"c9203fa7.8d00a","name":"Once per minute","topic":"Once per minute","payload":"","payloadType":"date","repeat":"60","crontab":"","once":true,"onceDelay":0.1,"x":130,"y":1020,"wires":[["40da90a5.079b1"]]},{"id":"40da90a5.079b1","type":"function","z":"c9203fa7.8d00a","name":"On the hour","func":"const now = new Date()\nconst m = now.getMinutes()\nif(m===0){\n msg.payload = now.getHours()\n return msg;\n}","outputs":1,"noerr":0,"x":340,"y":1020,"wires":[["e1860bbc.f6df98","1199300a.129758","61113c51.410d84"]]},{"id":"e1860bbc.f6df98","type":"function","z":"c9203fa7.8d00a","name":"Collect this hour","func":"const energyThisHour = flow.get('energyThisHour')\nconst energyPreviousHour = flow.get('energyPreviousHour') || {}\nconst energyToday = flow.get('energyToday') || {}\nconst copy = Object.assign({},energyThisHour)\nconst m = new Date().getMinutes().toString()\nconst h = new Date().getHours().toString()\n\n//Insert new data into the flow var\nfor(let id in energyThisHour){\n const hourlyData = energyToday[h] || {} \n hourlyData[id] = energyThisHour[id] - (energyPreviousHour[id] || 0)\n energyToday[h] = hourlyData\n}\nflow.set('energyToday',energyToday)\n\n\n//Create payload for bar chart\nconst series = []\nconst labels = []\nconst data = []\n\n\nfor( let seriesId in energyToday[h]){\n series.push(seriesId)\n}\n\nfor( let seriesIdx in series ){\n const seriesName = series[seriesIdx]\n const thisSeriesData = []\n data.push(thisSeriesData)\n for( let hourNum=0; hourNum<24; hourNum++ ){\n const hour = hourNum.toString()\n if( typeof energyToday[hour] !== 'undefined'){\n thisSeriesData.push(energyToday[hour][seriesName])\n }else{\n thisSeriesData.push(0)\n }\n \n }\n}\n\nfor( let hour=0; hour<24; hour++){\n labels.push(hour.toString())\n}\n\nmsg.payload = [\n {\n 'series': series,\n 'data': data,\n 'labels': labels\n }\n]\n\n\nflow.set('energyPreviousHour',copy)\nreturn [msg,{payload: flow.get('energyToday')},{payload: flow.get('energyPreviousHour')},{payload: flow.get('energyThisHour')}];","outputs":4,"noerr":0,"x":880,"y":940,"wires":[["4f7628ba.c1cef8","d5b8a0c8.9fd228","57035332.cbad1c"],["24673e62.d30f9a"],["7d383029.7f9d28"],["a1b1aeb0.7a3de"]],"outputLabels":["chart data","hourly_totals","previous_hour","this_hour"]},{"id":"1199300a.129758","type":"debug","z":"c9203fa7.8d00a","name":"On the hour","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","x":870,"y":880,"wires":[]},{"id":"4f7628ba.c1cef8","type":"debug","z":"c9203fa7.8d00a","name":"Chart data","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","x":1130,"y":860,"wires":[]},{"id":"a176d3b6.d8f588","type":"comment","z":"c9203fa7.8d00a","name":"Testing","info":"","x":90,"y":1800,"wires":[]},{"id":"73d2575d.ae80e8","type":"inject","z":"c9203fa7.8d00a","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":100,"y":1880,"wires":[["b62f4ec3.d0963"]]},{"id":"b62f4ec3.d0963","type":"function","z":"c9203fa7.8d00a","name":"Check inverter energy","func":"const energyThisHour = flow.get('energyThisHour')\nmsg.payload = energyThisHour['solar/energy']\n\nreturn msg;","outputs":1,"noerr":0,"x":300,"y":1880,"wires":[["d35724e7.0c7078"]]},{"id":"d35724e7.0c7078","type":"debug","z":"c9203fa7.8d00a","name":"Inverter Energy","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","x":540,"y":1880,"wires":[]},{"id":"1ae7da6b.fd3d2e","type":"debug","z":"c9203fa7.8d00a","name":"Solar/energy","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","x":410,"y":820,"wires":[]},{"id":"bd01a707.810458","type":"mqtt in","z":"c9203fa7.8d00a","name":"Metered Solar Energy","topic":"solar/energy_metered","qos":"2","broker":"3256e0e9.783578","x":140,"y":760,"wires":[["fc15c554.61035"]]},{"id":"d5b8a0c8.9fd228","type":"ui_chart","z":"c9203fa7.8d00a","name":"Energy Today","group":"e3ca8497.c4aac8","order":0,"width":0,"height":0,"label":"24h Avg kW/h","chartType":"bar","legend":"false","xformat":"HH:mm:ss","interpolate":"linear","nodata":"No Data","dot":false,"ymin":"","ymax":"","removeOlder":1,"removeOlderPoints":"","removeOlderUnit":"3600","cutout":0,"useOneColor":false,"colors":["#2ca02c","#98df8a","#666666","#ff9896","#98df8a","#d62728","#ff9896","#9467bd","#c5b0d5"],"useOldStyle":false,"x":1140,"y":900,"wires":[[],[]]},{"id":"f3aefc25.e7ae48","type":"inject","z":"c9203fa7.8d00a","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":340,"y":1060,"wires":[["e1860bbc.f6df98"]]},{"id":"8aa61db8.594a6","type":"inject","z":"c9203fa7.8d00a","name":"","topic":"Inject time","payload":"","payloadType":"date","repeat":"","crontab":"","once":true,"onceDelay":0.1,"x":140,"y":1120,"wires":[["19724283.e6189d"]]},{"id":"19724283.e6189d","type":"function","z":"c9203fa7.8d00a","name":"Get Hour","func":"const now = new Date()\nmsg.payload = now.getHours()\nreturn msg;\n","outputs":1,"noerr":0,"x":350,"y":1120,"wires":[["61113c51.410d84"]]},{"id":"b277f301.1896d","type":"ui_template","z":"c9203fa7.8d00a","group":"e3ca8497.c4aac8","name":"Time","order":0,"width":0,"height":0,"format":"<div layout=\"row\" layout-align=\"start center\">\n <div style=\"width: 28px; height: 20px\">\n \n </div>\n <div style=\"width: 100%\">\n <div style=\"positon: relative; background-color: rgba(176, 186, 156, 0.0); z-index: -100; height:317px; float: left; margin-top: -357px; width:{{ msg.payload }}%\"></div>\n <div style=\"positon: relative; background-color: rgba(176, 186, 156, 0.4); height:317px; float: right; margin-top: -357px; width:{{ 100-msg.payload }}%\"></div>\n </div>\n \n</div>\n<script language=\"javascript\">\n document.getElementById('Energy_Summary_Energy_Summary_cards').children[0].style.zIndex = 1;\n</script>","storeOutMessages":true,"fwdInMessages":false,"templateScope":"local","x":730,"y":1200,"wires":[[]]},{"id":"93d39555.14a578","type":"debug","z":"c9203fa7.8d00a","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":550,"y":1920,"wires":[]},{"id":"61113c51.410d84","type":"function","z":"c9203fa7.8d00a","name":"Percentage","func":"msg.payload = Math.round((msg.payload+1)/24*100)\nreturn msg;","outputs":1,"noerr":0,"x":550,"y":1200,"wires":[["b277f301.1896d"]]},{"id":"c316002c.529148","type":"function","z":"c9203fa7.8d00a","name":"Reset 24h Energy Totalizer","func":"flow.set('energyToday',{})\nreturn msg;","outputs":1,"noerr":0,"x":320,"y":1920,"wires":[["93d39555.14a578"]]},{"id":"969c883.0319478","type":"inject","z":"c9203fa7.8d00a","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":100,"y":1920,"wires":[["c316002c.529148"]]},{"id":"57035332.cbad1c","type":"function","z":"c9203fa7.8d00a","name":"Collect Day","func":"const energyToday = flow.get('energyToday') || {}\nconst m = new Date().getMinutes().toString()\nlet hourNow = new Date().getHours()\n\nhourNow = hourNow===0 ? 24 : hourNow\n\nconst dayTotals = {}\n\nlet cont = true\nlet hour = 0\nwhile(cont){\n if( hour<=hourNow){\n if( typeof energyToday[hour.toString()] !== 'undefined' ){\n for( let id in energyToday[hour.toString()] ){\n \n const reading = parseFloat(energyToday[hour.toString()][id])\n const energy = isNaN(reading) ? 0 : reading\n dayTotals[id] = energy + dayTotals[id] || 0\n \n }\n }\n \n }else{\n cont = false\n }\n \n \n hour += 1\n}\nmsg.payload = dayTotals\nreturn msg;","outputs":1,"noerr":0,"x":1090,"y":1080,"wires":[["8d54e487.0c3238","49d1094b.db719"]]},{"id":"8d54e487.0c3238","type":"debug","z":"c9203fa7.8d00a","name":"Day Totals","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","x":1290,"y":1080,"wires":[]},{"id":"d2c0a50f.84a68","type":"inject","z":"c9203fa7.8d00a","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":900,"y":1080,"wires":[["57035332.cbad1c"]]},{"id":"20fc1d51.c51732","type":"function","z":"c9203fa7.8d00a","name":"Create Query","func":"const data = msg.payload\ndata.timestamp = new Date()\nmsg.payload = [data]\nreturn msg;","outputs":1,"noerr":0,"x":1490,"y":1140,"wires":[["8db4fdb3.efe5f8"]]},{"id":"8db4fdb3.efe5f8","type":"bigmongo in","z":"c9203fa7.8d00a","service":"_ext_","configNode":"e7706f11.1fe1c","name":"Save Daily Energy","collection":"energy","operation":"insertOne","x":1690,"y":1100,"wires":[["a9adb9b5.a18e6","2436d9bc.58437e"],[]]},{"id":"49d1094b.db719","type":"function","z":"c9203fa7.8d00a","name":"After Midnight","func":"const hourNow = new Date().getHours()\nif(hourNow===0){\n return msg;\n}\n","outputs":1,"noerr":0,"x":1300,"y":1140,"wires":[["20fc1d51.c51732"]]},{"id":"a9adb9b5.a18e6","type":"debug","z":"c9203fa7.8d00a","name":"Mongo DB Return ","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","x":1920,"y":1100,"wires":[]},{"id":"e380bdd7.a2844","type":"debug","z":"c9203fa7.8d00a","name":"Grid/energy","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","x":410,"y":780,"wires":[]},{"id":"f486fb43.028658","type":"bigmongo in","z":"c9203fa7.8d00a","service":"_ext_","configNode":"e7706f11.1fe1c","name":"Load Daily Energy","collection":"energy","operation":"find.toArray","x":1570,"y":640,"wires":[["4a9b32c0.310334","a1dcb424.0053b"],[]]},{"id":"2436d9bc.58437e","type":"function","z":"c9203fa7.8d00a","name":"Inject Dates","func":"const endDate = new Date()\nconst startDate = new Date()\nstartDate.setDate(startDate.getDate() - 30)\n\n\nmsg.payload = {\n timestamp: {\n $gte: startDate,\n $lt: endDate\n }\n}\n\nreturn msg;","outputs":1,"noerr":0,"x":1360,"y":640,"wires":[["f486fb43.028658","40db1a08.d049fc"]]},{"id":"d8fbd0f1.e27a2","type":"debug","z":"c9203fa7.8d00a","name":"Energy Collected","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","x":2070,"y":640,"wires":[]},{"id":"71a06f63.2618e8","type":"inject","z":"c9203fa7.8d00a","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":1160,"y":640,"wires":[["2436d9bc.58437e"]]},{"id":"40db1a08.d049fc","type":"debug","z":"c9203fa7.8d00a","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":1550,"y":700,"wires":[]},{"id":"4a9b32c0.310334","type":"function","z":"c9203fa7.8d00a","name":"Create collection","func":"const days = msg.payload\n\nif(!Array.isArray(days)){\n return\n}\n\nconst numdays = days.length\n\n//Create payload for bar chart\nconst series = []\nconst labels = []\nconst data = []\nconst seriesAssociative = {}\n\nfor( let i in days ){\n const data = days[i]\n for(let key in data){\n if( key !== 'timestamp' && key !== '_id')\n seriesAssociative[key] = 1\n }\n}\n\nfor(let seriesKey in seriesAssociative){\n series.push(seriesKey)\n const thisSeriesData = [] \n data.push(thisSeriesData)\n for(let d in days){\n const thisDaySeriesData = days[d][seriesKey]\n if(thisDaySeriesData){\n thisSeriesData.push(thisDaySeriesData)\n }else{\n thisSeriesData.push(0)\n }\n \n }\n}\n\nconst reverseDates = []\nconst date = new Date()\ndate.setDate(date.getDate() - numdays)\nfor(let n=0; n<numdays; n++){\n reverseDates.push(date.getDate().toString())\n date.setDate(date.getDate() + 1)\n}\n\nfor(let n=0; n<numdays; n++){\n labels.push(reverseDates[n])\n}\n\nmsg.payload = [\n {\n 'series': series,\n 'data': data,\n 'labels': labels\n }\n]\n\nreturn msg;","outputs":1,"noerr":0,"x":1820,"y":640,"wires":[["d8fbd0f1.e27a2","e721178.816e768"]]},{"id":"e721178.816e768","type":"ui_chart","z":"c9203fa7.8d00a","name":"","group":"e3ca8497.c4aac8","order":0,"width":0,"height":0,"label":"Past 30 days kWh/day","chartType":"line","legend":"false","xformat":"HH:mm:ss","interpolate":"linear","nodata":"","dot":false,"ymin":"","ymax":"","removeOlder":1,"removeOlderPoints":"","removeOlderUnit":"3600","cutout":0,"useOneColor":false,"colors":["#ff7f0e","#ff7f0e","#1f77b4","#2ca02c","#98df8a","#d62728","#ff9896","#9467bd","#c5b0d5"],"useOldStyle":false,"x":2080,"y":700,"wires":[[],[]]},{"id":"26161baf.42bd54","type":"persist out","z":"c9203fa7.8d00a","name":"this_hour","storageNode":"713680c7.a7fe8","x":580,"y":40,"wires":[["fefafde1.735d08"]]},{"id":"fefafde1.735d08","type":"function","z":"c9203fa7.8d00a","name":"Restore energy totalizer","func":"flow.set('energyThisHour',msg.payload)\nreturn msg;","outputs":1,"noerr":0,"x":850,"y":40,"wires":[["aa54a874.d763a8"]]},{"id":"457812b.5f814ec","type":"persist out","z":"c9203fa7.8d00a","name":"hourly_totals","storageNode":"713680c7.a7fe8","x":590,"y":80,"wires":[["42407538.0b1194"]]},{"id":"f2cfb32c.05e5a","type":"persist out","z":"c9203fa7.8d00a","name":"previous_hour","storageNode":"713680c7.a7fe8","x":600,"y":120,"wires":[["9b7eae2c.d20a18"]]},{"id":"42407538.0b1194","type":"function","z":"c9203fa7.8d00a","name":"Restore Daily Totalizer","func":"flow.set('energyToday',msg.payload)\nreturn msg;","outputs":1,"noerr":0,"x":840,"y":80,"wires":[["a6944f54.efc6b8"]]},{"id":"9b7eae2c.d20a18","type":"function","z":"c9203fa7.8d00a","name":"Restore Previous Hour","func":"flow.set('energyPreviousHour',msg.payload)\nreturn msg;","outputs":1,"noerr":0,"x":840,"y":120,"wires":[["30fa9240.631a56"]]},{"id":"aa54a874.d763a8","type":"debug","z":"c9203fa7.8d00a","name":"This_hour","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","x":1100,"y":40,"wires":[]},{"id":"a6944f54.efc6b8","type":"debug","z":"c9203fa7.8d00a","name":"Hourly totals","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","x":1110,"y":80,"wires":[]},{"id":"30fa9240.631a56","type":"debug","z":"c9203fa7.8d00a","name":"Previous hour","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","x":1120,"y":120,"wires":[]},{"id":"24673e62.d30f9a","type":"persist in","z":"c9203fa7.8d00a","name":"hourly_totals","storageNode":"713680c7.a7fe8","x":1130,"y":940,"wires":[]},{"id":"7d383029.7f9d28","type":"persist in","z":"c9203fa7.8d00a","name":"previous_hour","storageNode":"713680c7.a7fe8","x":1140,"y":980,"wires":[]},{"id":"a1b1aeb0.7a3de","type":"persist in","z":"c9203fa7.8d00a","name":"this_hour","storageNode":"713680c7.a7fe8","x":1120,"y":1020,"wires":[]},{"id":"ff575d5d.ba0d58","type":"persist in","z":"c9203fa7.8d00a","name":"this_hour","storageNode":"713680c7.a7fe8","x":560,"y":840,"wires":[]},{"id":"700ef808.2dcad","type":"comment","z":"c9203fa7.8d00a","name":"Draw 30-day graph","info":"","x":1170,"y":580,"wires":[]},{"id":"a1dcb424.0053b","type":"debug","z":"c9203fa7.8d00a","name":"Daily Energy Collection","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","x":1820,"y":600,"wires":[]},{"id":"6412f0e7.968248","type":"comment","z":"c9203fa7.8d00a","name":"Draw monthly graphs","info":"","x":1180,"y":260,"wires":[]},{"id":"dca7dc49.ab04b8","type":"function","z":"c9203fa7.8d00a","name":"Inject Dates","func":"\n\nmsg.payload = {\n //All data\n}\n\nreturn msg;","outputs":1,"noerr":0,"x":1360,"y":340,"wires":[["b68e1648.57551"]]},{"id":"b68e1648.57551","type":"bigmongo in","z":"c9203fa7.8d00a","service":"_ext_","configNode":"e7706f11.1fe1c","name":"Load All Energy","collection":"energy","operation":"find.toArray","x":1580,"y":340,"wires":[["872b746a.9eca08","f2e9651.2cdbf18"],[]]},{"id":"872b746a.9eca08","type":"function","z":"c9203fa7.8d00a","name":"Create Collection","func":"const days = msg.payload\nconst optimalProduction = [79,71,79,82,87,85,113,104,100,115,103,98]\nconst statisticalProduction = [65,64,75,83,92,93,121,107,96,101,84,78]\nif(!Array.isArray(days)){\n return\n}\n\nconst numdays = days.length\n\n//Create payload for bar chart\nconst series = [\"Target\",\"Optimal\"]\nconst labels = [\"Jan\",\"Feb\",\"Mar\",\"Apr\",\"May\",\"Jun\",\"Jul\",\"Aug\",\"Sep\",\"Oct\",\"Nov\",\"Dec\"]\nconst data = [statisticalProduction,optimalProduction]\nconst seriesAssociative = {}\nconst dataAssociative = {}\nconst key = \"solar/energy\"\n\n\nfor(let d in days){\n let timestamp = days[d]['timestamp']\n let monthForThisDay = timestamp.toISOString().substring(5,7)\n let yearForThisDay = timestamp.toISOString().substring(0,4)\n \n seriesAssociative[yearForThisDay] = parseInt(yearForThisDay)\n if( !dataAssociative[yearForThisDay] ) dataAssociative[yearForThisDay] = {};\n if( !dataAssociative[yearForThisDay][monthForThisDay] ) dataAssociative[yearForThisDay][monthForThisDay] = 0;\n \n dataAssociative[yearForThisDay][monthForThisDay] += days[d][key]\n \n}\n\n//Find smallest year\nconst firstYear = Object.keys(seriesAssociative).reduce( (earliestYear,key) => seriesAssociative[key] < earliestYear ? seriesAssociative[key] : earliestYear, 9999 )\nconst lastYear = Object.keys(seriesAssociative).reduce( (oldestYear,key) => seriesAssociative[key] > oldestYear ? seriesAssociative[key] : oldestYear, 0 )\n\nfor(y=firstYear; y<=lastYear; y++){\n const yData = [\"01\",\"02\",\"03\",\"04\",\"05\",\"06\",\"07\",\"08\",\"09\",\"10\",\"11\",\"12\"].map( m => {\n\n if( dataAssociative[`${y}`] && dataAssociative[`${y}`][m]){\n return dataAssociative[`${y}`][m]\n }else{\n return 0;\n } \n })\n \n data.push(yData)\n series.push(`${y}`)\n}\n\n\nmsg.payload = [\n {\n 'series': series,\n 'data': data,\n 'labels': labels\n }\n]\n\n\nreturn msg;","outputs":1,"noerr":0,"x":1840,"y":340,"wires":[["5f7cd9e2.122b9","44ef6bdd.4f8e04"]]},{"id":"5f7cd9e2.122b9","type":"debug","z":"c9203fa7.8d00a","name":"Number of All Hours","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","x":2080,"y":340,"wires":[]},{"id":"56d28d14.83cbcc","type":"inject","z":"c9203fa7.8d00a","name":"","topic":"","payload":"","payloadType":"date","repeat":"3600","crontab":"","once":true,"onceDelay":"5","x":1150,"y":340,"wires":[["dca7dc49.ab04b8"]]},{"id":"44ef6bdd.4f8e04","type":"ui_chart","z":"c9203fa7.8d00a","name":"","group":"e3ca8497.c4aac8","order":0,"width":0,"height":0,"label":"Monthly Solar Production (kWh)","chartType":"line","legend":"true","xformat":"HH:mm:ss","interpolate":"bezier","nodata":"","dot":false,"ymin":"","ymax":"","removeOlder":1,"removeOlderPoints":"","removeOlderUnit":"3600","cutout":0,"useOneColor":false,"colors":["#BFC4CA","#5D5E61","#CF7F00","#BF7F00","#AF7F00","#AF8F00","#AF9F00","#AFAF00","#AFBF00"],"useOldStyle":false,"x":2110,"y":400,"wires":[[],[]]},{"id":"f2e9651.2cdbf18","type":"function","z":"c9203fa7.8d00a","name":"Create Collection","func":"const days = msg.payload\n\nif(!Array.isArray(days)){\n return\n}\n\nconst numdays = days.length\n\n//Create payload for bar chart\nconst series = []\nconst labels = [\"Jan\",\"Feb\",\"Mar\",\"Apr\",\"May\",\"Jun\",\"Jul\",\"Aug\",\"Sep\",\"Oct\",\"Nov\",\"Dec\"]\nconst data = []\nconst dataAssociative = {}\nconst seriesAssociative = {}\nconst keys = [\"solar/energy_metered\",\"grid/energy\"]\nconst reducer = (accumulator, currentValue) => accumulator + currentValue;\n\nfor(let d in days){\n let timestamp = days[d]['timestamp']\n let monthForThisDay = timestamp.toISOString().substring(5,7)\n let yearForThisDay = timestamp.toISOString().substring(0,4)\n \n seriesAssociative[yearForThisDay] = parseInt(yearForThisDay)\n if( !dataAssociative[yearForThisDay] ) dataAssociative[yearForThisDay] = {};\n if( !dataAssociative[yearForThisDay][monthForThisDay] ) dataAssociative[yearForThisDay][monthForThisDay] = 0;\n \n dataAssociative[yearForThisDay][monthForThisDay] += keys.reduce( (tot,key) => (days[d][key]||0) + tot, 0 )\n \n}\n\n//Find smallest year\nconst firstYear = Object.keys(seriesAssociative).reduce( (earliestYear,key) => seriesAssociative[key] < earliestYear ? seriesAssociative[key] : earliestYear, 9999 )\nconst lastYear = Object.keys(seriesAssociative).reduce( (oldestYear,key) => seriesAssociative[key] > oldestYear ? seriesAssociative[key] : oldestYear, 0 )\n\nfor(y=firstYear; y<=lastYear; y++){\n const yData = [\"01\",\"02\",\"03\",\"04\",\"05\",\"06\",\"07\",\"08\",\"09\",\"10\",\"11\",\"12\"].map( m => {\n \n \n if( dataAssociative[`${y}`] && dataAssociative[`${y}`][m]){\n return dataAssociative[`${y}`][m]\n }else{\n return 0;\n } \n })\n \n data.push(yData)\n series.push(`${y}`)\n}\n\nmsg.payload = [\n {\n 'series': series,\n 'data': data,\n 'labels': labels\n }\n]\n\n\nreturn msg;","outputs":1,"noerr":0,"x":1850,"y":480,"wires":[["c6901819.23d1c8","d2ccc1d.bc856c"]]},{"id":"c6901819.23d1c8","type":"debug","z":"c9203fa7.8d00a","name":"Number of All Hours","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","x":2080,"y":480,"wires":[]},{"id":"d2ccc1d.bc856c","type":"ui_chart","z":"c9203fa7.8d00a","name":"","group":"e3ca8497.c4aac8","order":0,"width":0,"height":0,"label":"Monthly Consumption (kWh)","chartType":"line","legend":"true","xformat":"HH:mm:ss","interpolate":"bezier","nodata":"","dot":false,"ymin":"","ymax":"","removeOlder":1,"removeOlderPoints":"","removeOlderUnit":"3600","cutout":0,"useOneColor":false,"colors":["#FF7F0E","#DF7F00","#CF7F00","#BF7F00","#AF7F00","#AF8F00","#AF9F00","#AFAF00","#AFBF00"],"useOldStyle":false,"x":2100,"y":540,"wires":[[],[]]},{"id":"d9f11fec.dd94f8","type":"mqtt out","z":"c9203fa7.8d00a","name":"Grid Power","topic":"grid/power","qos":"","retain":"","broker":"3256e0e9.783578","x":650,"y":280,"wires":[]},{"id":"a7dd587b.9eabd","type":"mqtt out","z":"c9203fa7.8d00a","name":"","topic":"solar/power","qos":"","retain":"","broker":"3256e0e9.783578","x":790,"y":640,"wires":[]},{"id":"13b080f.e2a147f","type":"delay","z":"c9203fa7.8d00a","name":"","pauseType":"rate","timeout":"5","timeoutUnits":"seconds","rate":"1","nbRateUnits":"5","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":true,"x":640,"y":700,"wires":[[]]},{"id":"8deffeb0.31252","type":"persist in","z":"c9203fa7.8d00a","name":"previous_hour","storageNode":"713680c7.a7fe8","x":580,"y":880,"wires":[]},{"id":"59c260dc.75fa28","type":"mqtt in","z":"c9203fa7.8d00a","name":"Demand Energy","topic":"demand/energy","qos":"2","broker":"3256e0e9.783578","x":120,"y":940,"wires":[["fc15c554.61035"]]},{"id":"3256e0e9.783578","type":"mqtt-broker","z":"","name":"local_mqtt","broker":"localhost","port":"1883","clientid":"","usetls":false,"compatmode":true,"keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"0","birthRetain":"false","birthPayload":"","closeTopic":"","closeQos":"0","closeRetain":"false","closePayload":"","willTopic":"","willQos":"0","willRetain":"false","willPayload":""},{"id":"905ac2ff.0ef58","type":"ui_group","z":"","name":"Consumption","tab":"8429fd02.33cd9","disp":true,"width":"4","collapse":false},{"id":"ed849b5e.f52f18","type":"ui_group","z":"","name":"Grid","tab":"8429fd02.33cd9","disp":true,"width":"4","collapse":false},{"id":"c82bdb5e.575a48","type":"ui_group","z":"","name":"Solar","tab":"8429fd02.33cd9","disp":true,"width":"4","collapse":false},{"id":"e7706f11.1fe1c","type":"bigmongo","z":"","uri":"mongodb://localhost:27017/solar","name":"solar","options":"","parallelism":"-1","warncodes":"","ignoredcodes":""},{"id":"65998117.00a648","type":"ui_group","z":"","name":"Configuration","tab":"d6c85b96.d8e1f","disp":true,"width":"6","collapse":true},{"id":"e3ca8497.c4aac8","type":"ui_group","z":"","name":"Energy Summary","tab":"b5367a4c.cc5678","order":4,"disp":true,"width":"12","collapse":false},{"id":"713680c7.a7fe8","type":"persist-store","z":"","filename":"/etc/nodered-persist.json","interval":"60"},{"id":"8429fd02.33cd9","type":"ui_tab","z":"","name":"Instant Power","icon":"dashboard","order":1},{"id":"d6c85b96.d8e1f","type":"ui_tab","z":"","name":"Configuration","icon":"dashboard","order":5},{"id":"b5367a4c.cc5678","type":"ui_tab","z":"","name":"Energy Summary","icon":"dashboard","order":2}]