Hey, das Skript ist ja SUPER ! Vielen Dank für's Teilen.
Ich bin auch gerade ganz neu bei den Shellys. Ich wollte gerne die Ein-Knopf Bedienung mit einem BLU 4 realisieren:
Also, dass man immer nur den Knopf ein Mal drückt und dadurch die folgenden Zustände durchklickt:
runter - stop - rauf - stop .... runter - stop - rauf - stop ... usw.
Dazu muss das Skript sich die Zahl des Zustands merken 1, 2, 3, 4, 1, 2, 3, 4 und dann einfach bei jedem Knopfdruck weiterzählen und auf Grund der Zahl das entsprechende tun.
Ich habe 3 Rolläden, die alle das gleiche Skript bekommen, man muss bloß die "listen" variable ändern, auf welchen Knopf dieser Rolladen reagieren soll. Da das Skript lokal läuft, muss ich nicht über URLs schalten sondern kann es über die lokalen open / close Befehle machen.
Auf dem BLU4 hab ich noch nen 4. Knopf frei gehabt, da hab ich drauf gelegt, dass ALLE Rolläden auf den hören und bei einem Klick rauf und bei zwei Klicks runter gehen.
Hier ist mein Code, vielleicht inspiriert es ja den einen oder anderen.
/** =============================== CHANGE HERE =============================== */
let bluButtonAddress = "7c:c6:b6:57:9e:41" ; //the mac address of shelly blu Wall Switch 4 that will trigger the actions
let listen = 3 ; // To which button of the BLU should this shelly listen
/** =============================== STOP CHANGING HERE =============================== */
let urlsPerCall = 3;
let urlsQueue = [];
let callsCounter = 0;
let Zustand = 0;
let ALLTERCO_MFD_ID_STR = "0ba9";
let BTHOME_SVC_ID_STR = "fcd2";
let uint8 = 0;
let int8 = 1;
let uint16 = 2;
let int16 = 3;
let uint24 = 4;
let int24 = 5;
let BTH = {};
BTH[0x00] = { n: "pid", t: uint8 };
BTH[0x01] = { n: "Battery", t: uint8, u: "%" };
BTH[0x05] = { n: "Illuminance", t: uint24, f: 0.01 };
BTH[0x1a] = { n: "Door", t: uint8 };
BTH[0x20] = { n: "Moisture", t: uint8 };
BTH[0x2d] = { n: "Window", t: uint8 };
BTH[0x3a] = { n: "Button", t: uint8, b: 1 };
function getByteSize(type) {
if (type === uint8 || type === int8) return 1;
if (type === uint16 || type === int16) return 2;
if (type === uint24 || type === int24) return 3;
//impossible as advertisements are much smaller;
return 255;
}
let BTHomeDecoder = {
utoi: function (num, bitsz) {
let mask = 1 << (bitsz - 1);
return num & mask ? num - (1 << bitsz) : num;
},
getUInt8: function (buffer) {
return buffer.at(0);
},
getInt8: function (buffer) {
return this.utoi(this.getUInt8(buffer), 8);
},
getUInt16LE: function (buffer) {
return 0xffff & ((buffer.at(1) << 8) | buffer.at(0));
},
getInt16LE: function (buffer) {
return this.utoi(this.getUInt16LE(buffer), 16);
},
getUInt24LE: function (buffer) {
return (
0x00ffffff & ((buffer.at(2) << 16) | (buffer.at(1) << 8) | buffer.at(0))
);
},
getInt24LE: function (buffer) {
return this.utoi(this.getUInt24LE(buffer), 24);
},
getBufValue: function (type, buffer) {
if (buffer.length < getByteSize(type)) return null;
let res = null;
if (type === uint8) res = this.getUInt8(buffer);
if (type === int8) res = this.getInt8(buffer);
if (type === uint16) res = this.getUInt16LE(buffer);
if (type === int16) res = this.getInt16LE(buffer);
if (type === uint24) res = this.getUInt24LE(buffer);
if (type === int24) res = this.getInt24LE(buffer);
return res;
},
unpack: function (buffer) {
//beacons might not provide BTH service data
if (typeof buffer !== "string" || buffer.length === 0) return null;
let result = {};
let _dib = buffer.at(0);
result["encryption"] = _dib & 0x1 ? true : false;
result["BTHome_version"] = _dib >> 5;
if (result["BTHome_version"] !== 2) return null;
//can not handle encrypted data
if (result["encryption"]) return result;
buffer = buffer.slice(1);
let _bth;
let _value;
let _name;
let _btnNum = 0;
while (buffer.length > 0) {
_bth = BTH[buffer.at(0)];
if (typeof _bth === "undefined") {
console.log("BTH: unknown type");
break;
}
buffer = buffer.slice(1);
_value = this.getBufValue(_bth.t, buffer);
if (_value === null) break;
if (typeof _bth.f !== "undefined") _value = _value * _bth.f;
_name = _bth.n;
if (typeof _bth.b !== "undefined"){
_name = _name + _btnNum.toString();
_btnNum++;
}
result[_name] = _value;
buffer = buffer.slice(getByteSize(_bth.t));
}
return result;
},
};
let lastPacketId = 0x100;
function bleScanCallback(event, result) {
//exit if the call is not for a received result
if (event !== BLE.Scanner.SCAN_RESULT) {
return;
}
//exit if the data is not coming from a Shelly Blu button1 and if the mac address doesn't match
if ( typeof result.local_name === "undefined" ||
typeof result.addr === "undefined" ||
result.local_name.indexOf("SBBT") !== 0 ||
result.addr !== bluButtonAddress
) {
return;
}
let servData = result.service_data;
//exit if service data is null/device is encrypted
if(servData === null || typeof servData === "undefined" || typeof servData[BTHOME_SVC_ID_STR] === "undefined") {
console.log("Can't handle encrypted devices");
return;
}
let receivedData = BTHomeDecoder.unpack(servData[BTHOME_SVC_ID_STR]);
//exit if unpacked data is null or the device is encrypted
if(receivedData === null || typeof receivedData === "undefined" || receivedData["encryption"]) {
console.log("Can't handle encrypted devices");
return;
}
//exit if the event is duplicated
if (lastPacketId === receivedData.pid) {
return;
}
//console.log("rd:",receivedData);
lastPacketId = receivedData["pid"];
for (button = 0; button < 4; button++) {
let _bpush = receivedData["Button"+button.toString(0)];
if (_bpush === 254) _bpush = 0; // ggf 5 für hold
console.log("Received Button ",button," event: ", _bpush);
//possible values: 0 .. 5 = ["", "singlePush", "doublePush", "triplePush", "longPush", "hold"]
switch (button) {
case 2 : // Knopf für alle
switch(_bpush) {
case 1 : // auf
console.log("all open");
Shelly.call("Cover.Open", {'id': 0});
break ;
case 2 : // stop
console.log("all close");
Shelly.call("Cover.Close", {'id': 0});
break ;
}
break ;
case (listen) :
switch (_bpush) {
case 1 : // Wenn der Knopf 1x gedrückt wird, dann führe Zustandsmaschine aus
switch(Zustand) {
case 0 : // stop
console.log("stop");
Shelly.call("Cover.Stop", {'id': 0});
Zustand = 1 ;
break ;
case 1 : // auf
console.log("open");
Shelly.call("Cover.Open", {'id': 0});
Zustand = 2 ;
break ;
case 2 : // stop
console.log("stop");
Shelly.call("Cover.Stop", {'id': 0});
Zustand = 3 ;
break ;
case 3 : // ab
console.log("close");
Shelly.call("Cover.Close", {'id': 0});
Zustand = 0 ;
break ;
} // switch Zustand
break ;
case 2 : // wenn Knopf 2 gedrückt wird, gehe auf 50 %
Shelly.call("Cover.GoToPosition", {'id': 0, 'pos': 50});
break ;
} //switch bpush
break ;
}
}
}
function bleScan() {
//check whether the bluethooth is enabled
let bleConfig = Shelly.getComponentConfig("ble");
//exit if the bluetooth is not enabled
if(bleConfig.enable === false) {
console.log("BLE is not enabled");
return;
}
//start the scanner
let bleScanner = BLE.Scanner.Start({
duration_ms: BLE.Scanner.INFINITE_SCAN,
active: true
});
//exist if the scanner can not be started
if(bleScanner === false) {
console.log("Error when starting the BLE scanner");
return;
}
BLE.Scanner.Subscribe(bleScanCallback);
console.log("BLE is successfully started");
}
function init() {
//exit if there isn't a blu button address
if(typeof bluButtonAddress !== "string") {
console.log("Error with the Shelly BLU button1's address");
return;
}
//start the ble scan
bleScan();
}
//init the script
init();
Alles anzeigen