Skip to content

Visualisierung

Hilfe zu Visualisierungen

9.4k Topics 103.9k Posts

NEWS

  • VIS / VIS-2 Übersicht Widgetkompatibilität

    Pinned vis
    41
    15 Votes
    41 Posts
    12k Views
    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

    Pinned Moved vis
    100
    3
    1 Votes
    100 Posts
    44k Views
    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 Material Widgets Signalbilder

    16
    0 Votes
    16 Posts
    991 Views
    R
    Hi zusammen, ist der Bug behoben worden? Bei den Widgets Universal & Multi aus "vis-iventwo" und universal aus "iventwo-design" sind weiterhin "nur" 3 Signalbilder möglich, obwohl zB 4 ausgewählt wurden
  • Reolink über go2rtc in VIS einbinden

    23
    1
    0 Votes
    23 Posts
    154 Views
    inviI
    Hallo Hans. http://Meine IP:1984/stream.html?src=Hauseingang-1&mode=webrtc läuft mit W-Lan auf einem Echo Show 8 ohne ruckeln. Grüße invi
  • Iqontrol - wie bindet man ein iframe ein?

    3
    0 Votes
    3 Posts
    43 Views
    JLegJ
    @weimaraner für eine "Digitaluhr" braucht's keinen iframe - ich habe z.B. ein "Widget" genommen, und bei "background_html" einen eigenen Datenpunkt vom Typ "string" eingetragen. Dazu läuft dann ein Script, das bei mir alle 10min bissel HTML in diesen Datenpunkt schreibt...
  • VIS(1): Ein PopUp für mehrere Lampen

    2
    0 Votes
    2 Posts
    67 Views
    grrfieldG
    Hallo, ich löse das über ein Javascript zusammen mit den MaterialDesign-Widgets. Ich habe unterschiedliche PopUps für Schalter, Dimmer, Heizung, Rolläden usw., die alle auf der aktiven View liegen und mit einem State versteckt oder sichtbar gemacht werden können. Die Position wird ebenfalls aus einem State übernommen: [image: 1771421693238-be3e94a0-2410-4d12-9040-494a569afc5f-image.png] [image: 1771421822741-7e3831eb-cf48-4fda-a0a5-192d7838c4df-image.png] Jedes Gerät auf meiner Karte hat ein Widget, das den Namen des Geräts und seine Position auf der Karte (hier Tischlampe<br>Wohnzimmer;14,538) in einen State schreibt: [image: 1771421365187-53cb068d-f180-47ca-8932-a91d04e15a63-image.png] [image: 1771421417931-618e6fc2-9ab8-4e33-9a50-505d05d60a13-image.png] Das Skript triggert auf den State, sucht den passenden PopUp heraus, bestimmt aus der Lage des Gerätewidgets die Position des Popups und macht diesen sichtbar - sieht dann so aus: [image: 1771439337444-871fb9d8-f391-4754-85d5-47a01becf458-image.png] Der Popup selbst ist eine View, in der je nach Gerät ein Schalter- oder Reglerwidget angeordnet sind, die ihre Werte wieder in einen State schreiben, der dann von meinem Skript an den betreffenden Schalter oder Dimmer weitergegeben wird: [image: 1771422077281-bcf524ac-e229-49a8-b1c1-7ce1f3c26ebd-image.png] [image: 1771422132044-4840fc4a-e9dc-4b92-a496-eec346d9ce48-image.png] Nach Betätigung des Schalters oder nach einer Totzeit macht das Skript den PopUp dann wieder unsichtbar. Das Skript ist sehr speziell für meine Zwecke angelegt, wenn es Dich interessiert und Du es anpassen möchtest, kannst Du es Dir hier ansehen: Spoiler /** * vHausSubDialog * Erzeugt die Subdialoge in den Hausplänen Steuerung der Geräte per vis * Die Dialoge werden über vXXXXSelectausgewählt, dann öffnet sich über * vis+'vXXXXDialog' ein Dialogfeld zum Einstellen des Wertes über * vis+'vXXXXLevel' * In vXXXXSelect werden auch die Koordinaten des Dialogfeldes angegeben * - das Format ist: 'Name;x-Position,y-Position;[View]' * * States: vis+'vDeviceSelect' // Auswahl Device * vis+'vDeviceSelectName' // Device Name * vis+'vDialogX' // x-Position des Dialogs * vis+'vDialogY' // y-Position des Dialogs * vis+'vDimmerDialog' // Dimmer Dialog anzeigen * vis+'vDimmerDialogClose' // Dimmer Dialog schließen * vis+'vDimmerLevel' // Helligkeit der mit vDeviceSelect ausgewählten Lampe * vis+'vSchalterDialog' // Schalter Dialog anzeigen * vis+'vSchalterDialogClose' // Schalter Dialog schließen * vis+'vSchalterState' // Zustand der mit vDeviceSelect ausgewählten Lampe * vis+'vHeizungDialog' // Heizungs Dialog anzeigen * vis+'vHeizungDialogClose' // Heizungs Dialog schließen * vis+'vHeizungLevel' // Temperatur der mit vDeviceSelect ausgewählten Heizung * vis+'vKlimaDialog' // Klima Dialog anzeigen * vis+'vKlimaDialogClose' // Klima Dialog schließen * vis+'vKlimagLevel' // Temperatur der mit vDeviceSelect ausgewählten Klimaanlage * vis+'vKlimaState' // Zustand der mit vDeviceSelect ausgewählten Klimaanlage * vis+'vRolloDialog' // Rolladen Dialog anzeigen * vis+'vRolloDialogClose' // Rolladen Dialog schließen * vis+'vRolloLevel' // Position des mit vDeviceSelect ausgewählten Rolladens * vis+'vBlindDialog' // Jalousie Dialog anzeigen * vis+'vBlindDialogClose' // Jalousie Dialog schließen * vis+'vBlindLevel' // Position der mit vDeviceSelect ausgewählten Jalousie * * log: vHD002 * debug: vHD113 */ DEBUG=true; /** * Einstellungen //Defaults */ // Positionierung der Dialoge [pixel] const ViewHaus={ height: 661, //661 width: 914, //914 buttonHeight: 64, //64 buttonWidth: 64 //64 }; const ViewRollos={ height: 678, //678 width: 889, //889 buttonHeight: 84, //84 buttonWidth: 220 //220 }; const ViewBlinds={ height: 678, //678 width: 889, //889 buttonHeight: 84, //84 buttonWidth: 220 //220 }; //Abstand der Dialoge zum Button und mindestens zum Rand [pixel] const distance=8; //8 // Dialoggröße [pixel] const DialogWidth=200; //200 const DimmerLevelHeight=298; //298 const SchalterStateHeight=186; //186 const TtasterStateHeight=186; //186 const RolloLevelHeight=368; //368 const BlindLevelHeight=368; //368 const HeizungLevelHeight=298; //298 const KlimaLevelHeight=348; //348 // Versatz Dialog gegen Button [pixel] const Dx=0; //0 const Dy=0; //0 // Timeout für Dialog [s] const DialogTimeout=30; //30 // Timeout für Wiederaufruf [ms] const LockTime=1000; //1000 // Wartezeit für Viewaufruf [ms] const ReViewTime=200; //100 // Entprellzeit [ms] const BouncingTime=400; //400 // Basis für Objekte const Haus=getState('Init.BasisHaus').val; const Heizung=getState('Init.BasisHeizung').val; const Licht=getState('Init.BasisLicht').val; const Tagesablauf=getState('Init.BasisTagesablauf').val; const Trigger=getState('Init.BasisTrigger').val; const Verschluss=getState('Init.BasisVerschluss').val; const Vis=getState('Init.Basisvis').val; const SwitchBot='0_userdata.0.SwitchBot.'; const BlindTilts=SwitchBot+'BlindTilts.'; // Browserinstance für Vis ['xxxxxxxx'] const VisInstance=getState(Vis+'Init.visTuer').val; // Vis-Name ['text'] const VisName='SM-P610' //'SM-P610' /** * States */ createState(Vis+'vDeviceSelect', {type: 'string', name: 'Auswahl Device'}); createState(Vis+'vDeviceSelectName', {type: 'string', name: 'Device Name'}); createState(Vis+'vDialogX', {type: 'number', name: 'x-Position des Dialogs'}); createState(Vis+'vDialogY', {type: 'number', name: 'y-Position des Dialogs'}); createState(Vis+'vDimmerDialog', false, {type: 'boolean', name: 'Dimmer Dialog anzeigen'}); createState(Vis+'vDimmerDialogClose', false, {type: 'boolean', name: 'Dimmer Dialog schließen'}); createState(Vis+'vDimmerLevel', {type: 'number', name: 'Helligkeit der mit vDeviceSelect ausgewählten Lampe'}); createState(Vis+'vSchalterDialog', false, {type: 'boolean', name: 'Schalter Dialog anzeigen'}); createState(Vis+'vSchalterDialogClose', false, {type: 'boolean', name: 'Schalter Dialog schließen'}); createState(Vis+'vSchalterState', false, {type: 'boolean', name: 'Zustand des mit vDeviceSelect ausgewählten Schalters'}); createState(Vis+'vTasterDialog', false, {type: 'boolean', name: 'Taster Dialog anzeigen'}); createState(Vis+'vTasterDialogClose', false, {type: 'boolean', name: 'Taster Dialog schließen'}); createState(Vis+'vTasterState', false, {type: 'boolean', name: 'Zustand des mit vDeviceSelect ausgewählten Tasters'}); createState(Vis+'vTasterIcon', '', {type: 'string', name: 'Taster Icon'}); createState(Vis+'vHeizungDialog', false, {type: 'boolean', name: 'Heizung Dialog anzeigen'}); createState(Vis+'vHeizungDialogClose', false, {type: 'boolean', name: 'Heizung Dialog schließen'}); createState(Vis+'vHeizungLevel', {type: 'number', name: 'Temperatur der mit vDeviceSelect ausgewählten Heizung'}); createState(Vis+'vRolloDialog', false, {type: 'boolean', name: 'Rolladen Dialog anzeigen'}); createState(Vis+'vRolloDialogClose', false, {type: 'boolean', name: 'Rolladen Dialog schließen'}); createState(Vis+'vRolloLevel', {type: 'number', name: 'Position des mit vDeviceSelect ausgewählten Rolladens'}); createState(Vis+'vBlindDialog', false, {type: 'boolean', name: 'Jalousie Dialog anzeigen'}); createState(Vis+'vBlindDialogClose', false, {type: 'boolean', name: 'Jalousie Dialog schließen'}); createState(Vis+'vBlindLevel', {type: 'number', name: 'Position der mit vDeviceSelect ausgewählten Jalousie'}); // Restart, wenn States noch nicht geschrieben if(!existsState(Vis+'vRolloLevel')) runScript(); /** * Initialisierung */ setState(Vis+'vDimmerDialog', false, true); setState(Vis+'vDimmerDialogClose', false, true); setState(Vis+'vSchalterDialog', false, true); setState(Vis+'vSchalterDialogClose', false, true); setState(Vis+'vTasterDialog', false, true); setState(Vis+'vTasterDialogClose', false, true); setState(Vis+'vTasterDialog', false, true); setState(Vis+'vTasterDialogClose', false, true); setState(Vis+'vHeizungDialog', false, true); setState(Vis+'vHeizungDialogClose', false, true); setState(Vis+'vRolloDialog', false, true); setState(Vis+'vRolloDialogClose', false, true); setState(Vis+'vBlindDialog', false, true); setState(Vis+'vBlindDialogClose', false, true); setState(Vis+'vDeviceSelect', ''); /** * Main */ let aktView=''; let deviceType=''; // 'Dimmer'||'Schalter'||'Taster'||'Heizung'||'Klima'||'Rolladen'||'Jalousie' let aktor=''; let aktorK=''; let tastLevel; let tastIcon=''; let dDialogOnID; let dDialogToID; let dCloseOnID; let sDialogOnID; let sDialogToID; let sCloseOnID; let tDialogOnID; let tDdialogToID; let tCloseOnID; let hDialogOnID; let hDialogToID; let hCloseOnID; let kDialogOnID; let kDialogToID; let kCloseOnID; let rDialogOnID; let rDialogToID; let rCloseOnID; let bDialogOnID; let bDialogToID; let bCloseOnID; let dlgToID; let lckToID; let lock=false; // Mehrfachaufruf blockieren // Aufruf durch Setzen des States vis+'vDeviceSelect' mit: Dimmer;X,Y;[View] on({id: Vis+'vDeviceSelect', change: 'any'}, select => { let device=select.state.val.slice(0, select.state.val.indexOf(';')); let x=Number(select.state.val.slice(select.state.val.indexOf(';')+1, select.state.val.indexOf(','))); let y; let view=''; x= x == NaN ? Dx : x+Dx; if(select.state.val.indexOf(';', select.state.val.indexOf(',')) == -1) { y=Number(select.state.val.slice(select.state.val.indexOf(',')+1)); } else { y=Number(select.state.val.slice(select.state.val.indexOf(',')+1, select.state.val.indexOf(';', select.state.val.indexOf(',')))); view=select.state.val.slice(select.state.val.indexOf(';', select.state.val.indexOf(','))+1); } y= y == NaN ? Dy : y+Dy; if(device != '' && !lock) { unsubscribe(dDialogOnID); unsubscribe(dCloseOnID); unsubscribe(sDialogOnID); unsubscribe(sCloseOnID); unsubscribe(tDialogOnID); unsubscribe(tCloseOnID); unsubscribe(hDialogOnID); unsubscribe(hCloseOnID); unsubscribe(kDialogOnID); unsubscribe(kCloseOnID); unsubscribe(rDialogOnID); unsubscribe(rCloseOnID); unsubscribe(bDialogOnID); unsubscribe(bCloseOnID); setState(Vis+'vDimmerDialog', false, true); setState(Vis+'vDimmerDialogClose', false, true); setState(Vis+'vSchalterDialog', false, true); setState(Vis+'vSchalterDialogClose', false, true); setState(Vis+'vTasterDialog', false, true); setState(Vis+'vTasterDialogClose', false, true); setState(Vis+'vHeizungDialog', false, true); setState(Vis+'vHeizungDialogClose', false, true); setState(Vis+'vKlimaDialog', false, true); setState(Vis+'vKlimaDialogClose', false, true); setState(Vis+'vRolloDialog', false, true); setState(Vis+'vRolloDialogClose', false, true); setState(Vis+'vBlindDialog', false, true); setState(Vis+'vBlindDialogClose', false, true); debug('vHD101 Device: '+device+'; x = '+x+', y = '+y); switch(device) { // Dimmer case 'Deckenstrahler<br>Küche': aktor='hm-rpc.2.xxxxxxxxxxxxxx.2.LEVEL'/*Deckenstrahler Küche LEVEL*/; deviceType='Dimmer'; aktView='2_HausEG'; break; case 'Tischlampe<br>Wohnzimmer': aktor='hm-rpc.2.xxxxxxxxxxxxxx'/*Tischlampe Wohnzimmer LEVEL*/; deviceType='Dimmer'; aktView='2_HausEG'; break; case 'Deckenlampe<br>Bad': aktor='hm-rpc.1.xxxxxxxxxx.1.LEVEL'/*Deckenlampe Bad LEVEL*/; deviceType='Dimmer'; aktView='2_HausOG'; break; case 'Strahler<br>Keller': aktor='hm-rpc.1.xxxxxxxxxx.1.LEVEL'/*Deckenstrahler Keller LEVEL*/; deviceType='Dimmer'; aktView='2_HausUG'; break; // Schalter case 'Arbeitslicht<br>Küche': aktor='hm-rpc.2.xxxxxxxxxxxxxx.3.STATE'/*Arbeitslicht Küche STATE*/; deviceType='Schalter'; aktView='2_HausEG'; break; case 'Licht<br>Terrasse': aktor='hm-rpc.2.xxxxxxxxxxxxxx3.STATE'/*Licht Terrasse STATE*/; deviceType='Schalter'; aktView='2_HausG'; break; // Taster case 'Robby': aktor='0_userdata.0.Trigger.RobbyClean'; deviceType='Taster'; tastLevel=true; tastIcon='power'; aktView='2_HausEG'; break; // Heizungen case 'Heizung<br>Wohnzimmer': aktor='hm-rpc.2.xxxxxxxxxxxxxx.1.SET_POINT_TEMPERATURE'/*Heizungssensor Wohnzimmer:Thermostat SET POINT TEMPERATURE*/; device='Wohnzimmer'; deviceType='Heizung'; aktView='2_HausEG'; break; // Rolladen case 'Rolladen<br>Terrasse': aktor=Verschluss+'RolladenTerrasse.LEVEL'/*Position*/; device='Terrasse'; deviceType='Rolladen'; aktView='2_HausEG'; break; case 'Rolladen<br>Küche': aktor=Verschluss+'RolladenKüche.LEVEL'/*Position*/; device='Küche'; deviceType='Rolladen'; aktView='2_HausEG'; break; // Jalousien case 'Jalousie<br>Arbeitszimmer': aktor=BlindTilts+'JalousieArbeitszimmer.LEVEL'; device='Arbeitszimmer'; deviceType='Jalousie'; aktView='2_HausOG'; break; default: log('vHD001 Device '+select.state.val+' not exist!', 'warn'); aktor=''; } if(view != '') aktView=view; debug('vHD102 View: '+aktView); setState(Vis+'vDeviceSelectName', device); if(aktor != '') { // Dimmer if(deviceType == 'Dimmer') { // alten Dimmerlevel in vis darstellen setState(Vis+'vDimmerLevel', getState(aktor).val); x= x+ViewHaus.buttonWidth+DialogWidth+2*distance < ViewHaus.width ? x+ViewHaus.buttonWidth+distance : x-distance-DialogWidth; y= y+DimmerLevelHeight+distance < ViewHaus.height ? y : y+ViewHaus.buttonHeight-DimmerLevelHeight; setState(Vis+'vDialogX', x); setState(Vis+'vDialogY', y); setStateDelayed(Vis+'vDimmerDialog', true, true, BouncingTime); viewReAkt(aktView); setStateDelayed('vis.0.control.command', 'changeView', ReViewTime+BouncingTime, () => { setState('vis.0.control.data', VisName+'/'+aktView); }); unsubscribe(dDialogOnID); dDialogOnID=on({id: Vis+'vDimmerLevel', change: 'ne'}, level => { debug('vHD103 Dimmer: '+device+' = '+aktor+', Level: '+level.state.val); // Dimmerlevel setzen setState(aktor, level.state.val); clearTimeout(dDialogToID); dDialogToID=setTimeout(() => { unsubscribe(dDialogOnID); unsubscribe(dCloseOnID); setState(Vis+'vDimmerDialog', false, true); setState(Vis+'vDeviceSelect', ''); setState(Vis+'vDimmerDialogClose', false); }, DialogTimeout*1000); }); unsubscribe(dCloseOnID); dCloseOnID=on({id: Vis+'vDimmerDialogClose', change: 'ne', val: true}, () => { unsubscribe(dDialogOnID); clearTimeout(dDialogToID); setState(Vis+'vDimmerDialog', false, true); setState(Vis+'vDeviceSelect', ''); setState(Vis+'vDimmerDialogClose', false); }); clearTimeout(dDialogToID); dDialogToID=setTimeout(() => { unsubscribe(dDialogOnID); unsubscribe(dCloseOnID); setState(Vis+'vDimmerDialog', false, true); setState(Vis+'vDeviceSelect', ''); setState(Vis+'vDimmerDialogClose', false); }, DialogTimeout*1000); // Schalter } else if(deviceType == 'Schalter') { // alten Schaltzustand in vis darstellen setState(Vis+'vSchalterState', getState(aktor).val); x= x+ViewHaus.buttonWidth+DialogWidth+2*distance < ViewHaus.width ? x+ViewHaus.buttonWidth+distance : x-distance-DialogWidth; y= y+SchalterStateHeight+distance < ViewHaus.height ? y : y+ViewHaus.buttonHeight-SchalterStateHeight; debug('vHD111 XY '+x+', '+y); setState(Vis+'vDialogX', x); setState(Vis+'vDialogY', y); setStateDelayed(Vis+'vSchalterDialog', true, true, BouncingTime); viewReAkt(aktView); unsubscribe(sDialogOnID); sDialogOnID=on({id: Vis+'vSchalterState', change: 'ne'}, level => { debug('vHD104 Schalter: '+device+' = '+aktor+', Level: '+level.state.val); // Schalterlevel setzen setState(aktor, level.state.val); clearTimeout(dDialogToID); sDialogToID=setTimeout(() => { unsubscribe(sDialogOnID); unsubscribe(sCloseOnID); setState(Vis+'vSchalterDialog', false, true); setState(Vis+'vDeviceSelect', ''); setState(Vis+'vSchalterDialogClose', false); }, DialogTimeout*1000); }); unsubscribe(sCloseOnID); sCloseOnID=on({id: Vis+'vSchalterDialogClose', change: 'ne', val: true}, () => { unsubscribe(sDialogOnID); clearTimeout(dDialogToID); setState(Vis+'vSchalterDialog', false, true); setState(Vis+'vDeviceSelect', ''); setState(Vis+'vSchalterDialogClose', false); }); clearTimeout(dDialogToID); sDialogToID=setTimeout(() => { unsubscribe(sDialogOnID); unsubscribe(sCloseOnID); setState(Vis+'vSchalterDialog', false, true); setState(Vis+'vDeviceSelect', ''); setState(Vis+'vSchalterDialogClose', false); }, DialogTimeout*1000); // Taster } else if(deviceType == 'Taster') { // alten Schaltzustand in vis darstellen setState(Vis+'vTasterIcon', tastIcon); x= x+ViewHaus.buttonWidth+DialogWidth+2*distance < ViewHaus.width ? x+ViewHaus.buttonWidth+distance : x-distance-DialogWidth; y= y+TtasterStateHeight+distance < ViewHaus.height ? y : y+ViewHaus.buttonHeight-TtasterStateHeight; debug('vHD112 XY '+x+', '+y); setState(Vis+'vDialogX', x); setState(Vis+'vDialogY', y); setStateDelayed(Vis+'vTasterDialog', true, true, BouncingTime); viewReAkt(aktView); unsubscribe(tDialogOnID); tDialogOnID=on({id: Vis+'vTasterState', change: 'any'}, () => { debug('vHD104 Taster: '+device+' = '+aktor+', Level: '+tastLevel); // Tasterlevel setzen setState(aktor, tastLevel); clearTimeout(tDdialogToID); tDdialogToID=setTimeout(() => { unsubscribe(dDialogOnID); unsubscribe(dCloseOnID); setState(Vis+'vTasterDialog', false, true); setState(Vis+'vDeviceSelect', ''); setState(Vis+'vTasterDialogClose', false, true); }, BouncingTime); }); unsubscribe(tCloseOnID); tCloseOnID=on({id: Vis+'vTasterDialogClose', change: 'ne', val: true}, () => { unsubscribe(tDialogOnID); clearTimeout(tDdialogToID); setState(Vis+'vTasterDialog', false, true); setState(Vis+'vDeviceSelect', ''); setState(Vis+'vTasterDialogClose', false, true); }); clearTimeout(tDdialogToID); tDdialogToID=setTimeout(() => { unsubscribe(dDialogOnID); unsubscribe(dCloseOnID); setState(Vis+'vTasterDialog', false, true); setState(Vis+'vDeviceSelect', ''); setState(Vis+'vTasterDialogClose', false, true); }, DialogTimeout*1000); // Heizung } else if(deviceType == 'Heizung') { // alten Heizunglevel in vis darstellen setState(Vis+'vHeizungLevel', getState(aktor).val); x= x+ViewHaus.buttonWidth+DialogWidth+2*distance < ViewHaus.width ? x+ViewHaus.buttonWidth+distance : x-distance-DialogWidth; y= y+HeizungLevelHeight+distance < ViewHaus.height ? y : y+ViewHaus.buttonHeight-HeizungLevelHeight; setState(Vis+'vDialogX', x); setState(Vis+'vDialogY', y); setStateDelayed(Vis+'vHeizungDialog', true, true, BouncingTime); viewReAkt(aktView); unsubscribe(hDialogOnID); hDialogOnID=on({id: Vis+'vHeizungLevel', change: 'ne'}, level => { debug('vHD105 Heizung: '+device+' = '+aktor+', Level: '+level.state.val); // Heizunglevel setzen setState(aktor, level.state.val); clearTimeout(hDialogToID); hDialogToID=setTimeout(() => { unsubscribe(hDialogOnID); unsubscribe(hCloseOnID); setState(Vis+'vHeizungDialog', false, true); setState(Vis+'vDeviceSelect', ''); setState(Vis+'vHeizungDialogClose', false, true); }, DialogTimeout*1000); }); unsubscribe(hCloseOnID); hCloseOnID=on({id: Vis+'vHeizungDialogClose', change: 'ne', val: true}, () => { unsubscribe(hDialogOnID); clearTimeout(hDialogToID); setState(Vis+'vHeizungDialog', false, true); setState(Vis+'vDeviceSelect', ''); setState(Vis+'vHeizungDialogClose', false, true); }); clearTimeout(hDialogToID); hDialogToID=setTimeout(() => { unsubscribe(hDialogOnID); unsubscribe(hCloseOnID); setState(Vis+'vHeizungDialog', false, true); setState(Vis+'vDeviceSelect', ''); setState(Vis+'vHeizungDialogClose', false, true); }, DialogTimeout*1000); // Rolladen } else if(deviceType == 'Rolladen') { // alte Rolladenposition in vis darstellen setState(Vis+'vRolloLevel', getState(aktor+'_CURRENT').val); if(aktView == '4_Rollos') { x= x+ViewRollos.buttonWidth+DialogWidth+2*distance < ViewRollos.width ? x+ViewRollos.buttonWidth/2+distance : x-distance-DialogWidth; y= y+RolloLevelHeight+distance < ViewRollos.height ? y : y+ViewRollos.buttonHeight-RolloLevelHeight; } else { x= x+ViewHaus.buttonWidth+DialogWidth+2*distance < ViewHaus.width ? x+ViewHaus.buttonWidth+distance : x-distance-DialogWidth; y= y+RolloLevelHeight+distance < ViewHaus.height ? y : y+ViewHaus.buttonHeight-RolloLevelHeight; } setState(Vis+'vDialogX', x); setState(Vis+'vDialogY', y); setStateDelayed(Vis+'vRolloDialog', true, true, BouncingTime); viewReAkt(aktView); unsubscribe(rDialogOnID); rDialogOnID=on({id: Vis+'vRolloLevel', change: 'ne'}, level => { debug('vHD106 Rolladen: '+device+' = '+aktor+', Level: '+level.state.val); // Rolladenposition setzen setState(aktor, level.state.val); clearTimeout(rDialogToID); rDialogToID=setTimeout(() => { unsubscribe(rDialogOnID); unsubscribe(rCloseOnID); setState(Vis+'vRolloDialog', false, true); setState(Vis+'vDeviceSelect', ''); setState(Vis+'vRolloDialogClose', false, true); }, DialogTimeout*1000); }); unsubscribe(rCloseOnID); rCloseOnID=on({id: Vis+'vRolloDialogClose', change: 'ne', val: true}, () => { unsubscribe(rDialogOnID); clearTimeout(rDialogToID); setState(Vis+'vRolloDialog', false, true); setState(Vis+'vDeviceSelect', ''); setState(Vis+'vRolloDialogClose', false, true); }); clearTimeout(rDialogToID); rDialogToID=setTimeout(() => { unsubscribe(rDialogOnID); unsubscribe(rCloseOnID); setState(Vis+'vRolloDialog', false, true); setState(Vis+'vDeviceSelect', ''); setState(Vis+'vRolloDialogClose', false, true); }, DialogTimeout*1000); // Jalousien } else if(deviceType == 'Jalousie') { // alte Jalousienposition in vis darstellen setState(Vis+'vBlindLevel', getState(aktor).val); x= x+ViewHaus.buttonWidth+DialogWidth+2*distance < ViewHaus.width ? x+ViewHaus.buttonWidth+distance : x-distance-DialogWidth; y= y+BlindLevelHeight+distance < ViewHaus.height ? y : y+ViewHaus.buttonHeight-BlindLevelHeight; setState(Vis+'vDialogX', x); setState(Vis+'vDialogY', y); setStateDelayed(Vis+'vBlindDialog', true, true, BouncingTime); viewReAkt(aktView); unsubscribe(bDialogOnID); bDialogOnID=on({id: Vis+'vBlindLevel', change: 'ne'}, level => { debug('vHD107 Jalousie: '+device+' = '+aktor+', Level: '+level.state.val); // Jalousieposition setzen setState(aktor, level.state.val); clearTimeout(bDialogToID); bDialogToID=setTimeout(() => { unsubscribe(bDialogOnID); unsubscribe(bCloseOnID); setState(Vis+'vBlindDialog', false, true); setState(Vis+'vDeviceSelect', ''); setState(Vis+'vBlindDialogClose', false, true); }, DialogTimeout*1000); }); unsubscribe(bCloseOnID); bCloseOnID=on({id: Vis+'vBlindDialogClose', change: 'ne', val: true}, () => { unsubscribe(bDialogOnID); clearTimeout(bDialogToID); setState(Vis+'vBlindDialog', false, true); setState(Vis+'vDeviceSelect', ''); setState(Vis+'vBlindDialogClose', false, true); }); clearTimeout(bDialogToID); bDialogToID=setTimeout(() => { unsubscribe(bDialogOnID); unsubscribe(bCloseOnID); setState(Vis+'vBlindDialog', false, true); setState(Vis+'vDeviceSelect', ''); setState(Vis+'vBlindDialogClose', false, true); }, DialogTimeout*1000); } else { log('vDL002 Aktor '+aktor+' not defined!', 'warn'); } } } if(!lock) { clearTimeout(dlgToID); // Nochmal alle Dialoge schließen, falls etwas nicht geklappt hat dlgToID=setTimeout(() => { setState(Vis+'vDimmerDialog', false, true); setState(Vis+'vDimmerDialogClose', false, true); setState(Vis+'vSchalterDialog', false, true); setState(Vis+'vSchalterDialogClose', false, true); setState(Vis+'vTasterDialog', false, true); setState(Vis+'vTasterDialogClose', false, true); setState(Vis+'vRolloDialog', false, true); setState(Vis+'vRolloDialogClose', false, true); setState(Vis+'vBlindDialog', false, true); setState(Vis+'vBlindDialogClose', false, true); setState(Vis+'vHeizungDialog', false, true); setState(Vis+'vHeizungDialogClose', false, true); setState(Vis+'vDeviceSelect', ''); lock=false; }, 1.5*DialogTimeout*1000); } lock=true; clearTimeout(lckToID); lckToID=setTimeout(() => { lock=false; }, LockTime); }, ); /** * View nochmal aufrufen, da Fehler in Vis: Dialog ist manchmal leer * @param {string} aView Viewname */ function viewReAkt(aView) { debug('vDH109 viewReAkt('+aView+')'); setState('vis.0.control.instance', VisInstance); setStateDelayed('vis.0.control.data', VisName+'/'+aView, ReViewTime); setStateDelayed('vis.0.control.command', 'changeView', ReViewTime+BouncingTime); } // ___|\/| // |
  • VIS 2: WLED Effekt (seg.0.fx) als Dropdown anzeigen

    32
    0 Votes
    32 Posts
    171 Views
    D
    @skvarel bin gespannt
  • Problem mit "Vis 2 inventwo Widgets" Update > v0.2.2

    18
    2
    0 Votes
    18 Posts
    774 Views
    jkvarelJ
    Immerhin ein Fortschritt. Dann scheint für die raspberrypi5 Adresse evtl. noch was blockiert zu werden. Ich kenne mich da leider auch zu wenig aus, um Tipps zu geben was das Problem sein könnte, tut mir leid. Vielleicht hat noch jemand anderes eine Idee
  • Lovelace: "Unknown request for /lovelace/default_view"

    7
    0 Votes
    7 Posts
    46 Views
    David G.D
    @Rico-Sander Aber warum denkst du ist das der korrekte link? Steht das wirklich unter link auf der Seite wie in meinem Screenshot? [image: 1771325850400-1000061304.jpg] da könnte man zum testen ja mal default_view rein schreiben.
  • iobroker Visu App - Lädt immer via pro.cloud

    5
    9
    0 Votes
    5 Posts
    91 Views
    CyberraphC
    @bahnuhr Jap, der admin mit Passwort ist überflüssig. Hab ich schon gelernt, aber bislang nicht raus getan. Jetzt hab ich es mal überall raus getan. Aber abseits davon: Auch nochmal bei meinem anderen Handy, wo alles sauber läuft herumprobiert. Die SSID "FRITZ!Box 7530 UO" mal anders eingegeben. Und zack, dann wird über .pro verbunden. Geb ich sie korrekt ein, läuft es korrekt offline / direkt über das lokale Netzwerk. Bleibt mir ein Rätsel, warum es auf einmal beim anderen Handy nicht mehr funktioniert (obwohl nix geändert wurde). Es trat auf einmal auf nach vermutlich einem Stromausfall -> Serverneustart zuletzt. Aber warum sich da auf einmal was querstellt. Naja ich belasse es mal dabei -> ohne .pro das andere Handy zu belassen, damit es lokal sich verbindet.
  • iQontrol Größe der Geräte-Kacheln anpassen ?

    1
    3
    0 Votes
    1 Posts
    46 Views
    No one has replied
  • Support Adapter Energiefluss-erweitert v0.7.7

    Moved vis
    5k
    9
    20 Votes
    5k Posts
    6m Views
    hotspot_2H
    Hallo zusammen, kurze Frage zur Animation der Elemente oder der Funktion "Elemente nach Wert füllen": Kann man die Animation beim Start irgendwie deaktivieren so das der Wert sofort korrekt angezeigt wird?
  • iQontrol Vis Support Thread

    android app vis how-to ios app iqontrol mobile ui vis
    2k
    5
    7 Votes
    2k Posts
    688k Views
    CephalopodC
    Eine Anfängerfrage: Ich möchte bei Betätigung einer Kachel einen bestimmten festen Wert in einen Datenpunkt schreiben. Also Kachel 1 schreibt beim Drücken "1" in den Datenpunkt, Kachel 2 schreibt "2" in den selben Datenpunkt, usw. Wie stelle ich das an?
  • Zeigt her eure Visu

    vis
    124
    2 Votes
    124 Posts
    29k Views
    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 Votes
    8 Posts
    93 Views
    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 Votes
    10 Posts
    830 Views
    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?
  • LovelaceUI Wettervorhersage -> wie weather Endität erzeugen?

    Moved
    3
    4
    0 Votes
    3 Posts
    53 Views
    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 Votes
    9 Posts
    78 Views
    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 Votes
    10 Posts
    108 Views
    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 Votes
    320 Posts
    52k Views
    M
    @MCU perfekt - funktioniert sofort... da wäre ich nie nie nie drauf gekommen :)

502

Online

32.7k

Users

82.4k

Topics

1.3m

Posts