Weiter zum Inhalt
  • Home
  • Aktuell
  • Tags
  • 0 Ungelesen 0
  • Kategorien
  • Unreplied
  • Beliebt
  • GitHub
  • Docu
  • Hilfe
Skins
  • Hell
  • Brite
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dunkel
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Standard: (Kein Skin)
  • Kein Skin
Einklappen
ioBroker Logo

Community Forum

donate donate
  1. ioBroker Community Home
  2. Deutsch
  3. Skripten / Logik
  4. Ostrom Api auslesen

NEWS

  • Neuer ioBroker-Blog online: Monatsrückblick März/April 2026
    BluefoxB
    Bluefox
    8
    1
    1.8k

  • Verwendung von KI bitte immer deutlich kennzeichnen
    HomoranH
    Homoran
    10
    1
    735

  • Monatsrückblick Januar/Februar 2026 ist online!
    BluefoxB
    Bluefox
    18
    1
    1.2k

Ostrom Api auslesen

Geplant Angeheftet Gesperrt Verschoben Skripten / Logik
4 Beiträge 3 Kommentatoren 643 Aufrufe 3 Beobachtet
  • Älteste zuerst
  • Neuste zuerst
  • Meiste Stimmen
Antworten
  • In einem neuen Thema antworten
Anmelden zum Antworten
Dieses Thema wurde gelöscht. Nur Nutzer mit entsprechenden Rechten können es sehen.
  • J Offline
    J Offline
    jpakusch
    schrieb am zuletzt editiert von jpakusch
    #1

    Hallo,

    da ich nirgends was passendes gefunden habe bin ich gerade dabei, mir ein Skript zum Auslesen der Verbrauchsdaten von meinem dynamischen Tarif meines Stromanbieters Ostrom abzufragen. Das ganze ist noch eine sehr frühe Version und ich arbeite noch dran, vermutlich werde ich das skript hier auch noch aktualisieren.

    Was aktuell geht:

    • Monatliche Verbräche abfragen des aktuellen Jahres
    • Tägliche Verbrauchsdaten des aktuellen Monats

    nur eine kleiner Schritt den ich noch gehen möchte: Stündliche Verbrauchsdaten des aktuellen Tages (bzw des gestrigen, der heutige geht noch nicht)

    Bin gespannt ob das hier noch jemanden interessiert, kann dann auch gern bei der Einrichtung helfen, auch wenn es mein erstes Skript mit Javaskript ist (ja ich hatte Hilfe von CHatGPT um mir ein Grundgerüst hinzustellen), verwende sonst eher Blockly oder außerhalb von iobroker Python.
    Bin auch gespannt auf Verbesserungsvorschläge

    const axios = require('axios');
    
    const clientId = getState('javascript.0.ostrom.client_id').val;
    const clientSecret = getState('javascript.0.ostrom.client_secret').val;
    const contractNumber = getState('javascript.0.ostrom.contract_number').val;
    
    async function getToken() {
        try {
            const authHeader = 'Basic ' + Buffer.from(`${clientId}:${clientSecret}`).toString('base64');
            const response = await axios.post(
                'https://auth.production.ostrom-api.io/oauth2/token',
                'grant_type=client_credentials',
                {
                    headers: {
                        'Authorization': authHeader,
                        'Content-Type': 'application/x-www-form-urlencoded',
                        'Accept': 'application/json'
                    }
                }
            );
    
            return response.data.access_token;
        } catch (err) {
            console.error('❌ Fehler bei getToken: ' + 
                          (err.response ? err.response.status + ' ' + JSON.stringify(err.response.data) : err.message));
            return null;
        }
    }
    
    async function getConsumption(token) {
        try {
            const response = await axios.get(`https://api.ostrom.de/contracts/${contractNumber}/consumption`, {
                headers: { Authorization: `Bearer ${token}` }
            });
            return response.data;
        } catch (err) {
            console.error('❌ Fehler bei getConsumption:');
            return [];
        }
    }
    async function updateConsumption_monthly() {
        try {
            const token = await getToken();
            if (!token) {
                console.error('❌ Zugriffstoken konnte nicht abgerufen werden');
                return;
            }
    
            const contractId = contractNumber
            const startDate = new Date(Date.UTC(new Date().getFullYear(), 0, 1)).toISOString();
            const endDate = new Date(Date.UTC(new Date().getFullYear(), new Date().getMonth() + 1, 0)).toISOString();
    
            const response = await axios.get(
                `https://production.ostrom-api.io/contracts/${contractId}/energy-consumption`,
                {
                    headers: {
                        Authorization: `Bearer ${token}`,
                        Accept: 'application/json'
                    },
                    params: {
                        startDate,
                        endDate,
                        resolution: 'MONTH'
                    }
                }
            );
    
            const consumptionData = response.data.data;
    
            if (!consumptionData || consumptionData.length === 0) {
                console.warn('⚠️ Keine Verbrauchsdaten verfügbar');
                return;
            }
    
            for (const item of consumptionData) {
                const date = new Date(item.date);
                const year = date.getFullYear();
                const month = (date.getMonth() + 1).toString().padStart(2, '0');
                const key = `javascript.0.ostrom.consumption_monthly.${year}_${month}`;
                const value = item.kWh || 0;
    
                await createStateAsync(key, value, { type: 'number', read: true, write: false });
                await setStateAsync(key, value, true);
            }
    
            console.log('✅ monthly Verbrauchsdaten erfolgreich aktualisiert');
    
        } catch (err) {
            console.error('❌ Fehler bei updateConsumption:' +(err.response ? err.response.status + ' ' + JSON.stringify(err.response.data) : err.message));
        }
    }
    
    async function updateConsumption_daily() {
        try {
            const token = await getToken();
            if (!token) {
                console.error('❌ Zugriffstoken konnte nicht abgerufen werden');
                return;
            }
    
            const contractId = contractNumber
            const jetzt = new Date();
            //const startDate = new Date(Date.UTC(jetzt.getUTCFullYear(), jetzt.getUTCMonth(), jetzt.getUTCDate()));
            //const endDate =   new Date(Date.UTC(jetzt.getUTCFullYear(), jetzt.getUTCMonth(), jetzt.getUTCDate()+1));
            const startDate = new Date(Date.UTC(new Date().getFullYear(), new Date().getMonth(), 1)).toISOString();
            const endDate =   new Date(Date.UTC(new Date().getFullYear(), new Date().getMonth(), jetzt.getUTCDate())).toISOString();
    
            const response = await axios.get(
                `https://production.ostrom-api.io/contracts/${contractId}/energy-consumption`,
                {
                    headers: {
                        Authorization: `Bearer ${token}`,
                        Accept: 'application/json'
                    },
                    params: {
                        startDate,
                        endDate,
                        resolution: 'DAY'
                    }
                }
            );
    
            const consumptionData = response.data.data;
    
            if (!consumptionData || consumptionData.length === 0) {
                console.warn('⚠️ Keine Verbrauchsdaten verfügbar');
                return;
            }
    
            for (const item of consumptionData) {
                const date = new Date(item.date);
                const year = date.getFullYear();
                const month = (date.getMonth() + 1).toString().padStart(2, '0');
                const day = date.getDate().toString().padStart(2, '0');
                const key = `javascript.0.ostrom.consumption_daily.${year}.${month}.${day}`;
                const value = item.kWh || 0;
    
                await createStateAsync(key, value, { type: 'number', read: true, write: false });
                await setStateAsync(key, value, true);
            }
    
            console.log('✅ daily Verbrauchsdaten erfolgreich aktualisiert');
    
        } catch (err) {
            console.error('❌ Fehler bei updateConsumption:' +(err.response ? err.response.status + ' ' + JSON.stringify(err.response.data) : err.message));
        }
    }
    
    // Hilfsfunktion für async createState
    function createStateAsync(id, value, options) {
        return new Promise(resolve => {
            if (!existsState(id)) {
                createState(id, value, options, () => resolve());
            } else {
                resolve();
            }
        });
    }
    
    updateConsumption_monthly();
    updateConsumption_daily();
    
    // Manueller Trigger
    on({ id: 'javascript.0.ostrom.update', val: true, ack: false }, async () => {
        await updateConsumption_monthly();
        await updateConsumption_daily();
        // Reset Trigger
        setState('javascript.0.ostrom.update', false, true);
    });
    //Monthly täglich updaten
    setInterval(updateConsumption_monthly, 24 * 60 * 60 * 1000);
    setInterval(updateConsumption_daily, 24 * 60 * 60 * 1000);
    
    1 Antwort Letzte Antwort
    0
    • J Offline
      J Offline
      jpakusch
      schrieb am zuletzt editiert von
      #2

      Screenshot 2025-08-20 123708.png

      Skyx3S 1 Antwort Letzte Antwort
      0
      • J jpakusch

        Screenshot 2025-08-20 123708.png

        Skyx3S Offline
        Skyx3S Offline
        Skyx3
        schrieb am zuletzt editiert von
        #3

        @jpakusch
        Super Danke, habe es getestet und es funktioniert. Das Thema Preise wäre noch spannend.

        1 Antwort Letzte Antwort
        0
        • NicolomaN Offline
          NicolomaN Offline
          Nicoloma
          schrieb am zuletzt editiert von
          #4

          ich habe weiter ein anderes:

          const axios = require('axios');
          
          // ======= OSTROM PROD =======
          const CLIENT_ID = 'DEINE_ID';
          const CLIENT_SECRET = 'DEIN_SECRET';
          const ZIP = '59759';
          
          // ======= INFLUXDB 2.x =======
          const INFLUX_URL = 'http://192.168.178.103:8086';
          const INFLUX_ORG = 'my_org';
          const INFLUX_BUCKET = 'iobroker';
          const INFLUX_TOKEN = 'DEIN_TOKEN';
          
          // ======= IO BROKER =======
          const BASE_DP = '0_userdata.0.ostrom';
          
          const AUTH_URL = 'https://auth.production.ostrom-api.io/oauth2/token';
          const API_URL = 'https://production.ostrom-api.io';
          
          let isRunning = false;
          
          createStates();
          
          // API nur selten abrufen
          schedule('30 14 * * *', fetchPrices);
          
          // Status stündlich aktualisieren
          schedule('0 * * * *', updateCurrentFromCache);
          
          // beim Start nur Status aus Cache aktualisieren
          setTimeout(updateCurrentFromCache, 10000);
          
          // manueller API-Abruf
          on({ id: `${BASE_DP}.control.runNow`, val: true }, async () => {
              await setStateAsync(`${BASE_DP}.control.runNow`, false, true);
              await fetchPrices();
          });
          
          async function fetchPrices() {
              if (isRunning) return;
          
              const lastFetch = getState(`${BASE_DP}.meta.lastFetch`)?.val || 0;
              const now = Date.now();
          
              if (now - lastFetch < 120000) {
                  log('Ostrom: Letzte API-Abfrage < 2 Minuten – überspringe', 'warn');
                  return;
              }
          
              isRunning = true;
          
              try {
                  const token = await getAccessToken();
                  const prices = await getPrices(token);
          
                  const sorted = prices
                      .slice()
                      .sort((a, b) => new Date(a.date).getTime() - new Date(b.date).getTime());
          
                  await setStateAsync(`${BASE_DP}.todayTomorrow.json`, JSON.stringify(sorted), true);
                  await updateCurrentFromPrices(sorted);
                  await updateForecast(sorted);
                  await writeToInflux(sorted);
          
                  await setStateAsync(`${BASE_DP}.meta.lastFetch`, now, true);
                  await setStateAsync(`${BASE_DP}.meta.lastFetchReadable`, new Date(now).toLocaleString('de-DE'), true);
          
                  log(`Ostrom OK: ${sorted.length} Preise`, 'info');
              } catch (err) {
                  if (err.response?.status === 429) {
                      log('Ostrom 429: Rate Limit – später erneut versuchen', 'warn');
                  } else {
                      log(`Ostrom Fehler: ${err.message}`, 'error');
                  }
          
                  if (err.response) {
                      log(`Status: ${err.response.status}`, 'error');
                      log(JSON.stringify(err.response.data), 'error');
                  }
              } finally {
                  isRunning = false;
              }
          }
          
          async function updateCurrentFromCache() {
              const json = getState(`${BASE_DP}.todayTomorrow.json`)?.val;
          
              if (!json) {
                  log('Ostrom: Kein Preis-Cache vorhanden', 'warn');
                  return;
              }
          
              try {
                  const prices = JSON.parse(json);
                  await updateCurrentFromPrices(prices);
                  log('Ostrom current.isFree stündlich aktualisiert', 'info');
              } catch (err) {
                  log(`Ostrom Cache Fehler: ${err.message}`, 'error');
              }
          }
          
          async function updateCurrentFromPrices(prices) {
              const current = findCurrentPrice(prices);
              if (!current) return;
          
              const grossKwhPrice = Number(current.grossKwhPrice ?? 0);
              const grossKwhTaxAndLevies = Number(current.grossKwhTaxAndLevies ?? 0);
          
              // echter variabler Bruttopreis ohne monatliche Kosten
              const effectiveGrossKwhPrice = grossKwhPrice + grossKwhTaxAndLevies;
          
              await setStateAsync(`${BASE_DP}.current.grossKwhPrice`, round(grossKwhPrice), true);
              await setStateAsync(`${BASE_DP}.current.grossKwhTaxAndLevies`, round(grossKwhTaxAndLevies), true);
              await setStateAsync(`${BASE_DP}.current.effectiveGrossKwhPrice`, round(effectiveGrossKwhPrice), true);
          
              await setStateAsync(`${BASE_DP}.current.date`, current.date, true);
              await setStateAsync(`${BASE_DP}.current.dateReadable`, new Date(current.date).toLocaleString('de-DE'), true);
              await setStateAsync(`${BASE_DP}.current.hour`, new Date(current.date).getHours(), true);
          
              await setStateAsync(`${BASE_DP}.current.isFree`, effectiveGrossKwhPrice <= 0, true);
          }
          
          async function updateForecast(prices) {
              const effectivePrices = prices.map(p => {
                  const gross = Number(p.grossKwhPrice ?? 0);
                  const tax = Number(p.grossKwhTaxAndLevies ?? 0);
          
                  return {
                      date: p.date,
                      value: gross + tax
                  };
              });
          
              const values = effectivePrices.map(p => p.value);
          
              const min = Math.min(...values);
              const max = Math.max(...values);
              const avg = values.reduce((a, b) => a + b, 0) / values.length;
          
              const cheapest = effectivePrices.find(p => p.value === min);
              const expensive = effectivePrices.find(p => p.value === max);
              const nextFree = effectivePrices.find(p => new Date(p.date).getTime() >= Date.now() && p.value <= 0);
          
              await setStateAsync(`${BASE_DP}.forecast.minEffectiveGrossKwhPrice`, round(min), true);
              await setStateAsync(`${BASE_DP}.forecast.maxEffectiveGrossKwhPrice`, round(max), true);
              await setStateAsync(`${BASE_DP}.forecast.avgEffectiveGrossKwhPrice`, round(avg), true);
          
              await setStateAsync(`${BASE_DP}.forecast.cheapestDate`, cheapest?.date || '', true);
              await setStateAsync(`${BASE_DP}.forecast.cheapestDateReadable`, cheapest ? new Date(cheapest.date).toLocaleString('de-DE') : '', true);
          
              await setStateAsync(`${BASE_DP}.forecast.mostExpensiveDate`, expensive?.date || '', true);
              await setStateAsync(`${BASE_DP}.forecast.mostExpensiveDateReadable`, expensive ? new Date(expensive.date).toLocaleString('de-DE') : '', true);
          
              await setStateAsync(`${BASE_DP}.forecast.nextFreeDate`, nextFree?.date || '', true);
              await setStateAsync(`${BASE_DP}.forecast.nextFreeDateReadable`, nextFree ? new Date(nextFree.date).toLocaleString('de-DE') : '', true);
              await setStateAsync(`${BASE_DP}.forecast.hasFreeHour`, !!nextFree, true);
          }
          
          async function getAccessToken() {
              const auth = Buffer.from(`${CLIENT_ID}:${CLIENT_SECRET}`).toString('base64');
          
              const res = await axios.post(
                  AUTH_URL,
                  'grant_type=client_credentials',
                  {
                      headers: {
                          Authorization: `Basic ${auth}`,
                          'Content-Type': 'application/x-www-form-urlencoded'
                      },
                      timeout: 15000
                  }
              );
          
              return res.data.access_token;
          }
          
          async function getPrices(token) {
              const now = new Date();
          
              const start = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0, 0, 0);
              const end = new Date(now.getFullYear(), now.getMonth(), now.getDate() + 2, 0, 0, 0);
          
              const res = await axios.get(`${API_URL}/spot-prices`, {
                  params: {
                      startDate: start.toISOString(),
                      endDate: end.toISOString(),
                      resolution: 'HOUR',
                      zip: ZIP
                  },
                  headers: {
                      Authorization: `Bearer ${token}`
                  },
                  timeout: 15000
              });
          
              return res.data.data || [];
          }
          
          async function writeToInflux(prices) {
              if (!prices.length) return;
          
              const lines = [];
          
              for (const p of prices) {
                  const ts = BigInt(new Date(p.date).getTime()) * 1000000n;
          
                  const grossKwhPrice = Number(p.grossKwhPrice ?? 0);
                  const grossKwhTaxAndLevies = Number(p.grossKwhTaxAndLevies ?? 0);
                  const effectiveGrossKwhPrice = grossKwhPrice + grossKwhTaxAndLevies;
          
                  lines.push(
                      `ostrom_prices,source=production,zip=${escapeTag(ZIP)} ` +
                      `grossKwhPrice=${grossKwhPrice},` +
                      `grossKwhTaxAndLevies=${grossKwhTaxAndLevies},` +
                      `effectiveGrossKwhPrice=${effectiveGrossKwhPrice} ` +
                      `${ts.toString()}`
                  );
              }
          
              const url =
                  `${INFLUX_URL}/api/v2/write` +
                  `?org=${encodeURIComponent(INFLUX_ORG)}` +
                  `&bucket=${encodeURIComponent(INFLUX_BUCKET)}` +
                  `&precision=ns`;
          
              await axios.post(url, lines.join('\n'), {
                  headers: {
                      Authorization: `Token ${INFLUX_TOKEN}`,
                      'Content-Type': 'text/plain'
                  },
                  timeout: 15000
              });
          }
          
          function findCurrentPrice(prices) {
              const now = new Date();
          
              return prices.find(p => {
                  const start = new Date(p.date);
                  const end = new Date(start.getTime() + 3600000);
          
                  return now >= start && now < end;
              });
          }
          
          async function createStates() {
              await ensure(`${BASE_DP}.control.runNow`, 'boolean', true, true, 'button');
          
              await ensure(`${BASE_DP}.meta.lastFetch`, 'number', 0, true, 'value');
              await ensure(`${BASE_DP}.meta.lastFetchReadable`, 'string', '', true, 'text');
          
              await ensure(`${BASE_DP}.todayTomorrow.json`, 'string', '', true, 'json');
          
              await ensure(`${BASE_DP}.current.grossKwhPrice`, 'number', 0, true, 'value', 'ct/kWh');
              await ensure(`${BASE_DP}.current.grossKwhTaxAndLevies`, 'number', 0, true, 'value', 'ct/kWh');
              await ensure(`${BASE_DP}.current.effectiveGrossKwhPrice`, 'number', 0, true, 'value', 'ct/kWh');
          
              await ensure(`${BASE_DP}.current.date`, 'string', '', true, 'text');
              await ensure(`${BASE_DP}.current.dateReadable`, 'string', '', true, 'text');
              await ensure(`${BASE_DP}.current.hour`, 'number', 0, true, 'value', 'h');
              await ensure(`${BASE_DP}.current.isFree`, 'boolean', false, true, 'indicator');
          
              await ensure(`${BASE_DP}.forecast.minEffectiveGrossKwhPrice`, 'number', 0, true, 'value', 'ct/kWh');
              await ensure(`${BASE_DP}.forecast.maxEffectiveGrossKwhPrice`, 'number', 0, true, 'value', 'ct/kWh');
              await ensure(`${BASE_DP}.forecast.avgEffectiveGrossKwhPrice`, 'number', 0, true, 'value', 'ct/kWh');
          
              await ensure(`${BASE_DP}.forecast.cheapestDate`, 'string', '', true, 'text');
              await ensure(`${BASE_DP}.forecast.cheapestDateReadable`, 'string', '', true, 'text');
          
              await ensure(`${BASE_DP}.forecast.mostExpensiveDate`, 'string', '', true, 'text');
              await ensure(`${BASE_DP}.forecast.mostExpensiveDateReadable`, 'string', '', true, 'text');
          
              await ensure(`${BASE_DP}.forecast.nextFreeDate`, 'string', '', true, 'text');
              await ensure(`${BASE_DP}.forecast.nextFreeDateReadable`, 'string', '', true, 'text');
              await ensure(`${BASE_DP}.forecast.hasFreeHour`, 'boolean', false, true, 'indicator');
          }
          
          async function ensure(id, type, def, write, role, unit = '') {
              const exists = await existsStateAsync(id);
          
              if (!exists) {
                  await createStateAsync(id, def, {
                      type,
                      role,
                      read: true,
                      write,
                      unit
                  });
              }
          }
          
          function round(value) {
              return Math.round(value * 1000) / 1000;
          }
          
          function escapeTag(value) {
              return String(value)
                  .replace(/ /g, '\\ ')
                  .replace(/,/g, '\\,')
                  .replace(/=/g, '\\=');
          }
          
          1 Antwort Letzte Antwort
          0

          Hey! Du scheinst an dieser Unterhaltung interessiert zu sein, hast aber noch kein Konto.

          Hast du es satt, bei jedem Besuch durch die gleichen Beiträge zu scrollen? Wenn du dich für ein Konto anmeldest, kommst du immer genau dorthin zurück, wo du zuvor warst, und kannst dich über neue Antworten benachrichtigen lassen (entweder per E-Mail oder Push-Benachrichtigung). Du kannst auch Lesezeichen speichern und Beiträge positiv bewerten, um anderen Community-Mitgliedern deine Wertschätzung zu zeigen.

          Mit deinem Input könnte dieser Beitrag noch besser werden 💗

          Registrieren Anmelden
          Antworten
          • In einem neuen Thema antworten
          Anmelden zum Antworten
          • Älteste zuerst
          • Neuste zuerst
          • Meiste Stimmen


          Support us

          ioBroker
          Community Adapters
          Donate

          302

          Online

          32.9k

          Benutzer

          83.0k

          Themen

          1.3m

          Beiträge
          Community
          Impressum | Datenschutz-Bestimmungen | Nutzungsbedingungen | Einwilligungseinstellungen
          ioBroker Community 2014-2025
          logo
          • Anmelden

          • Du hast noch kein Konto? Registrieren

          • Anmelden oder registrieren, um zu suchen
          • Erster Beitrag
            Letzter Beitrag
          0
          • Home
          • Aktuell
          • Tags
          • Ungelesen 0
          • Kategorien
          • Unreplied
          • Beliebt
          • GitHub
          • Docu
          • Hilfe