Navigation

    Logo
    • Register
    • Login
    • Search
    • Recent
    • Tags
    • Unread
    • Categories
    • Unreplied
    • Popular
    • GitHub
    • Docu
    • Hilfe
    1. Home
    2. Ro75

    NEWS

    • UPDATE 31.10.: Amazon Alexa - ioBroker Skill läuft aus ?

    • Monatsrückblick – September 2025

    • Neues Video "KI im Smart Home" - ioBroker plus n8n

    • Profile
    • Following 2
    • Followers 5
    • Topics 28
    • Posts 2026
    • Best 269
    • Groups 3

    Ro75

    @Ro75

    374
    Reputation
    169
    Profile views
    2026
    Posts
    5
    Followers
    2
    Following
    Joined Last Online
    Location Bautzen

    Ro75 Follow
    Pro Starter Most Active

    Best posts made by Ro75

    • RE: Einfach mal zeigen will….. :-) - Teil 3

      Habe noch einmal alles überarbeitet. Stelle alles (gesamte System) zur Verfügung. Soweit möglich auch alles anonymisiert.

      Alexa.png

      System.png

      Adapter:

      Adapter.png

      Die in dieser Liste vorhandenen Adapter sind alle konfiguriert. Adapter die ihr nicht verwendet, müsstet ihr dann aus der VIS und den Java-Skripten entfernen. An dieser Stelle gleich der Hinweis, es ist alles eng miteinander verbunden. Und noch ein Hinweis. Benötigte Datenpunkte werden zu 99,9% bei der jeweiligen Funktion gleich mit erstellt, damit alles geht. Daten werden generell in "0_userdata.0" erstellt, abgeholt und gespeichert.

      1676055007780-vis.zip
      vis_skripte.txt
      vis_css.txt

      Das ist die komplette VIS mit allen Views. Auflösung 1920 * 1060. Dazu auch die CSS und Skripte innerhalb der VIS.

      1676102243305-1676055139628-javascript.zip

      Hier sind alle Java - Skripte. Achtung: Nicht gleich alle auf einmal einkopieren und starten. Die Skripte sind in Ordner, für eine bessere Übersicht, abgelegt. Einige Skripte verarbeiten auch Aufzählungen. Da bitte aufpassen.

      vis.0 teil 2.zip

      vis.0 teil 1.zip

      vis.0 teil 3.zip

      vis.0 teil 4.zip

      Diese 4 Dateien sind Bilder und Fonts und müssen zuerst entpackt werden. Dann habt ihr einzelne Ordner und Dateien. Die müssen alle über den Dateimanager (VIS dann System, ...) in den Ordner "/vis.0/" hochgeladen werden.

      Viel Spaß. Ich versuche bei Problemen zu helfen. Allerdings ist Support nicht unbedingt meine Stärke (Bei dem was ich heute so im Forum gelesen hab...). Eine Bitte. Wer meine Javascripte optimieren, verbessern, verkürzen,... kann bitte melden. Würde mich freuen.

      posted in Praktische Anwendungen (Showcase)
      Ro75
      Ro75
    • Skript zur dynamischen Generierung Batterie/Akku Symbol

      Hallo. Hier ein neues Skript von mir. Ich verwende in meiner Visualisierung (VIS 1) an diversen Stellen den (Lade)zustand von Batterie/Akku. Bisher habe ich das mit Grafiken (png, svg) realisiert.

      Dieses Skript erzeugt dynamisch ein farbliches Symbol im SVG Format. Diese reicht von rot bis grün. Der Prozentsatz ist zentriert enthalten. Weiterhin können auch kräftiger Farben oder ein Ladesymbol (frei positionierbar) aktiviert werden. Statt % kann auch jede andere Bezeichnung für den Wert, oder ein komplett anderer Text genutzt werden.

      Funktioniert mit VIS 1. Sollte aber auch mit VIS 2 oder anderen Modulen laufen.

      1669fd2f-5946-42bc-97ef-7b59dd56da9e-image.png
      a52d44d2-074f-4efd-a6f9-81a09c84066e-image.png
      696d718a-ffcb-434c-b810-42c4e3ac62cf-image.png
      fedfc5ea-1629-4fbb-9b39-2a8da2c73ae9-image.png
      c8a5082d-7dca-479e-97e1-e193bbcccbef-image.png

      Mit ein wenig Spielerei und Experimentierfreudigkeit kann man da auch andere Farben verwenden.

      Der Code generiert einen SVG Code der in einem Datenpunkt (Zeichen) gespeichert wird. Zur Darstellung wird in VIS 1 das String (unescaped) verwendet, das mit dem entsprechenden Datenpunkt verbunden ist.

      Der Code:

      //Ersteller: Ro75
      //Datum: 13.11.2025
      //Version: 1.0.8
      //Javascript: 8.9.2
      //NodeJS: 20.x / 22.x
      
      // dynamische Betterie-Icon Generierung
      
      // -------------------------------------------------------
      // Hilfsfunktionen
      // -------------------------------------------------------
      function clamp(v, a, b) { return Math.max(a, Math.min(b, v)); }
      function uid(prefix = 'id') { return `${prefix}-${Math.random().toString(36).slice(2,9)}`; }
      
      function hslToRgb(h, s, l) {
        s /= 100; l /= 100;
        const k = n => (n + h / 30) % 12;
        const a = s * Math.min(l, 1 - l);
        const f = n => l - a * Math.max(-1, Math.min(k(n) - 3, Math.min(9 - k(n), 1)));
        return [Math.round(255 * f(0)), Math.round(255 * f(8)), Math.round(255 * f(4))];
      }
      
      function luminance(r, g, b) {
        const srgb = [r, g, b].map(c => {
          c /= 255;
          return (c <= 0.04045) ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
        });
        return 0.2126 * srgb[0] + 0.7152 * srgb[1] + 0.0722 * srgb[2];
      }
      
      const SAMPLE_POINTS = [
        { p: 0, w: 2 }, { p: 5, w: 10 }, { p: 10, w: 19 }, { p: 15, w: 29 }, { p: 20, w: 38 },
        { p: 25, w: 48 }, { p: 30, w: 58 }, { p: 35, w: 67 }, { p: 40, w: 77 }, { p: 45, w: 86 },
        { p: 50, w: 96 }, { p: 55, w: 106 }, { p: 60, w: 115 }, { p: 65, w: 125 }, { p: 70, w: 134 },
        { p: 75, w: 144 }, { p: 80, w: 154 }, { p: 85, w: 163 }, { p: 90, w: 173 }, { p: 95, w: 182 },
        { p: 100, w: 192 }
      ];
      
      function interpolatedWidth(percent) {
        const p = clamp(percent, 0, 100);
        for (const s of SAMPLE_POINTS) if (s.p === p) return s.w;
        let lower = SAMPLE_POINTS[0], upper = SAMPLE_POINTS[SAMPLE_POINTS.length - 1];
        for (let i = 0; i < SAMPLE_POINTS.length - 1; i++) {
          const a = SAMPLE_POINTS[i], b = SAMPLE_POINTS[i + 1];
          if (p > a.p && p < b.p) { lower = a; upper = b; break; }
          if (p === b.p) return b.w;
        }
        const t = (p - lower.p) / (upper.p - lower.p);
        return Math.round(lower.w + t * (upper.w - lower.w));
      }
      
      // -------------------------------------------------------
      // Farb-Schemata mit strongColors-Effekt
      // -------------------------------------------------------
      function getFillColor(p, strongColors, colorScheme) {
        let hue;
        let saturation;
        let lightness;
      
        switch ((colorScheme || 'default').toLowerCase()) {
          case 'green':
            hue = 120;
            saturation = strongColors ? 100 : 80;
            lightness = strongColors ? 25 + (p / 100) * 25 : 35 + (p / 100) * 30;
            break;
          case 'yellow':
            hue = 50;
            saturation = strongColors ? 100 : 85;
            lightness = strongColors ? 25 + (p / 100) * 30 : 35 + (p / 100) * 30;
            break;
          case 'blue':
            hue = 210;
            saturation = strongColors ? 100 : 75;
            lightness = strongColors ? 20 + (p / 100) * 25 : 35 + (p / 100) * 30;
            break;
          case 'red':
            hue = 0;
            saturation = strongColors ? 100 : 75;
            lightness = strongColors ? 20 + (p / 100) * 25 : 35 + (p / 100) * 30;
            break;
          case 'orange':
            hue = 30;
            saturation = strongColors ? 100 : 80;
            lightness = strongColors ? 20 + (p / 100) * 25 : 35 + (p / 100) * 30;
            break;
          case 'brown':
            hue = 25;
            saturation = strongColors ? 85 : 65;
            lightness = strongColors ? 20 + (p / 100) * 20 : 25 + (p / 100) * 25;
            break;
          case 'grey':
            hue = 0;
            saturation = strongColors ? 15 : 0;
            lightness = strongColors ? 20 + (p / 100) * 40 : 25 + (p / 100) * 40;
            break;
          case 'purple':
            hue = 275;
            saturation = strongColors ? 95 : 75;
            lightness = strongColors ? 25 + (p / 100) * 25 : 35 + (p / 100) * 30;
            break;
          case 'black':
            hue = 0;
            saturation = strongColors ? 10 : 0;
            lightness = strongColors ? 1 + (p / 100) * 27 : 3 + (p / 100) * 20;
            break;
          default: // Standard: grün → rot Verlauf
            hue = Math.round((p / 100) * 120);
            saturation = strongColors ? 100 : 90;
            lightness = strongColors ? 35 : 50;
            break;
        }
      
        return `hsl(${hue},${saturation}%,${lightness}%)`;
      }
      
      // -------------------------------------------------------
      // Blitz-Farbverlauf passend zum Farbschema
      // -------------------------------------------------------
      function getBoltGradientFromScheme(strongColors, boltColorScheme) {
        const scheme = (boltColorScheme || 'default').toLowerCase();
      
        if (scheme === 'default') {
          return ['#f7b23b', '#f59e0b'];
        }
      
        let hue, saturation;
        switch (scheme) {
          case 'green': hue = 120; saturation = strongColors ? 100 : 80; break;
          case 'yellow': hue = 50; saturation = strongColors ? 100 : 85; break;
          case 'blue': hue = 210; saturation = strongColors ? 100 : 75; break;
          case 'red': hue = 0; saturation = strongColors ? 100 : 75; break;
          case 'orange': hue = 30; saturation = strongColors ? 100 : 80; break;
          case 'brown': hue = 25; saturation = strongColors ? 85 : 65; break;
          case 'grey': hue = 0; saturation = strongColors ? 15 : 0; break;
          case 'purple': hue = 275; saturation = strongColors ? 95 : 75; break;
          case 'black': hue = 0; saturation = strongColors ? 10 : 0; break;
          default: hue = 45; saturation = 100; break;
        }
      
        const lightLow = strongColors ? 25 : 40;
        const lightHigh = strongColors ? 65 : 70;
      
        return [
          `hsl(${hue},${saturation}%,${lightLow}%)`,
          `hsl(${hue},${saturation}%,${lightHigh}%)`
        ];
      }
      
      // -------------------------------------------------------
      // Hauptfunktion
      // -------------------------------------------------------
      function generateBatterySvg(percent, decimalPlaces = 0, labelSuffix = '%', customLabel = null, showPercent = true, strongColors = false, colorScheme = 'default', showBolt = false, boltPos = 100, blinkBolt = false, boltColorScheme = 'default')
      {
        const raw = Number(percent);
        const p = clamp(Number.isFinite(raw) ? raw : 0, 0, 100);
      
        const viewBoxW = 264, viewBoxH = 129;
        const outer = { x: 20, y: 24, w: 200, h: 80, rx: 18 };
        const inner = { x: 24, y: 28, h: 72, rx: 12 };
        const maxInnerWidth = 192;
      
        const fillW = interpolatedWidth(p);
        const fillColor = getFillColor(p, strongColors, colorScheme);
      
        const nums = (fillColor.match(/-?\d+(\.\d+)?/g) || []).map(Number);
        const [hVal = 0, sVal = 0, lVal = 50] = nums;
        const [r, g, b] = hslToRgb(hVal, sVal, lVal);
        const lum = luminance(r, g, b);
        const textFill = lum > 0.55 ? '#000' : '#fff';
        const outlineColor = (textFill === '#fff') ? 'rgba(0,0,0,0.85)' : 'rgba(255,255,255,0.95)';
      
        const formattedValue = Number(p).toFixed(decimalPlaces);
        const formattedTrimmed = (decimalPlaces === 0) ? String(Math.round(Number(formattedValue))) : formattedValue;
        const displayText = customLabel ?? `${formattedTrimmed}${labelSuffix}`;
      
        const fontSize = Math.max(12, Math.round(inner.h * 0.33 * 2.25));
        const textCenterX = inner.x + maxInnerWidth / 2;
        const textCenterY = inner.y + inner.h / 2;
        const TEXT_DY_EM = 0.35;
      
        const contact = { x: 224, y: 46, w: 20, h: 36 };
        const contactCenterX = contact.x + contact.w / 2;
        const contactCenterY = contact.y + contact.h / 2;
      
        const boltViewBox = { w: 102.7, h: 186.8 };
        const boltTargetH = outer.h * 1.7;
        const boltScale = boltTargetH / boltViewBox.h;
        const boltOffsetY = contactCenterY + 26;
      
        const clampedBoltPos = clamp(boltPos, 0, 100);
        const leftEdge = 0;
        const rightEdge = contactCenterX - 50;
        const baseX = leftEdge + ((rightEdge - leftEdge) * (clampedBoltPos / 100));
        let extraOffset = -30;
        if (clampedBoltPos === 0) extraOffset = -15;
        else if (clampedBoltPos === 100) extraOffset = 0;
        const boltX = baseX + extraOffset;
      
        const boltTransform = `
          translate(${boltX}, ${boltOffsetY})
          scale(${boltScale})
          translate(${-boltViewBox.w / 2}, ${-boltViewBox.h / 2})
        `.trim();
      
        const id = uid('b');
        const boltAnimation = blinkBolt ? `
          <style>
            @keyframes blinkBolt-${id} {
              0%, 100% { opacity: 1; }
              50% { opacity: 0.6; }
            }
            .blinking-bolt-${id} {
              animation: blinkBolt-${id} 1.8s ease-in-out infinite;
            }
          </style>` : '';
        const boltClass = blinkBolt ? `blinking-bolt-${id}` : '';
      
        const [boltColorDark, boltColorLight] = getBoltGradientFromScheme(strongColors, boltColorScheme || colorScheme);
      
        return `
          <svg xmlns="http://www.w3.org/2000/svg"
               xmlns:xlink="http://www.w3.org/1999/xlink"
               viewBox="0 0 ${viewBoxW} ${viewBoxH}"
               width="100%" height="100%"
               preserveAspectRatio="xMidYMid meet">
            ${boltAnimation}
            <defs>
              <linearGradient id="glass-${id}" x1="0" y1="0" x2="0" y2="1">
                <stop offset="0%" stop-color="#ffffff" stop-opacity="0.80"/>
                <stop offset="100%" stop-color="#ffffff" stop-opacity="0.10"/>
              </linearGradient>
              <linearGradient id="diagGlass-${id}" x1="0" y1="0" x2="1" y2="1">
                <stop offset="0%" stop-color="#ffffff" stop-opacity="0.75"/>
                <stop offset="45%" stop-color="#ffffff" stop-opacity="0.22"/>
                <stop offset="100%" stop-color="#ffffff" stop-opacity="0.03"/>
              </linearGradient>
              <pattern id="stripes-${id}" width="8" height="8" patternUnits="userSpaceOnUse">
                <rect width="8" height="8" fill="transparent"/>
                <path d="M-1,6 l8,-6 M-1,10 l8,-6" stroke="#fff" stroke-opacity="0.08" stroke-width="1"/>
              </pattern>
              <clipPath id="clip-fill-${id}">
                <rect x="${inner.x}" y="${inner.y}" width="${fillW}" height="${inner.h}" rx="${inner.rx}" ry="${inner.rx}"/>
              </clipPath>
              <linearGradient id="boltGradient-${id}" x1="8.7" x2="80.9" y1="17.1" y2="142.1" gradientUnits="userSpaceOnUse">
                <stop offset="0" stop-color="${boltColorLight}"/>
                <stop offset="1" stop-color="${boltColorDark}"/>
              </linearGradient>
              <symbol id="boltSymbol-${id}" viewBox="0 0 102.7 186.8">
                <path fill="url(#boltGradient-${id})" stroke="#000" stroke-width="6" stroke-linejoin="round"
                      d="m34.8 2-32 96h32l-16 80 80-112h-48l32-64h-48z"/>
              </symbol>
            </defs>
            <rect x="${outer.x}" y="${outer.y}" width="${outer.w}" height="${outer.h}" rx="${outer.rx}"
                  fill="#222" stroke="#ddd" stroke-width="4"/>
            <rect x="${inner.x}" y="${inner.y}" width="${fillW}" height="${inner.h}"
                  rx="${inner.rx}" ry="${inner.rx}" fill="${fillColor}"/>
            <g clip-path="url(#clip-fill-${id})">
              <rect x="${inner.x}" y="${inner.y}" width="${fillW}" height="${inner.h}"
                    rx="${inner.rx}" fill="url(#stripes-${id})" opacity="0.95"/>
              <rect x="${inner.x}" y="${inner.y}" width="${fillW}" height="${inner.h}"
                    rx="${inner.rx}" fill="url(#glass-${id})" opacity="0.25"/>
            </g>
            <rect x="${outer.x}" y="${outer.y}" width="${outer.w}" height="${outer.h}"
                  rx="${outer.rx}" fill="url(#diagGlass-${id})" opacity="0.9"/>
            <rect x="224" y="46" width="20" height="36" rx="6" fill="#ccc" stroke="#888" stroke-width="2"/>
            ${showBolt ? `<use href="#boltSymbol-${id}" class="${boltClass}" transform="${boltTransform}"/>` : ''}
            ${showPercent ? `
              <g transform="translate(${textCenterX}, ${textCenterY})">
                <text text-anchor="middle"
                      font-family="Arial, Helvetica, sans-serif"
                      font-size="${fontSize}" font-weight="700"
                      fill="${textFill}" stroke="${outlineColor}"
                      stroke-width="${Math.max(2, Math.round(fontSize * 0.15))}"
                      paint-order="stroke" dy="${TEXT_DY_EM}em">${displayText}</text>
              </g>` : ''}
          </svg>`.trim();
      }
      

      DOKUMENTATION: Prarameterübersicht

      Parameter Typ Standardwert Beschreibung
      percent number erforderlich Der Ladezustand der Batterie in Prozent (0–100). Werte außerhalb werden automatisch auf diesen Bereich begrenzt.
      decimalPlaces number 0 Anzahl der Nachkommastellen, die beim Prozentwert angezeigt werden. Beispiel: 1 → 56.7%.
      labelSuffix string '%' Text, der hinter dem Zahlenwert angezeigt wird. Kann z. B. '%', 'V', 'mAh', 'W' usw. sein.
      customLabel string \| null null Überschreibt die Standardanzeige des Werts vollständig. Beispiel: "FULL", "LOW", "READY", "Laden". Wenn gesetzt, werden decimalPlaces und labelSuffix ignoriert.
      showPercent boolean true Steuert, ob der Text (Wert oder Label) in der Batterie angezeigt wird. Bei false wird keine Beschriftung angezeigt.
      strongColors boolean false Aktiviert kräftigere, gesättigtere Farben und stärkeren Kontrast. Sichtbar besonders bei festen Farbschemata (red, blue, green, etc.).
      colorScheme string 'default' Legt das Farbschema fest. Mögliche Werte siehe unten.
      showBolt boolean false Blendet das Blitzsymbol (⚡) zur Anzeige von „Laden“ oder „Energie“ ein.
      boltPos number 100 Horizontale Position des Blitzsymbols von 0–100. 0 = links, 100 = rechts (am Kontakt).
      blinkBolt boolean false Aktiviert einen sanften Blinkeffekt für das Blitzsymbol (weiches Pulsieren).
      boltColorScheme string default Legt das Farbschema fest. Mögliche Werte siehe unten.

      DOKUMENTATION: Unterstützte Farbschemata (colorScheme)

      Name Beschreibung Verlauf / Charakteristik
      'default' Standardverlauf: grün → gelb → rot Farbverlauf abhängig vom Batteriestand
      'green' Grüntöne Dunkelgrün → Hellgrün
      'yellow' Gelbtöne Ocker → Hellgelb
      'blue' Blautöne Marineblau → Hellblau
      'red' Rottöne Dunkelrot → Hellrot
      'orange' Orangetöne Dunkelorange → Hellorange
      'brown' Brauntöne Dunkelbraun → Mittelbraun
      'grey' Graustufen Mittelgrau → Hellgrau
      'purple' zwischen Violett und Purpur kräftiges dunkles Lila → helleres Violett
      'black' Schwarzschema Links tiefschwarz, rechts dunkelgrau (deutlicher Kontrast)

      DOKUMENTATION: Unterstützte Farbschemata (boltColorScheme)

      Name Beschreibung Verlauf / Charakteristik
      'default' Standardverlauf: orange → gelb
      'green' Grüntöne Dunkelgrün → Hellgrün
      'yellow' Gelbtöne Ocker → Hellgelb
      'blue' Blautöne Marineblau → Hellblau
      'red' Rottöne Dunkelrot → Hellrot
      'orange' Orangetöne Dunkelorange → Hellorange
      'brown' Brauntöne Dunkelbraun → Mittelbraun
      'grey' Graustufen Mittelgrau → Hellgrau
      'purple' zwischen Violett und Purpur kräftiges dunkles Lila → helleres Violett
      'black' Schwarzschema von tiefschwarz, bis dunkelgrau (deutlicher Kontrast)

      💡 Hinweise zur Farbdarstellung

      • Bei strongColors = true werden:
        • die Farben satter (höhere Sättigung)
        • der Verlauf dunkler und kontrastreicher
      • Bei strongColors = false erhält man einen weicheren, neutraleren Verlauf.

      DOKUMENTATION: Blitzsymbol (showBolt, boltPos, blinkBolt)

      Option Wirkung
      showBolt: true Zeigt das Blitzsymbol an.
      boltPos Position des Blitzes auf der horizontalen Achse.
      blinkBolt: true Aktiviert ein sanftes „Atmen“ des Blitzsymbols (Opacity zwischen 1 ↔ 0.6).

      BEISPIEL mit Speicherung des SVG Code in einen Datenpunkt

      const ZielDP = '0_userdata.0.Batterie1'; // bitte anpassen
      
      const dValue = getState('fritzdect.0.DECT_099950330172.battery').val; // bitte anpassen
      const decimalPlaces = 0; // bitte anpassen
      const labelSuffix = '%'; // bitte anpassen
      const customLabel = null; // bitte anpassen
      const showPercent = true; // bitte anpassen
      const strongColors = true; // bitte anpassen
      const colorScheme = 'default'; // bitte anpassen
      const showBolt = false; // bitte anpassen
      const boltPos = 100; // bitte anpassen
      const blinkBolt = false; // bitte anpassen
      const boltColorScheme = 'default'; // bitte anpassen
      
      //Funktionsaufruf mit Speicherung der SVG in einen Datenpunkt
      setState(ZielDP, generateBatterySvg(dValue, decimalPlaces, labelSuffix, customLabel, showPercent, strongColors, colorScheme, showBolt, boltPos, blinkBolt, boltColorScheme), true);
      

      Viel Spaß beim testen und benutzen.

      Ro75.

      1.0.1: Korrekturen
      1.0.3: wahlweise kräftiger Farben und Ladesymbol
      1.0.5: Ladesymbol frei beweglich, freier Suffix (% oder z.B. V) oder komplett freier Text, Wert mit X Kommastellen
      1.0.6: Sortierung der Parameter, Ladesymbol kann auf Wunsch sanft blinken, Dokumentation und Beispiel angepasst
      1.0.8: Korrekt vom erstellten SVG-Code. Dieser kann nun in Dateien verwendet werden - ohne Fehler. Weiterer Parameter zur Steuerung des Farbschemas vom Ladesymbol.

      posted in JavaScript
      Ro75
      Ro75
    • RE: Meeting für ioBroker Core/Dev/Admin 18.09.24 20:30

      Ich bin zwar kein ioBroker - Entwickler, hatte aber selber 20 Jahre Windows-Software entwickelt. Aus meiner Sicht gibt es folgende Schwachstellen.

      1. In den Adaptern gibt es
        a) zuviel "denglisch"
        b) zuviel "fach-chinesisch" und
        c) nicht selbsterklärende Begriffe/Formulierungen

      2. Fehler. In den letzten 18 Monaten kommen zuviele Aktualisierungen mit Fehlern raus. Für mich wirkt das dann immer wie mit "heißer Nadel gestrickt".

      3. Gemeldete Fehler / Probleme werden nicht behoben - zumindest fühlt es sich so an. Und wenn dann Adapter viele Monate liefen und dann nicht mehr ist das schade und frustrierend >> siehe Parcel-Adapter - da tut sich nix

      4. Viel "lastest", kaum neue echte "stable" Versionen.

      Nur ein paar Anmerkungen als Nutzer.

      Ro75.

      posted in Entwickler-Meetings
      Ro75
      Ro75
    • RE: Betriebssystem-Paket-Updates, Linux ist auf neustem Stand

      @rickman sagte in Betriebssystem-Paket-Updates, Linux ist auf neustem Stand:

      Meine Meinung zu diesem "neuen Feature" ist in dem Fall einfach nur: So wichtig wie ein Kropf und kann eigentlich wieder weg oder könnte zumindest so gemacht werden, dass man es abstellen kann.

      Also, "abstellen" kann man das schon. Nur folgendes sollte immer wieder beachtet werden.

      1. Updates und hier speziell (Betriebs)Systemupdates werden nicht zum oder aus Spaß angeboten und verteilt. Es werden Fehler korrigiert und Sicherheitslücken geschlossen, manchmal auch neue Fehler "eingearbeitet" (kenne aber kein Betriebssystem wo das nicht schon mal passiert wäre).

      2. Neue Funktionen werden implementiert. Darauf bauen dann andere Programme/Entwickler. Ganz gutes Beispiel Debien 10 und nodejs. Dort werden Systemkomponenten in bestimmten Versionen vorausgesetzt, aber die kommen nicht mehr - weil System einfach zu alt oder ungepflegt.

      3. ioBroker ist für mich absolut genial, auch wenn es hier und da mal klemmt. ABER. Es gibt hier so viele Supporter, Helfer, Unterstützer die "kein finanzielles Interesse" haben und sich hier ein Bein ausreißen. Wenn man dann hier viel mitliest stoßen diese Helfer immer wieder auf die gleichen Probleme.
        a) veraltete Adapter
        b) veraltetetes ungepflegtes Betriebssystem
        c) ominöse Erklärungen "wie was gemacht wird"

      Jeder will (möchte) dass im bei seinem Anliegen geholfen wird und es wird geholfen. Aller dings in meinen Augen zu einem sehr hohen zeitlichen Preis. Von daher ist es in meinen Augen richtig, das hier auf die Pflege des Betriebssystem ein wenig (vielleicht auch mehr) vom System aus "genervt" wird. Weil sonst passiert meist gar nix.

      Letztlich muss jeder selber entscheiden wie er damit umgeht. Ich bin aber der Meinung, wer den kostenlosen Support und die Zeit der Supporter beansprucht / beanspruchen will, muss alles vorbereitet haben damit es reibungslos geht.

      dass man es abstellen kann.

      JA geht, nennt sich notification-manager. Wer diesen aber einsetzt und dann ein ungepflegtes System hat sollte aus meiner Sicht dann aber mit einem viel größeren Zeigefinger bedacht werden.

      Ro75.

      posted in Pflege des Betriebssystems
      Ro75
      Ro75
    • RE: Test Adapter homeconnect (BSH Home-Connect) v0.0.x

      Ich habe wieder mal etwas für die Visualisierung gebastelt. Vielleicht kann es ja einer gebrauchen.

      Klarspüler_grün_f.png
      Klarspüler_rot_f.png

      Salz_grün_f.png
      Salz_rot_f.png

      oder diese hier

      Klarspüler_rot_r.png
      Klarspüler_green_r.png

      Salz_rot_r.png
      Salz_green_r.png

      Ro75.

      posted in Tester
      Ro75
      Ro75
    • RE: Einfach mal zeigen will….. :-) - Teil 3

      Hauptseite.png

      System.png

      Wetter_1.png

      Wetter_2.png

      Tamken.png

      Alexa.png

      RSS.png

      ToDo.png

      Einstellungen.png

      Habe noch paar Screens angefügt. Muss mal schauen wie ich das so exportieren kann das es auch funktioniert.

      posted in Praktische Anwendungen (Showcase)
      Ro75
      Ro75
    • RE: Einfach mal zeigen will….. :-) - Teil 4

      In den letzten Jahren habe ich immer wieder mal meine VIS gezeigt, um Ideen / Anregungen zu liefern. Heute wieder ein neuer, aktueller Stand. Die größte Änderung bei mir, jetzt nutze ich Grafana (via InfluxDB und Infinity-Get). In der Vergangenheit hatte ich zuerst mit Flot, dann mit den e-Charts und zum Schluss mit Material-Design gearbeitet. Letztlich bin ich dann doch bei Grafana gelandet. MAcht es für mich, speziell mit dem Infinity-Get Plugin (Danke an das geteilte Wissen hier im Forum) recht einfach und flexibel.

      Wie immer soll es nur eine Anregung sein. Ein Export der VIS würde den Rahmen sprengen und nicht lauffähig sein, da hier Aliase und Skripte mit den Views eine Einheit bilden. Einige der Skripte findet ihr auch hier in der Datenbank.

      Hier nun die Haupt- und ein paar Neben-Views:

      Hauptseite_anonymized.png
      System_anonymized.png
      Energie_anonymized.png
      Licht_anonymized.png
      Wetter_anonymized.png
      Tanken_anonymized.png
      Roborock_anonymized.png
      Familie_anonymized.png
      Familie2_anonymized.png

      Radiosender.png

      Musikauswahl.png

      Einstellungen.png

      Artikelauswahl.png

      Das sind die verwendeten Adapter / Instanzen:

      Instanzen.png

      Ro75.

      posted in Praktische Anwendungen (Showcase)
      Ro75
      Ro75
    • RE: Einfach mal zeigen will….. :-) - Teil 3

      Am Anfang des Jahres hatte ich schon einmal meine VIS gezeigt. Es hat sich aber einiges getan. Von daher hier nun meine Weiterentwicklung.

      1Übersicht.png

      • Die Hauptseite

      2System.png
      *System-Monitoring

      3Energie.png
      *Energie!

      4Licht.png
      *Es werde Licht

      5Wetter.png
      *Das Wetter - Symbole sind alle animiert

      6Tanken.png
      *Tanken - am liebsten nicht, aber muss ja

      7Familie.png
      *Familienplaner - nur nichts vergessen

      8Schule.png
      *Schule - muss sein

      9Alexa.png
      AmazonMusic.png
      Artikelauswahl.png
      Radiosender.png
      *Echos - Musik, Timer, Einkauf, Lists, ...

      Einstellungen.png
      *Einstellungen - ein bissel flexibel sein

      Ro75.

      posted in Praktische Anwendungen (Showcase)
      Ro75
      Ro75
    • Skript Luftdaten

      Hallo. Heute stelle ich euch einmal mein Skript "Luftdaten" vor. Dieses Skript liest Daten einer Websiteaus. Es ermittelt wie auch andere Skripts (z.B. Wetter, Biowetter, AlleStörungen, usw.) Daten und schreibt diese zur Weiterverarbeitung in einzelne Datenpunkte.

      Ausgelesen werden Daten für Ozon, NO2, PM10 und PM25. Damit lassen sich einfache, individuelle Visualisierungen erstellen. Dies ist vielleicht ein weiteres Skript für Nutzer vom ioBroker.

      VORARBEITEN für SKRIPT - Anleitung um meinen Ort und damit die URL zu finden

      1. Adresse https://www.accuweather.com/ öffnen und im Suchfeld dein Ort eingeben und auswählen - Hinweis: Funktioniert mit Orten aus DE, AT, CH
        2d7aaaf9-e7ec-412d-aadf-6d492926ff1c-image.png

      2. Auf der neuen Seite, unterhalb des Suchfeldes auf den Link "LUFTQUALITÄT" klicken
        5284ee36-d54b-4b21-aa31-718b89226b41-image.png

      3. In der ersten Karte (LUFTQUALITÄT HEUTE) unten rechts auf den Link "plume labs" klicken
        65a95d62-4dc4-4dd5-a510-ff9274d4f03d-image.png

      4. Adresse im Browser kopieren und die Konstante sURL anpassen - sollte etwa so aussehen: https://air.plumelabs.com/air-quality-in-XXXXXX-aw-YYYYYYYY?utm_source=accuweather&utm_medium=current_aq_widget&utm_campaign=#ae16

      VORARBEITEN für Visualisierung (VIS) - ICON

      Nachfolgende Bilder müssen in den Ordner "luftdaten". Dieser ist ein Unterordner von "vis.0". Ergebnis: "/vis.0/luftdaten". Hinweis. Sollte eine andere Visualisierung genutzt werden, müssen ggfs. individuelle Anpassungen vorgenommen werden.

      aqip6.png
      aqip5.png
      aqip4.png
      aqip3.png
      aqip2.png
      aqip1.png
      luftdaten-images.zip

      //Version 1.0.0
      //23.09.2024
      //Ersteller Ro75.
      
      //Voraussetzungen (Version 1.0.0 getestet mit)
      //NodeJS: 20.x
      //Javascript-Adapter: 8.7.6
      //Admin-Adapter: 7.0.23
      //JS-Controller: 6.0.11
      
      //Vorarbeiten abarbeiten
      
      const sMainPath     = '0_userdata.0.Luftdaten.';
      //URL zum Auslesen - bitte anpassen - Anleitung beachten!!
      const sURL          = 'https://air.plumelabs.com/air-quality-in-bautzen-aw-171290?utm_source=accuweather&utm_medium=current_aq_widget&utm_campaign=#ae16'; // Ermittlung Schritt 1 - 4
      //nicht ändern!!!
      const airBasis      = 'O3,PM10,PM25,NO2';
      const airDetails    = 'hervorragend,angemessen,schlecht,ungesund,sehr ungesund,gefährlich';
      
      function Initalisierung(){
          let sAIR = airBasis.split(',');
          for (let i = 0; i <= sAIR.length-1; i++) {
              createState(sMainPath+sAIR[i]+'.value', 0, {name: 'Wert',type: 'number', read: true, write: true, unit: 'µg/m³'});
              createState(sMainPath+sAIR[i]+'.index', 0, {name: 'Index',type: 'number', read: true, write: true});
              createState(sMainPath+sAIR[i]+'.desc', '', {name: 'Beschreibung',type: 'string', read: true, write: true});
              createState(sMainPath+sAIR[i]+'.image', '', {name: 'VIS',type: 'string', read: true, write: true});
          }
          createState(sMainPath+'data_json', '', {name: 'JSON',type: 'string', def: '[]', read: true, write: true, desc: 'JSON Widget'});
          createState(sMainPath+'Gesamt.index', '', {name: 'Index',type: 'number', read: true, write: true});
          createState(sMainPath+'Gesamt.value', '', {name: 'Wert',type: 'number', read: true, write: true});
          createState(sMainPath+'Gesamt.desc', '', {name: 'Beschreibung',type: 'string', read: true, write: true});
          createState(sMainPath+'Gesamt.image', '', {name: 'VIS',type: 'string', read: true, write: true});
          //erster Datenabruf
          LuftMessDaten();
      }
      //START
      Initalisierung();
      
      //automatischer Abruf aller 15 Minuten - weniger nicht empfohlen
      schedule('*/15 * * * *', LuftMessDaten);
      
      
      function NormZahl(wert) {
          if(isNaN(wert)) {
              wert = 0;
          }
          return wert;
      }
      
      function LuftMessDaten() {
          httpGet(sURL, { timeout: 30000, "headers":{"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36 Edg/126.0.0.0"}}, (error, response) => {
              if (!error && response.statusCode == 200) {
                  let info = response.data;
                  let sAIR = airBasis.split(',');
                  for (let i = 0; i <= sAIR.length-1; i++) {
                      AuswertungLuftMessDaten(info,sAIR[i]);
                  }
                  AuswertungLuftMessDatenEx();
                  CreateJSON();
                  info = '';
              } else {
                  if (response.statusCode != 502) {
                      console.error('LuftMessDaten: ' + response.statusCode);
                  }
              }    
          })
      }
      
      
      function CreateJSON() {
          let JSON_List   = [];
          let sAIR = airBasis.split(',');
          for (let i = 0; i <= sAIR.length-1; i++) {
              JSON_List.push({"air": sAIR[i], "index": getState(sMainPath+sAIR[i]+'.index').val, "value": getState(sMainPath+sAIR[i]+'.value').val, "desc": getState(sMainPath+sAIR[i]+'.desc').val, "image": getState(sMainPath+sAIR[i]+'.image').val});
          }
          setState(sMainPath+'data_json', JSON.stringify(JSON_List), true);
          JSON_List = [];
      }
      
      function AuswertungLuftMessDaten(sData='', sIndex=''){
          var info = sData;
          var Position = info.indexOf('window.current_data');
          var dummy = info.substr(Position, 1000);
          var Position = dummy.indexOf('"'+sIndex+'"');
          var dummy = dummy.substr(Position, 100);
      
          var Position = dummy.indexOf('"pi":');
          var dummy = dummy.substr(Position+6, 7);
          setState(sMainPath+sIndex+'.index', parseInt(dummy), true);
          var lIndex = LuftIndex(parseInt(dummy));
          setState(sMainPath+sIndex+'.desc', airDetails.split(',')[lIndex-1], true);
          setState(sMainPath+sIndex+'.image', '/vis.0/luftdaten/aqip'+lIndex+'.png', true);
      
          var Position = info.indexOf('window.current_data');
          var dummy = info.substr(Position, 1000);
          var Position = dummy.indexOf('"'+sIndex+'"');
          var dummy = dummy.substr(Position, 100);
      
          var Position = dummy.indexOf('"value_upm":');
          var dummy = dummy.substr(Position+13, 7);
          setState(sMainPath+sIndex+'.value', parseFloat(dummy), true);
      }
      
      function AuswertungLuftMessDatenEx(){
          let sAIR = airBasis.split(',');
          var aqi = Math.max(NormZahl(getState(sMainPath+sAIR[0]+'.index').val), NormZahl(getState(sMainPath+sAIR[1]+'.index').val), NormZahl(getState(sMainPath+sAIR[2]+'.index').val), NormZahl(getState(sMainPath+sAIR[3]+'.index').val));
          var lIndex = LuftIndex(aqi);
      
          setState(sMainPath+'Gesamt.value', aqi, true);
          setState(sMainPath+'Gesamt.index', lIndex, true);
          setState(sMainPath+'Gesamt.desc', airDetails.split(',')[lIndex-1], true);
          setState(sMainPath+'Gesamt.image', '/vis.0/luftdaten/aqip'+lIndex+'.png', true);
      }
      
      function LuftIndex(aqi){
          if (aqi <= 20) {
              return 1;
          } else if (aqi <= 50) {
              return 2;
          } else if (aqi <= 100) {
              return 3;
          } else if (aqi <= 150) {
              return 4;
          } else if (aqi <= 250) {
              return 5;
          } else {
              return 6;
          }
      }
      

      Im Grunde sollte alles selbsterklärend sein. Die hinzugefügten Kommentare geben Info und Einstellmöglichkeiten. Für Anregungen bin ich offen, auch wenn es ggfs. nicht gleich umgesetzt werden kann (die gute Zeit).

      99be4083-ed00-4301-a5a4-94396ed1ac1f-image.png

      Ich wünsche euch viel Spaß.

      Ro75.

      posted in JavaScript
      Ro75
      Ro75
    • RE: Meeting für ioBroker Core/Dev/Admin 18.09.24 20:30

      @homoran sagte in Meeting für ioBroker Core/Dev/Admin 18.09.24 20:30:

      braucht es ausreichend (fehlendes) feedback

      Noch ein Punkt. Es wird immer wieder auf GIT "gelenkt". Ehrlich gesagt, habe ich schon gar keine Lust mehr was auf GIT zu melden. Probleme / Fehler oder "Unlogiken" (wie z.B. Admin Adaper + Skripte mit den Farbeinstellungen). Da werden die Hinweise "abgetan", "niedergebügelt". Manchmal kommt es mir so vor, als ob sich das nicht wirklich richtig durchgelesen wird und im Anschluss gibts noch eine Antwort die aller Logik widerspricht.

      Ro75.

      EDIT: Letzter Eintrag von mir - wollte nur eine (aber große) USER-Sicht aufzeigen.

      posted in Entwickler-Meetings
      Ro75
      Ro75

    Latest posts made by Ro75

    • RE: Skript zur dynamischen Generierung Batterie/Akku Symbol

      Version 1.0.8 mit Fehlerkorrektur ist raus. Die SVG-Codes können nun ohne Probleme in eine Datei gepackt werden. Weiterer Parameter für Farbschema Ladesymbol.

      0c23d90d-60af-4125-a042-b0cd70863eed-image.png

      test3.svg test2.svg test1.svg

      Ro75.

      posted in JavaScript
      Ro75
      Ro75
    • RE: Skript zur dynamischen Generierung Batterie/Akku Symbol

      @OliverIO wenn ich dann den korrigierten und erweiterten Code einstelle, passt du dann dein Beispiel an?

      Ro75.

      posted in JavaScript
      Ro75
      Ro75
    • RE: Skript zur dynamischen Generierung Batterie/Akku Symbol

      Ich arbeite gerade an einem Fix, der das Problem mit den Dateien löst. Weiterhin wird es einen weiteren Parameter geben, welcher das Farbschema vom Ladeblitz beeinflusst.

      Ro75.

      posted in JavaScript
      Ro75
      Ro75
    • RE: Skript zur dynamischen Generierung Batterie/Akku Symbol

      @rene55 SVG Code muss sich ja auch in andere Visualisierungen einfügen lassen.

      Ro75

      posted in JavaScript
      Ro75
      Ro75
    • RE: Skript zur dynamischen Generierung Batterie/Akku Symbol

      @rene55 als Datei ist nicht vorgesehen.

      Ro75

      posted in JavaScript
      Ro75
      Ro75
    • RE: Test Widget json template

      @oliverio super. Frage. Kann auch individuell das Ladesymbol zugeschalten werden, wenn Ladevorgang erkannt wird?

      Ro75.

      posted in Tester
      Ro75
      Ro75
    • RE: Skript zur dynamischen Generierung Batterie/Akku Symbol

      @maxtor62 wie lautet denn der Datenpunkt mit den Batterie Werten?
      Ro75

      posted in JavaScript
      Ro75
      Ro75
    • RE: Skript zur dynamischen Generierung Batterie/Akku Symbol

      @maxtor62 dValue muss praktisch dein Datenpunkt sein.

      Ro75.

      posted in JavaScript
      Ro75
      Ro75
    • RE: Skript zur dynamischen Generierung Batterie/Akku Symbol

      @maxtor62 schaue bitte Post #20.

      Ro75.

      posted in JavaScript
      Ro75
      Ro75
    • RE: Skript zur dynamischen Generierung Batterie/Akku Symbol

      @rene55 funktioniert nur via Datenpunkt. Als Datei speichern und dann öffnen geht nicht, da bekomme ich auch nur Meldungen.
      Zeige mal bitte den dazugehörigen Code, also den von der Funktion.

      Ro75.

      posted in JavaScript
      Ro75
      Ro75
    Community
    Impressum | Datenschutz-Bestimmungen | Nutzungsbedingungen
    The ioBroker Community 2014-2023
    logo