You are currently viewing Présence par tag Xiaomi dans ma domotique Jeedom

Présence par tag Xiaomi dans ma domotique Jeedom

Lien affilié

Xiaomi Smart Tag, Compatible Apple Find My et Google Android Find Hub, traqueur Bluetooth pour clés, Bagages, Sac, Portefeuille ou Animal de Compagnie, IP67, autonomie de Plus d’Un an, Lot de 4

  • À propos de cet article

    • Compatible écosystèmes Apple & Google: Fonctionne avec les services de localisation Apple (Find My) et Google (Find Hub), pour localiser vos objets depuis vos appareils Apple (iPhone, iPad, Mac) et Android, avec une grande précision.
    • Localisation simple et rapide: Placez le Xiaomi Tag dans votre sac à main ou votre portefeuille, ou attachez-le à des objets personnels tels que des clés, des bagues et des valises et retrouvez-les en quelques secondes via l’application compatible.
    • Protection de la vie privée: Données de localisation chiffrées lors de la transmission, pour que vous seul puissiez accéder à l’emplacement du Tag. En cas de détection d’un Tag inconnu vous suivant, une alerte anti-suivi est envoyée.

Je vous avais présenter les XIaomi tag

Voici comment les rendre compatibles à Jeedom

Tuto tasker : (facultatif)

Pour protéger ta vie privée et éviter qu’on puisse te pister dans la rue, ces tags utilisent le « MAC Randomization ». L’adresse MAC change toutes les quelques minutes.

Dans ce cas, filtrer par adresse MAC dans Tasker est impossible.

Mais grace au plugin MQTT DISCOVERY, j’ai pu voir que les 4 premiers caractères ne tournaient pas.

Ainsi, je peux filtrer avec TASKER :

Dans mon cas :

  • Le premier tag commence toujours par C3:80
  • Le second tag commence toujours par C4:02

On peut tout à fait utiliser cette piste dans Tasker ou Jeedom pour « fixer » ces tags malgré leurs changements d’adresses.

Tasker permet d’utiliser des Wildcards (astérisques) dans le champ adresse MAC. Cela permet d’ignorer la fin de l’adresse qui change tout le temps.

Ouvre ton profil Près du Bluetooth.

Créer un profil :

  1. ETAT / Réseau / BT proche

Dans le champ Adresse, saisis :

  1. Pour le premier tag : C3:80:*

Pour le second tag : C4:02:*

(Note : Si tu veux gérer les deux dans le même profil, tu peux mettre C3:80:*/C4:02:* avec un slash, mais il vaut mieux faire deux profils séparés pour savoir quel tag entre ou sort)

Puis créer l’action qui en découle.

Info : rafraîchissement toutes les 10 min

Exemple d’utilisation :

La fonction « Anti-Oubli » (Le Geofencing inversé)

C’est là que Tasker brille :

  • Déclencheur : Ton téléphone se connecte au Bluetooth de ta Voiture.
  • Action : Tasker vérifie si le Tag est « Près ».
  • Utilité : Si le tag n’est pas détecté, ton téléphone crie : « Attention, tu as oublié ton sac à la maison ! ». Tu es prévenu avant même d’avoir quitté l’allée.

1. Préparer la Tâche d’Alerte (« Alerte Oubli »)

On crée d’abord ce que le téléphone doit faire s’il ne voit pas le tag.

  1. Va dans l’onglet Tâches et clique sur +. Nomme-la Alerte Oubli Tag.
  2. Ajoute une action Alerte > Notification :
    • Titre : ⚠️ OUBLI TAG !
    • Texte : Tu as oublié ton tag Xiaomi à la maison !
    • Priorité : Max.
  3. Ajoute une action Alerte > Dire (optionnel mais génial) :
    • Texte : Attention, tu as oublié tes clés !
    • Moteur : Choisis le moteur de synthèse vocale français.

2. Créer le Profil de Surveillance (Le Déclencheur)

C’est ici qu’on définit le moment du contrôle.

  1. Crée un nouveau Profil : État > Réseau > Wi-Fi connecté.
  2. Dans SSID, clique sur la loupe et choisis ton Wi-Fi domestique.
  3. Coche la case Inverser (en bas).
    • Explication : Le profil s’activera quand tu seras DÉCONNECTÉ de ton Wi-Fi (donc quand tu pars).
  4. Tasker te demande une tâche : choisis Nouvelle Tâche (on va l’appeler Controle Presence).

3. Configurer la Tâche de Contrôle

Dans cette tâche Controle Presence, on va vérifier si le tag est à proximité.

  1. Action 1 :Réseau > Bluetooth Info.
    • Type : Nearby Devices (LE).
    • Timeout : 15 secondes (laisse le temps au téléphone de scanner).
  2. Action 2 :Variables > Variable Set.
    • Nom : %tag_present
    • Valeur : 1
    • Condition (If) : %bt_address ~ C3:80:* (ou C4:02:* selon le tag que tu veux surveiller).
  3. Action 3 :Tâche > Exécuter une tâche.
    • Nom : Alerte Oubli Tag (la tâche qu’on a créée au début).
    • Condition (If) : %tag_present n’est pas défini (Is Not Set).

Tuto Jeedom :

Ici nous allons traiter le tag comme un simple tag d’entrée et de sortie.

La contrainte est que je ne peux pas mettre bléa qui aurait facilité l’exploitation, car il me faudrait une 2ᵉ antenne déportée. Je suis en VM.

Plugin JMQTT/ Theen gateway /  Virtuel et scénario.

Le plugin theen gateway doit être configuré avec nom et mot de passe. (pour eviter les surchages)

Le plugin JMQTT :

Vous devez créer un équipement. Xiaomi Tags

Trouver le bon topic : pour moi : home/TGW_2185/BTtoMQTT/#

Puis créer une commande : tag : info/ autre : home/TGW_2185/BTtoMQTT/

Le virtuel :

Une commande info Binaire nommée : Présence  ici 36963 après sauvegarde

Une commande info Numérique :  RSSI ici 36965

Une autre commande info numérique : Batterie (ne fonctionne pas pour le moment) 

Attention les noms des commandes doivent être identique pour le code PHP.

Le scénario de recherche :

Adapter les 4 premières lignes selon votre commande JMQTT et virtuel.

// ─── IDs de configuration ────────────────────────────────────────────
const ID_EQUIPEMENT = 4115;
const ID_CMD_PRESENCE = 36963;
const ID_CMD_RSSI = 36965;
const PREFIXE_TAG = ‘C3:80’;
const NOM_TAG = ‘Xiaomi Tag’;
const DELAI_PRESENCE = 120; // secondes

// ─── Fonctions utilitaires ────────────────────────────────────────────
function sendEvent($cmdId, $value): void {
$cmd = cmd::byId($cmdId);
if (!is_object($cmd)) {
return;
}
$cmd->event($value);
}

function isCmdRecente($cmd, int $delaiMax): bool {
$collectDate = trim((string) $cmd->getCollectDate());
if ($collectDate ===  ») {
return false;
}
$lastUpdate = strtotime($collectDate);
return $lastUpdate !== false
&& $lastUpdate > 0
&& (time() – $lastUpdate) <= $delaiMax;
}

function parseTagData($cmd): ?array {
$msg = trim((string) $cmd->execCmd());
if ($msg ===  ») {
return null;
}
$data = json_decode($msg, true);
return is_array($data) ? $data : null;
}

function isTagCible(array $data, string $nom, string $prefixe): bool {
return ($data[‘name’] ??  ») === $nom
&& str_starts_with($data[‘id’] ??  », $prefixe);
}

// ─── Script principal ─────────────────────────────────────────────────
$eq = eqLogic::byId(ID_EQUIPEMENT);
if (!is_object($eq)) {
$scenario->setLog(‘Equipement Xiaomi Tags introuvable’);
return;
}

$tagTrouve = false;

foreach ($eq->getCmd(‘info’) as $cmd) {
if (!isCmdRecente($cmd, DELAI_PRESENCE)) {
continue;
}
$data = parseTagData($cmd);
if ($data === null || !isTagCible($data, NOM_TAG, PREFIXE_TAG)) {
continue;
}

sendEvent(ID_CMD_PRESENCE, 1);
if (isset($data[‘rssi’]) && is_numeric($data[‘rssi’])) {
sendEvent(ID_CMD_RSSI, (int) $data[‘rssi’]);
}
$scenario->setLog(sprintf(
‘Tag %s détecté : %s | RSSI=%s | CollectDate=%s’,
PREFIXE_TAG,
$data[‘id’],
$data[‘rssi’] ?? ‘n/a’,
$cmd->getCollectDate()
));

$tagTrouve = true;
break;
}

if (!$tagTrouve) {
sendEvent(ID_CMD_PRESENCE, 0);
$scenario->setLog(‘Tag ‘ . PREFIXE_TAG . ‘ absent’);
}

Le scénario de nettoyage :

const EQUIPMENT_ID    = 4115;
const MAX_AGE_DAYS    = 2;
const TAG_ROOT_NAME   = 'tag';
const XIAOMI_TAG_NAME = 'Xiaomi Tag';
const XIAOMI_UUID     = 'feaa';

$eq = eqLogic::byId(EQUIPMENT_ID);
if (!is_object($eq)) {
    $scenario->setLog('Equipement ' . EQUIPMENT_ID . ' introuvable');
    return;
}

// Sans filtre 'info' — inexploitable sur ce plugin
$cmds      = $eq->getCmd();
$maxAge    = MAX_AGE_DAYS * 86400;
$toDelete  = [];
$nbGardees = 0;

$scenario->setLog('Début nettoyage | Total commandes=' . count($cmds));

foreach ($cmds as $cmd) {
    $cmdId   = $cmd->getId();
    $cmdName = trim((string) $cmd->getName());

    if ($cmdName === TAG_ROOT_NAME) {
        $nbGardees++;
        continue;
    }

    // execCmd() est la seule méthode qui retourne les données
    $rawValue    = trim((string) ($cmd->execCmd() ?? ''));
    $collectDate = trim((string) $cmd->getCollectDate());

    if ($rawValue === '' || $collectDate === '') {
        $toDelete[] = ['cmd' => $cmd, 'reason' => 'vide', 'id' => $cmdId, 'name' => $cmdName];
        continue;
    }

    $data = json_decode($rawValue, true);

    if (!is_array($data)) {
        $toDelete[] = ['cmd' => $cmd, 'reason' => 'JSON invalide', 'id' => $cmdId, 'name' => $cmdName];
        continue;
    }

    if (($data['name'] ?? '') !== XIAOMI_TAG_NAME) {
        $toDelete[] = ['cmd' => $cmd, 'reason' => 'non Xiaomi Tag (name=' . ($data['name'] ?? 'inconnu') . ')', 'id' => $cmdId, 'name' => $cmdName];
        continue;
    }

    if (strtolower((string) ($data['servicedatauuid'] ?? '')) !== XIAOMI_UUID) {
        $toDelete[] = ['cmd' => $cmd, 'reason' => 'UUID inattendu', 'id' => $cmdId, 'name' => $cmdName];
        continue;
    }

    $lastUpdate = strtotime($collectDate);

    if ($lastUpdate === false || $lastUpdate <= 0) {
        $toDelete[] = ['cmd' => $cmd, 'reason' => 'date invalide', 'id' => $cmdId, 'name' => $cmdName];
        continue;
    }

    if ((time() - $lastUpdate) > $maxAge) {
        $toDelete[] = [
            'cmd'    => $cmd,
            'reason' => 'trop ancien (dernière vue=' . $collectDate . ')',
            'id'     => $cmdId,
            'name'   => $cmdName,
        ];
        continue;
    }

    $nbGardees++;
}

foreach ($toDelete as $entry) {
    $scenario->setLog(
        'Suppression [' . $entry['reason'] . '] : ID=' . $entry['id'] . ' | Nom=' . $entry['name']
    );
    $entry['cmd']->remove();
}

$scenario->setLog(
    'Nettoyage terminé | Gardées=' . $nbGardees . ' | Supprimées=' . count($toDelete)
);

Utilisation :

Ensuite on fait récupère la variable présence du virtuel :

On crée un widget simple qu’on applique à la commande.

Xiao Nico

Je suis l'erreur 404 du domaine de l'informatique, je recherchais une alarme suite à un cambriolage et je me suis retrouvé avec une alarme Xiaomi dans les mains. J'ai aimé, je me suis fait plein de copains et on s'éclate ! Mon but est de partager un max et surtout expliquer et aider les débutants comme je l'ai été. Donc toi qui ne comprends rien aujourdh'hui, ne t'inquiète pas j'étais comme toi ;) Me payer un café https://www.paypal.me/XiaoNico