Dieses Skript ermöglicht die Ausführung eines Shelly.call() abhängig von der Leistung (power):
In "configON" kann definiert werden, welcher Call ausgeführt werden sollen, wenn die Leistung (power) über dem "powerLimit" Wert (power > Limit) liegt und auf welchem Kanal (Channel) die Leistung ausgewertet werden soll. Hierbei kann es sich um einen EM Channel oder nur einen Switch Channel handeln oder etwas anderes solange es eine gültige Event Komponenten Bezeichnung ist. Bis zu fünf unterschiedliche Channels können gleichzeitig angegeben werden, wobei der "powerLimit"- und "powerTimer" Wert automatisch für alle Channels gilt.
"configOFF" ist genau so aufgebaut wie "configON" mit dem unterschied das hier die Leistung unter dem powerLimit-Wert sein muss (power <= Limit) damit die unterschiedlichen Calls ausgeführt werden.
Der "powerTimer" Wert gibt an wie lange die Power mindesten über oder unter dem Limit liegen muss bevor ein Call ausgeführt wird.
Als Key wird das Device samt Channel ID angegeben und als Value ein Shelly.call() als Array. Userdata sowie ne Callback Funktionen werden bei den Call()`s ebenfalls unterstütz. Über eine Callback Funktion im Call kann man mehrere Calls auf einmal ausführe.
Das Script:
//Config __There is a Maximum of 5 Channels/Devices__
var debug= false; //Create Debug output
var configON= { //Device Name and Channel als Key --> 'switch:0', Value als Shelly.Call Array.
called: [], //Called Variabel to reduce useless Calls
powerLimit: 2, //Limit in Watt, power needs to be > Limit for sending a Call
powerTime: 1, //Time in seconds, how long the power needs to be over the powerLimit, before sending a call
'switch:0': ['HTTP.GET',{url:'http://192.168.178.100/relay/0/?turn=on'},null,null,debug],
}
var configOFF= { //Device Name and Channel als Key --> 'switch:0', Value als Shelly.Call Array.
called: [], //Called Variabel to reduce useless Calls
powerLimit: 2, //Limit in Watt, power needs to be <= Limit for sending a Call
powerTime: 1, //Time in seconds, how long the power needs to be over the powerLimit, before sending a call
'switch:0': ['HTTP.GET',{url:'http://192.168.178.100/relay/0/?turn=off'},null,null,debug],
}
var tHandel= []; //global Variabl
function Clear_Timer(id){
Timer.clear(tHandel[id]); //Reset Timer
tHandel[id]= 0;
return id;
}
function DoCall(device,id,map){ //Do call
try{
map.called[id]= true;
tHandel[id]= 0; //Reset Timer Handel
Call(map[device][0],map[device][1],map[device][2],map[device][3],map[device][4]);
}catch(e){ErrorMsg(e,'DoCall()');}
}
function CheckPower(d){
try{
let r= Efilter(d,{device:Object.keys(configON), filterKey:['apower','id','component','state']},0); //Filter event data
if(r && r.state === false){ //Switch off if switch is off
configON.called[r.id]= false;
r.id= Clear_Timer(r.id);
tHandel[r.id]= Timer.set(1000*configOFF.powerTime,false,function(){DoCall(r.component, r.id, configOFF)}); //Delayed Call
}
if(!r || !Str(r.apower)) return; //Exit if usless data
if(r.apower > configON.powerLimit && !configON.called[r.id]){ //Check if over Powerlimit
configOFF.called[r.id]= false;
r.id= Clear_Timer(r.id);
tHandel[r.id]= Timer.set(1000*configON.powerTime,false,function(){DoCall(r.component, r.id, configON)}); //Delayed Call
}
if(r.apower <= configOFF.powerLimit && !configOFF.called[r.id]){ //Check if under Powerlimit
configON.called[r.id]= false;
r.id= Clear_Timer(r.id);
tHandel[r.id]= Timer.set(1000*configOFF.powerTime,false,function(){DoCall(r.component, r.id, configOFF)}); //Delayed Call
}
if(debug) print('Debug: found Event\n',r,'\nDebug:',r.component,'Timer activ:',tHandel[r.id]>0,'\nDebug: called ON:',configON.called[r.id],', OFF:',configOFF.called[r.id]); //Debug output
}catch(e){ErrorMsg(e,'CheckPower()');}
}
function Main(){ //Main Code
try{
let fakeEvents= {};
for(e in configON){ //Create Fake Power Event for Restart
if(Cut(e,':')){
let deviceType= Cut(e,':',0,true); //Getting Device Type
let channelID= Number(Cut(e,':',':')) //Getting Channel ID
fakeEvents[e]= {info: {}}; //Create fake power Event
fakeEvents[e].info.component= e;
fakeEvents[e].info.id= channelID;
fakeEvents[e].info.apower= Status(deviceType,channelID).apower;
}
}
for(e of fakeEvents){
CheckPower(e); //Send fake Power Event
}
}catch(e){ErrorMsg(e,'Creating Fake Power Event');}
fakeEvents= 0; //Delete useless Data
Shelly.addEventHandler(CheckPower); //Add EventHandler with Asyn CallBack
}
// Dekats Toolbox, 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= {};
if(p.noInfo){fR= d; d= {}; d.info= fR; fR= {};} if(p.inData && d.info.data){d.info= d.info.data; delete d.info.data;}
if(!d.info) fR.useless= true; if(p.device && p.device.length > 0 && p.device.indexOf(d.info.component) === -1) fR.useless= true;
if(p.device && p.device.length > 0 && !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; if(!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((nCall[0] || cCache[0]) && !tH7) tH7= Timer.set(1000*cSp,0,function(){tH7= 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; 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(l){ //Wating 2sek, to avoid a Shelly FW Bug
try{
if(Main && !tH9){tH9= Timer.set(2000,l,function(){print('\nStatus: started Script _[', scriptN,']_');
if(callLimit > 5){callLimit= 5;} try{Main();}catch(e){ErrorMsg(e,'Main()'); Setup();}});}}catch(e){ErrorMsg(e,'Setup()');}}
function ErrorMsg(e,s){ //Toolbox formatted Error Msg
try{
let i= 0; if(Cut(e.message, '-104: Timed out')) i= 'wrong URL or device may be offline';
if(s === 'Main()') 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() --->',e);}}
var tH7= 0, tH8= 0, tH9= 0, aC= 0, cCache= [], nCall= [], callLimit= 4, cacheLimit= 40, cSp= 0.2; //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 v2.5-Alpha(cut), Shelly FW >1.0.8
Setup();
Alles anzeigen
Das Skript fällt unter die, Apache License Version 2.0, January 2004, siehe Link für mehr Infos: https://github.com/ALLTERCO/shell…ob/main/LICENSE
Debug Log Vorschau: