-
-
Save yholkamp/8e6af834be1f277536e76dd355d523dd to your computer and use it in GitHub Desktop.
Post daily frank energie trading results to onbalansmarkt
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
| /** | |
| * JavaScript code om de opbrengst van een batterij naar Onbalansmarkt.com te sturen. | |
| * | |
| * Auteur: erdebee, met wijzigingen van verschillende gebruikers | |
| */ | |
| const timeZone = 'Europe/Amsterdam'; | |
| class FrankEnergie { | |
| constructor(authToken = null, refreshToken = null) { | |
| this.DATA_URL = "https://frank-graphql-prod.graphcdn.app/"; | |
| this.auth = authToken || refreshToken ? { authToken, refreshToken } : null; | |
| } | |
| async query(queryData) { | |
| const headers = { | |
| 'Content-Type': 'application/json', | |
| ...(this.auth && { 'Authorization': `Bearer ${this.auth.authToken}` }) | |
| }; | |
| try { | |
| const response = await fetch(this.DATA_URL, { | |
| method: 'POST', | |
| headers, | |
| body: JSON.stringify(queryData) | |
| }); | |
| const data = await response.json(); | |
| if (data.errors) { | |
| for (const error of data.errors) { | |
| if (error.message === "user-error:auth-not-authorised") { | |
| throw new Error("Authentication required"); | |
| } | |
| } | |
| } | |
| return data; | |
| } catch (error) { | |
| throw new Error(`Request failed: ${error.message}`); | |
| } | |
| } | |
| async login(username, password) { | |
| const query = { | |
| query: ` | |
| mutation Login($email: String!, $password: String!) { | |
| login(email: $email, password: $password) { | |
| authToken | |
| refreshToken | |
| } | |
| } | |
| `, | |
| operationName: "Login", | |
| variables: { email: username, password } | |
| }; | |
| const response = await this.query(query); | |
| this.auth = response.data.login; | |
| return this.auth; | |
| } | |
| async getPrices(startDate, endDate) { | |
| const query = { | |
| query: ` | |
| query MarketPrices($startDate: Date!, $endDate: Date!) { | |
| marketPricesElectricity(startDate: $startDate, endDate: $endDate) { | |
| from | |
| till | |
| marketPrice | |
| marketPriceTax | |
| sourcingMarkupPrice | |
| energyTaxPrice | |
| } | |
| marketPricesGas(startDate: $startDate, endDate: $endDate) { | |
| from | |
| till | |
| marketPrice | |
| marketPriceTax | |
| sourcingMarkupPrice | |
| energyTaxPrice | |
| } | |
| } | |
| `, | |
| variables: { | |
| startDate: new Date(startDate.toLocaleString('en-US', { timeZone })).toISOString().split('T')[0], | |
| endDate: new Date(endDate.toLocaleString('en-US', { timeZone })).toISOString().split('T')[0] | |
| }, | |
| operationName: "MarketPrices" | |
| }; | |
| return await this.query(query); | |
| } | |
| async getSmartBatteries() { | |
| if (!this.auth) { | |
| throw new Error("Authentication required"); | |
| } | |
| const query = { | |
| query: ` | |
| query SmartBatteries { | |
| smartBatteries { | |
| brand | |
| capacity | |
| createdAt | |
| externalReference | |
| id | |
| maxChargePower | |
| maxDischargePower | |
| provider | |
| updatedAt | |
| } | |
| } | |
| `, | |
| operationName: "SmartBatteries" | |
| }; | |
| return await this.query(query); | |
| } | |
| async getSmartBatterySessions(deviceId, startDate, endDate) { | |
| if (!this.auth) { | |
| throw new Error("Authentication required"); | |
| } | |
| const query = { | |
| query: ` | |
| query SmartBatterySessions($startDate: String!, $endDate: String!, $deviceId: String!) { | |
| smartBatterySessions( | |
| startDate: $startDate | |
| endDate: $endDate | |
| deviceId: $deviceId | |
| ) { | |
| deviceId | |
| periodEndDate | |
| periodStartDate | |
| periodTradingResult | |
| sessions { | |
| cumulativeTradingResult | |
| date | |
| tradingResult | |
| } | |
| totalTradingResult | |
| } | |
| } | |
| `, | |
| operationName: "SmartBatterySessions", | |
| variables: { | |
| deviceId, | |
| startDate: startDate.toLocaleDateString('en-CA', { timeZone: timeZone }), // specificeer de lokale datum in YYYY-mm-dd formaat | |
| endDate: endDate.toLocaleDateString('en-CA', { timeZone: timeZone }) | |
| } | |
| }; | |
| return await this.query(query); | |
| } | |
| isAuthenticated() { | |
| return this.auth !== null; | |
| } | |
| } | |
| class OnbalansMarkt { | |
| constructor(apiKey) { | |
| this.apiUrl = 'https://onbalansmarkt.com/api/live'; | |
| this.apiKey = apiKey; | |
| } | |
| async sendMeasurement({ | |
| timestamp, | |
| batteryResult, | |
| batteryResultTotal, | |
| batteryCharge = null, | |
| batteryPower = null, | |
| chargedToday = null, | |
| dischargedToday = null, | |
| loadBalancingActive = null, | |
| solarResult = null, | |
| chargerResult = null | |
| }) { | |
| // Validate required fields | |
| if (!timestamp || !batteryResult || !batteryResultTotal) { | |
| throw new Error('timestamp, batteryResult and batteryResultTotal are required fields'); | |
| } | |
| // Prepare the payload | |
| const payload = { | |
| timestamp: timestamp.toISOString(), | |
| batteryResult: batteryResult.toString(), | |
| batteryResultTotal: batteryResultTotal.toString(), | |
| ...(batteryCharge !== null && { batteryCharge: batteryCharge.toString() }), | |
| ...(batteryPower !== null && { batteryPower: batteryPower.toString() }), | |
| ...(chargedToday !== null && { chargedToday: chargedToday.toString() }), | |
| ...(dischargedToday !== null && { dischargedToday: dischargedToday.toString() }), | |
| ...(loadBalancingActive !== null && { loadBalancingActive: loadBalancingActive.toString() }), | |
| ...(solarResult !== null && { solarResult: solarResult.toString() }), | |
| ...(chargerResult !== null && { chargerResult: chargerResult.toString() }) | |
| }; | |
| try { | |
| const response = await fetch(this.apiUrl, { | |
| method: 'POST', | |
| headers: { | |
| 'Accept': 'application/json', | |
| 'Authorization': `Bearer ${this.apiKey}`, | |
| 'Content-Type': 'application/json' | |
| }, | |
| body: JSON.stringify(payload) | |
| }); | |
| if (!response.ok) { | |
| throw new Error(`HTTP error! status: ${response.status}`); | |
| } | |
| return await response.text(); | |
| } catch (error) { | |
| console.error('Error sending measurement:', error); | |
| throw error; | |
| } | |
| } | |
| } | |
| const frank = new FrankEnergie(); | |
| await frank.login("[email protected]", "mijnfrankpassword"); | |
| const onbalansmarkt = new OnbalansMarkt("API-KEY-ONBALANSMARKT.COM"); | |
| // Get all smart batteries | |
| const batteries = await frank.getSmartBatteries(); | |
| // we sturen met dit script de opbrengst van de batterij, op de huidige tijd, naar Onbalansmarkt.com | |
| let currentTime = new Date(); | |
| // wanneer je de opgenomen en geleverde kWhs beschikbaar hebt van je batterij, dan kun je die hier opha | |
| let kwhDischarged = null; | |
| // Get sessions for a specific battery | |
| if (batteries.data.smartBatteries.length > 0) { | |
| const batteryId = batteries.data.smartBatteries[0].id; | |
| const sessions = await frank.getSmartBatterySessions( | |
| batteryId, | |
| currentTime, | |
| currentTime | |
| ); | |
| console.log(sessions); | |
| onbalansmarkt.sendMeasurement({ | |
| timestamp: currentTime, | |
| batteryResult: sessions.data.smartBatterySessions.periodTradingResult, | |
| batteryResultTotal: sessions.data.smartBatterySessions.totalTradingResult, | |
| loadBalancingActive: "off", // stuur hier enkel 'on' in wanneer de batterij op dit moment beperkt is in zijn vermogen door load balancing | |
| chargedToday: kwhCharged !== null ? Math.round(kwhCharged) : null, | |
| dischargedToday: kwhDischarged !== null ? Math.round(kwhDischarged) : null | |
| }); | |
| } else { | |
| console.log("No batteries found"); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment