Mit 1.6.2 getestet und mit der 1.7.0
Habe ein leeres Start/Stop Script zum Test verwendet.
VPN/Proxy erkannt
Es scheint, dass Sie einen VPN- oder Proxy-Dienst verwenden. Bitte beachten Sie, dass die Nutzung eines solchen Dienstes die Funktionalität dieser Webseite einschränken kann.
Mit 1.6.2 getestet und mit der 1.7.0
Habe ein leeres Start/Stop Script zum Test verwendet.
eiche Vielen Dank. Für deine Mühe! Habe deine beiden Scripte getestet. Leider steigt der 2pm aktuell dabei genauso aus wie vorher. Ich warte jetzt mal auf eine neue Firmware.
Code Alles anzeigen/*---------------------------------Supported Blu Events-------------------------------------------- Blu *all: ---> "alive" "single_push" "hold_push" "pairing_push" "unknown_push" Blu Door/Window: ---> "open" "closed" Blu Motion: ---> "no_motion" "motion_detected" Blu Button: ---> "wake_up" "single_push" "double_push" "triple_push" "long_push" --------------------------------------------------------------------------------------------------*/ let eDebug= false, //Create debug output, true/false, set this only to true for short periods! //____Easy_Call_Config____ // easy_Start true/false, shows for 15 min, after a script start, blu "mac" ids near your Shelly. var easy_Start= true, actionMap= { "Oeffne_Rolladen_Schiebetuer": {id: "38:39:8f:ed:ad:40", event: "open", call: ["Cover.Open", {id:0}] }, //id 0 heißt hier Aktion Open lokal auf diesem shelly ausführen //"Oeffne_Rolladen_Kuechenfenster": {id: "e8:e0:7e:d0:90:77", event: "open", call: ["Cover.GoToPosition", {id:0, pos:40}] }, //id 0 heißt hier Aktion Open lokal auf diesem shelly ausführen "Stop_Rolladen_Schiebetuer_Automatic": {id: "38:39:8f:ed:ad:40", event: "open", call: ["Script.Stop", {id:2}] }, //id ist Nummer des Webhook Script "Start_Rolladen_Schiebetuer_Automatic": {id: "38:39:8f:ed:ad:40", event: "closed", call: ["Script.Start",{id:2}] }, };//Entries name Restriction: without Space!, unique entries only! //__Config_Blu_Events__ var battery_Fix= true, //Drop, 0% battery BTHome packages on Reboot Event, true/false activeScan= true, //Active or Passiv Bluetooth Scan, only used when BT Gateway false! get_All= false, //Get all data available and ship it in a Event, default false debug= false; //Create debug output, true/false, set this only to true for short periods. //~~~~~~~ Easy_Call v1.2 ~~~~~~~~~~ function Check_Event(d){ //Checking for Event Match try{ let blu= 0, normal= 0; if(easy_Start && !tH1) tH1= Timer.set(1000*60*15,0,function(){easy_Start= false;}); //15min Timer for easy_Start //Filter for blu Events if(bluShellys || easy_Start) blu= Efilter(d,{inData: true,filterValue: ['GBLE'], filterKey: ['mac','device_type','device_state']},eDebug); //Check for Blu Data if(blu && blu.GBLE){ if(easy_Start) print('Found Device: Blu _[',blu.device_type,']_ ---event---> _[',blu.device_state,']_ \n id: ---> ',blu.mac); for(a in actionMap){ if(actionMap[a].mac && actionMap[a].mac === blu.mac && actionMap[a].event === blu.device_state){ if(actionMap[a].call[2]) { //Check for Callback and pack event_data for Callback Call(actionMap[a].call[0],actionMap[a].call[1],actionMap[a].call[2],{event_data:d.info,user_data:actionMap[a].call[3]},actionMap[a].call[4]); }else{ Call(actionMap[a].call[0],actionMap[a].call[1],actionMap[a].call[2],actionMap[a].call[3],actionMap[a].call[4]); } } } } //Filter for normal Events if(dList.length < 1) return; normal= Efilter(d,{device: dList, filterKey: ['event']},eDebug); if(!normal) return; //Exit if useless Data for(a in actionMap){ if(actionMap[a].event === normal.event){ if(actionMap[a].call[2]) { //Check for Callback and pack event_data for Callback Call(actionMap[a].call[0],actionMap[a].call[1],actionMap[a].call[2],{event_data:d.info,user_data:actionMap[a].call[3]},actionMap[a].call[4]); }else{ Call(actionMap[a].call[0],actionMap[a].call[1],actionMap[a].call[2],actionMap[a].call[3],actionMap[a].call[4]); } } } }catch(e){ErrorMsg(e,'Check_Event()',debug);} //Error Handler } var dList= [], bluShellys= false; function Read_actionMap(a){ //Read actionMap try{ //Check for valied actionMap Entrys function cK(s){return typeof s !== 'string';} if(!actionMap[a].id || !actionMap[a].event || !actionMap[a].call || cK(actionMap[a].id) || cK(actionMap[a].event) || !Array.isArray(actionMap[a].call)){ throw new Error('Wrong actionMap Parameter, dropped actionMap Entry ----> '+actionMap[a].id+' --> '+actionMap[a].event); } //Check for Blu mac if(actionMap[a].id.length === 17) { print("Info: add --> Blu Device ---> ",actionMap[a].id); actionMap[a].mac= actionMap[a].id; delete actionMap[a].id; bluShellys= true; } //Add normal shellys to device List if(actionMap[a].id) print("Info: add --> Normal Device ---> ",actionMap[a].id); if(actionMap[a].id) dList.push(actionMap[a].id); //Device List }catch(e){ErrorMsg(e,'Read_actionMap()',debug);} //Error Handler } //========= Blu_Events v2.4 ========= let activeScan= true; //Active or Passiv Bluetooth Scan, only used when BT Gateway false! //notUsed-->let _cid = "0ba9"; //Allterco, Company ID(MFD) let devID1= "SBBT"; //Blu Button1, deviceID, --> SBBT-002C let devID2= "SBDW"; //Blu Door/Window, deviceID --> SBDW-002C let devID3= 'SBMO'; //Blu Motion, deviceID, --> SBMO-003Z let uuid= "fcd2"; //BTHome, Service ID --> UUID(16bit) let bluMap= {//Device Parameter, you can find the full BTH Device List at 'https://bthome.io/format' //bthObjectID:[Property,Datatype,Factor/Unit], '0xf0':['device_type_id','uint8','split2'], //All Blu Devices, special case [default --> uint16] '0xf1':['firmware_version','uint8','split4'], //All Blu Devices, special case [default--> uint32] '0xf2':['extra_data','uint8','split3'], //All Blu Devices, special case [default--> uint24] --> maybe FW version? '0x00':['pid','uint8'], //All Blu Devices '0x01':['battery','uint8','%'], //All Blu Devices '0x3a':['button','uint8'], //All Blu Devices '0x05':['illuminance','uint24',0.01], //Blu Motion & D/W '0x45':['temperature','sint16',0.1], //Blu Motion & H&T //notUsed-->'0x1a':['door','uint8'], //Blu D/W //notUsed-->'0x20':['moisture','uint8'], //Unknown '0x41':['distance','uint16',0.1], //BLU Sonic '0x03':['humidity','uint16',0.01], //BLU H&T '0x2d':['window','uint8'], //Blu D/W '0x3f':['rotation','int16',0.1], //Blu D/W '0x21':['motion','uint8'], //Blu Motion }; function CreateEvent(obj){ //Create Blu data and send Blu Events try{ //Somehow filter for device_type, with out local names obj.gen= 'GBLE'; obj.device_type= 'Unknown-Type'; if(typeof obj.button === 'number' && !obj.illuminance || obj.device_type_id === '2.1') obj.device_type= 'Button'; if(typeof obj.illuminance === 'number' && !obj.motion || obj.device_type_id === '2.2') obj.device_type= 'Door-Window'; if(typeof obj.motion === 'number' || obj.device_type_id === '2.5') obj.device_type= 'Motion'; //notUsed-->obj.device_type || obj.device_type_id ? obj.gen= 'GBLE': obj.device_type= 'Unknown-Type'; //Create device_states switch(obj.device_type){ case 'Button': obj.device_state= obj.input; break; case 'Door-Window': obj.window === 0 ? obj.device_state= obj.input||'closed': obj.device_state= obj.input||'open'; break; case 'Motion': obj.motion === 0 ? obj.device_state= obj.button_input||'no_motion': obj.device_state= obj.input||'motion_detected'; break; default: obj.device_state= 'unknown_state'; } if(obj.input) delete obj.input; if(obj.firmware_version){ obj.device_state= 'alive'; if(battery_Fix && obj.battery === 0) delete obj.battery; //Workaround a Blu FW_Update Battery Bug if(battery_Fix && get_All && obj.battery_string) delete obj.battery_string; //Workaround a Blu FW_Update Battery Bug } if(debug) print('\nDebug: Blu_data:\n',obj); Shelly.emitEvent(''+obj.device_state, obj); //Sending Event if(debug) print('Debug: sending Event __[',obj.device_state,']__'); }catch(e){ErrorMsg(e,'SendEvent()',debug);} } function CheckInput(bI){ //Check for Blu Button Events try{ if(typeof bI !== 'number') return null; let buttonMap= ['wake_up', 'single_push', 'double_push', 'triple_push', 'long_push', 'pairing_push', 'default_reset_push']; if(bI > 6 && bI !== 254) bI= 'unknown_push'; if(bI < 7) bI= buttonMap[bI]; if(bI === 254) bI= 'hold_push'; return bI; }catch(e){ErrorMsg(e,'CheckInput()',debug);} } function DeviceName(name){ //Check for locale Device Name try{ if(!name) return 'Hidden-Device'; if(Cut(name,devID1)) return 'Blu-Button1'; if(Cut(name,devID2)) return 'Blu-Door-Window'; if(Cut(name,devID3)) return 'Blu-Motion'; return 'Unknown-Device--> '+ name; }catch(e){ErrorMsg(e,'DeviceName()',debug);} } function Unpack(d,m,r,l){ //Create BTHome obj and Unpack BTHome data try{ //Setup declaring variabel and functions if(typeof d !== "string" || d.length < 3) return null; var obj= {mac: m, rssi: r, device_name: DeviceName(l)}, spC= 0, tmp= []; //Add extra data function Int_To_uInt(int, bytes){ let mask= 1 << (bytes - 1); if(int & mask) return int-(1 << bytes); return int; } //Unpack Info BTHome Byte byte= d.at(0); //Getting first Byte as dezimal if(byte & 0x01) obj.encryption= true; //Getting encryption; if(obj.encryption) throw new Error('BThome Service Data encripted, encription is not supported!'); if(get_All){ obj.bthome_version= byte >> 5; //Getting BTHome Version (byte & 0x02) ? obj.interval= 'irregular': obj.interval= 'regular'; //Get transmission interval if(obj.bthome_version !== 2) throw new Error('Wrong BThome Version: found v.'+obj.bthome_version+' only v.2 supported!'); }else{delete obj.encryption; if(obj.device_name === "Hidden-Device") delete obj.device_name;} //Reduce data d= d.slice(1); //Delete useless Info byte //Unpack BThome Values for(let value of d){ //Search for matching BTHome hex ID if(d.length < 1) break; if(!spC) byte= btoh(d[0]); //Getting BTHome object ID let bluData= bluMap['0x'+byte]; //Getting blu Data if(bluData === undefined){ //Debug handling print('Error: Unknown BThome Data--> HexID: 0x',byte,', you can add more id from the full objID list--> https://bthome.io/format'); obj.new_BTH_HexID= byte; obj.new_Data= btoa(d); obj.info= 'Please send the newBTH_HexID and newData to this script developer so that they can integrate it.'; break; } if(!spC) d= d.slice(1); //Delete usless bth ID byte // Merge value bytes let max= Number(Cut(bluData[1],'int','int'))/8; //Getting max Bytes out of dataType if(d.length < max) throw new Error('Wrong DataType, '+d.length+' Bytes, payload to big for DataType: '+bluData[1]+' max->'+max); if(max === 1) value= d.at(0); else if(max === 2) value= (d.at(1) << 8) | d.at(0); else if(max === 3) value= (d.at(2) << 16) | (d.at(1) << 8) | d.at(0); //notUsed-->else if(max === 4) value= (d.at(3) << 24) | (d.at(2) << 16) | (d.at(1) << 8) | d.at(0); d= d.slice(max); //Delete useless value Bytes if(!Cut(bluData[1],'u','u')) value= Int_To_uInt(value,max*8); //Convert int to uint if(value === undefined) break; //Exit value loop //Adding String/Unit to value let is_Str= typeof bluData[2] === 'string'; if (typeof bluData[2] === 'number') value= value*bluData[2]; //Adding factor if(is_Str && !spC && Cut(bluData[2],'split')) spC= Number(Cut(bluData[2],'split','split'))+1; //Get split counter if(spC){ tmp.push(value); //Saving value for special case spC--; //reduce split counter }else{ obj[bluData[0]]= value; //Saving value } if(is_Str && !spC && get_All) value= ''+value+bluData[2]; //Adding unit if(is_Str && !spC && get_All) obj[bluData[0]+'_string']= value; //Saving String Value if(spC === 1){ value= []; for(let i in tmp){ value[(tmp.length-1)-i]= tmp[i]; //Reverse Array } tmp= []; //Clear useless data obj[bluData[0]]= value.join('.'); //Join FW version into String spC= 0; //Exit special case } } return obj; }catch(e){ErrorMsg(e,'Unpack()',debug);} } var old_pid= [-1,-1,-1,-1], old_mac= [-1,-1,-1,-1], iX= 0; function ScanCB(e,r) { //BT Scan Loop try{ if(e !== 2 || !r) return; //Exit if empty scan if(!r.service_data || !r.service_data[uuid]) return; //Exit if not BTHome data let obj= Unpack(r.service_data[uuid],r.addr,r.rssi,r.local_name); //Create BTHome Obj & Unpack BTHome Data if(!obj) throw new Error('Failed to unpack service_data --> _[ '+btoa(r.service_data[uuid])+' ]_'); //Anti Double msg Logic if((obj.pid === old_pid[0] && obj.mac === old_mac[0])||(obj.pid === old_pid[1] && obj.mac === old_mac[1])|| (obj.pid === old_pid[2] && obj.mac === old_mac[2])||(obj.pid === old_pid[3] && obj.mac === old_mac[3]) ) return;//Exit if double msg if(debug) print('Debug: Anti Double, saved Data:',iX,'\n',old_pid,'\n',old_mac); if(iX >= old_pid.length) iX= 0; old_pid[iX]= obj.pid; old_mac[iX]= obj.mac; iX++ //increas counter; if(!get_All && obj.pid) delete obj.pid; //reduce data if(debug){ //Debug output r.service_data[uuid]= btoa(r.service_data[uuid]); r.advData= btoa(r.advData); print('\nDebug: BT_data:\n',r,'\nDebug: BTHome_data:\n', obj);} r= undefined, e= undefined; //Delete useless data obj.input= CheckInput(obj.button); if(!obj.input) delete obj.input; //Delete useless data CreateEvent(obj); //Creating Event out of bthObj }catch(e){ErrorMsg(e,'ScanCB()',debug);} } tH1= 0; //Global "easy_Start"" Timer Handler function Main(){ //Main syncron Script Code BLE.Scanner.Start({duration_ms: -1, active: activeScan}, ScanCB); //Sub to passiv BT Scanner, start a new scan if no scanner is runnning BLE.Scanner.isRunning() ? print('Status: BLE.Scanner is scanning in Background.'): print('Status: BLE.Scanner cannot be initiated, check your Bluetooth settings!'); Object.keys(actionMap).forEach(Read_actionMap); //Read actionMap Shelly.addEventHandler(Check_Event); //Start Check_Event() Loop } //Toolbox v1.0(base), a universal Toolbox for Shelly scripts function Efilter(d,p,deBug) { //Event Filter, d=eventdata, p={device:[], filterKey:[], filterValue:[], noInfo:true, inData:true}->optional_parameter try{ let fR= {}; //d.info= d.info.data; if(p.noInfo){fR= d; d= {}; d.info= fR; fR= {};} if(p.inData && d.info.data){Object.assign(d.info,d.info.data) delete d.info.data;} if(!d.info) fR.useless= true; if(p.device && p.device.length && p.device.indexOf(d.info.component) === -1) fR.useless= true; if(p.device && p.device.length && !fR.useless && !p.filterKey && !p.filterValue) fR= d.info; if(p.filterKey && !fR.useless) for(f of p.filterKey) for(k in d.info) if(f === k) fR[k]= d.info[k]; if(p.filterValue && !fR.useless) for(f of p.filterValue) for(v of d.info) if(Str(v) && f === v) fR[Str(v)]= v; if(deBug) print('\nDebug: EventData-> ', d, '\n\nDebug: Result-> ', fR, '\n'); if(Str(fR) === '{}' || fR.useless){return;} return fR;}catch(e){ErrorMsg(e,'Efilter()');}} function ErrorChk(r,e,m,d){ //Shelly.call error check try{ aC--; if(aC<0) aC= 0; if(d.CB && d.uD) d.CB(r,d.uD); if(d.CB && !d.uD) d.CB(r); if(!d.CB && d.uD) print('Debug: ',d.uD); if(e) throw new Error(Str(m)); if(Str(r) && Str(r.code) && r.code !== 200) throw new Error(Str(r)); }catch(e){ErrorMsg(e,'ErrorChk(), call Answer');}} function Cqueue(){ //Shelly.call queue try{ if(!cCache[0] && !nCall[0]) return; while(cCache[0] && aC < callLimit){if(cCache[0] && !nCall[0]){nCall= cCache[0]; cCache.splice(0,1);} if(nCall[0] && aC < callLimit){Call(nCall[0],nCall[1],nCall[2],nCall[3],nCall[4]); nCall= [];}} if(tH9){Timer.clear(tH9); tH9= 0;} if(nCall[0] || cCache[0])if(cSp <= 0) cSp= 0.1; tH9= Timer.set(1000*cSp,0,function(){tH9= 0; Cqueue();});}catch(e){ErrorMsg(e,'Cqueue()');}} function Call(m,p,CB,uD,deBug){ //Upgrade Shelly.call try{ let d= {}; if(deBug) print('Debug: calling:',m,p); if(CB) d.CB= CB; if(Str(uD)) d.uD= uD; if(!m && CB){CB(uD); return;} if(aC < callLimit){aC++; Shelly.call(m,p,ErrorChk,d);}else if(cCache.length < cacheLimit){ cCache.push([m,p,CB,uD,deBug]); if(deBug) print('Debug: save call:',m,p,', call queue now:',cCache.length); Cqueue(); }else{throw new Error('to many Calls in use, droping call: '+Str(m)+', '+Str(p));}}catch(e){ErrorMsg(e,'Call()');}} function Str(d){ //Upgrade JSON.stringify try{ if(d === null || d === undefined) return null; if(typeof d === 'string')return d; return JSON.stringify(d);}catch(e){ErrorMsg(e,'Str()');}} function Cut(f,k,o,i){ //Upgrade slice f=fullData, k=key-> where to cut, o=offset->offset behind key, i=invertCut try{ let s= f.indexOf(k); if(s === -1) return null; if(o) s= s+o.length || s+o; if(i) return f.slice(0,s); return f.slice(s);}catch(e){ErrorMsg(e,'Cut()');}} function Setup(){ //Wating 2sek, to avoid a Shelly FW Bug try{ if(Main && !tH9){tH9= Timer.set(2000,0,function(){print('\nStatus: started Script _[', scriptN,']_'); if(callLimit > 4){callLimit= 4;} try{Main();}catch(e){ErrorMsg(e,'Main()'); tH9= 0; Setup();}});}}catch(e){ErrorMsg(e,'Setup()');}} function ErrorMsg(e,s,deBug){ //Toolbox formatted Error Msg try{ let i=0; if(Cut(e.message, '-104: Timed out')) i= 'wrong URL or device may be offline'; if(Cut(e.message, 'calls in progress')) i= 'reduce _[ callLimit ]_ by 1 and try again, its a global variabel at the end of the toolbox'; if(s === 'Main()' || deBug) i= e.stack; if(Cut(e.message, '"Main" is not')) i= 'define a Main() function before using Setup()'; print('Error:',s || "",'---> ',e.type,e.message); if(i) print('Info: maybe -->',i);}catch(e){print('Error: ErrorMsg() --->',JSON.stringify(e));}} var tH8= 0, tH9= 0, aC= 0, cCache= [], nCall= [], callLimit= 4, cacheLimit= 40, cSp= 0.1; //Toolbox global variable var Status= Shelly.getComponentStatus, Config= Shelly.getComponentConfig; //Renamed native function var info= Shelly.getDeviceInfo(), scriptID= Shelly.getCurrentScriptId(), scriptN= Config('script',scriptID).name; //Pseudo const, variabel //Toolbox v1.0(base), Shelly FW >1.0.8 Setup();
eiche Das ist das komplette Script. Hatte es ganz am Anfang schonmal gepostet.
Danke eiche
Im Kern sind es die 3 Aktionen welche ich brauche und die in der Action Map des Easy_Call Scripts welches ich gepostet habe zu finden sind. Hier ein Beispiel:
"Oeffne_Rolladen_Schiebetuer": {id: "38:39:8f:ed:ad:40", event: "open", call: ["Cover.Open", {id:0}] }, //id 0 heißt hier Aktion Open lokal auf diesem shelly ausführen
"Stop_Rolladen_Schiebetuer_Automatic": {id: "38:39:8f:ed:ad:40", event: "open", call: ["Script.Stop", {id:2}] }, //id ist Nummer des Webhook Script
"Start_Rolladen_Schiebetuer_Automatic": {id: "38:39:8f:ed:ad:40", event: "closed", call: ["Script.Start",{id:2}] },
Na toll! Aber herzlichen Dank für die Mühe! Hoffe die beheben das zeitnah.
Hab Autostart für Scripte raus genommen. Bringt trotzdem nichts. Es läuft so nicht nur mit Beta. Auch mit der Stable Version... Oberhalb 1.5.1
Sieht bei mir anders aus. Aber es ist wohl der Schieberegler?
Wo ist der Autostart für Scripte zu finden?
Ich muss ihn per Hardreset neu einbinden. Damit ist alles gelöscht.
Nein. Funktioniert nicht. Webseite nicht erreichbar. Der Shelly ist komplett offline sobald das Script aktiv ist.
Mit 1.5.1 läuft es. Nach aktuellem Update mit 1.6.2 geht der 2pm Offline und ist nicht mehr erreichbar.
/*---------------------------------Supported Blu Events--------------------------------------------
Blu *all: ---> "alive" "single_push" "hold_push" "pairing_push" "unknown_push"
Blu Door/Window: ---> "open" "closed"
Blu Motion: ---> "no_motion" "motion_detected"
Blu Button: ---> "wake_up" "single_push" "double_push" "triple_push" "long_push"
--------------------------------------------------------------------------------------------------*/
let eDebug= false, //Create debug output, true/false, set this only to true for short periods!
//____Easy_Call_Config____
// easy_Start true/false, shows for 15 min, after a script start, blu "mac" ids near your Shelly.
var easy_Start= true,
actionMap= {
"Oeffne_Rolladen_Schiebetuer": {id: "38:39:8f:ed:ad:40", event: "open", call: ["Cover.Open", {id:0}] }, //id 0 heißt hier Aktion Open lokal auf diesem shelly ausführen
//"Oeffne_Rolladen_Kuechenfenster": {id: "e8:e0:7e:d0:90:77", event: "open", call: ["Cover.GoToPosition", {id:0, pos:40}] }, //id 0 heißt hier Aktion Open lokal auf diesem shelly ausführen
"Stop_Rolladen_Schiebetuer_Automatic": {id: "38:39:8f:ed:ad:40", event: "open", call: ["Script.Stop", {id:2}] }, //id ist Nummer des Webhook Script
"Start_Rolladen_Schiebetuer_Automatic": {id: "38:39:8f:ed:ad:40", event: "closed", call: ["Script.Start",{id:2}] },
};//Entries name Restriction: without Space!, unique entries only!
//__Config_Blu_Events__
var battery_Fix= true, //Drop, 0% battery BTHome packages on Reboot Event, true/false
activeScan= true, //Active or Passiv Bluetooth Scan, only used when BT Gateway false!
get_All= false, //Get all data available and ship it in a Event, default false
debug= false; //Create debug output, true/false, set this only to true for short periods.
//~~~~~~~ Easy_Call v1.2 ~~~~~~~~~~
function Check_Event(d){ //Checking for Event Match
try{
let blu= 0, normal= 0;
if(easy_Start && !tH1) tH1= Timer.set(1000*60*15,0,function(){easy_Start= false;}); //15min Timer for easy_Start
//Filter for blu Events
if(bluShellys || easy_Start) blu= Efilter(d,{inData: true,filterValue: ['GBLE'], filterKey: ['mac','device_type','device_state']},eDebug); //Check for Blu Data
if(blu && blu.GBLE){
if(easy_Start) print('Found Device: Blu _[',blu.device_type,']_ ---event---> _[',blu.device_state,']_ \n id: ---> ',blu.mac);
for(a in actionMap){
if(actionMap[a].mac && actionMap[a].mac === blu.mac && actionMap[a].event === blu.device_state){
if(actionMap[a].call[2]) { //Check for Callback and pack event_data for Callback
Call(actionMap[a].call[0],actionMap[a].call[1],actionMap[a].call[2],{event_data:d.info,user_data:actionMap[a].call[3]},actionMap[a].call[4]);
}else{
Call(actionMap[a].call[0],actionMap[a].call[1],actionMap[a].call[2],actionMap[a].call[3],actionMap[a].call[4]);
}
}
}
}
//Filter for normal Events
if(dList.length < 1) return;
normal= Efilter(d,{device: dList, filterKey: ['event']},eDebug);
if(!normal) return; //Exit if useless Data
for(a in actionMap){
if(actionMap[a].event === normal.event){
if(actionMap[a].call[2]) { //Check for Callback and pack event_data for Callback
Call(actionMap[a].call[0],actionMap[a].call[1],actionMap[a].call[2],{event_data:d.info,user_data:actionMap[a].call[3]},actionMap[a].call[4]);
}else{
Call(actionMap[a].call[0],actionMap[a].call[1],actionMap[a].call[2],actionMap[a].call[3],actionMap[a].call[4]);
}
}
}
}catch(e){ErrorMsg(e,'Check_Event()',debug);} //Error Handler
}
var dList= [], bluShellys= false;
function Read_actionMap(a){ //Read actionMap
try{
//Check for valied actionMap Entrys
function cK(s){return typeof s !== 'string';}
if(!actionMap[a].id || !actionMap[a].event || !actionMap[a].call || cK(actionMap[a].id) || cK(actionMap[a].event) || !Array.isArray(actionMap[a].call)){
throw new Error('Wrong actionMap Parameter, dropped actionMap Entry ----> '+actionMap[a].id+' --> '+actionMap[a].event);
}
//Check for Blu mac
if(actionMap[a].id.length === 17) {
print("Info: add --> Blu Device ---> ",actionMap[a].id);
actionMap[a].mac= actionMap[a].id;
delete actionMap[a].id;
bluShellys= true;
}
//Add normal shellys to device List
if(actionMap[a].id) print("Info: add --> Normal Device ---> ",actionMap[a].id);
if(actionMap[a].id) dList.push(actionMap[a].id); //Device List
}catch(e){ErrorMsg(e,'Read_actionMap()',debug);} //Error Handler
}
//========= Blu_Events v2.4 =========
let activeScan= true; //Active or Passiv Bluetooth Scan, only used when BT Gateway false!
//notUsed-->let _cid = "0ba9"; //Allterco, Company ID(MFD)
let devID1= "SBBT"; //Blu Button1, deviceID, --> SBBT-002C
let devID2= "SBDW"; //Blu Door/Window, deviceID --> SBDW-002C
let devID3= 'SBMO'; //Blu Motion, deviceID, --> SBMO-003Z
let uuid= "fcd2"; //BTHome, Service ID --> UUID(16bit)
let bluMap= {//Device Parameter, you can find the full BTH Device List at 'https://bthome.io/format'
//bthObjectID:[Property,Datatype,Factor/Unit],
'0xf0':['device_type_id','uint8','split2'], //All Blu Devices, special case [default --> uint16]
'0xf1':['firmware_version','uint8','split4'], //All Blu Devices, special case [default--> uint32]
'0xf2':['extra_data','uint8','split3'], //All Blu Devices, special case [default--> uint24] --> maybe FW version?
'0x00':['pid','uint8'], //All Blu Devices
'0x01':['battery','uint8','%'], //All Blu Devices
'0x3a':['button','uint8'], //All Blu Devices
'0x05':['illuminance','uint24',0.01], //Blu Motion & D/W
'0x45':['temperature','sint16',0.1], //Blu Motion & H&T
//notUsed-->'0x1a':['door','uint8'], //Blu D/W
//notUsed-->'0x20':['moisture','uint8'], //Unknown
'0x41':['distance','uint16',0.1], //BLU Sonic
'0x03':['humidity','uint16',0.01], //BLU H&T
'0x2d':['window','uint8'], //Blu D/W
'0x3f':['rotation','int16',0.1], //Blu D/W
'0x21':['motion','uint8'], //Blu Motion
};
function CreateEvent(obj){ //Create Blu data and send Blu Events
try{
//Somehow filter for device_type, with out local names
obj.gen= 'GBLE'; obj.device_type= 'Unknown-Type';
if(typeof obj.button === 'number' && !obj.illuminance || obj.device_type_id === '2.1') obj.device_type= 'Button';
if(typeof obj.illuminance === 'number' && !obj.motion || obj.device_type_id === '2.2') obj.device_type= 'Door-Window';
if(typeof obj.motion === 'number' || obj.device_type_id === '2.5') obj.device_type= 'Motion';
//notUsed-->obj.device_type || obj.device_type_id ? obj.gen= 'GBLE': obj.device_type= 'Unknown-Type';
//Create device_states
switch(obj.device_type){
case 'Button':
obj.device_state= obj.input;
break;
case 'Door-Window':
obj.window === 0 ? obj.device_state= obj.input||'closed': obj.device_state= obj.input||'open';
break;
case 'Motion':
obj.motion === 0 ? obj.device_state= obj.button_input||'no_motion': obj.device_state= obj.input||'motion_detected';
break;
default:
obj.device_state= 'unknown_state';
}
if(obj.input) delete obj.input;
if(obj.firmware_version){
obj.device_state= 'alive';
if(battery_Fix && obj.battery === 0) delete obj.battery; //Workaround a Blu FW_Update Battery Bug
if(battery_Fix && get_All && obj.battery_string) delete obj.battery_string; //Workaround a Blu FW_Update Battery Bug
}
if(debug) print('\nDebug: Blu_data:\n',obj);
Shelly.emitEvent(''+obj.device_state, obj); //Sending Event
if(debug) print('Debug: sending Event __[',obj.device_state,']__');
}catch(e){ErrorMsg(e,'SendEvent()',debug);}
}
function CheckInput(bI){ //Check for Blu Button Events
try{
if(typeof bI !== 'number') return null;
let buttonMap= ['wake_up', 'single_push', 'double_push', 'triple_push', 'long_push', 'pairing_push', 'default_reset_push'];
if(bI > 6 && bI !== 254) bI= 'unknown_push';
if(bI < 7) bI= buttonMap[bI];
if(bI === 254) bI= 'hold_push';
return bI;
}catch(e){ErrorMsg(e,'CheckInput()',debug);}
}
function DeviceName(name){ //Check for locale Device Name
try{
if(!name) return 'Hidden-Device';
if(Cut(name,devID1)) return 'Blu-Button1';
if(Cut(name,devID2)) return 'Blu-Door-Window';
if(Cut(name,devID3)) return 'Blu-Motion';
return 'Unknown-Device--> '+ name;
}catch(e){ErrorMsg(e,'DeviceName()',debug);}
}
function Unpack(d,m,r,l){ //Create BTHome obj and Unpack BTHome data
try{
//Setup declaring variabel and functions
if(typeof d !== "string" || d.length < 3) return null;
var obj= {mac: m, rssi: r, device_name: DeviceName(l)}, spC= 0, tmp= []; //Add extra data
function Int_To_uInt(int, bytes){
let mask= 1 << (bytes - 1);
if(int & mask) return int-(1 << bytes);
return int;
}
//Unpack Info BTHome Byte
byte= d.at(0); //Getting first Byte as dezimal
if(byte & 0x01) obj.encryption= true; //Getting encryption;
if(obj.encryption) throw new Error('BThome Service Data encripted, encription is not supported!');
if(get_All){
obj.bthome_version= byte >> 5; //Getting BTHome Version
(byte & 0x02) ? obj.interval= 'irregular': obj.interval= 'regular'; //Get transmission interval
if(obj.bthome_version !== 2) throw new Error('Wrong BThome Version: found v.'+obj.bthome_version+' only v.2 supported!');
}else{delete obj.encryption; if(obj.device_name === "Hidden-Device") delete obj.device_name;} //Reduce data
d= d.slice(1); //Delete useless Info byte
//Unpack BThome Values
for(let value of d){ //Search for matching BTHome hex ID
if(d.length < 1) break;
if(!spC) byte= btoh(d[0]); //Getting BTHome object ID
let bluData= bluMap['0x'+byte]; //Getting blu Data
if(bluData === undefined){ //Debug handling
print('Error: Unknown BThome Data--> HexID: 0x',byte,', you can add more id from the full objID list--> https://bthome.io/format');
obj.new_BTH_HexID= byte;
obj.new_Data= btoa(d);
obj.info= 'Please send the newBTH_HexID and newData to this script developer so that they can integrate it.';
break;
}
if(!spC) d= d.slice(1); //Delete usless bth ID byte
// Merge value bytes
let max= Number(Cut(bluData[1],'int','int'))/8; //Getting max Bytes out of dataType
if(d.length < max) throw new Error('Wrong DataType, '+d.length+' Bytes, payload to big for DataType: '+bluData[1]+' max->'+max);
if(max === 1) value= d.at(0);
else if(max === 2) value= (d.at(1) << 8) | d.at(0);
else if(max === 3) value= (d.at(2) << 16) | (d.at(1) << 8) | d.at(0);
//notUsed-->else if(max === 4) value= (d.at(3) << 24) | (d.at(2) << 16) | (d.at(1) << 8) | d.at(0);
d= d.slice(max); //Delete useless value Bytes
if(!Cut(bluData[1],'u','u')) value= Int_To_uInt(value,max*8); //Convert int to uint
if(value === undefined) break; //Exit value loop
//Adding String/Unit to value
let is_Str= typeof bluData[2] === 'string';
if (typeof bluData[2] === 'number') value= value*bluData[2]; //Adding factor
if(is_Str && !spC && Cut(bluData[2],'split')) spC= Number(Cut(bluData[2],'split','split'))+1; //Get split counter
if(spC){
tmp.push(value); //Saving value for special case
spC--; //reduce split counter
}else{
obj[bluData[0]]= value; //Saving value
}
if(is_Str && !spC && get_All) value= ''+value+bluData[2]; //Adding unit
if(is_Str && !spC && get_All) obj[bluData[0]+'_string']= value; //Saving String Value
if(spC === 1){
value= [];
for(let i in tmp){
value[(tmp.length-1)-i]= tmp[i]; //Reverse Array
}
tmp= []; //Clear useless data
obj[bluData[0]]= value.join('.'); //Join FW version into String
spC= 0; //Exit special case
}
}
return obj;
}catch(e){ErrorMsg(e,'Unpack()',debug);}
}
var old_pid= [-1,-1,-1,-1], old_mac= [-1,-1,-1,-1], iX= 0;
function ScanCB(e,r) { //BT Scan Loop
try{
if(e !== 2 || !r) return; //Exit if empty scan
if(!r.service_data || !r.service_data[uuid]) return; //Exit if not BTHome data
let obj= Unpack(r.service_data[uuid],r.addr,r.rssi,r.local_name); //Create BTHome Obj & Unpack BTHome Data
if(!obj) throw new Error('Failed to unpack service_data --> _[ '+btoa(r.service_data[uuid])+' ]_');
//Anti Double msg Logic
if((obj.pid === old_pid[0] && obj.mac === old_mac[0])||(obj.pid === old_pid[1] && obj.mac === old_mac[1])||
(obj.pid === old_pid[2] && obj.mac === old_mac[2])||(obj.pid === old_pid[3] && obj.mac === old_mac[3])
) return;//Exit if double msg
if(debug) print('Debug: Anti Double, saved Data:',iX,'\n',old_pid,'\n',old_mac);
if(iX >= old_pid.length) iX= 0;
old_pid[iX]= obj.pid; old_mac[iX]= obj.mac;
iX++ //increas counter;
if(!get_All && obj.pid) delete obj.pid; //reduce data
if(debug){ //Debug output
r.service_data[uuid]= btoa(r.service_data[uuid]);
r.advData= btoa(r.advData);
print('\nDebug: BT_data:\n',r,'\nDebug: BTHome_data:\n', obj);}
r= undefined, e= undefined; //Delete useless data
obj.input= CheckInput(obj.button);
if(!obj.input) delete obj.input; //Delete useless data
CreateEvent(obj); //Creating Event out of bthObj
}catch(e){ErrorMsg(e,'ScanCB()',debug);}
}
tH1= 0; //Global "easy_Start"" Timer Handler
function Main(){ //Main syncron Script Code
BLE.Scanner.Start({duration_ms: -1, active: activeScan}, ScanCB); //Sub to passiv BT Scanner, start a new scan if no scanner is runnning
BLE.Scanner.isRunning() ? print('Status: BLE.Scanner is scanning in Background.'): print('Status: BLE.Scanner cannot be initiated, check your Bluetooth settings!');
Object.keys(actionMap).forEach(Read_actionMap); //Read actionMap
Shelly.addEventHandler(Check_Event); //Start Check_Event() Loop
}
//Toolbox v1.0(base), a universal Toolbox for Shelly scripts
function Efilter(d,p,deBug) { //Event Filter, d=eventdata, p={device:[], filterKey:[], filterValue:[], noInfo:true, inData:true}->optional_parameter
try{
let fR= {}; //d.info= d.info.data;
if(p.noInfo){fR= d; d= {}; d.info= fR; fR= {};} if(p.inData && d.info.data){Object.assign(d.info,d.info.data) delete d.info.data;}
if(!d.info) fR.useless= true; if(p.device && p.device.length && p.device.indexOf(d.info.component) === -1) fR.useless= true;
if(p.device && p.device.length && !fR.useless && !p.filterKey && !p.filterValue) fR= d.info;
if(p.filterKey && !fR.useless) for(f of p.filterKey) for(k in d.info) if(f === k) fR[k]= d.info[k];
if(p.filterValue && !fR.useless) for(f of p.filterValue) for(v of d.info) if(Str(v) && f === v) fR[Str(v)]= v;
if(deBug) print('\nDebug: EventData-> ', d, '\n\nDebug: Result-> ', fR, '\n');
if(Str(fR) === '{}' || fR.useless){return;} return fR;}catch(e){ErrorMsg(e,'Efilter()');}}
function ErrorChk(r,e,m,d){ //Shelly.call error check
try{
aC--; if(aC<0) aC= 0;
if(d.CB && d.uD) d.CB(r,d.uD); if(d.CB && !d.uD) d.CB(r);
if(!d.CB && d.uD) print('Debug: ',d.uD); if(e) throw new Error(Str(m));
if(Str(r) && Str(r.code) && r.code !== 200) throw new Error(Str(r));
}catch(e){ErrorMsg(e,'ErrorChk(), call Answer');}}
function Cqueue(){ //Shelly.call queue
try{
if(!cCache[0] && !nCall[0]) return;
while(cCache[0] && aC < callLimit){if(cCache[0] && !nCall[0]){nCall= cCache[0]; cCache.splice(0,1);}
if(nCall[0] && aC < callLimit){Call(nCall[0],nCall[1],nCall[2],nCall[3],nCall[4]); nCall= [];}} if(tH9){Timer.clear(tH9); tH9= 0;}
if(nCall[0] || cCache[0])if(cSp <= 0) cSp= 0.1; tH9= Timer.set(1000*cSp,0,function(){tH9= 0; Cqueue();});}catch(e){ErrorMsg(e,'Cqueue()');}}
function Call(m,p,CB,uD,deBug){ //Upgrade Shelly.call
try{
let d= {};
if(deBug) print('Debug: calling:',m,p); if(CB) d.CB= CB; if(Str(uD)) d.uD= uD; if(!m && CB){CB(uD); return;}
if(aC < callLimit){aC++; Shelly.call(m,p,ErrorChk,d);}else if(cCache.length < cacheLimit){
cCache.push([m,p,CB,uD,deBug]); if(deBug) print('Debug: save call:',m,p,', call queue now:',cCache.length); Cqueue();
}else{throw new Error('to many Calls in use, droping call: '+Str(m)+', '+Str(p));}}catch(e){ErrorMsg(e,'Call()');}}
function Str(d){ //Upgrade JSON.stringify
try{
if(d === null || d === undefined) return null; if(typeof d === 'string')return d;
return JSON.stringify(d);}catch(e){ErrorMsg(e,'Str()');}}
function Cut(f,k,o,i){ //Upgrade slice f=fullData, k=key-> where to cut, o=offset->offset behind key, i=invertCut
try{
let s= f.indexOf(k); if(s === -1) return null; if(o) s= s+o.length || s+o; if(i) return f.slice(0,s);
return f.slice(s);}catch(e){ErrorMsg(e,'Cut()');}}
function Setup(){ //Wating 2sek, to avoid a Shelly FW Bug
try{
if(Main && !tH9){tH9= Timer.set(2000,0,function(){print('\nStatus: started Script _[', scriptN,']_');
if(callLimit > 4){callLimit= 4;} try{Main();}catch(e){ErrorMsg(e,'Main()'); tH9= 0; Setup();}});}}catch(e){ErrorMsg(e,'Setup()');}}
function ErrorMsg(e,s,deBug){ //Toolbox formatted Error Msg
try{
let i=0; if(Cut(e.message, '-104: Timed out')) i= 'wrong URL or device may be offline';
if(Cut(e.message, 'calls in progress')) i= 'reduce _[ callLimit ]_ by 1 and try again, its a global variabel at the end of the toolbox';
if(s === 'Main()' || deBug) i= e.stack; if(Cut(e.message, '"Main" is not')) i= 'define a Main() function before using Setup()';
print('Error:',s || "",'---> ',e.type,e.message); if(i) print('Info: maybe -->',i);}catch(e){print('Error: ErrorMsg() --->',JSON.stringify(e));}}
var tH8= 0, tH9= 0, aC= 0, cCache= [], nCall= [], callLimit= 4, cacheLimit= 40, cSp= 0.1; //Toolbox global variable
var Status= Shelly.getComponentStatus, Config= Shelly.getComponentConfig; //Renamed native function
var info= Shelly.getDeviceInfo(), scriptID= Shelly.getCurrentScriptId(), scriptN= Config('script',scriptID).name; //Pseudo const, variabel
//Toolbox v1.0(base), Shelly FW >1.0.8
Setup();
Alles anzeigen
Das funktioniert mit einem Blu Door bei mir. Dieser ist mit dem 2pm gekoppelt und die Adresse des Blu Door ist im Script angepasst.
Das Script lief wie gesagt sauber bisher - bis ich dummerweise ein Update ausgeführt habe. Da mir die Programmierkenntnisse fehlen wäre für mich ein zurück zu einer alten Firmware die Lösung. Wie kann ich denn die Firmware auf einen älteren Stand wieder setzen? Ich war schon hier http://archive.shelly-tools.de/ finde dort aber keinen passenden Typ.
Ok. Das hört sich interessant an. Leider ist mir gerade aufgefallen, dass ich das Thema falsch platziert habe. Es ist ein 2PM Plus - also nicht die 3. GEN. SORRY! 😞
Das Problem ist, ich kann das Script mit meinen sehr limitierten Programmierkenntnissen nicht verändern und testen, da der 2PM sich direkt aufhängt. Ob ich den Fehler dann finde steht auf einem anderen Blatt..
Es war das Easy_Call Script. Sobald ich es aktiviere steigt der 2pm aus. Ich habe es mehrfach getestet auch mit einem weiteren 2pm den ich upgedatet habe. Jetzt wäre die Frage wie ich auf die bisher lauffähige Firmware mit dem Script Version 20250318-152133/1.5.1-g01dd7ff downgraden kann?
Fritzbox! 7490. Nein Beta noch nicht. Gibt's da ne Verbesserung in dieser Sache?
Hallo. Ich habe einige 2PM an Rolläden verbaut. Diese laufen jetzt schon mind. Ein halbes Jahr ohne Probleme. Jetzt auf einmal ist einer offline und nicht mehr erreichbar. Weder über die Cloud noch direkt per IP. Sein eigener WLAN Acesspoint ist noch sichtbar, aber ich kann mich nicht mit ihm verbinden. IP Konfigurationsfehler. Ich habe ihn jetzt per Hardreset neu eingebunden. Jetzt ist er eine Nacht später wieder offline. Was kann ich tun?
Hi. Hast du den Fehler gefunden?
"Steckdose_Außen": {id: "b4:35:22:fe:68:97", event: "long_push", call: ["Http.get",{url: "http://192.168.10.57/relay/0?turn=toggle"}] },
wie schreibt man den Befehl wenn man mehrere Aktionen ausführen möchte z.b. shelly 1 toggle und shelly 2 toggle bei Long push?