Skip to content

Visualisierung

Hilfe zu Visualisierungen

9.4k Themen 103.8k 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]
  • iQontrol Vis Support Thread

    android app vis how-to ios app iqontrol mobile ui vis
    2k
    5
    7 Stimmen
    2k Beiträge
    686k Aufrufe
    Z
    klappt jetzt auch bei mir wieder. Was mir noch aufgefallen ist: Mit 2 Fingern auf dem Touch ging das verschieben auch, wenn auch mühselig..... Dafür fehlen mir jetzt auch meine Stromverbrauch Statistiken im Flowchart......hmmmmm..........
  • iobroker Visu App - Lädt immer via pro.cloud

    1
    9
    0 Stimmen
    1 Beiträge
    22 Aufrufe
    Niemand hat geantwortet
  • Support Adapter Energiefluss-erweitert v0.7.7

    Verschoben vis
    5k
    9
    20 Stimmen
    5k Beiträge
    6m Aufrufe
    jvfleJ
    [image: 1770891738436-screenshot-2026-02-12-111917-resized.png]
  • Zeigt her eure Visu

    vis
    124
    2 Stimmen
    124 Beiträge
    29k Aufrufe
    schaefersklausS
    @michl75 sagte in Zeigt her eure Visu: hier mal meine... ... Stark! Gefällt mir sehr gut! Besonders, wie aufwendig Du alleine die Teich-Steuerung umgesetzt/visualisiert hast! Wie sind diese Halbkreis-förmigen Stromverbrauchs-Diagramme realisiert worden? Welches Widget? Finde ich auch für einen Überblick richtig gut gelöst! Geht etwas in die Richtung "des Balkens" bei evcc, das finde ich auch gut gelöst. Danke und viele Grüße, Klaus.
  • Widget import klappt nicht in VIS-2

    8
    0 Stimmen
    8 Beiträge
    79 Aufrufe
    OliverIOO
    @Longbow So wie es aussieht, ist das eine Gruppe. D.h. es besteht aus mehreren einzelnen Widgets. Versuche mal in vis1 die Gruppe aufzulösen und dir anzuschauen, welche einzelnen Widgets es sind. Eventuell liegt es auch an der Gruppe, dass es nicht in vis2 zu importieren geht, dann ebenfalls die umgruppierten Widgets markieren, exportieren, und dann noch mal probieren. Dann kannst du in der Kompatibilitätsliste nachschauen, ob es da drin steht. Gegebenfalls musst du es in vis2 selber nachbauen, das dürfte nicht so schwer sein.
  • Hilfe zu Material-Design View Dialog

    10
    5
    0 Stimmen
    10 Beiträge
    811 Aufrufe
    L
    Ich bin über diesen Thread durch GOOGLE aufmerksam gemacht geworden, da ich (und auch andere) diesen hier beschriebenen Fehler ebenfalls haben (siehe auch https://forum.iobroker.net/post/1324142) So sieht es aus (falsch):[image: 1770727925696-457f5c11-5051-4c16-8f2f-e311d558baef-image-resized.png] Und hier kann man sehen wie es sein soll … aber einfach nicht will 😨 https://forum.iobroker.net/topic/32232/material-design-widgets-wetter-view. Hat jemand einen Vorschlag?
  • Problem mit "Vis 2 inventwo Widgets" Update > v0.2.2

    13
    2
    0 Stimmen
    13 Beiträge
    635 Aufrufe
    T
    bitte löschen -
  • LovelaceUI Wettervorhersage -> wie weather Endität erzeugen?

    Verschoben
    3
    4
    0 Stimmen
    3 Beiträge
    43 Aufrufe
    AtifanA
    Ah sorry bin im falschen Forum gelandet, war keine Absicht. Kannst du das ins deutsche Forum verschieben? Wenn nicht kopiere ich alles neu und lösche hier.
  • Vis2 Tabs Widget - Tab per URL anspringen

    9
    0 Stimmen
    9 Beiträge
    65 Aufrufe
    M
    @Sesamstrasse Einfach ist relativ. DPs anlegen und den Code in Skripte austauschen. DPs in ioBroker anlegen mit dem Skript Beispiele für DP setzen sind ausgeklammert, da die Werte angepasst werden müssen ioBroker javascript -> DPs anlegen // ************************ // VIS2TabControl v1.0.0 // Copyright ©MCU // ************************ // ioBroker javascript.0 - DPs für VIS2 Tabs anlegen const DP_MAIN = '0_userdata.0.vis2' const DP_TAB_EVENT = DP_MAIN + ".tabEvent"; // Client -> ioBroker const DP_TAB_CMD = DP_MAIN + ".tabCmd"; // ioBroker -> Client const DP_DEVICE_MAP = DP_MAIN + ".deviceMap"; // clientId -> clientName createState(DP_TAB_CMD, '', {name: 'VIS2 Tab Command',type: 'string', role:'', def: '', read: true, write: true, desc: ''}); createState(DP_TAB_EVENT, '', {name: 'VIS2 Tab Event',type: 'string', role:'', def: '', read: true, write: true, desc: ''}); createState(DP_DEVICE_MAP, '', {name: 'VIS2 Client Map',type: 'string', role:'', def: '', read: true, write: true, desc: ''}); // DEVICE_MAP - Aufbau /* { "d787264857bc0d13c393d37336f43dc9": "PC", "d7282dhf83hf832f944mhn4345n345n3": "Tablet" } */ // Beispiele /* setState(DP_TAB_CMD, JSON.stringify({ cmdId: `${Date.now()}-${Math.random().toString(16).slice(2)}`, target: ["d787264857bc0d13c393d37336f43dc9"], view: "datum", tab: "Licht", force: true }), false); */ // Wenn eine Zuordnung im Device_MAP vorhanden ist, kann man auch die Name nutzen /* setState(DP_TAB_CMD, JSON.stringify({ cmdId: `${Date.now()}-${Math.random().toString(16).slice(2)}`, target: ["PC"], view: "datum", tab: 2, force: true }), false); */ Script in VIS2 unter Skripte austauschen Script für VIS-2 Skripte /******************************************************************** * VIS-2 Global Script: Tabs steuern + Sync + Multi-Client Commands * * Fixes: * - Commands funktionieren mehrfach (Dedup nur über cmdId, wenn vorhanden) * - force:true klickt Tab auch wenn bereits selektiert * - periodisches resubscribe gegen verlorene Subscriptions ********************************************************************/ // =================== KONFIG =================== const DEBUG = false; // Tabs-Widget ID (aus deinem DOM) const TABS_WIDGET_ID = "w000016"; // URL Parameter const URL_PARAM_TAB = "tab"; // ?main&tab=Licht#datum // Datenpunkte (string) const DP_TAB_EVENT = "0_userdata.0.vis2.tabEvent"; // Client -> ioBroker const DP_TAB_CMD = "0_userdata.0.vis2.tabCmd"; // ioBroker -> Client const DP_DEVICE_MAP = "0_userdata.0.vis2.deviceMap"; // ioBroker -> Client (DeviceId -> Name) // Index-Format const INDEX_ONE_BASED = true; // true => 1..N, false => 0..N-1 // History const USE_PUSHSTATE = false; // false = replaceState (empfohlen) // Timing const OBSERVE_TIMEOUT_MS = 15000; // Re-Subscribe (gegen „geht nur einmal“) const RESUBSCRIBE_EVERY_MS = 30000; // localStorage Keys const LS_KEYS = { deviceId: "vis2.deviceId", deviceName: "vis2.deviceName", }; // ============================================== // =================== Helpers =================== function dlog(...a) { if (DEBUG) console.log("[VIS2Tabs]", ...a); } function getVis() { return (typeof window !== "undefined" && (window.vis || window.VIS)) || (typeof vis !== "undefined" ? vis : null); } let suppressUntil = 0; function suppress(ms = 350) { suppressUntil = Date.now() + ms; } function isSuppressed() { return Date.now() < suppressUntil; } function norm(s) { return String(s ?? "").trim().toLowerCase(); } function safeJsonParse(s) { try { return JSON.parse(s); } catch { return null; } } function getSearchParams() { return new URLSearchParams(window.location.search); } function getCurrentViewFromHash() { const h = (window.location.hash || "").replace(/^#/, ""); return (h.split("?")[0] || "").trim(); } function gotoView(view) { if (!view) return; const cur = getCurrentViewFromHash(); if (cur === view) return; suppress(600); window.location.hash = `#${view}`; } function getOrCreateDeviceId() { let id = localStorage.getItem(LS_KEYS.deviceId); if (id) return id; const buf = new Uint8Array(16); if (crypto?.getRandomValues) crypto.getRandomValues(buf); else for (let i = 0; i < buf.length; i++) buf[i] = Math.floor(Math.random() * 256); id = Array.from(buf).map(b => b.toString(16).padStart(2, "0")).join(""); localStorage.setItem(LS_KEYS.deviceId, id); return id; } // robustes Lesen aus vis.states Cache (DP oder DP.val / ggf. State-Objekt) function readVisValue(id) { const v = getVis(); if (!v?.states) return null; const candidates = [id + ".val", id]; for (const key of candidates) { try { let val = (v.states.attr && v.states.attr(key)) ?? v.states[key]; if (typeof val === "object" && val && "val" in val) val = val.val; // unwrap if (val !== undefined && val !== null) return val; } catch {} } return null; } function writeVisValue(id, value) { const v = getVis(); if (!v) return false; if (typeof v.setValue === "function") { v.setValue(id, value); return true; } if (v.conn && typeof v.conn.setState === "function") { v.conn.setState(id, value); return true; } return false; } // ============================================== // =================== Device Map =================== function applyDeviceNameFromMap() { const myId = getOrCreateDeviceId(); const raw = readVisValue(DP_DEVICE_MAP); const map = (typeof raw === "string" && raw.trim()) ? safeJsonParse(raw) : null; const name = map && typeof map === "object" ? map[myId] : null; if (name && String(name).trim()) { const n = String(name).trim(); localStorage.setItem(LS_KEYS.deviceName, n); return n; } return (localStorage.getItem(LS_KEYS.deviceName) || "").trim(); } // ============================================== // =================== URL: tab aus Query =================== function getTabParamFromSearch() { return getSearchParams().get(URL_PARAM_TAB) || null; } // NICHT URLSearchParams serialisieren (sonst wird aus ?main -> ?main=) // Wir ersetzen/appendieren nur "&tab=..." function setTabParamInSearch(tabValue) { if (!tabValue) return; const path = window.location.pathname; const hash = window.location.hash || ""; const raw = window.location.search || ""; const current = getTabParamFromSearch(); if (current === tabValue) return; let next = raw; if (/[?&]tab=/.test(next)) { next = next.replace(/([?&]tab=)[^&]*/i, `$1${encodeURIComponent(tabValue)}`); } else { next += (next.includes("?") ? "&" : "?") + `tab=${encodeURIComponent(tabValue)}`; } const newUrl = `${path}${next}${hash}`; suppress(450); if (USE_PUSHSTATE) history.pushState(null, "", newUrl); else history.replaceState(null, "", newUrl); } // ============================================== // =================== Tabs DOM Zugriff =================== function getTabButtons() { const root = document.getElementById(TABS_WIDGET_ID); if (!root) return []; return Array.from(root.querySelectorAll('button[role="tab"]')); } function isSelected(btn) { return ( btn?.getAttribute("aria-selected") === "true" || btn?.classList?.contains("Mui-selected") ); } function getSelectedTab() { const tabs = getTabButtons(); return tabs.find(isSelected) || null; } function getSelectedTabName() { const sel = getSelectedTab(); return sel ? (sel.textContent || "").trim() : ""; } function getSelectedTabIndex() { const tabs = getTabButtons(); const sel = getSelectedTab(); if (!sel) return null; const idx0 = tabs.indexOf(sel); if (idx0 < 0) return null; return INDEX_ONE_BASED ? (idx0 + 1) : idx0; } // force=true: klickt auch wenn schon selected function trySelectTab(tabParam, force = false) { if (tabParam == null) return false; const tabs = getTabButtons(); if (!tabs.length) return false; let target = null; const s = String(tabParam).trim(); if (/^\d+$/.test(s)) { const n = parseInt(s, 10); const idx = (n === 0) ? 0 : (n - 1); target = tabs[idx]; } else { const needle = norm(s); target = tabs.find(b => norm(b.textContent) === needle); } if (!target) return false; if (force || !isSelected(target)) { suppress(450); target.click(); } return true; } function forceSelectTab(tabParam, force = false) { if (trySelectTab(tabParam, force)) return; const obs = new MutationObserver(() => { if (trySelectTab(tabParam, force)) obs.disconnect(); }); obs.observe(document.body, { childList: true, subtree: true }); setTimeout(() => obs.disconnect(), OBSERVE_TIMEOUT_MS); } // ============================================== // =================== TabEvent -> DP =================== let lastSentSig = ""; function sendTabEventToDP() { const idx = getSelectedTabIndex(); const name = getSelectedTabName(); if (idx == null || !name) return; const sig = `${idx}|${name}`; if (sig === lastSentSig) return; lastSentSig = sig; const deviceId = getOrCreateDeviceId(); const deviceName = applyDeviceNameFromMap(); const view = getCurrentViewFromHash(); const payload = { deviceId, deviceName: deviceName || undefined, view: view || undefined, tabIndex: idx, tabName: name, ts: Date.now() }; writeVisValue(DP_TAB_EVENT, JSON.stringify(payload)); } // ============================================== // =================== URL -> Tab (Load/Navi) =================== function applyTabFromUrl() { if (isSuppressed()) return; const tabParam = getTabParamFromSearch(); if (!tabParam) return; forceSelectTab(tabParam, false); } // ============================================== // =================== Tab -> URL (bei Wechsel) =================== let lastWrittenName = ""; function writeUrlFromSelection() { if (isSuppressed()) return; const name = getSelectedTabName(); if (!name) return; if (name === lastWrittenName) return; lastWrittenName = name; setTabParamInSearch(name); } function wireTabHandlers() { const tabs = getTabButtons(); if (!tabs.length) return false; tabs.forEach(btn => { if (btn.__vis2TabWired) return; btn.__vis2TabWired = true; const handler = () => setTimeout(() => { writeUrlFromSelection(); sendTabEventToDP(); }, 0); btn.addEventListener("click", handler); btn.addEventListener("keydown", (e) => { if (e.key === "Enter" || e.key === " " || e.key === "Spacebar") handler(); }); }); return true; } function observeTabChanges() { const root = document.getElementById(TABS_WIDGET_ID); if (!root) return false; const obs = new MutationObserver(() => { wireTabHandlers(); writeUrlFromSelection(); sendTabEventToDP(); }); obs.observe(root, { subtree: true, childList: true, attributes: true, attributeFilter: ["aria-selected", "class"], }); wireTabHandlers(); writeUrlFromSelection(); sendTabEventToDP(); return true; } // ============================================== // =================== Command-DP -> Tab setzen =================== let lastCmdToken = ""; function isTargetForMe(cmd) { const myId = getOrCreateDeviceId(); const myName = applyDeviceNameFromMap(); if (!cmd || cmd.target == null) return false; const t = cmd.target; if (t === "*") return true; if (Array.isArray(t)) { return t.includes(myId) || (myName && t.includes(myName)); } if (typeof t === "string") { return t === myId || (myName && t === myName); } if (typeof t === "object") { if (t.deviceId && t.deviceId === myId) return true; if (t.deviceName && myName && t.deviceName === myName) return true; } return false; } function handleTabCmd(rawVal) { if (rawVal == null) return; // unwrap State-Objekt if (typeof rawVal === "object" && rawVal && "val" in rawVal) { rawVal = rawVal.val; } if (rawVal == null) return; let cmd = null; if (typeof rawVal === "string") { const s = rawVal.trim(); if (!s) return; if (s.startsWith("{") || s.startsWith("[")) cmd = safeJsonParse(s); if (!cmd) cmd = { target: "*", tab: s, ts: Date.now() }; } else if (typeof rawVal === "number") { cmd = { target: "*", tab: rawVal, ts: Date.now() }; } else if (typeof rawVal === "object") { cmd = rawVal; } if (!cmd) return; // Kompatibilität: event-artiges Format akzeptieren if (cmd.target == null && (cmd.deviceId || cmd.deviceName)) { cmd.target = { deviceId: cmd.deviceId, deviceName: cmd.deviceName }; } if (cmd.tab == null) { if (cmd.tabName != null) cmd.tab = cmd.tabName; else if (cmd.tabIndex != null) cmd.tab = cmd.tabIndex; } // ✅ Dedup NUR über cmdId (wenn vorhanden). Ohne cmdId wird NICHT deduped. if (cmd.cmdId != null) { const token = String(cmd.cmdId); if (token === lastCmdToken) return; lastCmdToken = token; } // Zielprüfung applyDeviceNameFromMap(); if (!isTargetForMe(cmd)) return; dlog("CMD accepted:", cmd); if (cmd.view) gotoView(String(cmd.view)); if (cmd.tab != null) forceSelectTab(cmd.tab, !!cmd.force); } // ============================================== // =================== Subscribe/Bind Setup =================== let subscribedIds = new Set(); function subscribeNow(ids) { const v = getVis(); if (!v?.conn?.subscribe) return; try { v.conn.subscribe(ids); ids.forEach(id => subscribedIds.add(id)); dlog("subscribed:", ids); } catch (e) { dlog("subscribe err", e); } } function ensureSubscribeAndBind(ids, onChange) { const v = getVis(); if (!v?.conn?.getStates || !v?.conn?.subscribe || !v?.states?.bind) { return false; } try { v.conn.gettingStates = 0; } catch {} v.conn.getStates(ids, (err, states) => { if (err) dlog("getStates err", err); // subscribe subscribeNow(ids); // cache füllen (hilft je nach Build) try { if (states && typeof v.updateStates === "function") v.updateStates(states); } catch {} ids.forEach(id => { const cb = (e, newVal, oldVal) => onChange(newVal, oldVal, id); // robust: DP und DP.val try { v.states.bind(id + ".val", cb); } catch {} try { v.states.bind(id, cb); } catch {} }); }); return true; } function setupCmdListener() { const ok = ensureSubscribeAndBind([DP_TAB_CMD], (newVal) => { if (isSuppressed()) return; handleTabCmd(newVal); }); if (ok) return true; // Fallback Polling let last = null; const timer = setInterval(() => { try { let v = readVisValue(DP_TAB_CMD); if (typeof v === "object" && v && "val" in v) v = v.val; if (v != null && v !== last) { last = v; if (!isSuppressed()) handleTabCmd(v); } } catch {} }, 500); window.addEventListener("beforeunload", () => clearInterval(timer)); return true; } function setupDeviceMapListener() { const ok = ensureSubscribeAndBind([DP_DEVICE_MAP], () => { if (isSuppressed()) return; const n = applyDeviceNameFromMap(); dlog("deviceName updated:", n); }); applyDeviceNameFromMap(); return ok; } function startPeriodicResubscribe() { setInterval(() => { // immer wieder subscribe, falls VIS2 nach Reconnect „vergisst“ subscribeNow([DP_TAB_CMD, DP_DEVICE_MAP]); }, RESUBSCRIBE_EVERY_MS); } // ============================================== // =================== Init =================== (function init() { const id = getOrCreateDeviceId(); dlog("deviceId:", id); const n = applyDeviceNameFromMap(); dlog("deviceName:", n); applyTabFromUrl(); if (!observeTabChanges()) { const obs = new MutationObserver(() => { if (observeTabChanges()) obs.disconnect(); }); obs.observe(document.body, { childList: true, subtree: true }); setTimeout(() => obs.disconnect(), OBSERVE_TIMEOUT_MS); } setupCmdListener(); setupDeviceMapListener(); startPeriodicResubscribe(); window.addEventListener("popstate", applyTabFromUrl); })(); [image: 1770574125750-vis2-tabcontrol.gif]
  • VIS-2 binding operation json

    10
    1
    0 Stimmen
    10 Beiträge
    83 Aufrufe
    M
    @Cyberraph Offenes Problem zusätzlich https://github.com/ioBroker/ioBroker.vis-2/issues/521
  • Jarvis 3.1.8 - zukünftige Strompreise - Skalierung, Farben

    320
    1
    0 Stimmen
    320 Beiträge
    52k Aufrufe
    M
    @MCU perfekt - funktioniert sofort... da wäre ich nie nie nie drauf gekommen :)
  • Darstellung json-Tipperpreise m

    2
    0 Stimmen
    2 Beiträge
    53 Aufrufe
    M
    @docadams https://github.com/hombach/ioBroker.tibberlink?tab=readme-ov-file#graph-output-configuration
  • [GELÖST] VIS-2 - Überbleibsel Widget trotz Löschung Adapter

    4
    3
    0 Stimmen
    4 Beiträge
    56 Aufrufe
    crunchipC
    @Cyberraph sagte in GELÖST - VIS-2 - Überbleibsel Widget trotz Löschung Adapter: Holt das im Prinzip nochmal alles "rein" und zieht alles "glatt" Kann man so sagen
  • Lovelace: Verlauf in Thremostat-Karte

    1
    3
    0 Stimmen
    1 Beiträge
    30 Aufrufe
    Niemand hat geantwortet
  • Jarvis 3.1.8 / 3.2.0 und Wetter Modul

    3
    0 Stimmen
    3 Beiträge
    93 Aufrufe
    N
    @MCU Done! https://github.com/Zefau/ioBroker.jarvis/issues/2968
  • JSON Table aus viessmannapi-Adapter darstellen

    1
    2
    0 Stimmen
    1 Beiträge
    32 Aufrufe
    Niemand hat geantwortet
  • VIS2 - keine Attribute in Gruppierung mehr möglich ?

    6
    1
    0 Stimmen
    6 Beiträge
    482 Aufrufe
    F
    da ich aktuell auch gerade am umstellen auf Vis2 bin, betrifft mich das Problem auch, habe ziemlich viele Gruppierungen mit groupAttr. is die funktion komplett raus oder kommt die noch
  • Problem mit dem VIS-2 weather widget

    1
    1
    0 Stimmen
    1 Beiträge
    47 Aufrufe
    Niemand hat geantwortet

304

Online

32.6k

Benutzer

82.3k

Themen

1.3m

Beiträge