Skip to content

Visualisierung

Hilfe zu Visualisierungen

9.4k Themen 104.2k Beiträge

NEWS

  • VIS / VIS-2 Übersicht Widgetkompatibilität

    Angeheftet vis
    41
    15 Stimmen
    41 Beiträge
    12k Aufrufe
    OliverIOO
    @bongo Jeder view hat eine url. Ob die von vis1 oder vis2 ausgeliefert wird ist dem Browser egal
  • Liste mit Geräten und deren Auflösung für VIS

    Angeheftet Verschoben vis
    100
    3
    1 Stimmen
    100 Beiträge
    44k Aufrufe
    B
    Ich bin ehrlich, ich habe alles versucht habe ein Samsung TabA 10.1 Zoll mit Fully Browser habe auch alles gemacht wie beschrieben aber im Vis kann ich die Größe ändern wie ich will es sind auf dem Tablet rechts und unten immer 5mm die nicht ausgefüllt bzw. schwarz sind. Die muss ich beim Neustart jedes Mal auseinander ziehen. Die Screen-Resolution zeigt mir 1333x799 an. Ich habe es schon fast aufgegeben. Vielleicht liegt es auch an Einstellungen vom Fully Browser. Falls jemand einen Tipp hat sehr gerne. Danke [image: 1768406307278-79cb9ff7-e6e6-4eb6-b8d6-f39e1c2b0d05-grafik.png]
  • VIS-2 unter IoBroker.net aktualisiert teile des Views nicht

    1
    0 Stimmen
    1 Beiträge
    19 Aufrufe
    Niemand hat geantwortet
  • Content scrollen

    12
    0 Stimmen
    12 Beiträge
    96 Aufrufe
    Uwe WaizmannU
    Super, vielen Dank es klappt wunderbar
  • Energiefluss-erweitert wert durch text ersetzen

    5
    0 Stimmen
    5 Beiträge
    72 Aufrufe
    F
    Aaaaah [image: 1773907878187-28a7a2e5-8c2f-4803-a3a8-6ec9188fc0ab-image.png] kacke, der eigentliche Datenpunkt ist ja ein anderer, wegen Prozentualem füllen gibt es eine möglichkeit, das der zusätzliche Datenpunkt unabhängig davon aktualisiert wird??? Der zusätzliche Datenpunkt wäre ja als Datenquelle auch vorhanden, wenn das etwas bringt
  • VIS1: Vis aktualisiert Bilder nicht mehr

    14
    0 Stimmen
    14 Beiträge
    368 Aufrufe
    madingM
    Guten Morgen, endlich habe ich Zeit gefunden, mich damit weiter zu beschäftigen. Eine Suche nach writeFile brachte mich auf folgendes Thema. Nun läuft folgendes JS in einem cron Trigger in Blockly. var fs = require('fs'); const picture= fs.readFileSync('/opt/iobroker/iobroker-data/files/vis.0/main/img/webuntis-screenshot.png'); //liest linux-datei-system writeFile('vis.0','/main/img/webuntis-screenshot.png', picture, function (error) { }); //schreibt in iobroker system Funktioniert, danke, auch an @liv-in-sky für seine super dokumentierte Lösung!
  • VIS2 Inventwo HTML tags in Tabelle

    7
    2
    0 Stimmen
    7 Beiträge
    88 Aufrufe
    fuzzy1955F
    @skvarel sagte in VIS2 Inventwo HTML tags in Tabelle: hier geht es aber um inventwo Pardon ... das hab ich übersehen.
  • Material Design Widgets: Calendar Widget

    vis
    201
    2
    5 Stimmen
    201 Beiträge
    39k Aufrufe
    WG25W
    Moin, ist das Kalender Widget auch unter vis2 anwendbar? Ich kann es einbinden und die Termine werden auch angezeigt. Allerdings sind die Überschriften alle in englisch. Wo muss ich da was anpassen?
  • vis basic image aktualisiert sich nicht

    7
    5
    0 Stimmen
    7 Beiträge
    55 Aufrufe
    HomoranH
    @mading ich hab mal für dich gesucht. https://forum.iobroker.net/post/1265085 das müsste passen. Allerdings mit javascript!
  • Energiefluss-Erweitert Ansichten

    59
    1 Stimmen
    59 Beiträge
    14k Aufrufe
    skvarelS
    Als Popup [image: 1773676766859-fb5634c4-317a-4de7-a6bb-d5989dc8d284-image.png]
  • Google Material 3 / Material You - Vis2

    vis material css
    11
    7
    3 Stimmen
    11 Beiträge
    226 Aufrufe
    M
    Hier die Einstellungen: Was macht dieses Skript? Dieses Skript generiert ein komplettes Einstellungs-Menü (Setup-Tab) im Material 3 Design für euer vis-Dashboard. Es rendert sauberes HTML und bringt drei Hauptfunktionen mit: System & Automatiken: Eine elegante Listenansicht mit Schaltern, um z.B. Skripte (Rollladenautomatik, Urlaubsmodus) ein- und auszuschalten. Graphen-Filter (Chips): Interaktive Buttons (Chips), mit denen man Datenpunkte für ein Diagramm (z.B. Heizung) ein- und ausblenden kann. Dynamische Wallpaper-Auswahl: Das absolute Highlight! Das Skript liest einen festgelegten Ordner eures ioBrokers aus und generiert automatisch ein Popup-Menü mit allen darin enthaltenen Bildern (.jpg, .png, .webp). Wählt ihr ein Bild aus, wird der Pfad in einen Datenpunkt geschrieben (perfekt für die Kombination mit meinem "M3 Theme Master" Skript). Was muss vorbereitet werden? Damit das Skript auf euren ioBroker-Dateispeicher zugreifen darf, müsst ihr einen wichtigen Haken setzen: Geht in die Instanz-Einstellungen eures JavaScript-Adapters. Setzt den Haken bei "Erlaube das Kommando exec" (falls noch nicht geschehen) und tragt unter Zusätzliche NPM-Module das Modul fs ein, falls es dort nicht standardmäßig aktiv ist. Alternativ reicht es oft schon, in den JS-Adapter-Einstellungen den Haken bei "Erlaube Zugriff auf Dateisystem" zu setzen. Wallpaper-Ordner: Legt im ioBroker Dateimanager (unter vis.0 oder vis-2.0) einen Ordner an und ladet dort ein paar Bilder hoch. Passt den Pfad im Skript (WALLPAPER_WEB_DIR) entsprechend an. Eure Geräte eintragen: Schaut im Skript in die Funktion getListItems(). Dort tragt ihr einfach die Datenpunkte eurer eigenen ioBroker-Skripte oder Schalter ein. Wie wendet man das an? Das Skript erstellt alle nötigen Datenpunkte automatisch (standardmäßig unter 0_userdata.0.dashboard.). Startet das Skript. Zieht ein "Basic - String" (oder "Basic - HTML") Widget in eure vis. Tragt unter HTML / Inhalt den Datenpunkt-Namen in geschweiften Klammern ein: {0_userdata.0.dashboard.setupHTML} Zieht das Widget so groß wie nötig, das Skript bringt eine eigene, stylische M3-Scrollbar mit, falls der Platz nicht reicht. Das Skript (TypeScript) // ============================================================ // renderSetup — M3 Material You Styling (Kompakt & Robust-Scroll) // ============================================================ const fs = require('fs'); // === KONFIGURATION ========================================================== const BASE_PATH = '0_userdata.0.dashboard'; const DP_SETUP_HTML = `${BASE_PATH}.setupHTML`; const DP_IMAGE_PATH = `${BASE_PATH}.themeImagePath`; const DP_PRIVACY = `${BASE_PATH}.privacyMode`; // GRAPHEN-FILTER (Beispiele für eine Heizungs-Ansicht) const DP_CHART_BRENNER = `${BASE_PATH}.chartShowBrenner`; const DP_CHART_VALVE = `${BASE_PATH}.chartShowValve`; const DP_CHART_ACT = `${BASE_PATH}.chartShowAct`; const DP_CHART_SET = `${BASE_PATH}.chartShowSet`; const DP_CHART_WINDOW = `${BASE_PATH}.chartShowWindow`; const DP_CHART_HUMID = `${BASE_PATH}.chartShowHumid`; // ORDNER FÜR DIE HINTERGRUNDBILDER // Wichtig: Der Ordner muss im ioBroker Dateimanager existieren! const WALLPAPER_WEB_DIR = '/vis-2.0/Material_You/img/wallpaper/'; const WALLPAPER_SYS_DIR = '/opt/iobroker/iobroker-data/files' + WALLPAPER_WEB_DIR; // ============================================================================ // === AB HIER NUR ANPASSEN, WENN EIGENE LISTEN-EINTRÄGE GEWÜNSCHT SIND === // ============================================================================ const M3 = { primary: 'var(--m3-primary)', onPrimary: 'var(--m3-on-primary)', primaryContainer: 'var(--m3-primary-container)', onPrimaryContainer: 'var(--m3-on-primary-container)', surfaceContainerLow: 'var(--m3-surface-container-low)', surfaceContainerHighest:'var(--m3-surface-container-highest)', surfaceVariant: 'var(--m3-surface-variant)', onSurface: 'var(--m3-on-surface)', onSurfaceVariant: 'var(--m3-on-surface-variant)', outline: 'var(--m3-outline)', outlineVariant: 'var(--m3-outline-variant)' }; const ICONS: Record<string, string> = { 'party': 'M2 22l5-14 9 9-14 5zm3.3-3.3l7.05-2.5-4.55-4.55-2.5 7.05zM14.55 12.55l-1.05-1.05 5.6-5.6q.8-.8 1.925-.8t1.925.8l.6.6-1.05 1.05-.6-.6q-.35-.35-.875-.35t-.875.35l-5.6 5.6zM10.55 8.55l-1.05-1.05.6-.6q.35-.35.35-.85t-.35-.85l-.65-.65 1.05-1.05.65.65q.8.8.8 1.9t-.8 1.9l-.6.6zm2 2l-1.05-1.05 3.6-3.6q.35-.35.35-.875t-.35-.875l-1.6-1.6 1.05-1.05 1.6 1.6q.8.8.8 1.925t-.8 1.925l-3.6 3.6zm4 4l-1.05-1.05 1.6-1.6q.8-.8 1.925-.8t1.925.8l1.6 1.6-1.05 1.05-1.6-1.6q-.35-.35-.875-.35t-.875.35l-1.6 1.6z', 'guests': 'M16 11C17.66 11 18.99 9.66 18.99 8C18.99 6.34 17.66 5 16 5C14.34 5 13 6.34 13 8C13 9.66 14.34 11 16 11M8 11C9.66 11 10.99 9.66 10.99 8C10.99 6.34 9.66 5 8 5C6.34 5 5 6.34 5 8C5 9.66 6.34 11 8 11M8 13C5.67 13 1 14.17 1 16.5V19H15V16.5C15 14.17 10.33 13 8 13M16 13C15.71 13 15.38 13.02 15.03 13.05C16.19 13.89 17 15.02 17 16.5V19H23V16.5C23 14.17 18.33 13 16 13Z', 'sun': 'M20 14H18L14.8 23H16.7L17.4 21H20.6L21.3 23H23.2L20 14M17.8 19.7L19 16L20.2 19.7H17.8M7 9H15V11H7V9M7 12H15V14H7V12M7 15H15V16.5L14.8 17H7V15M13.7 20H7V18H14.5L13.7 20M16 8H6V20H4V8H2V4H20V8H18V12H16.6L16.1 13.3L16 13.7V8Z', 'alarm': 'M12 20A7 7 0 0 1 5 13A7 7 0 0 1 12 6A7 7 0 0 1 19 13A7 7 0 0 1 12 20M12 4A9 9 0 0 0 3 13A9 9 0 0 0 12 22A9 9 0 0 0 21 13A9 9 0 0 0 12 4M7.88 3.39L6.6 1.86L2 5.71L3.29 7.24L7.88 3.39M22 5.72L17.4 1.86L16.11 3.39L20.71 7.25L22 5.72M12.5 8H11V14L15.75 16.85L16.5 15.62L12.5 13.25V8Z', 'person': 'M12 4A4 4 0 0 1 16 8A4 4 0 0 1 12 12A4 4 0 0 1 8 8A4 4 0 0 1 12 4M12 14C16.42 14 20 15.79 20 18V20H4V18C4 15.79 7.58 14 12 14Z', 'moon': 'M12 21q-3.75 0-6.375-2.625T3 12q0-3.75 2.625-6.375T12 3q.35 0 .688.025t.662.075q-1.025.725-1.637 1.888T11.1 7.5q0 2.25 1.575 3.825T16.5 12.9q1.375 0 2.525-.612t1.875-1.638q.05.325.075.663T21 12q0 3.75-2.625 6.375T12 21Zm0-2q2.2 0 3.95-1.212T18.5 14.625q-.5.125-1 .2t-1 .075q-3.075 0-5.238-2.162T9.1 7.5q0-.5.075-1t.2-1q-1.95.8-3.162 2.55T5 12q0 2.9 2.05 4.95T12 19Zm-.25-6.75Z', 'auto': 'M11 19q1.3 0 2.47-.52t2.03-1.5q-3.2-.2-5.35-2.49T8 9q0-.32.02-.64t.08-.61q-1.42.8-2.26 2.2T5 13q0 2.5 1.75 4.25T11 19Zm0 2q-3.35 0-5.67-2.32t-2.33-5.68q0-3.35 2.32-5.67t5.68-2.33q.13 0 .25.01t.25.01q-.72.8-1.11 1.83T10 9q0 2.5 1.75 4.25T16 15q.78 0 1.51-.19t1.4-.56q-.45 2.95-2.7 4.85T11 21Zm2.8-10 3.2-9h2l3.2 9h-1.9l-.7-2H17.4l-.7 2h-1.9Zm3.05-3.35h2.3l-1.15-3.65-1.15 3.65ZM10.18-9.53Z', 'palette': 'M12 22q-2.05 0-3.875-.788t-3.187-2.15Q3.575 17.7 2.788 15.875T2 12q0-2.075.812-3.9t2.2-3.175Q6.4 3.575 8.25 2.788T12.2 2q2 0 3.775.688t3.112 1.9q1.338 1.212 2.125 2.875T22 10.95q0 2.875-1.75 4.413T16 17h-1.85q-.225 0-.313.125t-.087.275q0 .3 0.375.863T14.5 20.3q0 1.25-.688 1.85T12 22Zm0-10Zm-4.425.575q.425-.425.425-1.075t-.425-1.075q-.425-.425-1.075-.425t-1.075.425q-.425.425-.425 1.075t.425 1.075q.425.425 1.075.425t1.075-.425Zm3-4q.425-.425.425-1.075t-.425-1.075q-.425-.425-1.075-.425t-1.075.425q-.425.425-.425 1.075t.425 1.075q.425.425 1.075.425t1.075-.425Zm5 0q.425-.425.425-1.075t-.425-1.075q-.425-.425-1.075-.425t-1.075.425q-.425.425-.425 1.075t.425 1.075q.425.425 1.075.425t1.075-.425Zm3 4q.425-.425.425-1.075t-.425-1.075q-.425-.425-1.075-.425t-1.075.425q-.425.425-.425 1.075t.425 1.075q.425.425 1.075.425t1.075-.425ZM12 20q.225 0 .363-.125t.137-.325q0-.35-.375-.825T11.75 17.3q0-1.05.725-1.675T14.25 15h1.75q1.65 0 2.825-.963T20 10.95q0-3.025-2.312-5.038T12.2 3.9q-3.4 0-5.8 2.325T4 11.95q0 3.325 2.338 5.663T12 20Z', 'dropdown': 'M7 10l5 5 5-5H7z', 'thermostat': 'M15 13V5A3 3 0 0 0 9 5V13A5 5 0 1 0 15 13M12 4A1 1 0 0 1 13 5V8H11V5A1 1 0 0 1 12 4Z' }; interface ListItem { label: string; description: string; icon: string; oid: string; disableIf?: string; category: 'system' | 'appearance'; } // === EURE LISTEN-EINTRÄGE === function getListItems(): ListItem[] { const isPrivacy = getSafeVal(DP_PRIVACY, false) === true; const nameUser1 = isPrivacy ? 'Bewohner 1' : 'Eigener Name'; return [ { category: 'system', label: 'Rollladen Automatik', description: 'Die Rollladen werden nach Sonnenuntergang automatisch geschlossen.', icon: 'sun', oid: 'javascript.0.routines.auto_blinds' }, { category: 'system', label: 'WakeUp-Automatik', description: 'Bei Bewegung nach 6 Uhr am Morgen werden die Rolladen geöffnet.', icon: 'alarm', oid: 'javascript.0.routines.wakeup' }, { category: 'system', label: 'Partymodus', description: 'Schlaf-Taste bleibt verborgen. Automatiken werden pausiert.', icon: 'party', oid: '0_userdata.0.System.Partymodus' }, { category: 'system', label: 'Gäste im Haus', description: 'Verhindert das automatische Ausschalten in bestimmten Bereichen.', icon: 'guests', oid: '0_userdata.0.System.Gaeste' }, { category: 'system', label: nameUser1, description: `Für ${nameUser1} wird eine individuelle Routine aktiviert.`, icon: 'person', oid: 'javascript.0.routines.user1_routine' }, { category: 'appearance', label: 'Privacy Mode (Demo)', description: 'Anonymisiert Namen und Bilder für Screenshots.', icon: 'person', oid: DP_PRIVACY }, { category: 'appearance', label: 'Google JSON Theme', description: 'Aktiv: Nutzt Custom-JSON. Inaktiv: Farben aus dem Wallpaper.', icon: 'palette', oid: `${BASE_PATH}.themeUseJson` }, { category: 'appearance', label: 'Auto-Theme (Astro)', description: 'Wechselt bei Sonnenuntergang in den Dark-Mode.', icon: 'auto', oid: `${BASE_PATH}.autoTheme` }, { category: 'appearance', label: 'Manueller Dark Mode',description: 'Überschreibt das Farbschema (Wenn Auto-Theme aus ist).', icon: 'moon', oid: `${BASE_PATH}.darkMode`, disableIf: `${BASE_PATH}.autoTheme` } ]; } interface WallpaperItem { label: string; path: string; } function getDynamicWallpapers(): WallpaperItem[] { let wallpapers: WallpaperItem[] = []; try { if (fs.existsSync(WALLPAPER_SYS_DIR)) { const files = fs.readdirSync(WALLPAPER_SYS_DIR); files.forEach((file: string) => { const ext = file.toLowerCase(); if (ext.endsWith('.jpg') || ext.endsWith('.jpeg') || ext.endsWith('.png') || ext.endsWith('.webp')) { let cleanName = file.replace(/\.[^/.]+$/, "").replace(/[_-]/g, ' ').replace(/\b\w/g, c => c.toUpperCase()); wallpapers.push({ label: cleanName, path: WALLPAPER_WEB_DIR + file }); } }); } } catch (e: any) { // Ordner existiert nicht oder fs Modul fehlt } wallpapers.sort((a, b) => a.label.localeCompare(b.label)); return wallpapers; } let DYNAMIC_WALLPAPERS: WallpaperItem[] = getDynamicWallpapers(); function svgIcon(name: string, color: string, size: number = 24): string { const path = ICONS[name] || ICONS['person']; return `<svg xmlns="http://www.w3.org/2000/svg" width="${size}" height="${size}" viewBox="0 0 24 24" style="flex-shrink:0; transition: fill 0.3s ease;"><path fill="${color}" d="${path}"/></svg>`; } function getSafeVal(oid: string, fallback: any = false): any { if (existsState(oid)) return getState(oid).val; return fallback; } function getWallpaperNameByPath(path: string): string { const found = DYNAMIC_WALLPAPERS.find(wp => wp.path === path); return found ? found.label : 'Auswählen...'; } function renderListItem(item: ListItem): string { const rawVal = getSafeVal(item.oid, false); const active = (rawVal === true || rawVal === 1 || rawVal === 'true'); let disabled = false; if (item.disableIf) disabled = (getSafeVal(item.disableIf, false) === true); const trackBg = active ? M3.primary : M3.surfaceContainerHighest; const trackBorder = active ? M3.primary : M3.outline; const thumbSize = active ? 24 : 16; const thumbColor = active ? M3.onPrimary : M3.outline; const thumbLeft = active ? 'calc(100% - 26px)' : '6px'; const opacity = disabled ? '0.4' : '1'; const pointerEvents = disabled ? 'none' : 'auto'; const clickAction = disabled ? "" : `(function(e){ e.stopPropagation(); if(typeof vis!=='undefined'&&vis.conn&&vis.conn.setState)vis.conn.setState('${item.oid}', ${!active}); else if(typeof vis!=='undefined'&&vis.setValue)vis.setValue('${item.oid}', ${!active}); })(event);`.replace(/\n/g, ' '); const rippleJS = disabled ? "" : `(function(e,el){var evt=e.touches?e.touches[0]:e;if(!evt.clientX)return;var d=Math.max(el.clientWidth,el.clientHeight);var r=d/2;var rect=el.getBoundingClientRect();var x=evt.clientX-rect.left;var y=evt.clientY-rect.top;var c=document.createElement('span');c.style.width=c.style.height=d+'px';c.style.left=(x-r)+'px';c.style.top=(y-r)+'px';c.style.position='absolute';c.style.borderRadius='50%';c.style.backgroundColor='var(--m3-on-surface-variant)';c.style.opacity='0.1';c.style.transform='scale(0)';c.style.animation='m3-ripple-anim 0.5s linear';c.style.pointerEvents='none';el.appendChild(c);setTimeout(function(){c.remove();},500);})(event,this)`; return ` <div onclick="${clickAction}" onmousedown="${rippleJS}" ontouchstart="${rippleJS}" style="position:relative; overflow:hidden; width:100%; border-radius:16px; padding:12px 16px; box-sizing:border-box; background:${M3.surfaceContainerLow}; cursor:${disabled ? 'default' : 'pointer'}; user-select:none; display:flex; align-items:center; opacity:${opacity}; pointer-events:${pointerEvents}; font-family:Roboto,'Segoe UI',system-ui,sans-serif; margin-bottom: 8px; -webkit-tap-highlight-color:transparent; transition: background-color 0.3s ease;"> <div style="flex: 0 0 40px; width:40px; height:40px; border-radius:50%; background:${M3.surfaceVariant}; display:flex; align-items:center; justify-content:center; margin-right:14px;"> ${svgIcon(item.icon, M3.onSurfaceVariant, 20)} </div> <div style="flex: 1 1 0%; min-width: 0; display: block; padding: 2px 0;"> <div style="font-size:16px; font-weight:500; color:${M3.onSurface}; line-height:1.3; margin-bottom:2px; white-space:normal; overflow-wrap:break-word;">${item.label}</div> <div style="font-size:13px; font-weight:400; color:${M3.onSurfaceVariant}; opacity:0.85; line-height:1.4; white-space:normal; overflow-wrap:break-word;">${item.description}</div> </div> <div style="flex: 0 0 52px; width:52px; height:32px; margin-left:12px; border-radius:16px; background:${trackBg}; border:2px solid ${trackBorder}; box-sizing:border-box; position:relative; transition:all 0.25s cubic-bezier(0.2, 0, 0, 1);"> <div style="position:absolute; left:${thumbLeft}; top:50%; transform:translateY(-50%); width:${thumbSize}px; height:${thumbSize}px; border-radius:50%; background:${thumbColor}; transition:all 0.25s cubic-bezier(0.2, 0, 0, 1);"></div> </div> </div>`; } // === RECHTSBÜNDIGE FILTER CHIPS === function renderChartChips(): string { const actVal = getSafeVal(DP_CHART_ACT, true); const setVal = getSafeVal(DP_CHART_SET, true); const winVal = getSafeVal(DP_CHART_WINDOW, true); const brennerVal = getSafeVal(DP_CHART_BRENNER, true); const valveVal = getSafeVal(DP_CHART_VALVE, false); const humidVal = getSafeVal(DP_CHART_HUMID, true); const makeChip = (label: string, active: boolean, dp: string) => { const bg = active ? M3.primaryContainer : 'transparent'; const fg = active ? M3.onPrimaryContainer : M3.onSurfaceVariant; const border = active ? `1px solid ${M3.primaryContainer}` : `1px solid ${M3.outline}`; const iconHtml = active ? `<svg width="18" height="18" viewBox="0 0 24 24" style="margin-right:4px; margin-left:-4px;"><path fill="currentColor" d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"/></svg>` : ''; const js = `(function(e){ e.stopPropagation(); if(typeof vis!=='undefined'&&vis.conn&&vis.conn.setState)vis.conn.setState('${dp}', ${!active}); else if(typeof vis!=='undefined'&&vis.setValue)vis.setValue('${dp}', ${!active}); })(event);`.replace(/\n/g, ' '); return `<div onclick="${js}" style="display:inline-flex; align-items:center; height:32px; padding:0 12px; border-radius:8px; background:${bg}; border:${border}; color:${fg}; font-size:14px; font-weight:500; cursor:pointer; transition:all 0.2s ease;">${iconHtml}${label}</div>`; }; return ` <div style="width:100%; border-radius:16px; padding:12px 16px; box-sizing:border-box; background:${M3.surfaceContainerLow}; margin-bottom:8px; font-family:Roboto,'Segoe UI',system-ui,sans-serif; display:flex; align-items:flex-start;"> <div style="flex:0 0 40px; width:40px; height:40px; border-radius:50%; background:${M3.surfaceVariant}; display:flex; align-items:center; justify-content:center; margin-right:14px;"> ${svgIcon('thermostat', M3.onSurfaceVariant, 20)} </div> <div style="flex: 1 1 0%; min-width: 0;"> <div style="font-size:16px; font-weight:500; color:${M3.onSurface}; margin-bottom:2px;">Graphen-Anzeige</div> <div style="font-size:13px; color:${M3.onSurfaceVariant}; opacity:0.85; margin-bottom:12px; line-height:1.4;">Wähle aus, welche Linien in den Diagrammen gezeichnet werden.</div> <div style="display:flex; flex-wrap:wrap; gap:8px; justify-content:flex-end;"> ${makeChip('Ist-Temp', actVal, DP_CHART_ACT)} ${makeChip('Soll-Temp', setVal, DP_CHART_SET)} ${makeChip('Luftfeuchte', humidVal, DP_CHART_HUMID)} ${makeChip('Fenster', winVal, DP_CHART_WINDOW)} ${makeChip('Brenner', brennerVal, DP_CHART_BRENNER)} ${makeChip('Ventil', valveVal, DP_CHART_VALVE)} </div> </div> </div>`; } function renderMenuWallpaperItem(wp: WallpaperItem, currentPath: string): string { const active = (wp.path === currentPath); const bg = active ? M3.surfaceVariant : 'transparent'; const textColor = active ? M3.primary : M3.onSurface; const clickAction = `(function(e){ e.stopPropagation(); if(typeof vis!=='undefined'&&vis.conn&&vis.conn.setState)vis.conn.setState('${DP_IMAGE_PATH}', '${wp.path}'); else if(typeof vis!=='undefined'&&vis.setValue)vis.setValue('${DP_IMAGE_PATH}', '${wp.path}'); document.getElementById('m3-wallpaper-menu').style.opacity='0'; document.getElementById('m3-wallpaper-menu').style.pointerEvents='none'; })(event);`.replace(/\n/g, ' '); return `<div onclick="${clickAction}" style="position:relative; width:100%; padding:10px 16px; box-sizing:border-box; border-radius:12px; background:${bg}; cursor:pointer; user-select:none; margin-bottom:2px; display:flex; align-items:center; font-family:Roboto,'Segoe UI',system-ui,sans-serif; -webkit-tap-highlight-color:transparent; transition: background-color 0.2s ease;"> <img src="${wp.path}" style="flex:0 0 44px; width:44px; height:32px; border-radius:6px; object-fit:cover; background:${M3.surfaceVariant}; margin-right:14px;"> <div style="flex:1 1 0%; min-width:0; display:block; font-size:15px; font-weight:500; color:${textColor}; line-height:1.4; white-space:normal; overflow-wrap:break-word;">${wp.label}</div> </div>`; } function renderSetup(): void { const allItems = getListItems(); const systemHtml = allItems.filter(item => item.category === 'system').map(item => renderListItem(item)).join(''); const appearanceHtml = allItems.filter(item => item.category === 'appearance').map(item => renderListItem(item)).join(''); const chartChipsHtml = renderChartChips(); const currentWpPath = getSafeVal(DP_IMAGE_PATH, ''); const currentWpName = getWallpaperNameByPath(currentWpPath); const menuItemsHtml = DYNAMIC_WALLPAPERS.map(wp => renderMenuWallpaperItem(wp, currentWpPath)).join(''); const openMenuJS = `document.getElementById('m3-wallpaper-menu').style.opacity='1'; document.getElementById('m3-wallpaper-menu').style.pointerEvents='auto';`; const closeMenuJS = `document.getElementById('m3-wallpaper-menu').style.opacity='0'; document.getElementById('m3-wallpaper-menu').style.pointerEvents='none';`; const rippleJS = `(function(e,el){var evt=e.touches?e.touches[0]:e;if(!evt.clientX)return;var d=Math.max(el.clientWidth,el.clientHeight);var r=d/2;var rect=el.getBoundingClientRect();var x=evt.clientX-rect.left;var y=evt.clientY-rect.top;var c=document.createElement('span');c.style.width=c.style.height=d+'px';c.style.left=(x-r)+'px';c.style.top=(y-r)+'px';c.style.position='absolute';c.style.borderRadius='50%';c.style.backgroundColor='var(--m3-on-surface-variant)';c.style.opacity='0.1';c.style.transform='scale(0)';c.style.animation='m3-ripple-anim 0.5s linear';c.style.pointerEvents='none';el.appendChild(c);setTimeout(function(){c.remove();},500);})(event,this)`; const html = ` <style> @keyframes m3-ripple-anim { to { transform: scale(4); opacity: 0; } } [id^="vis_widget_"] .vis-view-inner-html-html, [id^="vis_widget_"] .vis-view-inner-html-html > div { height: 100% !important; } .m3-scroll-container::-webkit-scrollbar, .m3-menu-scroll::-webkit-scrollbar { width: 6px; } .m3-scroll-container::-webkit-scrollbar-track, .m3-menu-scroll::-webkit-scrollbar-track { background: transparent; } .m3-scroll-container::-webkit-scrollbar-thumb, .m3-menu-scroll::-webkit-scrollbar-thumb { background: var(--m3-outline-variant); border-radius: 3px; } .m3-scroll-container::-webkit-scrollbar-thumb:hover, .m3-menu-scroll::-webkit-scrollbar-thumb:hover { background: var(--m3-outline); } </style> <div class="m3-scroll-container" style="position: absolute; inset: 0; background: var(--m3-surface-container-low, rgb(237, 239, 232)); border-radius: 0 0 28px 28px; padding: 24px; display: block; width: 100%; box-sizing: border-box; overflow-y: auto; transition: background-color 0.3s ease;"> <div style="font-size:12px; font-weight:700; color:${M3.primary}; text-transform:uppercase; letter-spacing:1.2px; margin: 4px 0 8px 4px;">Erscheinungsbild & Anzeige</div> ${appearanceHtml} ${chartChipsHtml} <div style="position:relative; width:100%; border-radius:16px; padding:12px 16px; box-sizing:border-box; background:${M3.surfaceContainerLow}; user-select:none; margin-bottom:24px; display:flex; align-items:center; font-family:Roboto,'Segoe UI',system-ui,sans-serif; -webkit-tap-highlight-color:transparent; transition: all 0.3s ease;"> <div style="flex:0 0 40px; width:40px; height:40px; border-radius:50%; background:${M3.surfaceVariant}; display:flex; align-items:center; justify-content:center; margin-right:14px;">${svgIcon('palette', M3.onSurfaceVariant, 20)}</div> <div style="flex:1 1 0%; min-width:0; display:block;"><div style="font-size:16px; font-weight:500; color:${M3.onSurface}; line-height:normal;">Hintergrundbild</div></div> <div onclick="${openMenuJS}" onmousedown="${rippleJS}" ontouchstart="${rippleJS}" style="flex:0 0 auto; margin-left:12px; position:relative; overflow:hidden; display:flex; align-items:center; gap:8px; background:${M3.surfaceVariant}; padding:8px 16px; border-radius:20px; cursor:pointer; color:${M3.onSurfaceVariant}; transition: background-color 0.2s ease;"> <span style="font-size:14px; font-weight:500; line-height:normal;">${currentWpName}</span>${svgIcon('dropdown', M3.onSurfaceVariant, 20)} </div> </div> <div style="font-size:12px; font-weight:700; color:${M3.primary}; text-transform:uppercase; letter-spacing:1.2px; margin: 0 0 8px 4px;">System & Automatiken</div> ${systemHtml} <div style="height: 24px; flex-shrink: 0;"></div> </div> <div id="m3-wallpaper-menu" style="position: fixed; top: 0; left: 0; right: 0; bottom: 0; z-index: 999999; display: flex; align-items: center; justify-content: center; opacity: 0; pointer-events: none; transition: opacity 0.2s;"> <div onclick="${closeMenuJS}" style="position: absolute; inset: 0; background: rgba(0,0,0,0.4);"></div> <div style="position: relative; width: 380px; max-height: 80vh; background: var(--m3-surface-container-highest, #e1e3dc); border-radius: 20px; box-shadow: 0 12px 32px rgba(0,0,0,0.3); display: flex; flex-direction: column; overflow: hidden; font-family:Roboto,'Segoe UI',system-ui,sans-serif;"> <div style="padding: 20px 24px 12px 24px; font-size: 15px; font-weight: 600; color:${M3.onSurfaceVariant}; border-bottom: 1px solid ${M3.outlineVariant};">Hintergrundbild auswählen</div> <div class="m3-menu-scroll" style="overflow-y: auto; padding: 12px; display:flex; flex-direction:column;"> ${DYNAMIC_WALLPAPERS.length > 0 ? menuItemsHtml : `<div style="padding:20px; text-align:center; color:${M3.onSurfaceVariant}; font-size:14px;">Keine Bilder gefunden. Ordner prüfen!</div>`} </div> </div> </div>`; setState(DP_SETUP_HTML, html, true); } // === INIT & SUBSCRIPTIONS ====================================================== // Verschachtelte createState Aufrufe stellen sicher, dass alle Datenpunkte existieren, bevor abonniert wird. createState(DP_SETUP_HTML, '', { type: 'string', name: 'Setup HTML (M3)', role: 'html' }, () => { createState(DP_CHART_BRENNER, true, { type: 'boolean', name: 'Show Brenner Chart', role: 'switch' }, () => { createState(DP_CHART_VALVE, false, { type: 'boolean', name: 'Show Valve Chart', role: 'switch' }, () => { createState(DP_CHART_ACT, true, { type: 'boolean', name: 'Show Actual Temp Chart', role: 'switch' }, () => { createState(DP_CHART_SET, true, { type: 'boolean', name: 'Show Set Temp Chart', role: 'switch' }, () => { createState(DP_CHART_WINDOW, true, { type: 'boolean', name: 'Show Window Chart', role: 'switch' }, () => { createState(DP_CHART_HUMID, true, { type: 'boolean', name: 'Show Humidity Chart', role: 'switch' }, () => { createState(DP_PRIVACY, false, { type: 'boolean', name: 'Privacy Mode Toggle', role: 'switch' }, () => { createState(DP_IMAGE_PATH, '', { type: 'string', name: 'Theme Image Path', role: 'text' }, () => { getListItems().forEach(item => { if (existsState(item.oid)) on({ id: item.oid, change: 'any' }, () => renderSetup()); if (item.disableIf && existsState(item.disableIf)) on({ id: item.disableIf, change: 'any' }, () => renderSetup()); }); on({ id: [DP_CHART_BRENNER, DP_CHART_VALVE, DP_CHART_ACT, DP_CHART_SET, DP_CHART_WINDOW, DP_CHART_HUMID], change: 'any' }, () => renderSetup()); on({ id: DP_IMAGE_PATH, change: 'any' }, () => renderSetup()); renderSetup(); }); }); });});});});});}); }); [image: 1773605233417-setup2.jpg] [image: 1773605233425-setup1.jpg]
  • Zeigt her eure Visu

    vis
    127
    2 Stimmen
    127 Beiträge
    30k Aufrufe
    M
    @Horst-Böttcher Ich habe begonnen die Skripte hier zu veröffentlichen.
  • In VIS nach verwaisten Datenpunkten suchen?

    13
    0 Stimmen
    13 Beiträge
    208 Aufrufe
    M
    Der Ansatz ist gut, nun schränkt sich die Suche schon mal ein. Man kann dann die Länsten schon noch manuell suchen. Danke für die Antwort.
  • Iqontrol Hintergrund dynamisch ändern

    1
    0 Stimmen
    1 Beiträge
    32 Aufrufe
    Niemand hat geantwortet
  • VIS2 Metro Tile ValueList

    10
    2
    0 Stimmen
    10 Beiträge
    737 Aufrufe
    skvarelS
    @Qlink .. hast du dir mal unsere inventwo Widgets angeschaut? Da kannst du beliebig viele Zustände hinzufügen. [image: 1773480918030-cbecce53-5c6e-4931-943a-427f499429f3-image.png]
  • VIS2 - CSS allgemein - Nur für Gruppen

    vis
    2
    0 Stimmen
    2 Beiträge
    84 Aufrufe
    I
    Ich muss nochmal nachfragen, da bislang niemand geantwortet hat. Bin ich der Einzige mit dem Problem oder nutzt niemand die Funktion ganze Seiten abhängig vom Benutzer/Gruppe ausblenden zu lassen, so dass sie auch im Navigationsmenü nicht erscheinen? Oder nutzt ihr eine mir bisher verborgene Technik, um das zu realisieren. Danke
  • [gelöst] VIS-2: Problem mit dem"Gauge" (Widget-Sammlung)

    20
    1
    0 Stimmen
    20 Beiträge
    171 Aufrufe
    fuzzy1955F
    @carsten04 sagte in [gelöst] VIS-2: Problem mit dem"Gauge" (Widget-Sammlung): Du warst noch auf einer ziemlich alten Version Ja, klar. Diese war im Stable. Danke für deine Tipps!
  • [gelöst] VIS-1 - externes Widget einbinden

    7
    1
    0 Stimmen
    7 Beiträge
    63 Aufrufe
    OliverIOO
    @bommel_030 sagte in [gelöst] VIS-1 - externes Widget einbinden: Das umformatieren hätte ich aber nicht hinbekommen. Ich mach das mit notepad++ und Plugin jstools Zum formatieren
  • iQontrol Vis Support Thread

    android app vis how-to ios app iqontrol mobile ui vis
    2k
    5
    7 Stimmen
    2k Beiträge
    693k Aufrufe
    WG25W
    @Cephalopod sagte in iQontrol Vis Support Thread: @WG25 sagte in iQontrol Vis Support Thread: Erledigt Wäre sinnvoll zu wissen, WIE es erledigt wurde, da der eine oder andere mit dem selben Problem es auch gerne wüsste ... Na dann, hier meine Lösung per Screenshots: STATE: Türkontakt LOCK_STATE & LOCK_OPEN: DLD [image: 1773064799844-a78aa2b2-08ed-4779-b071-1e09b265a6ba-image.png] Einstellungen des DLD LOCK_STATE DPs [image: 1773064900871-905719a9-8f36-4d45-893b-569c8fb0397f-image.png] Alle vier DP Felder zeigen auf LOCK_TARGET_LEVEL [image: 1773065006524-566c0c7a-91f2-4513-913b-586dbcd9b72e-image.png] Optionen im IQontrol Gerät (Warum bei LOCK_OPEN eine 2 stehen muss und nicht OPEN, keine Ahnung) [image: 1773065184892-80c6d1b4-1e98-4ac9-aac9-7baf67b356ce-image.png]
  • Problem mit "Vis 2 inventwo Widgets" Update > v0.2.2

    20
    2
    0 Stimmen
    20 Beiträge
    977 Aufrufe
    T
    Also, dieses Vorgehen kann ich bei meiner Installation nicht bestätigen! Ich habe HTTPS immer aktiv. Übrigens: Update auf 0.6.1 lief bei mir problemlos!

576

Online

32.7k

Benutzer

82.5k

Themen

1.3m

Beiträge