Real-time Solar PV & Surplus Management with Solar-Log + Shelly

This flow integrates a Solar-Log Base device to monitor photovoltaic (PV) production and household electricity consumption in real-time. It dynamically calculates energy surplus (import/export) and intelligently activates resistive loads (heating elements, accumulators) through Shelly relays, maximizing self-consumption efficiency.

Solar-Log Base Monitoring Dashboard

⚙️ Features

  • 🔌 Live Data Acquisition

    • Fetches production (AC/DC power), consumption, voltages, and surplus power using the Solar-Log Base JSON API.
  • 🌡️ Automatic Resistor Activation

    • Controls resistive loads (e.g., water heaters, thermal accumulators) via Shelly relays, optimizing surplus energy usage.
  • 📈 Data Logging

    • Records historical data to MySQL/MariaDB for detailed analysis.
  • 📊 Dashboard Visualization

    • Interactive, real-time dashboard displaying:
      • PV Production (kW)
      • Consumption (kW)
      • Import/Export Energy (kW)
      • Daily historical performance curves
  • 📡 MQTT Integration

    • Real-time data publishing via MQTT for seamless IoT system integration.

🚀 Ideal Use Cases

  • Residential or commercial solar installations
  • Smart heating management using surplus PV energy
  • Automated energy management and self-consumption optimization
  • IoT-based renewable energy projects

📥 Installation

  • Import the provided JSON flow into your Node-RED environment.
  • Adjust the configuration nodes (Solar-Log IP, MQTT broker, MySQL database, Shelly relay IP addresses) as needed.

[{"id":"8c654e7081755568","type":"tab","label":"Flux 3","disabled":true,"info":"","env":[]},{"id":"35ab82024e2b6083","type":"group","z":"8c654e7081755568","name":"MQTT","style":{"label":true},"nodes":["31f7524c39d5316b","a44bca9a275baea5","3605625cbbf2e4b9"],"x":984,"y":539,"w":592,"h":82},{"id":"90d6b02a176e4781","type":"group","z":"8c654e7081755568","name":"Live...","style":{"label":true,"stroke":"#ffC000","color":"#777777","fill":"#ffefbf"},"nodes":["f6d896b62026ec26","00cc1d46e0e6da18","84f48d9e9f86cbc7","8b3c400f352aad9a","acf432e67865f34f","f8a6f88a43b66702","70f04c02453f2b16","05cccc9d40f5729f","4a2ccd6c769c7c82"],"x":984,"y":59,"w":592,"h":322},{"id":"450356e6b9801405","type":"group","z":"8c654e7081755568","name":"","style":{"stroke":"#92d04f","fill":"#e3f3d3","label":true,"color":"#777777"},"nodes":["8444630b82358654","92e42d0d658c3f4a"],"x":984,"y":679,"w":342,"h":82},{"id":"2835bcf6dd906cd1","type":"group","z":"8c654e7081755568","name":"MySQL","style":{"label":true},"nodes":["d7b544a6dc864401","dab256b3ee44537b"],"x":984,"y":439,"w":422,"h":82},{"id":"32422056b1ff5e3e","type":"inject","z":"8c654e7081755568","name":"","props":[{"p":"timestamp","v":"iso","vt":"date"}],"repeat":"1","crontab":"","once":true,"onceDelay":"1","topic":"","x":105,"y":300,"wires":[["f24b504025d80de3"]],"l":false},{"id":"c2a405a0fe858043","type":"http request","z":"8c654e7081755568","name":"Requête vers Solar-Log","method":"POST","ret":"txt","paytoqs":"ignore","url":"http://192.168.67.226/getjp","tls":"","persist":false,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[],"x":500,"y":300,"wires":[["c792513c7cebc03c"]]},{"id":"c792513c7cebc03c","type":"function","z":"8c654e7081755568","name":"Traiter JSON","func":"try {\n    \n    var data = JSON.parse(msg.payload);\n\n    // Vérification que les données attendues existent\n    if (!data['801'] || !data['801']['170']) {\n        node.status({ fill: \"red\", shape: \"dot\", text: \"Données manquantes\" });\n        node.error(\"Les données JSON ne contiennent pas les clés attendues.\", msg);\n        return null;\n    }\n\n    var liveData = data['801']['170'];\n\n    msg.payload = {\n        \"lastUpdateTime\": liveData[\"100\"], // Time in format dd.mm.yy hh:mm:ss\n        \"Pac\": liveData[\"101\"],            // Total output PAC (W)\n        \"Pdc\": liveData[\"102\"],            // Total output PDC (W)\n        \"Uac\": liveData[\"103\"],            // Average voltage UAC (V)\n        \"DC_voltage\": liveData[\"104\"],     // Average voltage UDC (V)\n        \"yieldDay\": liveData[\"105\"],       // Total yield for the day (Wh)\n        \"yieldYesterday\": liveData[\"106\"], // Total yield for the previous day (Wh)\n        \"yieldMonth\": liveData[\"107\"],     // Total yield for the month (Wh)\n        \"yieldYear\": liveData[\"108\"],      // Total yield for the year (Wh)\n        \"yieldTotal\": liveData[\"109\"],     // Total yield from all inverters (Wh)\n        \"consPac\": liveData[\"110\"],        // Current total consumption PAC (W)\n        \"consYieldDay\": liveData[\"111\"],   // Total consumption for the day (Wh)\n        \"consYieldYesterday\": liveData[\"112\"], // Total consumption for the previous day (Wh)\n        \"consYieldMonth\": liveData[\"113\"], // Total consumption for the month (Wh)\n        \"consYieldYear\": liveData[\"114\"],  // Total consumption for the year (Wh)\n        \"consYieldTotal\": liveData[\"115\"], // Accumulated total consumption (Wh)\n        \"totalPower\": liveData[\"116\"],     // Installed generator power (Wp)\n        \"surplus\": liveData[\"101\"] - liveData[\"110\"] // Surplus power (W)\n    };\n\n    // Indiquer que le fichier a été traité correctement\n    node.status({ fill: \"green\", shape: \"dot\", text: \"Réponse traitée avec succès\" });\n\n    return msg;\n\n} catch (err) {\n    node.status({ fill: \"red\", shape: \"dot\", text: \"Erreur de traitement\" });\n    node.error(\"Erreur lors du traitement des données JSON : \" + err.message, msg);\n    return null;\n}\n\n//        \"surplus\": Math.max(0, liveData[\"101\"] - liveData[\"110\"]) // Surplus power (W)\n","outputs":1,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[],"x":740,"y":300,"wires":[["f6d896b62026ec26","00cc1d46e0e6da18","84f48d9e9f86cbc7","8444630b82358654","3605625cbbf2e4b9","4a2ccd6c769c7c82","d7b544a6dc864401"]]},{"id":"f24b504025d80de3","type":"function","z":"8c654e7081755568","name":"Requête POST","func":"msg.headers = {\n    \"Content-Length\": \"20\",\n    \"Connection\": \"keep-alive\",\n    \"Pragma\": \"no-cache\",\n    \"Cache-Control\": \"no-cache\"\n};\n\nmsg.payload = {\n    \"801\": {\n        \"170\": null\n    }\n};\n\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":250,"y":300,"wires":[["c2a405a0fe858043"]]},{"id":"46ac0697f35bf2ef","type":"inject","z":"8c654e7081755568","name":"","props":[{"p":"timestamp","v":"iso","vt":"date"}],"repeat":"","crontab":"","once":true,"onceDelay":"1","topic":"","x":105,"y":100,"wires":[["900093f0a4f71e35"]],"l":false},{"id":"900093f0a4f71e35","type":"function","z":"8c654e7081755568","name":"Récupération des données","func":"msg.topic = `SELECT \n\n        DATE_FORMAT(timestamp, '%Y-%m-%dT%H:%i:00Z')    AS timestamp,\n        AVG(production_watt)                            AS production_watt,\n        AVG(consumption_watt)                           AS consumption_watt,\n        AVG(production_watt - consumption_watt)         AS surplus_watt\n        \n    FROM infr__data__raw\n    \n    WHERE DATE(timestamp) = CURDATE()\n    \n    GROUP BY DATE_FORMAT(timestamp, '%Y-%m-%d %H:%i')\n    \n    ORDER BY timestamp ASC`;\n\nreturn msg;\n","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":290,"y":100,"wires":[["a12bc8cb8a8cf468"]]},{"id":"04e12b6cdf7b0465","type":"function","z":"8c654e7081755568","name":"Traitement données journalières","func":"delete msg.topic;\nconst groupByFiveMinutes = {};\n\nmsg.payload.forEach(item => {\n    const date = new Date(item.timestamp);\n    date.setMinutes(Math.floor(date.getMinutes() / 5) * 5, 0, 0);\n    const fiveMinInterval = date.toISOString();\n\n    if (!groupByFiveMinutes[fiveMinInterval]) {\n        groupByFiveMinutes[fiveMinInterval] = { production: [], consommation: [], surplus: [] };\n    }\n\n    groupByFiveMinutes[fiveMinInterval].production.push(item.production_watt / 1000);\n    groupByFiveMinutes[fiveMinInterval].consommation.push(item.consumption_watt / 1000);\n    groupByFiveMinutes[fiveMinInterval].surplus.push(item.surplus_watt / 1000);\n});\n\nconst Production = [];\nconst Consommation = [];\nconst Export = [];\nconst Import = [];\nlet prevValue = null;\n\nObject.keys(groupByFiveMinutes).sort().forEach(interval => {\n    const prodValue = groupByFiveMinutes[interval].production.reduce((a, b) => a + b, 0) / groupByFiveMinutes[interval].production.length;\n    const consValue = groupByFiveMinutes[interval].consommation.reduce((a, b) => a + b, 0) / groupByFiveMinutes[interval].consommation.length;\n    const surplusValue = groupByFiveMinutes[interval].surplus.reduce((a, b) => a + b, 0) / groupByFiveMinutes[interval].surplus.length;\n\n    Production.push({ time: interval, value: prodValue });\n    Consommation.push({ time: interval, value: consValue });\n\n    if (surplusValue < 0) {\n        if (prevValue !== null && prevValue >= 0) {\n            Export.push({ time: interval, value: 0 });\n            Import.push({ time: interval, value: 0 });\n        }\n        Import.push({ time: interval, value: surplusValue });\n    } else {\n        if (prevValue !== null && prevValue < 0) {\n            Import.push({ time: interval, value: 0 });\n            Export.push({ time: interval, value: 0 });\n        }\n        Export.push({ time: interval, value: surplusValue });\n    }\n    prevValue = surplusValue;\n});\n\nnode.send({ payload: [] });\n\nnode.send({ topic: \"Production\", payload: Production });\nnode.send({ topic: \"Consommation\", payload: Consommation });\nnode.send({ topic: \"Export\", payload: Export });\nnode.send({ topic: \"Import\", payload: Import });\n","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":820,"y":100,"wires":[["70f04c02453f2b16"]]},{"id":"31f7524c39d5316b","type":"mqtt out","z":"8c654e7081755568","g":"35ab82024e2b6083","name":"MQTT Publish","topic":"","qos":"0","retain":"true","respTopic":"","contentType":"","userProps":"","correl":"","expiry":"","broker":"","x":1470,"y":580,"wires":[]},{"id":"a44bca9a275baea5","type":"rbe","z":"8c654e7081755568","g":"35ab82024e2b6083","name":"","func":"rbei","gap":"","start":"","inout":"out","septopics":true,"property":"payload","topi":"topic","x":1345,"y":580,"wires":[["31f7524c39d5316b"]],"l":false},{"id":"3605625cbbf2e4b9","type":"function","z":"8c654e7081755568","g":"35ab82024e2b6083","name":"Préparation des messages MQTT","func":"let currentData = msg.payload;\nlet messages = [];\n\ndelete msg.payload.lastUpdateTime;\n\nfor (let key in currentData) {\n    node.send({\n        topic: `electricity/${key}`,\n        payload: currentData[key]\n    });\n}","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1150,"y":580,"wires":[["a44bca9a275baea5"]]},{"id":"f6d896b62026ec26","type":"function","z":"8c654e7081755568","g":"90d6b02a176e4781","name":"Excédent","func":"const Surplus = msg.payload.surplus / 1000;\n\nif (msg.payload.Pac > 0) {\n    node.status({ fill: \"green\", shape: \"ring\", text: `${Surplus} kW` });\n} \n\nelse {\n    node.status({ fill: \"red\", shape: \"ring\", text: `${Surplus} ` });\n}\n\nnode.send({\n    time: msg.timestamp,\n    timestamp: msg.timestamp,\n    payload: Surplus,\n    value: Surplus,\n    ui_update: {\n        label: `Import/Export`,\n        min: -200,\n        max: 200,\n        units: `kW`\n    },\n    topic: `Import/Export`\n});\n\ncontext.set(\"previousValue\", 0);","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1070,"y":260,"wires":[["f8a6f88a43b66702"]]},{"id":"00cc1d46e0e6da18","type":"function","z":"8c654e7081755568","g":"90d6b02a176e4781","name":"Consommation actuelle","func":"const previousValue = context.get(\"previousValue\") || 0;\nconst zeroTimerSet = context.get(\"zeroTimerSet\") || false;\n\nconst consPac = msg.payload.consPac / 1000;\nconst surplus = msg.payload.surplus;\n\nif (consPac === 0 && previousValue > 0 && !zeroTimerSet) {\n    \n    // On déclenche un timer d'attente\n    context.set(\"zeroTimerSet\", true);\n\n    setTimeout(() => {\n        // Si aucune nouvelle valeur est arrivée, on met à jour à 0\n        node.status({ fill: \"grey\", shape: \"dot\", text: `0 kW (timeout)` });\n\n        node.send({\n            time: msg.timestamp,\n            timestamp: msg.timestamp,\n            payload: 0,\n            value: 0,\n            ui_update: {\n                label: `Consommation`,\n                min: 0,\n                max: 100,\n                units: `kWh`\n            },\n            topic: `Consommation`\n        });\n\n        context.set(\"previousValue\", 0);\n        context.set(\"zeroTimerSet\", false);\n    }, 30000);\n\n    // Ne rien envoyer pour l'instant\n    return null;\n}\n\nif (consPac > 0) {\n    // Valeur normale, on remet tout à zéro\n    context.set(\"zeroTimerSet\", false);\n    context.set(\"previousValue\", consPac);\n\n    const color = surplus > 0 ? \"orange\" : \"red\";\n\n    node.status({ fill: color, shape: \"ring\", text: `${consPac} kW` });\n\n    return {\n        time: msg.timestamp,\n        timestamp: msg.timestamp,\n        payload: consPac,\n        value: consPac,\n        ui_update: {\n            label: `Consommation`,\n            min: 0,\n            max: 100,\n            units: `kW`\n        },\n        topic: `Consommation`\n    };\n}\n\n// consPac = 0 mais pas de chute depuis >0, ou timer déjà en attente\nreturn null;\n","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1120,"y":220,"wires":[["acf432e67865f34f"]]},{"id":"84f48d9e9f86cbc7","type":"function","z":"8c654e7081755568","g":"90d6b02a176e4781","name":"Prod. actuelle","func":"const Pac = msg.payload.Pac / 1000;\n\nif (Pac > 0) {\n    node.status({ fill: \"green\", shape: \"ring\", text: `${Pac} kW` });\n} \n\nelse {\n    node.status({ fill: \"black\", shape: \"ring\", text: `${Pac} ` });\n}\n\nnode.send([\n    {\n        payload: Pac,\n        ui_update: {\n            label: `Production`,\n            min: 0,\n            max: 180,\n            units: `kW`\n        },\n        topic: `Production`\n    }, \n    {\n        payload : [{\n            time: msg.timestamp,\n            value: Pac,\n        }],\n        topic: `Production`\n    }\n]);","outputs":2,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1090,"y":180,"wires":[["8b3c400f352aad9a"],[]]},{"id":"8b3c400f352aad9a","type":"ui-gauge","z":"8c654e7081755568","g":"90d6b02a176e4781","name":"","group":"bacacbbeac35fe5b","order":3,"width":"2","height":3,"gtype":"gauge-34","gstyle":"needle","title":"gauge","units":"units","icon":"","prefix":"","suffix":"","segments":[{"from":"0","color":"#c9e3f5"},{"from":"50","color":"#94c9ed"},{"from":"100","color":"#369adc"},{"from":"150","color":"#185f8d"}],"min":0,"max":"180","sizeThickness":16,"sizeGap":4,"sizeKeyThickness":8,"styleRounded":true,"styleGlow":false,"className":"","x":1380,"y":180,"wires":[]},{"id":"acf432e67865f34f","type":"ui-gauge","z":"8c654e7081755568","g":"90d6b02a176e4781","name":"","group":"bacacbbeac35fe5b","order":2,"width":"2","height":3,"gtype":"gauge-34","gstyle":"needle","title":"gauge","units":"units","icon":"","prefix":"","suffix":"","segments":[{"from":"0","color":"#ffd5bf"},{"from":"40","color":"#ff915b"},{"from":"75","color":"#f24f00"}],"min":0,"max":"100","sizeThickness":16,"sizeGap":4,"sizeKeyThickness":8,"styleRounded":true,"styleGlow":false,"className":"","x":1380,"y":220,"wires":[]},{"id":"f8a6f88a43b66702","type":"ui-gauge","z":"8c654e7081755568","g":"90d6b02a176e4781","name":"","group":"bacacbbeac35fe5b","order":1,"width":3,"height":3,"gtype":"gauge-half","gstyle":"needle","title":"gauge","units":"kW","icon":"","prefix":"","suffix":"","segments":[{"from":"-200","color":"#d62728"},{"from":"0","color":"#47cd47"}],"min":"-200","max":"200","sizeThickness":16,"sizeGap":4,"sizeKeyThickness":8,"styleRounded":true,"styleGlow":false,"className":"","x":1380,"y":260,"wires":[]},{"id":"70f04c02453f2b16","type":"ui-chart","z":"8c654e7081755568","g":"90d6b02a176e4781","group":"bacacbbeac35fe5b","name":"Cons. / prod. journalière","label":"Cons. / prod. journalière","order":4,"chartType":"line","category":"topic","categoryType":"msg","xAxisLabel":"","xAxisProperty":"time","xAxisPropertyType":"property","xAxisType":"time","xAxisFormat":"","xAxisFormatType":"auto","xmin":"","xmax":"","yAxisLabel":"Puissance [kW]","yAxisProperty":"value","yAxisPropertyType":"property","ymin":"-100","ymax":"200","bins":"","action":"append","stackSeries":false,"pointShape":"false","pointRadius":4,"showLegend":true,"removeOlder":1,"removeOlderUnit":"86400","removeOlderPoints":"","colors":["#1f77b4","#ff8040","#47cd47","#d62728","#98df8a","#d62728","#ff9896","#9467bd","#c5b0d5"],"textColor":["#666666"],"textColorDefault":true,"gridColor":["#e5e5e5"],"gridColorDefault":true,"width":"7","height":"10","className":"","interpolation":"linear","x":1440,"y":100,"wires":[[]]},{"id":"05cccc9d40f5729f","type":"ui-text","z":"8c654e7081755568","g":"90d6b02a176e4781","group":"bacacbbeac35fe5b","order":5,"width":"3","height":"2","name":"","label":"","format":"{{msg.payload}}","layout":"col-center","style":true,"font":"Lucida Sans Typewriter,Lucida Console,Monaco,monospace","fontSize":"26","color":"#717171","wrapText":true,"className":"","x":1380,"y":340,"wires":[]},{"id":"4a2ccd6c769c7c82","type":"function","z":"8c654e7081755568","g":"90d6b02a176e4781","name":"Conso. hier / aujourd'hui","func":"const consYieldDay = msg.payload.consYieldDay / 1000;\nconst consYieldYesterday = msg.payload.consYieldYesterday / 1000;\n\nnode.status({ fill: 'red', shape: \"ring\", text: `${consYieldYesterday} / ${consYieldDay} kWh` });\n\nreturn {\n    payload: `hier: ${consYieldYesterday} kWh  ajd : ${consYieldDay} kWh`,\n    timestamp: msg.timestamp,\n    ui_update: {\n        label: `Consommation journ.`,\n        min: 0,\n        max: 100,\n        units: `kWh`\n    },\n    topic: `Consommation`\n};","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1120,"y":340,"wires":[["05cccc9d40f5729f"]]},{"id":"8444630b82358654","type":"function","z":"8c654e7081755568","g":"450356e6b9801405","name":"Gestion des devices","func":"// Récupérer la configuration des appareils (depuis global context ou une base de données)\nconst devices = global.get(\"devicesConfig\") || [];\n\nconst bufferSize = 30;\nvar surplusBuffer = context.get(\"surplusBuffer\") || [];\n\nvar surplus = Math.max(0, msg.payload.Pac - msg.payload.consPac);\nsurplusBuffer.push(surplus);\n\n// Garder uniquement les 30 dernières valeurs\nif (surplusBuffer.length > bufferSize) {\n    surplusBuffer.shift();\n}\n\n// Sauvegarder le buffer\ncontext.set(\"surplusBuffer\", surplusBuffer);\n\n// Calculer la moyenne du surplus\nvar avgSurplus = surplusBuffer.reduce((a, b) => a + b, 0) / surplusBuffer.length;\n\n// Trier les appareils par priorité (1 = plus prioritaire)\ndevices.sort((a, b) => a.priority - b.priority);\n\nvar commands = [];\n\n// Parcours des appareils pour assigner le surplus disponible\nfor (let device of devices) {\n    let powerNeeded = device.power_per_phase; // Puissance nécessaire par phase\n    let phasesOn = 0; // Nombre de phases activées pour cet appareil\n    let shellyBaseURL = `http://${device.shelly_ip}/rpc/Switch.Set?id=`;\n\n    for (let phase = 0; phase < device.phases; phase++) {\n        if (avgSurplus >= powerNeeded) {\n            commands.push(shellyBaseURL + phase + \"&on=true\");\n            avgSurplus -= powerNeeded;\n            phasesOn++;\n        } else {\n            commands.push(shellyBaseURL + phase + \"&on=false\");\n        }\n    }\n\n    node.status({\n        fill: phasesOn > 0 ? \"green\" : \"red\",\n        shape: \"dot\",\n        text: `${device.id}: ${phasesOn}/${device.phases} phases actives`\n    });\n}\n\n// Envoyer les commandes HTTP\nmsg.payload = commands;\nmsg.devices = commands.length;\nreturn msg;\n","outputs":1,"timeout":0,"noerr":0,"initialize":"// Le code ajouté ici sera exécuté une fois\n// à chaque démarrage du noeud.\ndevices = [\n    {\n        \"id\": \"R1\",\n        \"description\": \"Thermocoupleur ECS 4.5kW\",\n        \"shelly_ip\": \"192.168.1.100\",\n        \"power_per_phase\": 1500,\n        \"phases\": 3,\n        \"priority\": 2\n    },\n    {\n        \"id\": \"R2\",\n        \"description\": \"Thermocoupleur accu 9kW\",\n        \"shelly_ip\": \"192.168.1.101\",\n        \"power_per_phase\": 3000,\n        \"phases\": 3,\n        \"priority\": 1\n    }\n];\n\nglobal.set(\"devicesConfig\", devices); ","finalize":"","libs":[],"x":1110,"y":720,"wires":[["92e42d0d658c3f4a"]]},{"id":"92e42d0d658c3f4a","type":"debug","z":"8c654e7081755568","g":"450356e6b9801405","name":"","active":false,"tosidebar":true,"console":false,"tostatus":true,"complete":"true","targetType":"full","statusVal":"devices","statusType":"msg","x":1265,"y":720,"wires":[],"icon":"node-red/light.svg","l":false},{"id":"d7b544a6dc864401","type":"function","z":"8c654e7081755568","g":"2835bcf6dd906cd1","name":"Enregistrement des données","func":"msg.topic = `INSERT INTO infr__data__raw (\n    timestamp, \n    production_watt, \n    consumption_watt, \n    dc_power, \n    dc_voltage, \n    ac_voltage, \n    daily_production_wh, \n    total_production_wh, \n    daily_consumption_wh, \n    total_consumption_wh\n) VALUES (\n    NOW(),\n    ${msg.payload.Pac},\n    ${msg.payload.consPac},\n    ${msg.payload.Pdc},\n    ${msg.payload.DC_voltage},\n    ${msg.payload.Uac},\n    ${msg.payload.yieldDay},\n    ${msg.payload.yieldTotal},\n    ${msg.payload.consYieldDay},\n    ${msg.payload.consYieldTotal}\n)`;\n\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1130,"y":480,"wires":[["dab256b3ee44537b"]]},{"id":"dab256b3ee44537b","type":"debug","z":"8c654e7081755568","g":"2835bcf6dd906cd1","name":"sortie MySQL","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"topic","targetType":"msg","statusVal":"","statusType":"auto","x":1345,"y":480,"wires":[],"l":false},{"id":"a12bc8cb8a8cf468","type":"mysql2","z":"8c654e7081755568","name":"","server":"","bind":"","topic":"","x":540,"y":100,"wires":[["04e12b6cdf7b0465"]]},{"id":"bacacbbeac35fe5b","type":"ui-group","name":"Production","page":"15f61a0a743db0b5","width":"7","height":1,"order":1,"showTitle":false,"className":"","visible":"true","disabled":"false","groupType":"default"},{"id":"15f61a0a743db0b5","type":"ui-page","name":"Electricité","ui":"9648cbf635d68ff9","path":"/electricity","icon":"home","layout":"grid","theme":"46a4dfce6d975308","breakpoints":[{"name":"Default","px":"0","cols":"3"},{"name":"Tablet","px":"576","cols":"6"},{"name":"Small Desktop","px":"768","cols":"9"},{"name":"Desktop","px":"1024","cols":"12"}],"order":1,"className":"electricity","visible":"true","disabled":"false"},{"id":"9648cbf635d68ff9","type":"ui-base","name":"FESP","path":"/dashboard","appIcon":"","includeClientData":true,"acceptsClientConfig":["ui-notification","ui-control"],"showPathInSidebar":false,"navigationStyle":"default","titleBarStyle":"default"},{"id":"46a4dfce6d975308","type":"ui-theme","name":"Default Theme","colors":{"surface":"#ffffff","primary":"#0094CE","bgPage":"#eeeeee","groupBg":"#ffffff","groupOutline":"#cccccc"},"sizes":{"density":"default","pagePadding":"12px","groupGap":"12px","groupBorderRadius":"4px","widgetGap":"12px"}}]

Flow Info

Created 1 month ago
Rating: not yet rated

Owner

Actions

Rate:

Node Types

Core
  • debug (x2)
  • function (x11)
  • http request (x1)
  • inject (x2)
  • mqtt out (x1)
  • rbe (x1)
Other

Tags

  • solarlog
  • dashboard2.0
  • mysql
  • photovoltaic
  • mqtt
  • shelly
  • pv
Copy this flow JSON to your clipboard and then import into Node-RED using the Import From > Clipboard (Ctrl-I) menu option