@förster einen Reload kannst du direkt über den VIS-Adapter anstoßen. Steht hier beschrieben:
NEWS
Best posts made by Hiltex
-
RE: ioBroker App 2023 [Android & iOS] - jetzt erhältlich
-
Test Adapter vis-homekittiles v0.0.x Latest
Aktuelle Test Version 0.0.4 Veröffentlichungsdatum 01.11.2023 Github Link https://github.com/Standarduser/ioBroker.vis-homekittiles Hallo zusammen,
ich habe vor einiger Zeit meine VIS in der Facebook-Gruppe vorgestellt und recht viel Zuspruch dafür erhalten. Schon damals war geplant, die Widgets in einen Adapter zu kippen und das habe ich nun zumindest in einigen Teilen getan.Die damals gezeigte VIS basierte auf den Standard-Widgets, die ich mit exzessivem CSS-Code dazu gebracht hatte so auszusehen. Dieser Widget-Adapter hier bietet etwas mehr, denn es wurden komplett neue Widgets auf Basis bereits bestehender erzeugt und diese mit neuen Funktionen versehen, bzw. oft mehrere Widgets in ein gemeinsames gekippt, sodass ein Widget mehrere Datenpunkte darstellen/steuern kann.
Ich denke mir, dass sich viele Sachen von selbst erklären, aber es gibt auch ein bisschen Dokumentation dazu:
Die aktuelle Versionsnummer befindet sich bei 0.0.x. Das bedeutet, dass es auch nochmal grundlegende Änderungen an den bestehenden Widgets geben kann, wenn sich im weiteren Verlauf herausstellt, dass diese nicht optimal funktionieren.
Bitte beachtet, dass der Adapter für VIS 1.x gebaut wurde. Eine Anpassung für VIS 2 ist erst für später geplant.
Der Adapter kann über das Latest-Repository installiert werden.Viel Spaß beim Testen. Solltet ihr Fehler finden, dann erstellt bitte ein Issue auf Github. Danke.
-
RE: Kategorie Adapter
Ich interpretiere deinen Post so, dass du im Forum die Kategorie Adapter gerne zurück hättest. Da schließe ich mich mal an.
-
RE: [Vorlage] Spotify Skript
Hallo zusammen,
da der Code im ersten Post des Threads durch die Foren-Umstellung zerstört wurde, hab ich ihn mal aus dem Cache von Bing geholt. Vielleicht mag ja der TE seinen ersten Post mal überarbeiten.
/*Version 0.5.3 letzte änderung 11.02.2018 19:25 Read Me !!!!!!! wie bekomme ich dieses Skript zum laufen ? Es muß das NPM Modul querystring im Javascript Adapter hinzugefügt werden ! 1.Registriere dich auch https://developer.spotify.com 2.Erstelle einen Application, du erhällst einen Client ID und eine Client Secret 3.trage in den App Settings deiner Application bei Redirect URIs 'http://localhost' ein 4.trage hier in diesem Skript deine Cliend ID und Client Secret ein 5.Starte dieses Skript 6.wechsle zum Tap Objekte und klicke unter 'javascript.0.Spotify.Authorization.Authorized' auf den Button Get_Authorization 7.Kopiere die unter 'javascript.0.Spotify.Authorization.Authorization_URL' angezeigte URL in einen Webbrowser und rufe sie auf. 8.Der Browser wird die Verbindung ablehnen und in der Adresszeile eine URL zurückgeben 9.kopiere jetzt wider diese URL und füge sie im State 'javascript.0.Spotify.Authorization.Authorization_Return_URI' ein 10.wenn alles funktioniert hat wechselt 'javascript.0.Spotify.Authorization.Authorized' auf true */ createState('javascript.0.Spotify.Player.Play', false,{type: "boolean", role: "button"}); createState('javascript.0.Spotify.Player.Pause', false,{type: "boolean", role: "button"}); createState('javascript.0.Spotify.Player.Skip_Plus', false,{type: "boolean", role: "button"}); createState('javascript.0.Spotify.Player.Skip_Minus', false,{type: "boolean", role: "button"}); createState('javascript.0.Spotify.Player.Repeat_Track', false,{type: "boolean", role: "button"}); createState('javascript.0.Spotify.Player.Repeat_Context', false,{type: "boolean", role: "button"}); createState('javascript.0.Spotify.Player.Repeat_off', false,{type: "boolean", role: "button"}); createState('javascript.0.Spotify.Player.Volume', 0,{type: "number", role: "Volume %"}); createState('javascript.0.Spotify.Player.TrackId','' ,{type: "string", role: "Track Id to Play"}); createState('javascript.0.Spotify.Player.Playlist_ID','' ,{type: "string", role: "Playlist Id to Play"}); createState('javascript.0.Spotify.Player.Seek', 0,{type: "number", role: "Seek To Position (s)"}); createState('javascript.0.Spotify.Player.Shuffle', false,{type: "boolean", role: "Shuffle"}); createState('javascript.0.Spotify.Devices.Get_Devices', false,{type: "boolean", role: "button"}); //createState('javascript.0.Spotify.Authorization.Login', false,{type: "boolean", role: "button"}); createState('javascript.0.Spotify.Authorization.Get_Authorization', false,{type: "boolean", role: "button"}); createState('javascript.0.Spotify.Authorization.Authorization_URL','',{type: "string", role: "Authorization_URL",write:false}); createState('javascript.0.Spotify.Authorization.Authorization_Return_URI','',{type: "string", role: "Authorization_Return_URI"}); createState('javascript.0.Spotify.Authorization.User_ID','',{type: "string", role: "User ID",write:false}); createState('javascript.0.Spotify.Authorization.Authorized',false,{type: "boolean", role: "Authorized",write:false}); createState('javascript.0.Spotify.Get_User_Playlists', false,{type: "boolean", role: "button"}); createState('javascript.0.Spotify.PlaybackInfo.Track_Id','' ,{type: "string", role: "Track Id",write:false}); createState('javascript.0.Spotify.PlaybackInfo.Artist_Name','' ,{type: "string", role: "Artist Name",write:false}); createState('javascript.0.Spotify.PlaybackInfo.Type','' ,{type: "string", role: "Type",write:false}); createState('javascript.0.Spotify.PlaybackInfo.Album','' ,{type: "string", role: "Album",write:false}); createState('javascript.0.Spotify.PlaybackInfo.timestamp',0 ,{type: "number", role: "Timestamp",write:false}); createState('javascript.0.Spotify.PlaybackInfo.progress_ms',0 ,{type: "number", role: "progress_ms",write:false}); createState('javascript.0.Spotify.PlaybackInfo.progress',0 ,{type: "string", role: "progress",write:false}); createState('javascript.0.Spotify.PlaybackInfo.is_playing',false ,{type: "boolean", role: "is_playing",write:false}); createState('javascript.0.Spotify.PlaybackInfo.image_url','' ,{type: "string", role: "Image URL",write:false}); createState('javascript.0.Spotify.PlaybackInfo.Track_Name','' ,{type: "string", role: "Track_Name",write:false}); createState('javascript.0.Spotify.PlaybackInfo.duration_ms',0 ,{type: "number", role: "Duration ms",write:false}); createState('javascript.0.Spotify.PlaybackInfo.duration',0 ,{type: "string", role: "duration",write:false}); createState('javascript.0.Spotify.PlaybackInfo.Playlist','' ,{type: "string", role: "Playlist",write:false}); createState('javascript.0.Spotify.PlaybackInfo.Device.id','',{type: "string", role: "id",write:false}); createState('javascript.0.Spotify.PlaybackInfo.Device.is_active',false,{type: "boolean", role: "is active",write:false}); createState('javascript.0.Spotify.PlaybackInfo.Device.is_restricted',false,{type: "boolean", role: "is restricted",write:false}); createState('javascript.0.Spotify.PlaybackInfo.Device.name','',{type: "string", role: "Name",write:false}); createState('javascript.0.Spotify.PlaybackInfo.Device.type','',{type: "string", role: "Type",write:false}); createState('javascript.0.Spotify.PlaybackInfo.Device.volume_percent',0,{type: "number", role: "volume_percent",write:false}); //createState('javascript.0.Spotify.Playlist_Names','',{type: "string", role: "String of Playlist Names",write:false}); //createState('javascript.0.Spotify.Playlist_Index',0 ,{type: "number", role: "Playlist_Index"}); var request = require('request'); var querystring = require('querystring'); var fs = require('fs'); var Application = { User_ID:'',//Nichts eintragen !! BaseURL:'https://api.spotify.com', Client_ID:'HIER DEINE CLIENT ID !!', Client_Secret:'HIER DEIN CLIENT SECRET', redirect_uri:'http://localhost', // in älteren Versionen wird 'https://example.com/callback/' verwendet, 'http://localhost' ist eine Sichere Variante Token:'', //Nichts eintragen !! refresh_token:'',//Nichts eintragen !! code:'',//Nichts eintragen !! State:'',//Nichts eintragen !! TokenFilePath:'/opt/Spotify.token' }; var Device_Data={ last_active_device_id:'', last_select_device_id:'', }; //############### Initial ########## ReadTokenFiles(function(err,Token){ //23.01.2018 Funktion überarbeitet if(!err) { Application.Token=Token.AccessToken; Application.refresh_token=Token.RefreshToken; SendRequest('/v1/me','GET','',function(err,data){ if(!err) { GetUserInformation(data); setState('javascript.0.Spotify.Authorization.Authorized',val=true,akt=true); SendRequest('/v1/me/player/devices','GET','',function(err,data){ if(!err){CreateDevices(data)} }); } else{ setState('javascript.0.Spotify.Authorization.Authorized',val=false,akt=true); console.error('SendRequest in ReadTokenFiles '+err); } }); } else{ setState('javascript.0.Spotify.Authorization.Authorized',val=false,akt=true); console.warn(err); } }); //################################# function ReadTokenFiles(callback){ fs.readFile(Application.TokenFilePath,'utf8', function(err, data) { if(!err){ //wenn keine Fehler var Token=JSON.parse(data); var ATF="undefined" !== typeof Token.AccessToken &&(Token.AccessToken!==''); var RTF="undefined" !== typeof Token.RefreshToken &&(Token.RefreshToken!==''); if(ATF&&RTF){ console.log('Spotify Token aus Datei gelesen !'); return callback(null,Token); } else{return callback('Keine Token in Datei gefunden !',null)} } else{ console.log (err); return callback('keine Token-Datei gefunden !, wird erstellt nach Autorisierung ',null); } }); }// End of Function ReadTokenFiles //###################################################################################### FUNCTION SEND REQUEST ################################################################################### function SendRequest(Endpoint,Method,Send_Body,callback){ var options = { url: Application.BaseURL+Endpoint, method: Method, headers: {Authorization: 'Bearer '+Application.Token}, form:Send_Body }; //console.log(options.form); //console.log('Spotify API Call...'+ Endpoint); request(options,function (error, response, body){ if(!error){ switch (response.statusCode){ case 200: // OK return callback(null,JSON.parse(body)); case 202: //Accepted, processing has not been completed. return callback(response.statusCode,null); case 204: // OK, No Content return callback(null,null); case 400: //Bad Request, message body will contain more information case 500: //Server Error case 503: //Service Unavailable case 404: //Not Found case 502: //Bad Gateway return callback(response.statusCode,null); case 401: //Unauthorized if(JSON.parse(body).error.message=='The access token expired'){ console.log('Access Token Abgelaufen!!'); setState('javascript.0.Spotify.Authorization.Authorized',val=false,akt=true); // neu 05.02.2018 Refresh_Token(function(err){ if (!err){ setState('javascript.0.Spotify.Authorization.Authorized',val=true,akt=true); SendRequest(Endpoint,Method,Send_Body,function(err,data){ // dieser Request holt die Daten die zuvor mit altem Token gefordert wurden if (!err){ console.log('Daten mit neuem Token'); return callback(null,data); } else if(err==202){ console.log (err+' Anfrage akzeptiert, keine Daten in Antwort, veruch es nochnal ;-)'); return callback(err,null); } else { console.error('FEHLER BEIM ERNEUTEN DATEN ANFORDERN ! '+err); return callback(err,null); } }); } else{ //05.02.2018 19:43 console.error(err); return callback(err,null); } }); } else{ //wenn anderer Fehler mit Code 401 setState('javascript.0.Spotify.Authorization.Authorized',val=false,akt=true); // neu 05.01.2018 console.error(JSON.parse(body).error.message); return callback(response.statusCode,null); } break; default: console.warn('HTTP Request Fehler wird nicht behandelt, bitte Debuggen !!'); return callback(response.statusCode,null); } } else{ console.error('erron in Request'); return callback(0,null); } });//end Request }//End of Function SendRequest //###################################################################################### END OF FUNCTION SEND REQUEST ################################################################################### function CreatePlaybackInfo(P_Body){ //console.log(JSON.stringify(P_Body)) if (P_Body.hasOwnProperty('device')){ Device_Data.last_active_device_id=P_Body.device.id; setState( 'javascript.0.Spotify.PlaybackInfo.Device.id',val=P_Body.device.id,akt=true); } if(P_Body.hasOwnProperty('is_playing')){ setState('javascript.0.Spotify.PlaybackInfo.is_playing',val=P_Body.is_playing,akt=true); if(P_Body.is_playing===true){ setState('javascript.0.Spotify.PlaybackInfo.Track_Id',val=P_Body.item.id,akt=true); setState('javascript.0.Spotify.PlaybackInfo.Artist_Name',val=P_Body.item.artists[0].name,akt=true); if (P_Body.context!==null){ setState('javascript.0.Spotify.PlaybackInfo.Type',val=P_Body.context.type,akt=true); if(P_Body.context.type=='playlist'){ var IndexOfUser=P_Body.context.uri.indexOf("user:")+5; var EndIndexOfUser=P_Body.context.uri.indexOf(":",IndexOfUser); var IndexOfPlaylistID=P_Body.context.uri.indexOf("playlist:")+9; var query={ fields:'name', }; SendRequest('/v1/users/'+P_Body.context.uri.substring(IndexOfUser, EndIndexOfUser)+'/playlists/'+P_Body.context.uri.slice(IndexOfPlaylistID)+'?'+querystring.stringify(query),'GET','',function(err,P_Body){ if(!err&&P_Body.hasOwnProperty('name')){ setState('javascript.0.Spotify.PlaybackInfo.Playlist',val=P_Body.name,akt=true); //console.log(JSON.stringify(P_Body)) } else{console.warn(err + ' function CreatePlaybackInfo')} }); } else{setState('javascript.0.Spotify.PlaybackInfo.Playlist',val='',akt=true)} } else{ setState('javascript.0.Spotify.PlaybackInfo.Type',val=P_Body.item.type,akt=true); setState('javascript.0.Spotify.PlaybackInfo.Playlist',val='',akt=true); } setState('javascript.0.Spotify.PlaybackInfo.Album',val=P_Body.item.album.name,akt=true); setState('javascript.0.Spotify.PlaybackInfo.timestamp',val=P_Body.timestamp,akt=true); setState('javascript.0.Spotify.PlaybackInfo.progress_ms',val=P_Body.progress_ms,akt=true); setState('javascript.0.Spotify.PlaybackInfo.image_url',val=P_Body.item.album.images[0].url,akt=true); setState( 'javascript.0.Spotify.PlaybackInfo.Track_Name',val=P_Body.item.name,akt=true); setState( 'javascript.0.Spotify.PlaybackInfo.duration_ms',val=P_Body.item.duration_ms,akt=true); setState( 'javascript.0.Spotify.PlaybackInfo.duration',val=DigiClock(P_Body.item.duration_ms),akt=true); setState( 'javascript.0.Spotify.PlaybackInfo.progress',val=DigiClock(P_Body.progress_ms),akt=true); setState( 'javascript.0.Spotify.PlaybackInfo.Device.is_active',val=P_Body.device.is_active,akt=true); setState( 'javascript.0.Spotify.PlaybackInfo.Device.is_restricted',val=P_Body.device.is_restricted,akt=true); setState( 'javascript.0.Spotify.PlaybackInfo.Device.name',val=P_Body.device.name,akt=true); setState( 'javascript.0.Spotify.PlaybackInfo.Device.type',val=P_Body.device.type,akt=true); setState( 'javascript.0.Spotify.PlaybackInfo.Device.volume_percent',val=P_Body.device.volume_percent,akt=true); } } }//End of Function CreatePlaybackInfo function DigiClock(ms){ //Milisekunden zu Digitaluhr, Beispiel 3:59=238759 var Min=Math.floor(ms/60000); var Sec=Math.floor(((ms%360000)%60000)/1000); if(Min<10){Min='0'+Min} if(Sec<10){Sec='0'+Sec} return Min+':'+Sec; }//End Function DigiClock function GetUserInformation(P_Body){ Application.User_ID=P_Body.id; setState('javascript.0.Spotify.Authorization.User_ID',val=P_Body.id,akt=true); }//End of Function GetUserInformation function GetUsersPlaylist(offset){ var PlaylistString; if(Application.User_ID!==''){ var query ={ limit:30, offset:offset }; SendRequest('/v1/users/'+Application.User_ID+'/playlists?'+querystring.stringify(query),'GET','',function(err,P_Body){ if(!err) { for (i = 0; i < P_Body.items.length; i++) { var Pfad='javascript.0.Spotify.Playlists.'+P_Body.items[i].name.replace(/\s+/g, ''); PlaylistString=P_Body.items[i].name+';'+PlaylistString; if (getObject(Pfad+'.id')===null) { createState(Pfad+'.Play_this_List',false,{type:'boolean', role:'button'}); createState(Pfad+'.id',P_Body.items[i].id,{type:'string', role:'id',write:false}); createState(Pfad+'.owner',P_Body.items[i].owner.id,{type:'string', role:'owner',write:false}); createState(Pfad+'.name',P_Body.items[i].name,{type:'string', role:'Name',write:false}); createState(Pfad+'.tracks_total',P_Body.items[i].tracks.total,{type:'number', role:'tracks_total',write:false}); } else { setState(Pfad+'.id',P_Body.items[i].id,akt=true); setState(Pfad+'.owner',P_Body.items[i].owner.id,akt=true); setState(Pfad+'.name',P_Body.items[i].name,akt=true); setState(Pfad+'.tracks_total',P_Body.items[i].tracks.total,akt=true); } Get_Playlist_Tracks(P_Body.items[i].owner.id,P_Body.items[i].id,Pfad); } if(P_Body.items.length!==0 &&(P_Body['next']!==null)){GetUsersPlaylist(P_Body.offset+P_Body.limit)} //setState('javascript.0.Spotify.Playlist_Names',PlaylistString); } }); } } // End of Function GetUsersPlaylist function Device_Handel(Device_Data){ if (Device_Data.last_select_device_id===""){ return Device_Data.last_active_device_id; } else{ return Device_Data.last_select_device_id; } } function Get_Playlist_Tracks(owner,id,Pfad){ //NEU var reg_param=owner+'/playlists/'+id+'/tracks'; var query={ fields:'items.track.name,items.track.id,items.track.artists.name,total,offset', limit:100, offset:0 }; SendRequest('/v1/users/'+reg_param+'?'+querystring.stringify(query),'GET','',function(err,data){ if(!err){ var StateString=''; var ListString=''; var Track_ID_String=''; for (i = 0; i < data.items.length; i++) { StateString=StateString+i.toString()+':'+data.items[i].track.name+'-'+data.items[i].track.artists[0].name+';'; ListString=ListString+data.items[i].track.name+'-'+data.items[i].track.artists[0].name+';'; Track_ID_String=Track_ID_String+i.toString()+':'+data.items[i].track.id+';'; } if (getObject(Pfad+'.Track_List')===null) { createState(Pfad+'.Track_List',-1,{type: "number", role: "Tracks",states:StateString,Track_ID:Track_ID_String}); } else{ //setState(Pfad+'.Track_List',StateString,Track_ID=Track_ID_String,akt=true); } if (getObject(Pfad+'.Track_List_String')===null) { createState(Pfad+'.Track_List_String',ListString,{type: "string", role: "Tracks List String"}); } else{ setState(Pfad+'.Track_List_String',ListString,akt=true); } } }); }//End of Function Get_Playlist_Tracks function CreateDevices(P_Body){ for (i = 0; i < P_Body.devices.length; i++) { for (var ObjName in P_Body.devices[i]) { if (!getObject('javascript.0.Spotify.Devices.'+P_Body.devices[i].name.replace(/\s+/g, '')+'.'+ObjName)){ createState('javascript.0.Spotify.Devices.'+P_Body.devices[i].name.replace(/\s+/g, '')+'.'+ObjName,P_Body.devices[i][ObjName],{type: typeof P_Body.devices[i][ObjName], role: ObjName}); createState('javascript.0.Spotify.Devices.'+P_Body.devices[i].name.replace(/\s+/g, '')+'.'+'Use_for_Playback',false,{type:'boolean', role:'button'}); } else{setState('javascript.0.Spotify.Devices.'+P_Body.devices[i].name.replace(/\s+/g, '')+'.'+ObjName,P_Body.devices[i][ObjName],akt=true)} } } }//End of Function CreateDevices function generateRandomString (length) { var text = ''; var possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; for (var i = 0; i < length; i++) { text += possible.charAt(Math.floor(Math.random() * possible.length)); } return text; } function request_authorization(){ Application.State=generateRandomString (20); var query ={ client_id:Application.Client_ID, response_type: 'code', redirect_uri :Application.redirect_uri, state:Application.State, scope:'user-modify-playback-state user-read-playback-state user-read-currently-playing playlist-read-private' }; var options = { url:'https://accounts.spotify.com/de/authorize/?'+querystring.stringify(query), method: 'GET', followAllRedirects: true, }; setState('javascript.0.Spotify.Authorization.Authorization_URL',val=options.url); var debug=false; if(debug){ request(options, function (error, response,body,formData){ // console.log(options.url); console.log('STATUS_CODE ' +response.statusCode); //console.log('RESPONSE*************'+JSON.stringify(response)); //console.log('BODY*****'+body); //console.log('ERROR'+error); //console.log('FORM'+request.form); //console.log('HEADERS *****'+JSON.stringify(response.headers)); //console.log('HTML *****'+JSON.stringify(response.html)); }); } }// End of Function request_authorization function GetToken(){ var options = { url: 'https://accounts.spotify.com/api/token', method: 'POST', headers: {Authorization: 'Basic '+Buffer.from(Application.Client_ID + ':' + Application.Client_Secret).toString('base64')}, form: {grant_type:'authorization_code',code:Application.code,redirect_uri:Application.redirect_uri} }; request(options, function (error, response, body){ SaveToken(JSON.parse(body),function(err,Token){ if(!err){ setState('javascript.0.Spotify.Authorization.Authorization_URL',val='',akt=true); setState('javascript.0.Spotify.Authorization.Authorization_Return_URI',val='',akt=true); setState('javascript.0.Spotify.Authorization.Authorized',val=true,akt=true); Application.Token=Token.AccessToken; Application.refresh_token=Token.RefreshToken; } else{console.log(err)} }); }); }//End of Function GetToken function Refresh_Token(callback){ console.log('Token wird erneut angefordert ! '); var options = { url: 'https://accounts.spotify.com/api/token', method: 'POST', headers: {Authorization: 'Basic '+Buffer.from(Application.Client_ID + ':' + Application.Client_Secret).toString('base64')}, form: {grant_type:'refresh_token',refresh_token:Application.refresh_token} }; if(Application.refresh_token!==''){ request(options, function (error, response, body){ // dieser Request holt den neuen Token if(response.statusCode==200){ console.log('neuer Token eingetroffen'); //console.log(body); var P_Body=JSON.parse(body); if(!P_Body.hasOwnProperty('refresh_token')){P_Body.refresh_token=Application.refresh_token} //console.log(JSON.stringify(P_Body)) SaveToken(P_Body,function(err,Token){ if(!err){ Application.Token=Token.AccessToken; return callback(null); //Application.refresh_token=Token.refresh_token; } else{ console.log(err); return callback(err); } }); } else{return callback(response.statusCode)} //05.02.2018 19:37 }); }// end if }//End of Function Refresh_Token function SaveToken(P_Body,callback){ //var ParsedBody=JSON.parse(Body); //console.log(ParsedBody.hasOwnProperty('access_token')) if ("undefined" !== typeof P_Body.access_token && ("undefined" !== typeof P_Body.refresh_token)){ var Token ={ AccessToken:P_Body.access_token, RefreshToken:P_Body.refresh_token }; fs.writeFile(Application.TokenFilePath, JSON.stringify(Token),'utf8', function (err) { if (!err) { console.log('Token Saved!'); return callback(null,Token); } else{return callback('Fehler beim Token Speichern',null)} }); } else{return callback('keine Token in Serverantwort gefunden ! ',null)} }//End of Function SaveToken on({id:'javascript.0.Spotify.Authorization.Authorization_Return_URI',change:"any"}, function (obj){ if (!obj.state.ack) { var return_uri=querystring.parse(obj.state.val.slice(obj.state.val.search('[?]')+1, obj.state.val.length)); if(return_uri.state==Application.State){ Application.code=return_uri.code; GetToken(); } } }); on({id:'javascript.0.Spotify.Authorization.Get_Authorization',val:true}, function (obj){ request_authorization(); setState('javascript.0.Spotify.Authorization.Authorized',val=false,akt=true); }); on({id: /\.Use_for_Playback$/, val:true},function (obj){ Device_Data.last_select_device_id=getState(obj.id.slice(0,obj.id.lastIndexOf("."))+'.id').val; var send={ device_ids:[Device_Data.last_select_device_id], //Divice IDs als Array ! //play:false //True = Wiedergabe startet sofort auf diesem Gerät, FALSE = Wiedergabe anhängig von Playback State }; SendRequest('/v1/me/player','PUT',JSON.stringify(send),function(err,data){ //if(!err){Device_Data.last_select_device_id=getState(obj.id.slice(0,obj.id.lastIndexOf("."))+'.id').val} }); }); on({id: /\.Track_List$/,valGe:0,valNe:null,ack:false},function (obj){ //eine bestimmten Track aus Playliste sofort abspielen var StateName = obj.common.Track_ID.split(';'); var StateArr=[]; for(var i = 0; i < StateName.length; i++) { var ele = StateName[i].split(':'); StateArr[ele[0]] = ele[1]; } if(StateArr[obj.state.val]!==''&&(StateArr[obj.state.val]!==null)){ var send ={ uris:['spotify:track:'+StateArr[obj.state.val]], offset:{ position:0 } }; SendRequest('/v1/me/player/play','PUT',JSON.stringify(send),function(err){ if(!err){setState(obj.id,obj.state.val,ack=true)} }); } }); on({id: /\.Play_this_List$/, val:true},function (obj){ //eine bestimmte Playlist sofort abspielen var send ={ context_uri:'spotify:user:'+getState(obj.id.slice(0,obj.id.lastIndexOf("."))+'.owner').val+':playlist:'+getState(obj.id.slice(0,obj.id.lastIndexOf("."))+'.id').val, offset:{ position:1 } }; var query ={device_id:Device_Handel(Device_Data)}; SendRequest('/v1/me/player/play?'+querystring.stringify(query),'PUT',JSON.stringify(send),function(){ SendRequest('/v1/me/player','GET','',function(err,data){ if(!err) {CreatePlaybackInfo(data)} }); }); }); on({id:'javascript.0.Spotify.Player.Play',val:true}, function (obj){ var query ={device_id:Device_Handel(Device_Data)}; console.log(Device_Handel(Device_Data)) SendRequest('/v1/me/player/play?'+querystring.stringify(query),'PUT','',function(){}); }); on({id:'javascript.0.Spotify.Player.Pause',val:true}, function (obj){ var query ={device_id:Device_Handel(Device_Data)}; SendRequest('/v1/me/player/pause?'+querystring.stringify(query),'PUT','',function(){}); }); on({id:'javascript.0.Spotify.Player.Skip_Plus',val:true}, function (obj){ var query ={device_id:Device_Handel(Device_Data)}; SendRequest('/v1/me/player/next?'+querystring.stringify(query),'POST','',function(err,data){ }); }); on({id:'javascript.0.Spotify.Player.Skip_Minus',val:true}, function (obj){ var query ={device_id:Device_Handel(Device_Data)}; SendRequest('/v1/me/player/previous?'+querystring.stringify(query),'POST','',function(){}); }); on({id:'javascript.0.Spotify.Player.Repeat_Track',val:true}, function (obj){ SendRequest('/v1/me/player/repeat?state=track','PUT','',function(){}); }); on({id:'javascript.0.Spotify.Player.Repeat_Context',val:true}, function (obj){ SendRequest('/v1/me/player/repeat?state=context','PUT','',function(){}); }); on({id:'javascript.0.Spotify.Player.Repeat_off',val:true}, function (obj){ SendRequest('/v1/me/player/repeat?state=off','PUT','',function(){}); }); on({id:'javascript.0.Spotify.Player.Volume'}, function (obj){ SendRequest('/v1/me/player/volume?volume_percent='+obj.state.val,'PUT','',function(err){ if (!err){ // setState('javascript.0.Spotify.Player.Volume', true/*ack*/); } }); }); on({id:'javascript.0.Spotify.Player.Seek'}, function (obj){ SendRequest('/v1/me/player/seek?position_ms='+obj.state.val*1000,'PUT','',function(){}); }); on({id:'javascript.0.Spotify.Player.Shuffle'}, function (obj){ if (obj.state.val===true){ SendRequest('/v1/me/player/shuffle?state=true','PUT','',function(){})} else{ SendRequest('/v1/me/player/shuffle?state=false','PUT','',function(){})} }); on({id:'javascript.0.Spotify.Player.TrackId'}, function (obj){ var send ={ uris:['spotify:track:'+obj.state.val], offset:{ position:0 } }; SendRequest('/v1/me/player/play','PUT',JSON.stringify(send),function(){}); }); on({id:'javascript.0.Spotify.Player.Playlist_ID'}, function (obj){ var send ={ context_uri:'spotify:user:'+Application.User_ID+':playlist:'+obj.state.val, offset:{ position:1 } }; SendRequest('/v1/me/player/play','PUT',JSON.stringify(send),function(){}); }); on({id:'javascript.0.Spotify.Get_User_Playlists'}, function (obj){ GetUsersPlaylist(0) }); on({id:'javascript.0.Spotify.Devices.Get_Devices'}, function (obj){ SendRequest('/v1/me/player/devices','GET','',function(err,data){ if(!err){CreateDevices(data)} }); }); on({id:'javascript.0.Spotify.Get_Playback_Info'}, function (obj){ SendRequest('/v1/me/player','GET','',function(err,data){ if(!err) {CreatePlaybackInfo(data)} }); }); on({id:'javascript.0.Spotify.Authorization.Authorized'}, function (obj){ if(obj.state.val===true){ Intervall = setInterval(function () { SendRequest('/v1/me/player','GET','',function(err,data){ //console.log('Intervall'+err) if(!err) {CreatePlaybackInfo(data)} else if(err==202||(err==502)||(err==401)){ //202,401 und 502 lassen den Interval weiter laufen DummyBody={is_playing:false};//tritt ein wenn kein Player geöffnet ist CreatePlaybackInfo(DummyBody)} else{ //andere Fehler stoppen den Intervall clearInterval(Intervall); console.warn('Spotify Intervall gestoppt !'); } }); },5000); } else{ if ("undefined" !== typeof Intervall){clearInterval(Intervall)} } }); // on({id:'javascript.0.Spotify.Authorization.Login'}, function (obj){}); onStop(function () { setState('javascript.0.Spotify.Authorization.Authorization_URL',val='',akt=true); setState('javascript.0.Spotify.Authorization.Authorization_Return_URI',val='',akt=true); setState('javascript.0.Spotify.Player.TrackId',val='',akt=true); setState('javascript.0.Spotify.Player.Playlist_ID',val='',akt=true); setState('javascript.0.Spotify.Authorization.User_ID',val='',akt=true); setState('javascript.0.Spotify.Authorization.Authorized',val=false,akt=true); if ("undefined" !== typeof Intervall){clearInterval(Intervall)} }, 1000 /*ms*/);
-
RE: Test Adapter MEATER v1.0.x Latest
Ich habe gerade die Version 0.2.0 veröffentlicht.
Dabei gab es folgende Änderungen:- hinzugefügt: Es gibt einen neuen Datenpunkt, mit dem man das Update manuell antriggern kann
- verbessert: Beschreibung von Fehlern (ob es ein Fehler vom MEATER Cloud Server oder ein im Adapter unbehandelter Fehler ist)
- behoben: Wenn der MEATER Cloud Server einen Fehler zurückgesandt hat, der nicht von der API kam, dann hat der Adapter bis zum Neustart keine keine Daten mehr abgerufen
Viel Spaß beim Testen.
-
RE: Steinel L600 CAM
@joedi Auch wenn jetzt hier gerade nicht so viel Feedback kommt - ich, und sicher auch einige andere, lesen hier ziemlich gespannt mit
-
Login per VIS / Kennwortabfrage
Hallo zusammen,
weil es in der Facebookgruppe gefragt wurde zeige ich hier einmal, wie ich den Login in meiner VIS realisiert habe.
Ziel:
Über eine Passwortabfrage soll realisiert werden, dass bestimmte Elemente für eine unbefugte Bedienung gesperrt werden. Es geht dabei nicht darum, ein super sicheres System herzustellen, sondern unbefugtes Bedienen durch Besucher zu unterbinden.Datenpunkte in ioBroker:
Die Erteilung von Berechtigungen erfolgt über Datenpunkte, die ich in ioBroker angelegt habe:
0_userdata.0.Visualisierung.Berechtigungen.countdown
(Typ String / Zeichenkette)
0_userdata.0.Visualisierung.Berechtigungen.hint
(Typ String / Zeichenkette)
0_userdata.0.Visualisierung.Berechtigungen.isAdmin
(Typ Boolean / Logikwert)
0_userdata.0.Visualisierung.Berechtigungen.pinInput
(Typ Number / Zahl)Umsetzung in VIS:
Ich habe eine View erstellt, über die die Eingabe realisiert wird. Die Eingabetasten sind vom Typjqui - Button State
und schreiben ihren Zahlenwert, bzw. das hinterlegte Zeichen in den Datenpunkt0_userdata.0.Visualisierung.Berechtigungen.pinInput
.Das Anzeigefeld ist vom Typ
basic - String
und zeigt den Inhalt des States0_userdata.0.Visualisierung.Berechtigungen.hint
an.Der Login-Button oben rechts im Eingangsbild ist vom Typ
jqui - container - Button - view in jqui Dialog
und ruft die View mit den Eingabetasten in einem Popup-Fenster auf.Die zu sperrenden Elemente erhalten im Feld
CSS Klasse
den (zusätzlichen) Eintragvis-user-disabled
, der bereits Bestandteil von VIS ist und die Bedienung des jeweiligen Elementes verhindert. Da dieser Eintrag dynamisch gesetzt werden soll, abhängig davon, ob man eingeloggt ist, oder nicht, sieht der Gesamteintrag so aus:
{w:0_userdata.0.Visualisierung.Berechtigungen.isAdmin; w == "false" ? "vis-user-disabled" : ""}
Hinweis: Es handelt sich dabei um eine Standard-Funktion, mit der man auch Farben dynamisieren kann. Das Funktioniert bei CSS-Klassen genauso.Steuerscript:
Gesteuert wird das ganze über ein Script in ioBroker. Das funktioniert im Prinzip so:- Bei Neustart des Scripts, der Javascript-Instanz oder ioBroker wird ausgeloggt
- Das Script nimmt die Eingabewerte aus dem Datenpunkt
0_userdata.0.Visualisierung.Berechtigungen.pinInput
entgegen und und schreibt zur visuellen Bestätigung einen Punkt in den State0_userdata.0.Visualisierung.Berechtigungen.hint
. - Wenn 4 Zeichen eingegeben wurden wird geprüft, ob die Eingabe dem fest im Script hinterlegten Wert entspricht. Der State
0_userdata.0.Visualisierung.Berechtigungen.isAdmin
wird auftrue
gesetzt und es erfolgt wieder eine visuelle Bestätigung. - Zeitgleich wird ein Timeout gesetzt, das nach 5 Minuten den State
isAdmin
auffalse
setzt. - Der Countdown wird sekündlich neu berechnet und im State
0_userdata.0.Visualisierung.Berechtigungen.countdown
angezeigt
(Blockly-Export am Ende des Beitrags)
Optionales:
Man kann den State0_userdata.0.Visualisierung.Berechtigungen.isAdmin
natürlich auch dafür verwenden, den Login-Button beitrue
auszublenden und den Logout-Button, sowie den Countdown einzublenden.Erfahrungen:
Eigentlich ist die Umsetzung ziemlich billig, aber sie reicht meines Erachtens nach vollkommen aus, zumindest für meine Zwecke. Was ich etwas schade finde ist, dass es ganze etwas träge bei der Eingabe ist. Wenn man die Zahlen zu schnell eintippt, dann kann sich das ganze durchaus auch mal verschlucken und man hat plötzlich nur 3 oder sogar 5 Zahlen eingegeben.Export des Blockly-Scriptes:
blockly_berechtigungen.txt
(Neues Blockly-Script anlegen und oben rechts aufBlöcke importieren
klicken) -
RE: Neue iPhone App
@Niklas96 dazu solltest du mal diesen Thread hier lesen. Den Schnellstart für die Motivation hast du ja geschafft
-
RE: [neuer Adapter] Gardena Smart System API
@Kaiman55
Bei dir steht da OK_searching. Er lädt nicht, weil er noch nicht in der Ladestation ist. Lass dir doch mal testweise den Datenpunkt Status per Telegram schicken, wenn er sich ändert. Damit bekommst du einen guten Eindruck davon, wie sich der Robi verhält. -
RE: Vis Design nur aus den 2000ern?
Ich hab anfangs genauso da gesessen, wie der TE. Die Vorzüge von ioBroker selbst habe ich ganz schnell zu schätzen gewusst, aber mit VIS habe ich lange gebraucht warm zu werden.
Klar, fast alles ist machbar, aber manchmal ist es schon frustrierend, dass zwei sehr ähnliche Widgets beide etwas können, das das andere nicht kann, aber es kein Widget gibt, das beide Funktionen beinhaltet.
Ich gebe auch jedem recht der sagt, dass die Standard-Themes einfach nicht mehr zeitgemäß sind. Man kann zwar alles mögliche aus den Widgets bauen, aber man muss viel Zeit investieren, bis man den Dreh heraus hat. Das ist eben nicht jedermanns Sache.
Meiner Ansicht nach merkt man bei den Widgets, dass es an einem einheitlichen Designkonzept fehlt. Aber das lässt sich ja ändern. Ist ja alles OpenSource und mit den vielen Beispielen im Forum kann man sich auch schnell eine gute Basis zusammenkopieren. Ganz ohne Mühe geht es dann eben auch nicht.
Latest posts made by Hiltex
-
RE: Test Adapter MEATER v1.0.x Latest
@martinp
Es gibt ja keinen Cloud-Zwang. Das Thermometer funktioniert völlig autark, lediglich das Übertragen der Daten zu ioBroker geschieht via Cloud und ist optional. Wird der Server abgeschaltet, dann kann man das Thermometer dennoch weiter lokal mit dem Smartphone verwenden.Aber der Link sieht spannend aus. Das schaue ich mir auch mal an. Vermutlich wird man jedoch einen Bluetooth-Empfänger in der Nähe des Grills haben müssen, was zumindest bei mir derzeit nicht der Fall ist.
-
RE: Test Adapter MEATER v1.0.x Latest
@flisse
Die Meater-Thermometer funktionieren alle über Bluetooth, sodass die Reichweite begrenzt ist.Aber es gibt den Meater Block, der es ermöglicht, die Thermometer über WLAN zu betreiben. Er bildet dann die Schnittstelle zur Cloud, sodass man mit dem Smartphone nicht mehr in der Nähe bleiben muss, weil die Thermometer mit dem Block gekoppelt sind.
-
RE: Test Adapter Device-Watcher v2.x.x GitHub/Latest
@deekay-0
Ping wird bei mir ganz normal verarbeitet. Wenn Geräte offline sind meldet der Adapter das sofort, wenn sie wieder online sind verschwinden die Meldungen auch sofort wieder.Ich hab hingegen Probleme mit der Überwachung von Instanzen. Wenn eine Instanz aussteigt wird das sofort erkannt, aber wenn sie wieder normal ist, dann muss ich oft die Device-Watcher-Instanz neu starten, damit die Meldung verschwindet. Das passiert insbesondere bei dem iot-Adapter.
Bei der regelmäßigen Meldung über gestörte Instanzen taucht mittlerweile 3x „undefined: nicht verbunden mit Gerät oder Service“
-
RE: JavaScript 7.11.0 - Neue Datei-Bausteine (lesen / schreiben)
@haus-automatisierung sagte in JavaScript 7.11.0 - Neue Datei-Bausteine (lesen / schreiben):
Das ist ja auch nicht richtig so. Du brauchst den kompletten Pfad zur Datei. Nicht nur den Namen. Dafür habe ich
createTempFile
als Funktion eingebaut. ... Fehlt Dir da was?Tatsächlich ja, allerdings muss ich gestehen, dass das zitierte Blockly falsch war (sorry). Gebaut habe ich folgendes:
Das Problem ist folgendes: Das Bild wird nicht versendet, vermutlich weil der Dateiname fehlt, wie du geschrieben hast. Auf TempFile hat man aber nur Zugriff, wenn man mit einem Trigger auf Dateiänderungen reagiert. In meinem Fall funktioniert das aber so nicht, bzw. wünsche ich mir das anders.
Ich möchte, wenn jemand die Klingel an der Haustür drückt, per Telegram ein Bild von der Kamera an der Haustür haben. Es gibt aber noch weitere Möglichkeiten das Kamera-Bild abzurufen, z.B. per Telegram-Tastatur oder wenn die Haustür geöffnet wird, während ich nicht zuhause bin.
Bisher werte ich dafür die Objekt-ID aus, die getriggert hat und gebe dem Bild dann eine Beschriftung mit ("Es hat geklingelt" oder "Haustür wurde geöffnet"). Wenn jetzt mit einem Trigger das Bild abgelegt wird und mit einem weiteren Trigger auf die Änderung des Bildes reagiert wird, dann geht mir die Information verloren, woher das ursprünglich kam und ich kann das Bild nicht mehr Beschriften.
Gibt es dafür einen Weg, dass ich innerhalb von einem Trigger das Kamera-Bild abrufen und direkt auch versenden kann?
-
RE: JavaScript 7.11.0 - Neue Datei-Bausteine (lesen / schreiben)
@haus-automatisierung
Vielen Dank für die Mühe und Energie, die du in den Adapter investierst.@haus-automatisierung sagte in JavaScript 7.11.0 - Neue Datei-Bausteine (lesen / schreiben):
@eisbaer721 Da muss ich den Telegram Adapter noch anpassen damit das klappt
Hattest du schon Zeit das im Telegram-Adapter anzupassen?
Ich habe Telegram gerade aus dem Latest installiert und bekomme trotzdem kein Bild zugesandt.
Vom Aufbau her hab ich das so gemacht, wie hier:@eisbaer721 sagte in JavaScript 7.11.0 - Neue Datei-Bausteine (lesen / schreiben):
-
RE: Adapter: ebus
Ich war auch betroffen - gestern 11:26 Uhr
@dette
Danke für den Hinweis. Ich hab das bei mir eingefügt und aktuell läuft der Adapter wieder korrekt, alle Werte sind da.Letztes Mal hatte bei mir ein Neustart des Systems gereicht, auf dem ebusd läuft. Das habe ich dieses Mal jedoch nicht ausprobiert, sondern direkt den Parameter hinzugefügt.
-
RE: eBus Adapter Vaillant
@akloud
Man kann Broadcast-Meldungen nicht überschreiben. Das würde auch überhaupt keinen Sinn ergeben, denn mit Broadcast werden aktuelle Informationen/Zustände ungefragt an alle Busteilnehmer verteilt.Wenn du etwas steuern willst dann musst du das in einem anderen Datenpunkt suchen.
-
RE: ioBroker App 2023 [Android & iOS] - jetzt erhältlich
@heinz2100
Eine andere App zu starten geht per Link, wenn es die App unterstützt. Wenn du zum Beispiel Spotify öffnen willst, dass muss dein Button einfach die URL spotify:// aufrufen.
Kannst du gleich mal hier probieren, wenn du den Beitrag mit deinem Handy liest und Spotify installiert hastEdit: scheint hier nicht zu funktionieren, aber wenn ich das direkt in die Adresszeile eingebe, dann öffnet sich Spotify bei mir.
-
RE: Feature: Geofence/Anwesenheitserkennung - Visu App v1.1
Ich habe bei mir gestern auch die Geofence-Funktion eingerichtet.
Die Abwesenheit von einem Android-Telefon wurde heute leider nicht erkannt.
App-Version ist die aktuelle aus dem PlayStore, der it-Adapter hat Version 3.2.2 -
RE: ioBroker App 2023 [Android & iOS] - jetzt erhältlich
@foxriver76 wenn man sich eure Datenschutzerklärung mal kritisch durchliest, dann erkennt man schon ein paar Lücken, bzw. Fehler.
Da steht zum Beispiel
1. Datensammlung: Die ioBroker Visu App sammelt keine Daten von ihren Benutzern.
Was genau soll denn „Datensammlung“ eigentlich heißen? Wenn, dann werden Daten doch gespeichert, und das geschieht ja auch. Ich gebe zumindest eine Adresse, Benutzername und Passwort ein, die von der App gespeichert werden. Aus eurer Erklärung geht nicht explizit hervor, wozu diese Daten notwendig sind, wo sie gespeichert werden, was im weiteren Verlauf damit geschieht und ob so vielleicht irgendwohin übertragen werden.
Mir persönlich, und vermutlich auch den meisten anderen hier, ist schon klar, was das bedeutet, aber jemand, der ioBroker nicht kennt, wird das vermutlich nicht verstehen.
Wo ich auch Lücken sehe ist, dass die einzelnen Dienste (cloud, iot, pro) zwar irgendwie aufgezählt werden, aber was die machen, welche Daten übertragen werden, und wie lange die Daten gespeichert bleiben, geht nicht so wirklich und zweifelsfrei daraus hervor.
Ich bin jetzt kein Experte, aber meiner Ansicht nach muss die gesamte Seite einmal überarbeitet werden. Ein Stück weit ist das ja auch wichtig, damit ihr selbst geschützt seid. Nicht dass nachher noch irgendein dahergelaufener Anwalt um die Ecke kommt, dem Datenschutz eigentlich völlig egal ist, und euch abmahnt, nur um die Kohle zu kassieren.