Shelly Gen2 et scripts dont antenne bluetooth pour Nut et modules "beacon compatible"

Ça semble bouger chez Shelly.

Capture d’écran du 2023-11-14 18-26-29

J’aime beaucoup ton idée d’utiliser les shelly comme des antennes de présence :wink: 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 :slight_smile: gg :slight_smile:

1 « J'aime »

Le firmware 1.1.0 vient de sortir, il permet de retrouver le fonctionnement normal du script.

1 « J'aime »

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 ! :wink:

1 « J'aime »

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 !

1 « J'aime »

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?

Capture d’écran du 2024-02-11 11-14-36

date('d/m/Y H:i:s', #value#)

A partir de la version 4.4.

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]);