[
  {"id":"mhb-universal-tab","type":"tab","label":"MHB Cerbo koppeling","disabled":false,"info":"Universele MHB-flow. Vul alleen PORTAL_ID en TOKEN in de node MHB-configuratie in."},
  {"id":"mhb-universal-note","type":"comment","z":"mhb-universal-tab","name":"Universeel · vul Portal-ID en unieke sleutel in · geen systeem aan/uit","info":"Gebruik voor iedere klant een eigen sleutel uit MHB Beheer.","x":400,"y":40,"wires":[]},
  {"id":"mhb-universal-poll","type":"inject","z":"mhb-universal-tab","name":"Iedere 2 seconden","props":[{"p":"payload"}],"repeat":"2","once":true,"onceDelay":1,"payload":"","payloadType":"date","x":150,"y":100,"wires":[["mhb-universal-config"]]},
  {"id":"mhb-universal-config","type":"function","z":"mhb-universal-tab","name":"MHB-configuratie · HIER INVULLEN","func":"// Vul per Cerbo alleen deze twee waarden in:\nconst PORTAL_ID = 'VUL_VRM_PORTAL_ID_IN';\nconst TOKEN = 'VUL_UNIEKE_MHB_SLEUTEL_IN';\n\nif(PORTAL_ID.startsWith('VUL_') || TOKEN.startsWith('VUL_')) { node.status({fill:'red',shape:'ring',text:'configuratie invullen'}); return null; }\nflow.set('mhb_portal_id',PORTAL_ID);\nflow.set('mhb_token',TOKEN);\nmsg.method='GET';\nmsg.url='https://mhbbeheer.site/api/cerbo-node-red/'+PORTAL_ID+'/commands/next';\nmsg.headers={'X-MHB-Cerbo-Token':TOKEN};\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":425,"y":100,"wires":[["mhb-universal-http-get"]]},
  {"id":"mhb-universal-http-get","type":"http request","z":"mhb-universal-tab","name":"Opdracht ophalen","method":"use","ret":"obj","paytoqs":"ignore","url":"","persist":false,"insecureHTTPParser":false,"authType":"","senderr":false,"headers":[],"x":680,"y":100,"wires":[["mhb-universal-dispatch"]]},
  {"id":"mhb-universal-dispatch","type":"function","z":"mhb-universal-tab","name":"Alleen veilige DVCC-opdracht","func":"const job=(msg.payload||{}).job;if(!job)return [null,null,null];\nif(job.type!=='dvcc'||!job.payload){node.error('Opdracht niet toegestaan',msg);return [null,null,null];}\nconst p=job.payload,c=p.current_enabled?Number(p.charge_current):-1,v=p.voltage_enabled?Number(p.charge_voltage):0;\nif((c!==-1&&(c<1||c>200))||(v!==0&&(v<40||v>64))){node.error('Waarde buiten veilige grens',msg);return [null,null,null];}\nflow.set('mhb_pending',{id:job.id,current:c,voltage:v});return [{payload:c},{payload:v},{payload:job.id}];","outputs":3,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":935,"y":100,"wires":[["mhb-universal-out-current"],["mhb-universal-out-voltage"],["mhb-universal-delay"]]},
  {"id":"mhb-universal-out-current","type":"victron-output-ess","z":"mhb-universal-tab","service":"com.victronenergy.settings","path":"/Settings/SystemSetup/MaxChargeCurrent","serviceObj":{"service":"com.victronenergy.settings","name":"Settings"},"pathObj":{"path":"/Settings/SystemSetup/MaxChargeCurrent","type":"float","name":"DVCC Charge current limit (A)","mode":"both"},"initial":"","name":"Schrijf DVCC-laadstroom","x":1240,"y":75,"wires":[]},
  {"id":"mhb-universal-out-voltage","type":"victron-output-ess","z":"mhb-universal-tab","service":"com.victronenergy.settings","path":"/Settings/SystemSetup/MaxChargeVoltage","serviceObj":{"service":"com.victronenergy.settings","name":"Settings"},"pathObj":{"path":"/Settings/SystemSetup/MaxChargeVoltage","type":"float","name":"DVCC Maximum charge voltage (V)","mode":"both"},"initial":"","name":"Schrijf DVCC-laadspanning","x":1245,"y":125,"wires":[]},
  {"id":"mhb-universal-read-current","type":"victron-input-ess","z":"mhb-universal-tab","service":"com.victronenergy.settings","path":"/Settings/SystemSetup/MaxChargeCurrent","serviceObj":{"service":"com.victronenergy.settings","name":"Settings"},"pathObj":{"path":"/Settings/SystemSetup/MaxChargeCurrent","type":"float","name":"DVCC Charge current limit (A)","mode":"both"},"name":"Werkelijke laadstroom","onlyChanges":true,"roundValues":"2","rateLimit":0,"conditionalMode":false,"outputOnChange":false,"debounce":0,"x":180,"y":230,"wires":[["mhb-universal-store-current"]]},
  {"id":"mhb-universal-store-current","type":"function","z":"mhb-universal-tab","name":"Onthoud stroom","func":"flow.set('mhb_actual_current',Number(msg.payload));return msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":440,"y":230,"wires":[["mhb-universal-debug"]]},
  {"id":"mhb-universal-read-voltage","type":"victron-input-ess","z":"mhb-universal-tab","service":"com.victronenergy.settings","path":"/Settings/SystemSetup/MaxChargeVoltage","serviceObj":{"service":"com.victronenergy.settings","name":"Settings"},"pathObj":{"path":"/Settings/SystemSetup/MaxChargeVoltage","type":"float","name":"DVCC Maximum charge voltage (V)","mode":"both"},"name":"Werkelijke laadspanning","onlyChanges":true,"roundValues":"2","rateLimit":0,"conditionalMode":false,"outputOnChange":false,"debounce":0,"x":185,"y":280,"wires":[["mhb-universal-store-voltage"]]},
  {"id":"mhb-universal-store-voltage","type":"function","z":"mhb-universal-tab","name":"Onthoud spanning","func":"flow.set('mhb_actual_voltage',Number(msg.payload));return msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":445,"y":280,"wires":[["mhb-universal-debug"]]},
  {"id":"mhb-universal-debug","type":"debug","z":"mhb-universal-tab","name":"Werkelijke lokale waarde","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","x":700,"y":255,"wires":[]},
  {"id":"mhb-universal-delay","type":"delay","z":"mhb-universal-tab","name":"Wacht 2 seconden","pauseType":"delay","timeout":"2","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"x":955,"y":180,"wires":[["mhb-universal-complete"]]},
  {"id":"mhb-universal-complete","type":"function","z":"mhb-universal-tab","name":"Bevestig werkelijke waarden","func":"const p=flow.get('mhb_pending'),portal=flow.get('mhb_portal_id'),token=flow.get('mhb_token');if(!p||!portal||!token)return null;\nconst c=flow.get('mhb_actual_current'),v=flow.get('mhb_actual_voltage');\nconst ok=Number.isFinite(c)&&Number.isFinite(v)&&Math.abs(c-p.current)<0.05&&Math.abs(v-p.voltage)<0.05;\nmsg.method='POST';msg.url='https://mhbbeheer.site/api/cerbo-node-red/'+portal+'/commands/'+p.id+'/complete';msg.headers={'X-MHB-Cerbo-Token':token,'Content-Type':'application/json'};msg.payload={ok:ok,result:{charge_current:c,charge_voltage:v,confirmed_locally:ok},error:ok?null:'lokale_waarde_niet_bevestigd'};return msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1215,"y":180,"wires":[["mhb-universal-http-complete"]]},
  {"id":"mhb-universal-http-complete","type":"http request","z":"mhb-universal-tab","name":"Resultaat naar MHB","method":"use","ret":"obj","paytoqs":"ignore","url":"","persist":false,"insecureHTTPParser":false,"authType":"","senderr":false,"headers":[],"x":1480,"y":180,"wires":[["mhb-universal-result"]]},
  {"id":"mhb-universal-result","type":"debug","z":"mhb-universal-tab","name":"MHB-resultaat","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","x":1705,"y":180,"wires":[]},
  {"id":"mhb-live-soc","type":"victron-input-system","z":"mhb-universal-tab","service":"com.victronenergy.system/0","path":"/Dc/Battery/Soc","serviceObj":{"service":"com.victronenergy.system/0","name":"Venus system","communityTag":"system"},"pathObj":{"path":"/Dc/Battery/Soc","type":"float","name":"Battery State of Charge (%)"},"name":"battery_soc","onlyChanges":true,"roundValues":"1","rateLimit":0,"conditionalMode":false,"outputOnChange":false,"debounce":0,"x":135,"y":360,"wires":[["mhb-live-store"]]},
  {"id":"mhb-live-bv","type":"victron-input-system","z":"mhb-universal-tab","service":"com.victronenergy.system/0","path":"/Dc/Battery/Voltage","serviceObj":{"service":"com.victronenergy.system/0","name":"Venus system","communityTag":"system"},"pathObj":{"path":"/Dc/Battery/Voltage","type":"float","name":"Battery voltage (V)"},"name":"battery_voltage","onlyChanges":true,"roundValues":"2","rateLimit":0,"conditionalMode":false,"outputOnChange":false,"debounce":0,"x":145,"y":400,"wires":[["mhb-live-store"]]},
  {"id":"mhb-live-bi","type":"victron-input-system","z":"mhb-universal-tab","service":"com.victronenergy.system/0","path":"/Dc/Battery/Current","serviceObj":{"service":"com.victronenergy.system/0","name":"Venus system","communityTag":"system"},"pathObj":{"path":"/Dc/Battery/Current","type":"float","name":"Battery current (A)"},"name":"battery_current","onlyChanges":true,"roundValues":"1","rateLimit":0,"conditionalMode":false,"outputOnChange":false,"debounce":0,"x":145,"y":440,"wires":[["mhb-live-store"]]},
  {"id":"mhb-live-bp","type":"victron-input-system","z":"mhb-universal-tab","service":"com.victronenergy.system/0","path":"/Dc/Battery/Power","serviceObj":{"service":"com.victronenergy.system/0","name":"Venus system","communityTag":"system"},"pathObj":{"path":"/Dc/Battery/Power","type":"float","name":"Battery Power (W)"},"name":"battery_power","onlyChanges":true,"roundValues":"0","rateLimit":0,"conditionalMode":false,"outputOnChange":false,"debounce":0,"x":140,"y":480,"wires":[["mhb-live-store"]]},
  {"id":"mhb-live-bt","type":"victron-input-system","z":"mhb-universal-tab","service":"com.victronenergy.system/0","path":"/Dc/Battery/Temperature","serviceObj":{"service":"com.victronenergy.system/0","name":"Venus system","communityTag":"system"},"pathObj":{"path":"/Dc/Battery/Temperature","type":"float","name":"Battery temperature (°C)"},"name":"battery_temperature","onlyChanges":true,"roundValues":"1","rateLimit":0,"conditionalMode":false,"outputOnChange":false,"debounce":0,"x":155,"y":520,"wires":[["mhb-live-store"]]},
  {"id":"mhb-live-pv","type":"victron-input-system","z":"mhb-universal-tab","service":"com.victronenergy.system/0","path":"/Dc/Pv/Power","serviceObj":{"service":"com.victronenergy.system/0","name":"Venus system","communityTag":"system"},"pathObj":{"path":"/Dc/Pv/Power","type":"float","name":"MPPTs - power (W)"},"name":"pv_power","onlyChanges":true,"roundValues":"0","rateLimit":0,"conditionalMode":false,"outputOnChange":false,"debounce":0,"x":125,"y":560,"wires":[["mhb-live-store"]]},
  {"id":"mhb-live-grid","type":"victron-input-system","z":"mhb-universal-tab","service":"com.victronenergy.system/0","path":"/Ac/Grid/L1/Power","serviceObj":{"service":"com.victronenergy.system/0","name":"Venus system","communityTag":"system"},"pathObj":{"path":"/Ac/Grid/L1/Power","type":"float","name":"Grid L1 (W)"},"name":"grid_power","onlyChanges":true,"roundValues":"0","rateLimit":0,"conditionalMode":false,"outputOnChange":false,"debounce":0,"x":130,"y":600,"wires":[["mhb-live-store"]]},
  {"id":"mhb-live-store","type":"function","z":"mhb-universal-tab","name":"Live Cerbo-data onthouden","func":"const names=['battery_soc','battery_voltage','battery_current','battery_power','battery_temperature','pv_power','grid_power'];\nconst source=String(msg.topic||'');\nif(names.includes(source)) flow.set('mhb_live_'+source,msg.payload);\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":450,"y":540,"wires":[]},
  {"id":"mhb-universal-heartbeat","type":"inject","z":"mhb-universal-tab","name":"Status iedere 10 seconden","props":[{"p":"payload"}],"repeat":"10","once":true,"onceDelay":3,"payload":"","payloadType":"date","x":185,"y":800,"wires":[["mhb-universal-heartbeat-build"]]},
  {"id":"mhb-universal-heartbeat-build","type":"function","z":"mhb-universal-tab","name":"Status maken","func":"const portal=flow.get('mhb_portal_id'),token=flow.get('mhb_token');if(!portal||!token)return null;msg.method='POST';msg.url='https://mhbbeheer.site/api/cerbo-node-red/'+portal+'/heartbeat';msg.headers={'X-MHB-Cerbo-Token':token,'Content-Type':'application/json'};msg.payload={charge_current:flow.get('mhb_actual_current'),charge_voltage:flow.get('mhb_actual_voltage'),battery_soc:flow.get('mhb_live_battery_soc'),battery_voltage:flow.get('mhb_live_battery_voltage'),battery_current:flow.get('mhb_live_battery_current'),battery_power:flow.get('mhb_live_battery_power'),battery_temperature:flow.get('mhb_live_battery_temperature'),pv_power:flow.get('mhb_live_pv_power'),grid_power:flow.get('mhb_live_grid_power'),system_state:flow.get('mhb_live_system_state'),charge_disabled:flow.get('mhb_live_charge_disabled'),discharge_disabled:flow.get('mhb_live_discharge_disabled')};return msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":435,"y":800,"wires":[["mhb-universal-heartbeat-http"]]},
  {"id":"mhb-universal-heartbeat-http","type":"http request","z":"mhb-universal-tab","name":"Cerbo-status naar MHB","method":"use","ret":"obj","paytoqs":"ignore","url":"","persist":false,"insecureHTTPParser":false,"authType":"","senderr":false,"headers":[],"x":690,"y":370,"wires":[]},
  {"id":"victron-client-id","type":"victron-client","name":"Victron Energy Client","showValues":true,"contextStore":true,"enablePolling":false}
]
