Last active
October 1, 2025 10:28
-
-
Save sevenissimo/7df0f8e5a56a267faa071deaeb4084e3 to your computer and use it in GitHub Desktop.
JavaScript snippets to download energy data (injected/withdrawn from e-distribuzione, or produced from Huawei inverter) in CSV format.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| (async function() { | |
| 'use strict'; | |
| const wait = s => new Promise(fn => setTimeout(fn, Math.random() * s * 1000 + 500)); | |
| const isoStr = d => [d.getFullYear(), String(d.getMonth() + 1).padStart(2, '0'), String(d.getDate()).padStart(2, '0')].join('-'); | |
| const csvRow = (s, arr) => (s + ';' + arr.map(e => String(e).replace('--', '0').replace('.', ',')).join(';')); | |
| const header = 'Giorno;'+Array.from({length:96}, (_, i) => new Date(i * 9e5).toLocaleTimeString('it-IT',{timeZone:'UTC'})).join(';'); | |
| let station; | |
| async function init() { | |
| console.log("βοΈ Inizializzazione script per Huawei FusionSolar..."); | |
| const match = window.location.hash.match(/NE=(\d+)/); | |
| station = match ? match[1] : null; | |
| if (!station) { | |
| return console.error("β Errore: station non trovato nell'URL hash (#NE=...). Seleziona un impianto."); | |
| } | |
| console.log(`β Inizializzazione completata. Impianto: ${station}`); | |
| } | |
| async function fetchMonth(year, month) { | |
| if (!station) return []; | |
| const date = new Date(year, month - 1, 1); // MonthIndex [0..11] | |
| const end = new Date(year, month, 1); // EndOfMonth | |
| const rows = []; | |
| console.log(`β‘οΈ Recupero dati per ${year}-${String(month).padStart(2, '0')}...`); | |
| while (date < end) { | |
| const d = isoStr(date); // format YYYY-MM-DD | |
| const url = `https://uni003eu5.fusionsolar.huawei.com/rest/pvms/web/station/v3/overview/energy-balance` | |
| + `?stationDn=NE%3D${station}&timeDim=2&queryTime=${date.getTime()}&timeZone=2.0&timeZoneStr=Europe/Rome` | |
| + `&_=${Date.now()}&dateStr=${d}%2000%3A00%3A00`; | |
| try { | |
| const resp = await fetch(url); | |
| if (!resp.ok) throw new Error(`Errore HTTP: ${resp.status}`); | |
| const json = await resp.json(); | |
| if (json.success && json.data?.productPower) { | |
| const power = json.data.productPower; | |
| const energy = []; | |
| // Converte i dati di potenza (kW) media per 5 minuti | |
| // in energia totale (kWh) per il quarto d'ora: (P1+P2+P3) * (5/60 min) | |
| for (let i=0; i < power.length; i += 3) { | |
| energy.push((power.slice(i, i+3).reduce((sum, n) => sum + (parseFloat(n)||0), 0) / 12).toFixed(3)); | |
| } | |
| rows.push(csvRow(d, energy)); | |
| } else { | |
| console.warn(`β Nessun dato valido per ${d}.\n\t ${json.failReason}`); | |
| } | |
| } catch (error) { | |
| console.error(`β Errore per ${d}:`, error.message); | |
| return []; | |
| } | |
| date.setDate(date.getDate() + 1); // Next day | |
| await wait(0.5); | |
| } | |
| return rows; | |
| } | |
| window.downloadMonth = async function(year, month) { | |
| const d = `${year}-${String(month).padStart(2, '0')}`; // format YYYY-MM | |
| console.log(`π¦ Avvio download per ${d}`); | |
| const rows = await fetchMonth(year, month); | |
| if (rows.length > 0) { | |
| rows.unshift(header); | |
| const a = document.createElement('a'); | |
| a.href = URL.createObjectURL( | |
| new Blob([ rows.join('\n') ], | |
| { type:'text/csv;charset=utf-8;' }) ); | |
| a.download = `${d}-prodotta.csv`; | |
| a.click(); | |
| URL.revokeObjectURL(a.href); | |
| console.log(`\t β Download avviato...`); | |
| } else { | |
| console.log(`\t β Nessun dato trovato per ${d}.`); | |
| } | |
| console.log(`π Download per ${d} completato`); | |
| } | |
| window.downloadSince = async function(year, month) { | |
| const date = new Date(year, month - 1, 1); | |
| const today = new Date(); | |
| console.log("π Avvio download massivo"); | |
| while (date <= today) { | |
| await window.downloadMonth(date.getFullYear(), date.getMonth() + 1); | |
| date.setMonth(date.getMonth() + 1); // Next month | |
| } | |
| console.log("π Processo di download massivo completato!"); | |
| } | |
| await init(); | |
| })(); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| (async function() { | |
| 'use strict'; | |
| const wait = s => new Promise(fn => setTimeout(fn, Math.random() * s * 1000 + 500)); | |
| const isoStr = d => [d.getFullYear(), String(d.getMonth() + 1).padStart(2, '0'), String(d.getDate()).padStart(2, '0')].join('-'); | |
| const csvRow = (s, arr) => (s + ';' + arr.map(e => String(e).replace('.', ',')).join(';')); | |
| const header = 'Giorno;'+Array.from({length:96}, (_, i) => new Date(i * 9e5).toLocaleTimeString('it-IT',{timeZone:'UTC'})).join(';'); | |
| let token, context; | |
| async function init() { | |
| console.log("βοΈ Inizializzazione in corso..."); | |
| if (typeof aura === 'undefined') { | |
| return console.error("β Errore: Framework Aura non trovato."); | |
| } | |
| token = localStorage.getItem('$AuraClientService.token$siteforce:communityApp'); | |
| if (!token) { | |
| return console.error("β Errore: Token non trovato in Local Storage."); | |
| } | |
| const rawContext = aura.getContext(); | |
| context = { | |
| mode: "PROD", | |
| fwuid: rawContext.Hr, | |
| app: "siteforce:communityApp", | |
| loaded: rawContext.loaded, | |
| dn: [], | |
| globals: { srcdoc: true }, | |
| uad: true | |
| }; | |
| console.log("β Inizializzazione completata."); | |
| } | |
| async function fetchMonth(year, month, type) { | |
| if (!token) return []; | |
| const message = { | |
| actions: [{ | |
| id: `${Math.random()};a`, | |
| descriptor: 'apex://PED_CurveDiCaricoController/ACTION$QueryLoadProfile', | |
| callingDescriptor: 'markup://c:PED_Curva_di_carico_main', | |
| params: { | |
| Startdate: isoStr(new Date(year, month - 1, 1)), // ISO format YYYY-MM-DD | |
| Enddate: isoStr(new Date(year, month, 0)), // ISO format YYYY-MM-DD | |
| Magnitude: type, | |
| isDelegate: false }, | |
| longRunning: true | |
| }], | |
| }; | |
| const payload = { | |
| 'message': JSON.stringify(message), | |
| 'aura.context': JSON.stringify(context), | |
| 'aura.pageURI': window.location.pathname, | |
| 'aura.token': token, | |
| }; | |
| try { | |
| const resp = await fetch('/PortaleClienti/s/sfsites/aura?r=1&other.PED_CurveDiCarico.QueryLoadProfile=1', { | |
| method: 'POST', | |
| headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' }, | |
| body: new URLSearchParams(payload).toString(), | |
| }); | |
| const text = await resp.text(); | |
| const json = JSON.parse(text.replace("while(1);", "").replace("*/", "")); | |
| const action = json.actions?.[0]; | |
| if (action?.state !== 'SUCCESS') throw new Error(action?.error?.[0]?.message || 'Risposta non valida.'); | |
| const data = action.returnValue.MappaDailyLoadProfile; | |
| if ( !data || Object.keys(data).length === 0 ) return []; | |
| return Object.keys(data).map(key => { // format YYYYMM-DD | |
| return csvRow( `${key.substring(0, 4)}-${key.substring(4, 9)}`, // ISO format YYYY-MM-DD | |
| Object.values( data[key] )); | |
| }); | |
| } catch (error) { | |
| console.error(`β Errore per ${year}-${month} (${type}):`, error.message); | |
| return []; | |
| } | |
| } | |
| window.downloadMonth = async function(year, month) { | |
| const types = { 'A+': 'prelevata', 'A-': 'immessa' }; | |
| const d = `${year}-${String(month).padStart(2, '0')}`; // format YYYY-MM | |
| console.log(`π¦ Avvio download per ${d}`); | |
| for (const [type, desc] of Object.entries(types)) { | |
| console.log(`\t β‘οΈ Recupero energia ${desc}...`); | |
| const rows = await fetchMonth(year, month, type); | |
| if (rows.length > 0) { | |
| rows.unshift(header); | |
| const a = document.createElement('a'); | |
| a.href = URL.createObjectURL( | |
| new Blob([ rows.join('\n') ], | |
| { type:'text/csv;charset=utf-8;' }) ); | |
| a.download = `${d}-${desc}.csv`; | |
| a.click(); | |
| URL.revokeObjectURL(a.href); | |
| console.log(`\t β Download avviato...`); | |
| } else { | |
| console.log(`\t β Nessun dato trovato per energia ${desc}.`); | |
| } | |
| await wait(2); | |
| } | |
| console.log(`π Download per ${d} completato.`); | |
| } | |
| window.downloadSince = async function(year, month) { | |
| const date = new Date(year, month - 1, 1); // MonthIndex [0..11] | |
| const today = new Date(); | |
| console.log("π Avvio download massivo."); | |
| while (date <= today) { | |
| await window.downloadMonth(date.getFullYear(), date.getMonth() + 1); | |
| date.setMonth(date.getMonth() + 1); | |
| } | |
| console.log("π Processo di download massivo completato!"); | |
| } | |
| await init(); | |
| })(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment