Skip to content
  • Home
  • Aktuell
  • Tags
  • 0 Ungelesen 0
  • Kategorien
  • Unreplied
  • Beliebt
  • GitHub
  • Docu
  • Hilfe
Skins
  • Light
  • Brite
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • 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. JavaScript
  5. [TypeSkript] Wetter.com Forecast/Vorhersage

NEWS

  • Jahresrückblick 2025 – unser neuer Blogbeitrag ist online! ✨
    BluefoxB
    Bluefox
    16
    1
    1.1k

  • Neuer Blogbeitrag: Monatsrückblick - Dezember 2025 🎄
    BluefoxB
    Bluefox
    13
    1
    699

  • Weihnachtsangebot 2025! 🎄
    BluefoxB
    Bluefox
    25
    1
    2.0k

[TypeSkript] Wetter.com Forecast/Vorhersage

Geplant Angeheftet Gesperrt Verschoben JavaScript
25 Beiträge 5 Kommentatoren 370 Aufrufe 13 Watching
  • Ä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.
  • nik82N Offline
    nik82N Offline
    nik82
    Most Active
    schrieb am zuletzt editiert von
    #13

    Du bist echt der Beste!!!!
    Vielen Dank :-)

    1 Antwort Letzte Antwort
    0
    • S Online
      S Online
      Schimi
      schrieb am zuletzt editiert von
      #14

      Danke, aber ich mache nicht viel...

      Das meiste macht "Gemini"

      1 Antwort Letzte Antwort
      0
      • M Offline
        M Offline
        MartyBr
        schrieb am zuletzt editiert von
        #15

        @schimi

        Ich setze die 1.4.9 ein. Seit der 1.4.8 habe ich den u.a. Fehler. Der Datenpunkt liegt nicht vor. Muss er von Hand eingetragen werden?

        
        javascript.2	15:15:49.056	error	
        [Wetter.com] Fehler: ICON_BASE_URL is not defined
        
        

        Gruß
        Martin


        Intel NUCs mit Proxmox / Iobroker als VM unter Debian
        Raspeberry mit USB Leseköpfen für Smartmeter
        Homematic und Homematic IP

        1 Antwort Letzte Antwort
        0
        • S Online
          S Online
          Schimi
          schrieb am zuletzt editiert von
          #16

          versuche mal die hier im Spoiler... bitte um Feedback, dann tausche ich die oben aus

          /**
          * ioBroker Script: Wetter.com Forecast API v4.0
          * API: https://doc.meteonomiqs.com/doc/forecast_v4_0.html
          * * Changelog:
          * 1.4.11: FIX: Fallback-Werte für Konfigurations-Variablen (ICON_BASE_URL, DEFAULT_LANGUAGE) integriert. 
          * Verhindert Abstürze ("ReferenceError"), wenn beim Update der Konfig-Bereich nicht aktualisiert wurde.
          * 1.4.10: Feature: Dynamische Spracheinstellung.
          * 1.4.8: Icon-URL Anpassung.
          * * free API-Key anfordern: https://www.meteonomiqs.com/de/wetter-api/#heading_PricePackages/
          */
          
          // --- KONFIGURATION ---
          const API_KEY = 'DEIN_API_KEY_HIER'; // <-- BITTE HIER DEINEN API-KEY EINTRAGEN
          const BASE_URL = 'https://forecast.meteonomiqs.com/v4_0';
          const ICON_BASE_URL = 'https://cs3.wettercomassets.com/wcomv5/images/icons/weather'; 
          const DP_PATH = '0_userdata.0.wetter_com';
          const DEFAULT_LANGUAGE = 'de'; // Fallback, falls System-Sprache nicht ermittelbar
          const FORECAST_DAYS = 7; 
          
          // --- STANDORT KONFIGURATION ---
          const MANUAL_LATITUDE = ''; 
          const MANUAL_LONGITUDE = '';
          const FORCE_MANUAL_LOCATION = false; 
          
          // --- RANDOMISIERUNG DER ZEITEN ---
          
          function getRandomCron(startHour, endHour, minMinute = 0) {
             const hour = Math.floor(Math.random() * (endHour - startHour + 1)) + startHour;
             let minute;
             if (hour === startHour) {
                 minute = Math.floor(Math.random() * (60 - minMinute)) + minMinute;
             } else if (hour === endHour) {
                 minute = 0; 
             } else {
                 minute = Math.floor(Math.random() * 60);
             }
             return `${minute} ${hour} * * *`;
          }
          
          const cron1 = getRandomCron(0, 5, 2);
          const cron2 = getRandomCron(13, 17, 2);
          
          console.log(`[Wetter.com] Schedules für heute gesetzt auf: "${cron1}" und "${cron2}"`);
          
          // --- HILFSFUNKTIONEN ---
          
          /**
          * Formatiert ein Datum manuell in das Format: "DD.MM.YYYY"
          */
          function formatDate(dateStr) {
             if (!dateStr) return '';
             const date = new Date(dateStr);
             if (isNaN(date.getTime())) return dateStr;
             const day = String(date.getDate()).padStart(2, '0');
             const month = String(date.getMonth() + 1).padStart(2, '0');
             const year = date.getFullYear();
             return `${day}.${month}.${year}`;
          }
          
          /**
          * Ermittelt den Wochentag basierend auf der übergebenen Sprache (Locale)
          */
          function getDayName(dateStr, locale) {
             if (!dateStr) return '';
             const date = new Date(dateStr);
             if (isNaN(date.getTime())) return '';
             return date.toLocaleDateString(locale, { weekday: 'long' });
          }
          
          /**
          * Ermittelt Einstellungen (Coords + Sprache) aus ioBroker System-Config
          */
          async function getSystemSettings() {
             // Safety check für Variablen, falls User Config nicht aktualisiert hat
             const manualLat = (typeof MANUAL_LATITUDE !== 'undefined') ? MANUAL_LATITUDE : '';
             const manualLon = (typeof MANUAL_LONGITUDE !== 'undefined') ? MANUAL_LONGITUDE : '';
             const forceManual = (typeof FORCE_MANUAL_LOCATION !== 'undefined') ? FORCE_MANUAL_LOCATION : false;
             const defLang = (typeof DEFAULT_LANGUAGE !== 'undefined') ? DEFAULT_LANGUAGE : 'de';
          
             // 1. Manuelle Location?
             let coords = null;
             if (forceManual && manualLat && manualLon) {
                  console.log(`[Wetter.com] Nutze manuell konfigurierte Koordinaten (Override).`);
                  coords = { lat: parseFloat(manualLat).toFixed(3), lon: parseFloat(manualLon).toFixed(3) };
             }
          
             // 2. System Config lesen
             const systemConf = await new Promise((resolve) => {
                 getObject('system.config', (err, obj) => {
                     if (!err && obj && obj.common) {
                         resolve({
                             lat: obj.common.latitude ? parseFloat(obj.common.latitude).toFixed(3) : null,
                             lon: obj.common.longitude ? parseFloat(obj.common.longitude).toFixed(3) : null,
                             lang: obj.common.language || defLang
                         });
                     } else {
                         resolve({ lat: null, lon: null, lang: defLang });
                     }
                 });
             });
          
             // 3. Fallback Logik
             if (!coords) {
                 if (systemConf.lat && systemConf.lon) {
                     coords = { lat: systemConf.lat, lon: systemConf.lon };
                 } else if (manualLat && manualLon) {
                     console.log('[Wetter.com] Warnung: Keine System-Koordinaten. Nutze Fallback.');
                     coords = { lat: parseFloat(manualLat).toFixed(3), lon: parseFloat(manualLon).toFixed(3) };
                 }
             }
          
             if (!coords) return null;
          
             return { ...coords, lang: systemConf.lang };
          }
          
          async function ensureStructure(path, index, isInfo = false) {
             if (isInfo) {
                 await createStateAsync(`${DP_PATH}.info.last_sync`, '', false, { name: 'Letztes erfolgreiches Update', type: 'string', role: 'text' });
                 await createStateAsync(`${DP_PATH}.info.requests_today`, 0, false, { name: 'Anfragen heute', type: 'number', role: 'value' });
                 await createStateAsync(`${DP_PATH}.info.requests_month`, 0, false, { name: 'Anfragen aktueller Monat', type: 'number', role: 'value' });
                 await createStateAsync(`${DP_PATH}.info.next_schedules`, '', false, { name: 'Geplante Abrufe', type: 'string', role: 'text' });
                 return;
             }
          
             const states = {
                 'date': { name: 'Datum', type: 'string', role: 'text', def: '' },
                 'day_name': { name: 'Wochentag', type: 'string', role: 'text', def: '' },
                 'temp_max': { name: 'Max Temperatur', type: 'number', unit: '°C', role: 'value.temperature.max', def: 0 },
                 'temp_min': { name: 'Min Temperatur', type: 'number', unit: '°C', role: 'value.temperature.min', def: 0 },
                 'weather_text': { name: 'Wetterzustand', type: 'string', role: 'weather.state', def: '' },
                 'weather_code': { name: 'Wetter Code', type: 'number', role: 'value', def: 0 },
                 'weather_icon': { name: 'Wetter Icon URL', type: 'string', role: 'weather.icon', def: '' },
                 'prec_probability': { name: 'Regenrisiko', type: 'number', unit: '%', role: 'value.precipitation.probability', def: 0 },
                 'prec_sum': { name: 'Regenmenge', type: 'number', unit: 'mm', role: 'value.precipitation', def: 0 },
                 'sun_hours': { name: 'Sonnenstunden', type: 'number', unit: 'h', role: 'value.sunshine', def: 0 },
                 'wind_speed_max': { name: 'Windböen Max', type: 'number', unit: 'km/h', role: 'value.speed.wind.gust', def: 0 },
                 'wind_direction': { name: 'Windrichtung', type: 'string', role: 'weather.direction', def: '' }
             };
          
             for (const [id, config] of Object.entries(states)) {
                 await createStateAsync(`${path}.${id}`, config.def, false, {
                     name: `Tag ${index}: ${config.name}`,
                     type: config.type,
                     role: config.role,
                     unit: config.unit || '',
                     read: true,
                     write: false
                 });
             }
          }
          
          async function performRequest(url, options) {
             return new Promise((resolve, reject) => {
                 httpGet(url, options, (error, response) => {
                     if (error) return reject(new Error(error));
                     if (response.statusCode === 429) return reject(new Error('LIMIT_REACHED'));
                     if (response.statusCode !== 200) return reject(new Error(`HTTP Status ${response.statusCode}`));
                     resolve(response);
                 });
             });
          }
          
          async function cleanupObsoleteDays() {
             const channels = $(`${DP_PATH}.day_*`);
             channels.each(function(id) {
                 const parts = id.split('.');
                 const lastPart = parts[parts.length - 1]; 
                 const dayIndex = parseInt(lastPart.replace('day_', ''));
                 if (!isNaN(dayIndex) && dayIndex >= FORECAST_DAYS) {
                     deleteObject(id, true);
                 }
             });
          }
          
          async function updateUsageInfo() {
             const now = new Date();
             const day = String(now.getDate()).padStart(2, '0');
             const month = String(now.getMonth() + 1).padStart(2, '0');
             const year = now.getFullYear();
             const hours = String(now.getHours()).padStart(2, '0');
             const minutes = String(now.getMinutes()).padStart(2, '0');
             const seconds = String(now.getSeconds()).padStart(2, '0');
             
             const timestamp = `${day}.${month}.${year} ${hours}:${minutes}:${seconds}`;
             await setStateAsync(`${DP_PATH}.info.last_sync`, String(timestamp), true);
             
             const currentCountState = await getStateAsync(`${DP_PATH}.info.requests_today`);
             const currentCount = currentCountState ? (currentCountState.val || 0) : 0;
             await setStateAsync(`${DP_PATH}.info.requests_today`, currentCount + 1, true);
          
             const currentMonthState = await getStateAsync(`${DP_PATH}.info.requests_month`);
             const currentMonthCount = currentMonthState ? (currentMonthState.val || 0) : 0;
             await setStateAsync(`${DP_PATH}.info.requests_month`, currentMonthCount + 1, true);
             
             const s1 = cron1.split(' ');
             const s2 = cron2.split(' ');
             await setStateAsync(`${DP_PATH}.info.next_schedules`, `${s1[1].padStart(2,'0')}:${s1[0].padStart(2,'0')} Uhr & ${s2[1].padStart(2,'0')}:${s2[0].padStart(2,'0')} Uhr`, true);
          }
          
          // --- LOGIK ---
          
          async function fetchWeatherData() {
             try {
                 const settings = await getSystemSettings();
                 if (!settings) {
                     console.error('[Wetter.com] Fehler: Keine Koordinaten gefunden!');
                     return;
                 }
                 
                 console.log(`[Wetter.com] Starte Abruf für Lat ${settings.lat}, Lon ${settings.lon} (Sprache: ${settings.lang})`);
          
                 const url = `${BASE_URL}/forecast/${settings.lat}/${settings.lon}/summary`;
                 const options = { headers: { 'x-api-key': API_KEY, 'Accept-Language': settings.lang } };
          
                 try {
                     const response = await performRequest(url, options);
                     const data = JSON.parse(response.data);
                     if (data && data.items) {
                         await processForecastData(data.items, settings.lang);
                         await cleanupObsoleteDays();
                         await updateUsageInfo();
                     }
                 } catch (err) {
                     if (err.message === 'LIMIT_REACHED') {
                         console.error('[Wetter.com] Fehler 429: Monatslimit erreicht.');
                     } else {
                         console.error(`[Wetter.com] Fehler: ${err.message}`);
                     }
                 }
             } catch (e) {
                 console.error(`[Wetter.com] Script-Fehler: ${e.message}`);
             }
          }
          
          async function processForecastData(items, lang) {
             await ensureStructure('', 0, true); 
             const daysToProcess = Math.min(items.length, FORECAST_DAYS);
          
             // Fallback URL, falls Variable durch Teil-Update fehlt
             const iconBaseUrl = (typeof ICON_BASE_URL !== 'undefined') 
                 ? ICON_BASE_URL 
                 : 'https://cs3.wettercomassets.com/wcomv5/images/icons/weather';
          
             for (let i = 0; i < daysToProcess; i++) {
                 const day = items[i];
                 const dayPath = `${DP_PATH}.day_${i}`;
                 await ensureStructure(dayPath, i);
          
                 const germanDate = formatDate(day.date);
                 const dayName = getDayName(day.date, lang);
                 
                 const weatherCode = day.weather?.state ?? 0;
                 const iconUrl = `${iconBaseUrl}/d_${weatherCode}.svg`;
          
                 await setStateAsync(`${dayPath}.date`, germanDate, true);
                 await setStateAsync(`${dayPath}.day_name`, dayName, true);
                 await setStateAsync(`${dayPath}.temp_max`, day.temperature?.max ?? 0, true);
                 await setStateAsync(`${dayPath}.temp_min`, day.temperature?.min ?? 0, true);
                 await setStateAsync(`${dayPath}.weather_text`, day.weather?.text || '', true);
                 await setStateAsync(`${dayPath}.weather_code`, weatherCode, true);
                 await setStateAsync(`${dayPath}.weather_icon`, iconUrl, true);
                 await setStateAsync(`${dayPath}.prec_probability`, day.prec?.probability ?? 0, true);
                 await setStateAsync(`${dayPath}.prec_sum`, day.prec?.sum ?? 0, true);
                 await setStateAsync(`${dayPath}.sun_hours`, day.sunHours ?? 0, true);
                 await setStateAsync(`${dayPath}.wind_speed_max`, day.wind?.max ?? 0, true);
                 await setStateAsync(`${dayPath}.wind_direction`, day.wind?.direction || '', true);
             }
             console.log(`[Wetter.com] Update von ${daysToProcess} Tagen abgeschlossen.`);
          }
          
          schedule("0 0 * * *", () => {
             setState(`${DP_PATH}.info.requests_today`, 0, true);
          });
          
          schedule("0 0 1 * *", () => {
             setState(`${DP_PATH}.info.requests_month`, 0, true);
          });
          
          schedule(cron1, fetchWeatherData);
          schedule(cron2, fetchWeatherData);
          
          ensureStructure('', 0, true).then(() => {
             fetchWeatherData();
          });
          

          1 Antwort Letzte Antwort
          1
          • M Offline
            M Offline
            MartyBr
            schrieb am zuletzt editiert von
            #17

            Sieht gut. Kein Fehler mehr.
            Ich lasse diese Version nun laufen.

            Danke für die prompte Fehlerbehebung.

            Gruß
            Martin


            Intel NUCs mit Proxmox / Iobroker als VM unter Debian
            Raspeberry mit USB Leseköpfen für Smartmeter
            Homematic und Homematic IP

            1 Antwort Letzte Antwort
            1
            • S Online
              S Online
              Schimi
              schrieb zuletzt editiert von
              #18

              so, habe die 24 Std vorhersage eingebaut (und den 3ten API-Key verbraucht ;-))

              es gab auch eine große Änderung!!!!!

              Das Skript ist nun in TypeSkript geschrieben.

              Ihr müsst es als neues Skript importieren und dort "TypeSkript" auswählen

              Für mich wäre es dann jetzt "future-complete" und ich würde nur noch was bei Fehlern ändern und solange selber nutzen :-)

              1 Antwort Letzte Antwort
              0
              • M Offline
                M Offline
                MartyBr
                schrieb zuletzt editiert von
                #19

                Leider wieder der Fehler mit ICON_BASE_URL:

                javascript.2
                2026-01-14 08:57:47.384	error	script.js.Wetter.Forecast_Wetter_com_1-8-3: TypeScript compilation failed:';; ^ERROR: Unterminated string literal. lang: obj.common.language || DEFAULT_LANGUAGE ^ERROR: Cannot find name 'DEFAULT_LANGUAGE'. resolve({ lat: null, lon: null, lang: DEFAULT_LANGUAGE }); ^ERROR: Cannot find name 'DEFAULT_LANGUAGE'. await setStateAsync(`${dayPath}.weather_icon`, String(`${ICON_BASE_URL}/d_${day.weather?.state}.svg`), true); ^ERROR: Cannot find name 'ICON_BASE_URL'. await setStateChangedAsync(`${hPath}.weather_icon`, String(`${ICON_BASE_URL}/d_${h.weather?.state}.svg`), true); ^ERROR: Cannot find name 'ICON_BASE_URL'.
                
                javascript.2
                2026-01-14 08:57:47.297	info	script.js.Wetter.Forecast_Wetter_com_1-8-3: Compiling TypeScript source
                
                javascript.2
                2026-01-14 08:57:43.337	info	script.js.Wetter.Forecast_Wetter_com_1-8-3: Stopping script
                
                javascript.2
                2026-01-14 08:57:31.016	error	script.js.Wetter.Forecast_Wetter_com_1-8-3: TypeScript compilation failed:';; ^ERROR: Unterminated string literal. lang: obj.common.language || DEFAULT_LANGUAGE ^ERROR: Cannot find name 'DEFAULT_LANGUAGE'. resolve({ lat: null, lon: null, lang: DEFAULT_LANGUAGE }); ^ERROR: Cannot find name 'DEFAULT_LANGUAGE'. await setStateAsync(`${dayPath}.weather_icon`, String(`${ICON_BASE_URL}/d_${day.weather?.state}.svg`), true); ^ERROR: Cannot find name 'ICON_BASE_URL'. await setStateChangedAsync(`${hPath}.weather_icon`, String(`${ICON_BASE_URL}/d_${h.weather?.state}.svg`), true); ^ERROR: Cannot find name 'ICON_BASE_URL'.
                
                javascript.2
                2026-01-14 08:57:30.119	info	script.js.Wetter.Forecast_Wetter_com_1-8-3: Compiling TypeScript source
                

                Gruß
                Martin


                Intel NUCs mit Proxmox / Iobroker als VM unter Debian
                Raspeberry mit USB Leseköpfen für Smartmeter
                Homematic und Homematic IP

                1 Antwort Letzte Antwort
                0
                • S Online
                  S Online
                  Schimi
                  schrieb zuletzt editiert von Schimi
                  #20

                  @martybr versuche mal das im Spoiler... vielleicht auch mal den Datenpunkt komplett löschen und neu erstellen lassen (in den Objekten)

                  Nicht das durch den Wechsel auf TypeSkript da auch was geändert wurde

                  /**
                  * ioBroker Script: Wetter.com Forecast API v4.0 (TrueScript)
                  * API: https://doc.meteonomiqs.com/doc/forecast_v4_0.html
                  * * * Changelog:
                  * 1.8.4: FIX: Compiler-Fehler & Syntax-Bereinigung.
                  * - Konfiguration in 'CONFIG'-Objekt gekapselt, um Scope-Fehler ("Cannot find name") zu beheben.
                  * - Bereinigung von Template-Strings (entfernte redundante String()-Wrapper).
                  * - Typsichere Implementierung von getObject-Callbacks.
                  * 1.8.3: FIX: Namenskonflikte behoben (wcom-Präfix).
                  */
                  
                  // --- KONFIGURATION ---
                  const CONFIG = {
                     API_KEY: 'DEIN_API_KEY_HIER', // <-- BITTE HIER DEINEN API-KEY EINTRAGEN
                     BASE_URL: 'https://forecast.meteonomiqs.com/v4_0',
                     ICON_BASE_URL: 'https://cs3.wettercomassets.com/wcomv5/images/icons/weather',
                     DP_PATH: '0_userdata.0.wetter_com',
                     DEFAULT_LANGUAGE: 'de',
                     FORECAST_DAYS: 7, // max. 16 Tage
                     ENABLE_HOURLY: true,
                     ENABLE_SPACES: true,
                     LOCATION: {
                         LAT: '', // Leer lassen für System-Einstellung
                         LON: '', // Leer lassen für System-Einstellung
                         FORCE_MANUAL: false
                     }
                  };
                  
                  // --- INTERFACES ---
                  
                  interface WetterComValue {
                     avg?: number;
                     value?: number;
                     sum?: number;
                     max?: number;
                     min?: number;
                  }
                  
                  interface WetterComWeather {
                     state: number;
                     text: string;
                     icon?: string;
                  }
                  
                  interface WetterComWind {
                     avg?: number | WetterComValue;
                     gusts?: number | WetterComValue | { value: number | null };
                     direction?: string;
                     unit?: string;
                  }
                  
                  interface WetterComPrec {
                     probability: number;
                     sum: number | WetterComValue;
                  }
                  
                  interface ForecastSummary {
                     date: string;
                     weather: WetterComWeather;
                     temperature: { min: number | WetterComValue; max: number | WetterComValue; avg?: number | WetterComValue };
                     wind: WetterComWind;
                     prec: WetterComPrec;
                     clouds: number | WetterComValue;
                     relativeHumidity: number | WetterComValue;
                  }
                  
                  interface ForecastSpaceSegment {
                     temperature: number | WetterComValue;
                     weather: WetterComWeather;
                     prec: WetterComPrec;
                     wind: WetterComWind;
                     clouds: number | WetterComValue;
                     relativeHumidity: number | WetterComValue;
                  }
                  
                  interface ForecastSpace {
                     morning?: ForecastSpaceSegment;
                     afternoon?: ForecastSpaceSegment;
                     evening?: ForecastSpaceSegment;
                     night?: ForecastSpaceSegment;
                  }
                  
                  interface ForecastHourly {
                     from: string;
                     date: string;
                     weather: WetterComWeather;
                     temperature: number | WetterComValue;
                     windchill: number | WetterComValue;
                     wind: WetterComWind;
                     prec: WetterComPrec;
                     relativeHumidity: number | WetterComValue;
                  }
                  
                  interface WetterComResponse {
                     summary: ForecastSummary[];
                     spaces: ForecastSpace[];
                     hourly: ForecastHourly[];
                  }
                  
                  // --- HILFSFUNKTIONEN ---
                  
                  const wcomWait = (ms: number): Promise<void> => new Promise(resolve => setTimeout(resolve, ms));
                  
                  function wcomExtractValue(val: any): number {
                     if (val === null || val === undefined) return 0;
                     if (typeof val === 'number') return val;
                     if (typeof val === 'object') {
                         if (val.avg !== undefined) return val.avg;
                         if (val.value !== undefined) return val.value;
                         if (val.sum !== undefined) return val.sum;
                         if (val.max !== undefined) return val.max;
                         if (val.min !== undefined) return val.min;
                         if (val.gusts && typeof val.gusts === 'object' && val.gusts.value !== undefined) return val.gusts.value;
                     }
                     return parseFloat(String(val)) || 0;
                  }
                  
                  function wcomFormatDate(dateStr: string): string {
                     if (!dateStr) return '';
                     const date = new Date(dateStr);
                     if (isNaN(date.getTime())) return dateStr;
                     return `${String(date.getDate()).padStart(2, '0')}.${String(date.getMonth() + 1).padStart(2, '0')}.${date.getFullYear()}`;
                  }
                  
                  function wcomGetDayName(dateStr: string, locale: string): string {
                     if (!dateStr) return '';
                     const date = new Date(dateStr);
                     if (isNaN(date.getTime())) return '';
                     return date.toLocaleDateString(locale, { weekday: 'long' });
                  }
                  
                  async function wcomGetSystemSettings(): Promise<{ lat: string; lon: string; lang: string } | null> {
                     let coords: { lat: string; lon: string } | null = null;
                     if (CONFIG.LOCATION.FORCE_MANUAL && CONFIG.LOCATION.LAT && CONFIG.LOCATION.LON) {
                          coords = { lat: parseFloat(CONFIG.LOCATION.LAT).toFixed(3), lon: parseFloat(CONFIG.LOCATION.LON).toFixed(3) };
                     }
                  
                     const systemConf: any = await new Promise((resolve) => {
                         getObject('system.config', (err, obj: any) => {
                             if (!err && obj && obj.common) {
                                 resolve({
                                     lat: obj.common.latitude ? parseFloat(String(obj.common.latitude)).toFixed(3) : null,
                                     lon: obj.common.longitude ? parseFloat(String(obj.common.longitude)).toFixed(3) : null,
                                     lang: obj.common.language || CONFIG.DEFAULT_LANGUAGE
                                 });
                             } else { resolve({ lat: null, lon: null, lang: CONFIG.DEFAULT_LANGUAGE }); }
                         });
                     });
                  
                     if (!coords && systemConf.lat && systemConf.lon) coords = { lat: systemConf.lat, lon: systemConf.lon };
                     return coords ? { ...coords, lang: systemConf.lang } : null;
                  }
                  
                  async function wcomEnsureSubStructure(path: string, name: string, type: 'device' | 'channel' = 'channel'): Promise<void> {
                     if (!path) return;
                     if (!existsObject(path)) {
                         await extendObjectAsync(path, {
                             type: type,
                             common: { name: name },
                             native: {}
                         });
                         await wcomWait(50);
                     }
                  }
                  
                  async function wcomEnsureDayStates(path: string, index: number): Promise<void> {
                     const states: Record<string, { name: string; type: iobJS.CommonType; role: string; unit?: string; init: any }> = {
                         'date': { name: 'Datum', type: 'string', role: 'text', init: '' },
                         'day_name': { name: 'Wochentag', type: 'string', role: 'text', init: '' },
                         'temp_max': { name: 'Max Temp', type: 'number', unit: '°C', role: 'value.temperature.max', init: 0 },
                         'temp_min': { name: 'Min Temp', type: 'number', unit: '°C', role: 'value.temperature.min', init: 0 },
                         'weather_text': { name: 'Wetter', type: 'string', role: 'weather.state', init: '' },
                         'weather_icon': { name: 'Icon URL', type: 'string', role: 'weather.icon', init: '' },
                         'prec_probability': { name: 'Regenrisiko', type: 'number', unit: '%', role: 'value.precipitation.probability', init: 0 },
                         'prec_sum': { name: 'Regenmenge', type: 'number', unit: 'mm', role: 'value.precipitation', init: 0 },
                         'wind_gusts': { name: 'Windböen', type: 'number', unit: 'km/h', role: 'value.speed.wind.gust', init: 0 },
                         'clouds': { name: 'Bewölkung', type: 'number', unit: '%', role: 'value', init: 0 },
                         'humidity': { name: 'Relative Feuchte', type: 'number', unit: '%', role: 'value.humidity', init: 0 }
                     };
                  
                     for (const [id, cfg] of Object.entries(states)) {
                         await createStateAsync(`${path}.${id}`, cfg.init, false, { 
                             name: `Tag ${index}: ${cfg.name}`, 
                             type: cfg.type,
                             role: cfg.role,
                             unit: cfg.unit || '',
                             read: true, 
                             write: false 
                         });
                     }
                  }
                  
                  // --- LOGIK ---
                  
                  async function wcomFetchWeatherData(): Promise<void> {
                     try {
                         const settings = await wcomGetSystemSettings();
                         if (!settings) return;
                         
                         console.log(`[Wetter.com] Abruf für Lat ${settings.lat}, Lon ${settings.lon}`);
                  
                         const url: string = `${CONFIG.BASE_URL}/forecast/${settings.lat}/${settings.lon}`;
                         const options = { headers: { 'x-api-key': CONFIG.API_KEY, 'Accept-Language': settings.lang } };
                  
                         httpGet(url, options, async (err, response) => {
                             if (response && response.statusCode === 429) {
                                 console.error('[Wetter.com] Das Limit von 100 API-Calls im Monat ist ausgeschöpft.');
                                 return;
                             }
                  
                             if (err || (response && response.statusCode !== 200)) {
                                 console.error(`[Wetter.com] API-Fehler: ${err || (response ? response.statusCode : 'Unbekannter Status')}`);
                                 return;
                             }
                  
                             let data: WetterComResponse;
                             try {
                                 data = JSON.parse(response.data);
                             } catch (e) { return; }
                  
                             if (data && data.summary) {
                                 await wcomProcessForecastData(data, settings.lang);
                                 await wcomCleanupObsoleteDays();
                                 await wcomUpdateUsageInfo();
                             }
                         });
                     } catch (e: any) { console.error(`[Wetter.com] Script-Fehler: ${e.message}`); }
                  }
                  
                  async function wcomProcessForecastData(data: WetterComResponse, lang: string): Promise<void> {
                     await wcomEnsureSubStructure(CONFIG.DP_PATH, 'Wetter.com Forecast', 'device');
                     await wcomEnsureSubStructure(`${CONFIG.DP_PATH}.info`, 'Informationen');
                     await createStateAsync(`${CONFIG.DP_PATH}.info.last_sync`, '', false, { name: 'Letztes Update', type: 'string', role: 'text' } as any);
                     await createStateAsync(`${CONFIG.DP_PATH}.info.requests_today`, 0, false, { name: 'Anfragen heute', type: 'number', role: 'value' } as any);
                  
                     const maxDays: number = Math.min(data.summary.length, CONFIG.FORECAST_DAYS);
                  
                     for (let i = 0; i < maxDays; i++) {
                         const day: ForecastSummary = data.summary[i];
                         const dayPath: string = `${CONFIG.DP_PATH}.day_${i}`;
                         
                         await wcomEnsureSubStructure(dayPath, `Tag ${i}`);
                         await wcomEnsureDayStates(dayPath, i);
                  
                         await setStateAsync(`${dayPath}.date`, String(wcomFormatDate(day.date)), true);
                         await setStateAsync(`${dayPath}.day_name`, String(wcomGetDayName(day.date, lang)), true);
                         await setStateAsync(`${dayPath}.temp_max`, wcomExtractValue(day.temperature?.max), true);
                         await setStateAsync(`${dayPath}.temp_min`, wcomExtractValue(day.temperature?.min), true);
                         await setStateAsync(`${dayPath}.weather_text`, String(day.weather?.text || ''), true);
                         await setStateAsync(`${dayPath}.weather_icon`, `${CONFIG.ICON_BASE_URL}/d_${day.weather?.state}.svg`, true);
                         await setStateAsync(`${dayPath}.prec_probability`, wcomExtractValue(day.prec?.probability), true);
                         await setStateAsync(`${dayPath}.prec_sum`, wcomExtractValue(day.prec?.sum), true);
                         await setStateAsync(`${dayPath}.wind_gusts`, wcomExtractValue(day.wind?.gusts), true);
                         await setStateAsync(`${dayPath}.clouds`, wcomExtractValue(day.clouds), true);
                         await setStateAsync(`${dayPath}.humidity`, wcomExtractValue(day.relativeHumidity), true);
                  
                         if (CONFIG.ENABLE_SPACES && data.spaces && data.spaces[i]) {
                             const spacesPath: string = `${dayPath}.spaces`;
                             await wcomEnsureSubStructure(spacesPath, 'Tagesabschnitte');
                             const segments: (keyof ForecastSpace)[] = ['morning', 'afternoon', 'evening', 'night'];
                             
                             for (const seg of segments) {
                                 const sData = data.spaces[i][seg];
                                 if (!sData) continue;
                                 const sPath: string = `${spacesPath}.${seg}`;
                                 await wcomEnsureSubStructure(sPath, seg);
                                 
                                 await createStateAsync(`${sPath}.temp`, 0, false, { name: 'Temperatur', type: 'number', unit: '°C', role: 'value.temperature' } as any);
                                 await setStateChangedAsync(`${sPath}.temp`, wcomExtractValue(sData.temperature), true);
                                 await createStateAsync(`${sPath}.text`, '', false, { name: 'Wetter', type: 'string', role: 'weather.state' } as any);
                                 await setStateChangedAsync(`${sPath}.text`, String(sData.weather?.text || ''), true);
                                 await createStateAsync(`${sPath}.prec_prob`, 0, false, { name: 'Regenrisiko', type: 'number', unit: '%', role: 'value.precipitation.probability' } as any);
                                 await setStateChangedAsync(`${sPath}.prec_prob`, wcomExtractValue(sData.prec?.probability), true);
                                 await createStateAsync(`${sPath}.prec_sum`, 0, false, { name: 'Regenmenge', type: 'number', unit: 'mm', role: 'value.precipitation' } as any);
                                 await setStateChangedAsync(`${sPath}.prec_sum`, wcomExtractValue(sData.prec?.sum), true);
                                 await createStateAsync(`${sPath}.wind_speed`, 0, false, { name: 'Windgeschwindigkeit', type: 'number', unit: 'km/h', role: 'value.speed.wind' } as any);
                                 await setStateChangedAsync(`${sPath}.wind_speed`, wcomExtractValue(sData.wind?.avg), true);
                                 await createStateAsync(`${sPath}.wind_gusts`, 0, false, { name: 'Windböen', type: 'number', unit: 'km/h', role: 'value.speed.wind.gust' } as any);
                                 await setStateChangedAsync(`${sPath}.wind_gusts`, wcomExtractValue(sData.wind?.gusts), true);
                                 await createStateAsync(`${sPath}.clouds`, 0, false, { name: 'Bewölkung', type: 'number', unit: '%', role: 'value' } as any);
                                 await setStateChangedAsync(`${sPath}.clouds`, wcomExtractValue(sData.clouds), true);
                                 await createStateAsync(`${sPath}.humidity`, 0, false, { name: 'Relative Feuchte', type: 'number', unit: '%', role: 'value.humidity' } as any);
                                 await setStateChangedAsync(`${sPath}.humidity`, wcomExtractValue(sData.relativeHumidity), true);
                             }
                         }
                  
                         if (CONFIG.ENABLE_HOURLY && i <= 1 && data.hourly) {
                             const dateIso: string = day.date.split('T')[0];
                             const hourlyPath: string = `${dayPath}.hourly`;
                             await wcomEnsureSubStructure(hourlyPath, 'Stündlich');
                             const dayHours = data.hourly.filter((h: ForecastHourly) => (h.from || h.date).startsWith(dateIso));
                             
                             for (const h of dayHours) {
                                 const hourDate: Date = new Date(h.from || h.date);
                                 const hourLabel: string = String(hourDate.getHours()).padStart(2, '0');
                                 const hPath: string = `${hourlyPath}.${hourLabel}`;
                                 
                                 await wcomEnsureSubStructure(hPath, `${hourLabel}:00 Uhr`);
                                 
                                 await createStateAsync(`${hPath}.time`, '', false, { name: 'Uhrzeit', type: 'string', role: 'text' } as any);
                                 await setStateChangedAsync(`${hPath}.time`, `${hourLabel}:00`, true);
                                 await createStateAsync(`${hPath}.temp`, 0, false, { name: 'Temperatur', type: 'number', unit: '°C', role: 'value.temperature' } as any);
                                 await setStateChangedAsync(`${hPath}.temp`, wcomExtractValue(h.temperature), true);
                                 await createStateAsync(`${hPath}.windchill`, 0, false, { name: 'Gefühlt', type: 'number', unit: '°C', role: 'value.temperature' } as any);
                                 await setStateChangedAsync(`${hPath}.windchill`, wcomExtractValue(h.windchill), true);
                                 await createStateAsync(`${hPath}.weather_text`, '', false, { name: 'Wetter', type: 'string', role: 'weather.state' } as any);
                                 await setStateChangedAsync(`${hPath}.weather_text`, String(h.weather?.text || ''), true);
                                 await createStateAsync(`${hPath}.weather_icon`, '', false, { name: 'Wetter Icon', type: 'string', role: 'weather.icon' } as any);
                                 await setStateChangedAsync(`${hPath}.weather_icon`, `${CONFIG.ICON_BASE_URL}/d_${h.weather?.state}.svg`, true);
                                 await createStateAsync(`${hPath}.prec_prob`, 0, false, { name: 'Regenwahrscheinlichkeit', type: 'number', unit: '%', role: 'value.precipitation.probability' } as any);
                                 await setStateChangedAsync(`${hPath}.prec_prob`, wcomExtractValue(h.prec?.probability), true);
                                 await createStateAsync(`${hPath}.prec_sum`, 0, false, { name: 'Regenmenge', type: 'number', unit: 'mm', role: 'value.precipitation' } as any);
                                 await setStateChangedAsync(`${hPath}.prec_sum`, wcomExtractValue(h.prec?.sum), true);
                                 await createStateAsync(`${hPath}.wind_speed`, 0, false, { name: 'Windgeschwindigkeit', type: 'number', unit: 'km/h', role: 'value.speed.wind' } as any);
                                 await setStateChangedAsync(`${hPath}.wind_speed`, wcomExtractValue(h.wind?.avg), true);
                                 await createStateAsync(`${hPath}.wind_dir`, '', false, { name: 'Windrichtung', type: 'string', role: 'weather.direction' } as any);
                                 await setStateChangedAsync(`${hPath}.wind_dir`, String(h.wind?.direction || ''), true);
                                 await createStateAsync(`${hPath}.wind_gusts`, 0, false, { name: 'Windböen', type: 'number', unit: 'km/h', role: 'value.speed.wind.gust' } as any);
                                 await setStateChangedAsync(`${hPath}.wind_gusts`, wcomExtractValue(h.wind?.gusts), true);
                                 await createStateAsync(`${hPath}.humidity`, 0, false, { name: 'Relative Feuchte', type: 'number', unit: '%', role: 'value.humidity' } as any);
                                 await setStateChangedAsync(`${hPath}.humidity`, wcomExtractValue(h.relativeHumidity), true);
                             }
                         }
                         await wcomWait(20); 
                     }
                  }
                  
                  async function wcomCleanupObsoleteDays(): Promise<void> {
                     for (let i = CONFIG.FORECAST_DAYS; i <= 25; i++) {
                         const path: string = `${CONFIG.DP_PATH}.day_${i}`;
                         if (existsObject(path)) {
                             await deleteObjectAsync(path, true);
                             await wcomWait(150);
                         }
                     }
                  }
                  
                  async function wcomUpdateUsageInfo(): Promise<void> {
                     const now: Date = new Date();
                     const timestamp: string = `${String(now.getDate()).padStart(2,'0')}.${String(now.getMonth()+1).padStart(2,'0')}.${now.getFullYear()} ${String(now.getHours()).padStart(2,'0')}:${String(now.getMinutes()).padStart(2,'0')}`;
                     await setStateAsync(`${CONFIG.DP_PATH}.info.last_sync`, String(timestamp), true);
                     const countState: iobJS.State | null = await getStateAsync(`${CONFIG.DP_PATH}.info.requests_today`);
                     await setStateAsync(`${CONFIG.DP_PATH}.info.requests_today`, (countState ? (Number(countState.val) || 0) : 0) + 1, true);
                  }
                  
                  // --- ZEITSTEUERUNG ---
                  
                  function wcomGetRandomCron(startHour: number, endHour: number, minMinute: number = 0): string {
                     const hour: number = Math.floor(Math.random() * (endHour - startHour + 1)) + startHour;
                     let minute: number = (hour === startHour) ? Math.floor(Math.random() * (60 - minMinute)) + minMinute : (hour === endHour ? 0 : Math.floor(Math.random() * 60));
                     return `${minute} ${hour} * * *`;
                  }
                  
                  schedule("0 0 * * *", () => setState(`${CONFIG.DP_PATH}.info.requests_today`, 0, true));
                  schedule(wcomGetRandomCron(0, 5, 2), wcomFetchWeatherData);
                  schedule(wcomGetRandomCron(13, 17, 2), wcomFetchWeatherData);
                  
                  wcomFetchWeatherData();
                  

                  1 Antwort Letzte Antwort
                  0
                  • M Offline
                    M Offline
                    MartyBr
                    schrieb zuletzt editiert von MartyBr
                    #21

                    Jetzt läuft das Script und die Datenpunkte wurden angelegt.

                    Hier das Log:

                    javascript.2
                    2026-01-14 10:10:38.171	info	script.js.Wetter.Forecast_Wetter_com_1-8-4: [Wetter.com] Abruf für Lat 52.aaaaa, Lon 13.xxxx
                    
                    javascript.2
                    2026-01-14 10:10:38.169	info	script.js.Wetter.Forecast_Wetter_com_1-8-4: registered 0 subscriptions, 3 schedules, 0 messages, 0 logs and 0 file subscriptions
                    
                    javascript.2
                    2026-01-14 10:10:38.154	info	script.js.Wetter.Forecast_Wetter_com_1-8-4: TypeScript compilation successful
                    
                    javascript.2
                    2026-01-14 10:10:37.928	info	script.js.Wetter.Forecast_Wetter_com_1-8-4: Compiling TypeScript source
                    
                    viessmannapi.0
                    2026-01-14 10:10:33.273	info	
                    

                    Gruß
                    Martin


                    Intel NUCs mit Proxmox / Iobroker als VM unter Debian
                    Raspeberry mit USB Leseköpfen für Smartmeter
                    Homematic und Homematic IP

                    S 1 Antwort Letzte Antwort
                    0
                    • M MartyBr

                      Jetzt läuft das Script und die Datenpunkte wurden angelegt.

                      Hier das Log:

                      javascript.2
                      2026-01-14 10:10:38.171	info	script.js.Wetter.Forecast_Wetter_com_1-8-4: [Wetter.com] Abruf für Lat 52.aaaaa, Lon 13.xxxx
                      
                      javascript.2
                      2026-01-14 10:10:38.169	info	script.js.Wetter.Forecast_Wetter_com_1-8-4: registered 0 subscriptions, 3 schedules, 0 messages, 0 logs and 0 file subscriptions
                      
                      javascript.2
                      2026-01-14 10:10:38.154	info	script.js.Wetter.Forecast_Wetter_com_1-8-4: TypeScript compilation successful
                      
                      javascript.2
                      2026-01-14 10:10:37.928	info	script.js.Wetter.Forecast_Wetter_com_1-8-4: Compiling TypeScript source
                      
                      viessmannapi.0
                      2026-01-14 10:10:33.273	info	
                      
                      S Online
                      S Online
                      Schimi
                      schrieb zuletzt editiert von
                      #22

                      @MartyBr Danke

                      mach mal Lat und Lon in deinem Log unkenntlich... sonst sieht jeder wo du wohnst ;-)

                      M 1 Antwort Letzte Antwort
                      0
                      • nik82N Offline
                        nik82N Offline
                        nik82
                        Most Active
                        schrieb zuletzt editiert von
                        #23

                        Also ich hab jetzt auch das neue TypeScript importiert, schaut soweit perfekt aus und hab keine Fehlermeldung.

                        1 Antwort Letzte Antwort
                        1
                        • S Schimi

                          @MartyBr Danke

                          mach mal Lat und Lon in deinem Log unkenntlich... sonst sieht jeder wo du wohnst ;-)

                          M Offline
                          M Offline
                          MartyBr
                          schrieb zuletzt editiert von
                          #24

                          @Schimi
                          Danke für den Hinweis. Ist erledigt!

                          Gruß
                          Martin


                          Intel NUCs mit Proxmox / Iobroker als VM unter Debian
                          Raspeberry mit USB Leseköpfen für Smartmeter
                          Homematic und Homematic IP

                          1 Antwort Letzte Antwort
                          1
                          • nik82N Offline
                            nik82N Offline
                            nik82
                            Most Active
                            schrieb zuletzt editiert von
                            #25

                            Hab mal eine schöne VIS gemacht, falls es irgendwer braucht:

                            image.png

                            Hier die View zum importieren:
                            wettercom_view.txt

                            1 Antwort Letzte Antwort
                            1
                            Antworten
                            • In einem neuen Thema antworten
                            Anmelden zum Antworten
                            • Älteste zuerst
                            • Neuste zuerst
                            • Meiste Stimmen


                            Support us

                            ioBroker
                            Community Adapters
                            Donate

                            795

                            Online

                            32.6k

                            Benutzer

                            82.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