Ça semble bouger chez Shelly.
J’aime beaucoup ton idée d’utiliser les shelly comme des antennes de présence j’ai aucun Bluetooth car je fais ma presence avec Homebridge (évidemment ;-)) mais je salue l’effort ! En lisant la doc Shelly des scripts j’ai justement vu cette partie Bluetooth et je pensais justement à la présence, j’ai cherché et tu l’avais fait gg
Le firmware 1.1.0 vient de sortir, il permet de retrouver le fonctionnement normal du script.
Oui j’ai vu ça ! C’est top !
Fini la bidouille côté Jeedom pour remonter la présence, c’est parfait !
Merci encore pour ce script, il ferme mon portail sans problèmes tous les jours !
Bonjour,
Merci pour le script , est ce qu’il est possible de jouer sur la fréquence des envois MQTT par le shelly ?
Je ne sais pas, il faudrait fouiller dans la documentation pour voir si il y a quelque chose.
Super ce sujet! Ça m’intéresse beaucoup! Je vais voir aussi pour faire remonter les infos de cateurs style Windows/door sur le fil mqtt ; merci @Jeandhom !
Merci pour le retour, j’ai bien cherché mais rien trouvé qui fonctionnait.
Autre question, tu as une astuce pour convertir dans jeedom les unixtime en datetime comme sur le widget?
J’ai modifié le script afin de pouvoir l’utiliser avec d’autres modules "beacon compatible"
comme des Shelly BLU Button.
Il convient de renseigner les adresses MAC dans le script.
let origine = Shelly.getDeviceInfo().name;
let genericTopic = "shellies/script/scanNut/";
let nutsShelly = []; //nuts vus par ce Shelly
let nutsBroker = []; //nuts vus par le broker
let nutsName = {
"11:11:11:11:11:11": "-Nut 01-",
"22:22:22:22:22:22": "-Nut 02-",
"33:33:33:33:33:33": "-Nut 03-",
"44:44:44:44:44:44": "-Nut 04-",
"55:55:55:55:55:55": "-Shelly Rouge-",
"66:66:66:66:66:66": "-Shelly Bleu-",
"77:77:77:77:77:77": "-Shelly Blanc-",
"88:88:88:88:88:88": "-Shelly Noir-"
};
let macList = Object.keys(nutsName);
if(MQTT.isConnected()) {
MQTT.publish(genericTopic + origine + '/nombreNut', "0", 0, false);
MQTT.publish(genericTopic + origine + '/nameNut', "", 0, false);
}
function isMacValid(mac) {
if (mac.length !== 17) {
return false;
}
for (let i=0; i<17; i++) {
if (i%3 === 2) {
if (mac.at(i) !== 0x3a) { //0x3a = :
return false;
}
} else {
//0x30 = 0, 0x39 = 9, 0x61 = a et 0x66 = f
if (mac.at(i) < 0x30 || (mac.at(i) > 0x39 && mac.at(i) < 0x61) || mac.at(i) > 0x66) {
return false;
}
}
}
return true;
}
function nutList (nuts, nutsName) {
let nutsList = "";
for (let i=0; i<nuts.length; i++) {
//nutsList += nutsName[nuts[i].mac] + " ";
nutsList += nutsName[nuts[i].mac];
}
//let long = nutsList.length - 1;
//nutsList = nutsList.slice(0, long);
return nutsList;
}
function nutAjout (mac, unixtime, nuts) {
let existePas = 1;
for (let i=0; i<nuts.length; i++) {
if (nuts[i].mac === mac) {
nuts[i].timePublish = unixtime;
existePas = 0;
}
}
if (existePas === 1 && isMacValid(mac)) {
nuts.push({mac: mac, timePublish: unixtime});
}
}
MQTT.subscribe(
genericTopic + "#",
function (topic, message, callback) {
let endTopic = topic.slice(callback[0].length + 18);
if (endTopic === "unixtime") {
let mac = topic.slice(callback[0].length, callback[0].length + 17);
nutAjout (mac, JSON.parse(message), callback[1]);
}
},
[genericTopic, nutsBroker]
);
Timer.set(
10000, //10s
true,
function (callback) {
for (let i=0; i<callback[1].length; i++) {
if (callback[1][i].timePublish + 110 <= Shelly.getComponentStatus("sys").unixtime) {
if(MQTT.isConnected()) {
MQTT.publish(callback[0] + callback[1][i].mac + '/presence', "0", 0, false);
}
}
}
for (let i=0; i<callback[3].length; i++) {
if (callback[3][i].timePublish + 110 <= Shelly.getComponentStatus("sys").unixtime) {
callback[3].splice(i, 1);
let list = nutList (callback[3], callback[4]);
if(MQTT.isConnected()) {
MQTT.publish(callback[0] + callback[2] + '/nombreNut', JSON.stringify(callback[3].length), 0, false);
MQTT.publish(callback[0] + callback[2] + '/nameNut', list, 0, false);
}
}
}
},
[genericTopic, nutsBroker, origine, nutsShelly, nutsName]
);
function scanCB(ev, res, callback) {
if (ev === BLE.Scanner.SCAN_RESULT) {
//if (res.local_name === 'nut' && isMacValid(res.addr)) {
if (macList.indexOf(res.addr) !== -1) {
let mac = res.addr;
let topic = callback[0] + mac + '/';
let unixtime = Shelly.getComponentStatus("sys").unixtime;
nutAjout (mac, unixtime, callback[1]);
let list = nutList (callback[1], callback[3]);
if(MQTT.isConnected()) {
MQTT.publish(topic + 'rssi', JSON.stringify(res.rssi), 0, false);
MQTT.publish(topic + 'unixtime', JSON.stringify(unixtime), 0, false);
MQTT.publish(topic + 'presence', "1", 0, false);
MQTT.publish(topic + 'origine', JSON.stringify(callback[2]), 0, false);
MQTT.publish(callback[0] + callback[2] + '/nombreNut', JSON.stringify(callback[1].length), 0, false);
MQTT.publish(callback[0] + callback[2] + '/nameNut', list, 0, false);
}
}
}
}
BLE.Scanner.Start({ duration_ms: -1}, scanCB, [genericTopic, nutsShelly, origine, nutsName]);
Ajout des Nuts absents et tri des listes.
let origine = Shelly.getDeviceInfo().name;
let genericTopic = "shellies/script/scanNut/";
let nutsShelly = []; //nuts vus par ce Shelly
let nutsBroker = []; //nuts vus par le broker
let nutsName = {
"11:11:11:11:11:11": "Nut 01",
"22:22:22:22:22:22": "Nut 02",
"33:33:33:33:33:33": "Nut 03",
"44:44:44:44:44:44": "Nut 04",
"55:55:55:55:55:55": "Shelly Rouge",
"66:66:66:66:66:66": "Shelly Bleu",
"77:77:77:77:77:77": "Shelly Blanc",
"88:88:88:88:88:88": "Shelly Noir"
};
let macList = Object.keys(nutsName);
//let nameList = Object.values(nutsName);
let nameList = [];
for (let i=0; i<macList.length; i++) {
nameList.push(nutsName[macList[i]]);
}
if(MQTT.isConnected()) {
MQTT.publish(genericTopic + origine + '/nombreNut', "0", 0, false);
MQTT.publish(genericTopic + origine + '/nameNut', "Vide", 0, false);
MQTT.publish(genericTopic + origine + '/missingNut', "Vide", 0, false);
}
function isMacValid(mac) {
if (mac.length !== 17) {
return false;
}
for (let i=0; i<17; i++) {
if (i%3 === 2) {
if (mac.at(i) !== 0x3a) { //0x3a = :
return false;
}
} else {
//0x30 = 0, 0x39 = 9, 0x61 = a et 0x66 = f
if (mac.at(i) < 0x30 || (mac.at(i) > 0x39 && mac.at(i) < 0x61) || mac.at(i) > 0x66) {
return false;
}
}
}
return true;
}
function sortArray(arr, order) {
let temp;
for (let i = 0; i < arr.length; i++) {
for (let j = i + 1; j < arr.length; j++) {
if ((order === "asc" && arr[i] > arr[j]) || (order === "dsc" && arr[i] < arr[j])) {
temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
}
return arr;
}
function nutList (nuts, nutsName) {
let nutsList = [];
for (let i=0; i<nuts.length; i++) {
nutsList.push(nutsName[nuts[i].mac]);
}
return sortArray(nutsList, "asc");
}
function nutAjout (mac, unixtime, nuts) {
let existePas = 1;
for (let i=0; i<nuts.length; i++) {
if (nuts[i].mac === mac) {
nuts[i].timePublish = unixtime;
existePas = 0;
}
}
if (existePas === 1 && isMacValid(mac)) {
nuts.push({mac: mac, timePublish: unixtime});
}
}
MQTT.subscribe(
genericTopic + "#",
function (topic, message, callback) {
let endTopic = topic.slice(callback[0].length + 18);
if (endTopic === "unixtime") {
let mac = topic.slice(callback[0].length, callback[0].length + 17);
nutAjout (mac, JSON.parse(message), callback[1]);
}
},
[genericTopic, nutsBroker]
);
Timer.set(
10000, //10s
true,
function (callback) {
function checkNut(nut) {
return aList.indexOf(nut) === -1;
}
for (let i=0; i<callback[1].length; i++) {
if (callback[1][i].timePublish + 110 <= Shelly.getComponentStatus("sys").unixtime) {
if(MQTT.isConnected()) {
MQTT.publish(callback[0] + callback[1][i].mac + '/presence', "0", 0, false);
}
}
}
for (let i=0; i<callback[3].length; i++) {
if (callback[3][i].timePublish + 110 <= Shelly.getComponentStatus("sys").unixtime) {
callback[3].splice(i, 1);
let aList = nutList(callback[3], callback[4]);
let aMissing = nameList.filter(checkNut);
aMissing = sortArray(aMissing, "asc");
let missing = aMissing.join('--');
if (missing.length === 0 ) {
missing = "Vide";
}
if(MQTT.isConnected()) {
MQTT.publish(callback[0] + callback[2] + '/nombreNut', JSON.stringify(callback[3].length), 0, false);
MQTT.publish(callback[0] + callback[2] + '/nameNut', aList.join('--'), 0, false);
MQTT.publish(callback[0] + callback[2] + '/missingNut', missing, 0, false);
}
}
}
},
[genericTopic, nutsBroker, origine, nutsShelly, nutsName]
);
function scanCB(ev, res, callback) {
if (ev === BLE.Scanner.SCAN_RESULT) {
if (macList.indexOf(res.addr) !== -1) {
function checkNut(nut) {
return aList.indexOf(nut) === -1;
}
let mac = res.addr;
let topic = callback[0] + mac + '/';
let unixtime = Shelly.getComponentStatus("sys").unixtime;
nutAjout (mac, unixtime, callback[1]);
let aList = nutList(callback[1], callback[3]);
let aMissing = nameList.filter(checkNut);
aMissing = sortArray(aMissing, "asc");
let missing = aMissing.join('--');
if (missing.length === 0 ) {
missing = "Vide";
}
if(MQTT.isConnected()) {
MQTT.publish(topic + 'rssi', JSON.stringify(res.rssi), 0, false);
MQTT.publish(topic + 'unixtime', JSON.stringify(unixtime), 0, false);
MQTT.publish(topic + 'presence', "1", 0, false);
MQTT.publish(topic + 'origine', JSON.stringify(callback[2]), 0, false);
MQTT.publish(callback[0] + callback[2] + '/nombreNut', JSON.stringify(callback[1].length), 0, false);
MQTT.publish(callback[0] + callback[2] + '/nameNut', aList.join('--'), 0, false);
MQTT.publish(callback[0] + callback[2] + '/missingNut', missing, 0, false);
}
}
}
}
BLE.Scanner.Start({ duration_ms: -1}, scanCB, [genericTopic, nutsShelly, origine, nutsName]);
Bonjour,
J’ai reçu mes shelly1 gen3 et j’essaie la détection de Nut.
Et … je crois que je vais avoir besoin d’aide
J’ai bien mis pour tester 2 mac de nut en remplacement de
let nutsName = {
« A4:C1:38:C9:8C:61 »: « Nut 01 »,
« A4:C1:38:B4:E3:7F »: « Nut 02 »,
« 33:33:33:33:33:33 »: « Nut 03 »,
« 44:44:44:44:44:44 »: « Nut 04 »,
« 55:55:55:55:55:55 »: « Shelly Rouge »,
« 66:66:66:66:66:66 »: « Shelly Bleu »,
« 77:77:77:77:77:77 »: « Shelly Blanc »,
« 88:88:88:88:88:88 »: « Shelly Noir »
};
mais rien n’y fait. Dans mqtt explorer :
alors qu’il devrait me trouver le nut 01 qui est présent.
Je merdois où ?
Bien cordialement
Il faut donner un nom (pour ne pas avoir « null ») différent à chacun de tes shelly.
Un copier coller du code modifié avec texte préformaté pour voir si il n’y a pas une erreur.
Hello
J’avais bien mis un nom.
Voici le code, j’ai recopié ce que tu avais posté normalement. Je n’ai renseigné que les mac de 2 nuts
let origine = Shelly.getDeviceInfo().name;
let genericTopic = "shellies/shelly1minig3/script/scanNut/";
let nutsShelly = []; //nuts vus par ce Shelly
let nutsBroker = []; //nuts vus par le broker
let nutsName = {
"A4:C1:38:C9:8C:61": "Nut 01",
"A4:C1:38:B4:E3:7F": "Nut 02",
"33:33:33:33:33:33": "Nut 03",
"44:44:44:44:44:44": "Nut 04",
"55:55:55:55:55:55": "Shelly Rouge",
"66:66:66:66:66:66": "Shelly Bleu",
"77:77:77:77:77:77": "Shelly Blanc",
"88:88:88:88:88:88": "Shelly Noir"
};
let macList = Object.keys(nutsName);
//let nameList = Object.values(nutsName);
let nameList = [];
for (let i=0; i<macList.length; i++) {
nameList.push(nutsName[macList[i]]);
}
if(MQTT.isConnected()) {
MQTT.publish(genericTopic + origine + '/nombreNut', "0", 0, false);
MQTT.publish(genericTopic + origine + '/nameNut', "Vide", 0, false);
MQTT.publish(genericTopic + origine + '/missingNut', "Vide", 0, false);
}
function isMacValid(mac) {
if (mac.length !== 17) {
return false;
}
for (let i=0; i<17; i++) {
if (i%3 === 2) {
if (mac.at(i) !== 0x3a) { //0x3a = :
return false;
}
} else {
//0x30 = 0, 0x39 = 9, 0x61 = a et 0x66 = f
if (mac.at(i) < 0x30 || (mac.at(i) > 0x39 && mac.at(i) < 0x61) || mac.at(i) > 0x66) {
return false;
}
}
}
return true;
}
function sortArray(arr, order) {
let temp;
for (let i = 0; i < arr.length; i++) {
for (let j = i + 1; j < arr.length; j++) {
if ((order === "asc" && arr[i] > arr[j]) || (order === "dsc" && arr[i] < arr[j])) {
temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
}
return arr;
}
function nutList (nuts, nutsName) {
let nutsList = [];
for (let i=0; i<nuts.length; i++) {
nutsList.push(nutsName[nuts[i].mac]);
}
return sortArray(nutsList, "asc");
}
function nutAjout (mac, unixtime, nuts) {
let existePas = 1;
for (let i=0; i<nuts.length; i++) {
if (nuts[i].mac === mac) {
nuts[i].timePublish = unixtime;
existePas = 0;
}
}
if (existePas === 1 && isMacValid(mac)) {
nuts.push({mac: mac, timePublish: unixtime});
}
}
MQTT.subscribe(
genericTopic + "#",
function (topic, message, callback) {
let endTopic = topic.slice(callback[0].length + 18);
if (endTopic === "unixtime") {
let mac = topic.slice(callback[0].length, callback[0].length + 17);
nutAjout (mac, JSON.parse(message), callback[1]);
}
},
[genericTopic, nutsBroker]
);
Timer.set(
10000, //10s
true,
function (callback) {
function checkNut(nut) {
return aList.indexOf(nut) === -1;
}
for (let i=0; i<callback[1].length; i++) {
if (callback[1][i].timePublish + 110 <= Shelly.getComponentStatus("sys").unixtime) {
if(MQTT.isConnected()) {
MQTT.publish(callback[0] + callback[1][i].mac + '/presence', "0", 0, false);
}
}
}
for (let i=0; i<callback[3].length; i++) {
if (callback[3][i].timePublish + 110 <= Shelly.getComponentStatus("sys").unixtime) {
callback[3].splice(i, 1);
let aList = nutList(callback[3], callback[4]);
let aMissing = nameList.filter(checkNut);
aMissing = sortArray(aMissing, "asc");
let missing = aMissing.join('--');
if (missing.length === 0 ) {
missing = "Vide";
}
if(MQTT.isConnected()) {
MQTT.publish(callback[0] + callback[2] + '/nombreNut', JSON.stringify(callback[3].length), 0, false);
MQTT.publish(callback[0] + callback[2] + '/nameNut', aList.join('--'), 0, false);
MQTT.publish(callback[0] + callback[2] + '/missingNut', missing, 0, false);
}
}
}
},
[genericTopic, nutsBroker, origine, nutsShelly, nutsName]
);
function scanCB(ev, res, callback) {
if (ev === BLE.Scanner.SCAN_RESULT) {
if (macList.indexOf(res.addr) !== -1) {
function checkNut(nut) {
return aList.indexOf(nut) === -1;
}
let mac = res.addr;
let topic = callback[0] + mac + '/';
let unixtime = Shelly.getComponentStatus("sys").unixtime;
nutAjout (mac, unixtime, callback[1]);
let aList = nutList(callback[1], callback[3]);
let aMissing = nameList.filter(checkNut);
aMissing = sortArray(aMissing, "asc");
let missing = aMissing.join('--');
if (missing.length === 0 ) {
missing = "Vide";
}
if(MQTT.isConnected()) {
MQTT.publish(topic + 'rssi', JSON.stringify(res.rssi), 0, false);
MQTT.publish(topic + 'unixtime', JSON.stringify(unixtime), 0, false);
MQTT.publish(topic + 'presence', "1", 0, false);
MQTT.publish(topic + 'origine', JSON.stringify(callback[2]), 0, false);
MQTT.publish(callback[0] + callback[2] + '/nombreNut', JSON.stringify(callback[1].length), 0, false);
MQTT.publish(callback[0] + callback[2] + '/nameNut', aList.join('--'), 0, false);
MQTT.publish(callback[0] + callback[2] + '/missingNut', missing, 0, false);
}
}
}
}
BLE.Scanner.Start({ duration_ms: -1}, scanCB, [genericTopic, nutsShelly, origine, nutsName]);
Le bluetooth est activé ?
Tu as aussi modifié le genericTopic. Il faudra laisser le même si tu mets le script sur d’autres shelly.
Oui
Le nut est bien en beacon mode ?
Oui modifié pour tout avoir sous shellies c’est plus clair à lire sous mqtt explorer.
beacon mode quesako ?
il fonctionne et est détecté par mon esp32 sous OMG en tout cas.
Avec OMG :
{"id":"A4:C1:38:C9:8C:61","name":"nutale","rssi":-77,"distance":7.119795,"brand":"nut","model":"Smart Tracker","model_id":"NUTALE","type":"TRACK","device":"nutale Tracker"}
Je n’ai pas d’autres idées à part vérifier que le script est bien lancé.
Oui quand même il est bien lancé.
Moi aussi je vois pas, je n’ai rien dans les logs, quand il scan tu vois passer dans la console en dessous du script ?
Même ton script simple qui scan les mac ne me donne rien. Je suis en firmware 1.3.3 je me demande s’ils ont pas modifié qqchose.