Transformez une roue IKEA LUSTIGT en une roue connectĂ©e WiFi 🎡

Transformez une roue IKEA LUSTIGT en une roue connectĂ©e WiFi 🎡

Chez Premier Octet, bien que nous soyons spĂ©cialisĂ©s dans le dĂ©veloppement d’applications React et React Native, rien ne nous empĂȘche de nous glisser sporadiquement dans le trĂ©pident domaine de l’IoT. Il y a quelques semaines, je me suis rendu chez IKEA pour y acheter des panneaux SKÅDIS et manger des hot-dogs 🌭. Comme l’impose la conception architecturale d’un IKEA, je suis passĂ© par tous les endroits possibles et imaginables du magasin et notamment celui des enfants, pour tomber nez Ă  nez avec LUSTIGT, une “roue de la chance” en bois. Ni une, ni deux, je me suis dit qu’il fallait ✹ la connecter Ă  Internet ✹.

Quelques hot-dogs plus tard, je repars donc, avec LUSTIGT (et SKÅDIS) dans les bras avec la ferme intention de hacker ce beau jouet.

TL;DR



Trouver le hack

Les choses sĂ©rieuses commencent : dans l’idĂ©al je souhaite pouvoir dĂ©clencher un webhook contenant la valeur de la case une fois la roue tournĂ©e. J’envisage donc d’utiliser 24 Ă©metteurs pour chaque case ainsi qu’un capteur maĂźtre pour les lire. Ils doivent ĂȘtre sans fil en raison de la mobilitĂ© de la roue. Le capteur maĂźtre doit lire les valeurs et les envoyer via une connexion WiFi. Autre contrainte, les Ă©metteurs sur la roue doivent ĂȘtre assez fins : l’espace Ă©tant infĂ©rieur Ă  2cm


Cela semble le job parfait pour du RFID !

La RFID

La RFID utilise des champs Ă©lĂ©ctro-magnĂ©tiques pour identifier des tags. Ceux-ci contiennent une puce Ă©lectronique leur permettant de recevoir et de rĂ©pondre aux requĂȘtes radio Ă©mises depuis l’émetteur. Les tags existent sous de nombreuses formes : cartes, porte-clĂ©s, badges mais aussi sous forme de stickers. Ces-derniers sont idĂ©aux pour ce projet, car ils sont :

  • TrĂšs fins (< 1mm) ;
  • Passifs (auto-alimentĂ©s par le champ radio) ;
  • Facilement positionnables ;
  • Peu onĂ©reux (environ 20€ les 50 stickers).

L’idĂ©e est donc de coller 24 stickers derriĂšre chaque case de la roue et d’ajouter un lecteur RFID Ă  sa base. Et pour envoyer les donnĂ©es Ă  Internet ? Un Photon !

Le Photon

Il y a 4 ans, j’ai dĂ©couvert le Photon : je n’ai depuis plus utilisĂ© d’Arduino. Comme ce-dernier, le Photon est un micro-contrĂŽleur avec beaucoup d’avantages :

  • WiFi embarquĂ© ;
  • Facilement programmable (comme l’Arduino) ;
  • MĂȘme PINs que l’Arduino ;
  • Accessible via une API ;
  • Web based IDE ;
  • TrĂšs bonne documentation ;
  • Open-source ;
  • Petit et accessible ($19).

Le Photon va nous permettre de contrĂŽler le systĂšme RFID et d’envoyer les donnĂ©es Ă  Internet.

Matériel nécessaire

Voici la liste du matĂ©riel nĂ©cessaire, comptez environ 60€ pour le tout :

Matériels

Et comme autres outils (que vous devriez avoir sous la main) :

  • Fer Ă  souder ;

  • Du double face ;

  • Une alimentation 5V micro USB (type Raspberry).

Le montage du hardware

Le montage est facile : il s’agit uniquement de souder les headers sur votre carte RFID afin de la connecter facilement au Photon. Pour cela insĂ©rez le header (celui coudĂ©) dans les slots de la carte RC522, et faites-y 6 points de soudure :

Matériels

Brancher les cartes

Une fois le header soudé, vous pouvez relier la carte RFID à votre Photon, pour cela utilisez les cùbles femelles en suivant ce schéma :

Function     RC522 Pin     Photon Pin
-------------------------------------
Reset        RST           D2
SPI SS       SDA           D1
SPI MOSI     MOSI          A5
SPI MISO     MISO          A4
SPI SCK      SCK           A3
IRQ          IRQ           -
GROUND       GND           GND
POWER        3.3V          3.3V # 🚹 Not 5V!

PCB

Attention, la carte RFID ne supporte pas le 5v, veillez à bien la brancher sur la pin 3.3V du Photon. Je me suis limité à ce montage qui est trÚs simple, pour les plus assidus vous pouvez créer votre propre PCB en passant par exemple par Eagles.

Configurer votre Photon

Si vous n’avez pas encore configurĂ© votre Photon, suivez les instructions sur https://setup.particle.io :

PCB

Une fois votre Photon connecté à Internet et configuré, il est temps de faire un peu de collage


Coller les stickers RFID

La stack hardware est prĂȘte, il nous faut maintenant coller nos stickers RFID derriĂšre chaque case de la roue. Veillez Ă  bien les placer au centre des deux bĂątons Ă  chaque fois pour Ă©viter des collisions d’UID lors de la lecture des tags.

Matériels

Fixer la carte RFID

Il ne reste plus qu’à fixer la carte RC522 sur la base de la roue, pour cela j’ai simplement utilisĂ© du double face et fixĂ© le Photon derriĂšre :

Montage

Code cÎté hardware

Il est maintenant temps de coder ! Nous allons envoyer notre programme Ă  notre Photon afin de piloter notre stack RFID. Si vous n’ĂȘtes pas familier avec l’écosystĂšme de Particle, sachez qu’il dispose d’un IDE en ligne permettant d’envoyer vos sketchs (au format .ino) directement sur votre Photon via le WiFi.

Lecture des tags UID

Il existe dĂ©jĂ  une librairie pour s’interfacer avec le module RFID, vous n’avez donc qu’à l’ajouter puis l’importer dans votre projet.

Voici le code minimal pour lire les UIDs de chaque tag :

#include "MFRC522/MFRC522.h"
#define SS_PIN D1
#define RST_PIN D2

MFRC522 mfrc522(SS_PIN, RST_PIN);

void setup() {
  mfrc522.setSPIConfig();
  mfrc522.PCD_Init();
}

void loop() {
  if (!mfrc522.PICC_IsNewCardPresent() && !mfrc522.PICC_ReadCardSerial()) {
    return
  }

  String UID = "";

  for (byte i = 0; i < mfrc522.uid.size; i++) {
    UID += String(mfrc522.uid.uidByte[i] < 0x10 ? "0" : "");
    UID += String(mfrc522.uid.uidByte[i], HEX);
  }

  mfrc522.PICC_HaltA();
  Particle.publish("WHEEL_VALUE", UID, 5, PRIVATE);
}

Le cloud Particle nous permet de partager facilement des donnĂ©es via la mĂ©thode Particle.publish(). Une fois publiĂ© vous pouvez voir l’évenement WHEEL_VALUE dans la partie event de la console :

Event dahsboard

Vous pouvez alors tourner votre roue afin de lire un par un les UIDs de vos tags et les classer par ordre croissant dans un tableau :

String wheelCases[] = {
    "044653120a3c80", // case 1
    "043653120a3c80",
    "04513d92ec5a80",
    "043c4892ec5a81",
    "04374892ec5a81",
    "04454792ec5a81",
    "043f4e92ec5a81",
    "04244e92ec5a81",
    "04414892ec5a81",
    "04294e92ec5a81",
    "042e4e92ec5a81",
    "04354e92ec5a81", // case 12
    "043a4e92ec5a81",
    "04444e92ec5a81",
    "046f4e92ec5a81",
    "044c4c92ec5a81",
    "045f4392ec5a80",
    "04484d92ec5a81",
    "04e64992ec5a80",
    "04514c92ec5a81",
    "04564c92ec5a81",
    "04f04992ec5a80",
    "043e53120a3c80",
    "042d53120a3c80" // case 24
};

AprĂšs cette tĂąche un peu fastidieuse, nous allons amĂ©liorer notre code afin qu’il n’envoie un Ă©vĂ©nement uniquement lorsque la roue s’arrĂȘte de tourner (une sorte de debouncing).

Implémenter la logique

Voici mon algo pour envoyer uniquement la derniĂšre valeur : lorsque aucune valeur n’a Ă©tĂ© lue depuis 1s, nous publions l’évenement avec Particle.publish(). Je publie Ă©galement un Ă©venement SPINNING afin de rajouter un feedback cĂŽtĂ© UI :

#include "MFRC522/MFRC522.h"
#define SS_PIN D1
#define RST_PIN D2

MFRC522 mfrc522(SS_PIN, RST_PIN); // Create MFRC522 instance.

String wheelCases[] = {
   // Ajouter votre mapping d'UIDs (voir ci-dessus)
};

long chrono = 0;
long debounceDelay = 1000;

bool isInit = true;
bool isSpinning = false;

String valueToCommit = "";

void setup() {
  mfrc522.setSPIConfig();
  mfrc522.PCD_Init();
}

void loop() {
    if (mfrc522.PICC_IsNewCardPresent() && mfrc522.PICC_ReadCardSerial()) {
        if (!isSpinning) {
            Particle.publish("SPINNING", "true", 5, PRIVATE);
            isSpinning = true;
        }

        String UID = "";
        String label = "";

        for (byte i = 0; i < mfrc522.uid.size; i++) {
          UID += String(mfrc522.uid.uidByte[i] < 0x10 ? "0" : "");
          UID += String(mfrc522.uid.uidByte[i], HEX);
        }

        mfrc522.PICC_HaltA();

        for (int i=0; i<24; i++){
            if (wheelCases[i] == UID){
                label = i + 1;
            }
        }

        if (!isInit) {
            valueToCommit = label;
            chrono = millis();
        }

        isInit = false;
    }

    if (valueToCommit != "" && (millis() - chrono) > debounceDelay) {
        Particle.publish("WHEEL_VALUE", valueToCommit, 5, PRIVATE);
        Particle.publish("SPINNING", "false", 5, PRIVATE);

        valueToCommit="";
        isSpinning = false;
    }
}

Applications

Notre roue est prĂȘte ! Elle envoie dĂ©sormais un Ă©venement SPINNING dĂšs que la roue tourne et la valeur de la derniĂšre case via l’évenement WHEEL_VALUE. Il est maintenant temps d’utiliser ces Ă©venements !

Hook everything

Grùce à la platforme Particle Web, nous pouvons facilement lier des évenements à des webhooks grùce à la partie intégration de la Particle Console :

Particle Console

Nous pouvons ainsi poster la valeur tirĂ©e au sort sur Slack en appelant un incoming webhook lors d’un Ă©venement WHEEL_VALUE.

Autre bonne nouvelle : IFTTT offre une intĂ©gration de la platforme Particle permettant de connecter n’importe quel Ă©venement Ă  l’ensemble des services IFTTT : Slack, Google Doc, Twitter
 Comme par exemple, insĂ©rer la valeur de chaque tirage dans un Google spreadsheet, ou bien la tweeter :

IFTTT Console

Application React

Chez Premier Octet, le React c’est notre dada
 Nous n’allions pas passer Ă  cĂŽtĂ© d’une occasion de dĂ©velopper une application affichant le rĂ©sultat de notre tirage en temps rĂ©el !

Particle met Ă  disposition une librairie JS permettant d’utiliser le Particle Cloud : particle-api-js. Nous allons donc pouvoir souscrire Ă  nos Ă©venements SPINNING et WHEEL_VALUE avec la mĂ©thode getEventStream() :

import React, { Component } from 'react';
import Particle from 'particle-api-js';

const DEVICE_ID = 'XXXXX';
const TOKEN = 'XXXXX';
const particle = new Particle();

class App extends Component {
  state = { isSpinning: false, event: null };

  componentDidMount() {
    particle.getEventStream({ deviceId: DEVICE_ID, auth: TOKEN }).then(stream => {
      stream.on('event', event => {
        if (event.name === 'SPINNING') {
          this.setState({ isSpinning: true });
        } else if (event.name === 'WHEEL_VALUE') {
          this.setState({ event: event.data, isSpinning: false });
        }
      });
    });
  }

  render() {
    return (
      <div className="app">
        <div className="caption">
          {this.state.isSpinning ? (
            <span>✹ Spinning ✚</span>
          ) : (
            <>{this.state.event ? <span>đŸ•ș {this.state.event} đŸ•ș</span> : <span>Spin the wheel! đŸ€žâ€â™€ïž</span>}</>
          )}
        </div>
      </div>
    );
  }
}

Nous affichons maintenant la derniĂšre valeur sur laquelle s’est arretĂ©e la roue. C’est bien mais l’idĂ©e initiale est de pouvoir tirer au sort une valeur parmi un groupe de choix : restaurants, noms de personnes


Nous allons donc créer un spreadsheet sur Google Doc afin de pouvoir mapper nos cases à nos labels. Il suffit de créer un classeur pour chaque jeu de données (foods, users) :

Google spreadsheets


 et de les lier grĂące Ă  l’API de Google Spreadsheet (nĂ©cessite de crĂ©er une clĂ© d’API) :

const API_KEY = 'xx';
const SPREADSHEET_ID = 'xx';
const SHEET_NAME = 'food';

loadLabels = async () => {
  const data = await fetch(
    `https://sheets.googleapis.com/v4/spreadsheets/${SPREADSHEET_ID}/values/${SHEET_NAME}!a1:a26?key=${API_KEY}`,
  ).then(res => res.json());

  return data.values;
};

Vous pouvez ensuite ajouter dans votre UI, un select pour choisir le jeu de donnĂ©es voulu avant de lancer la roue 🎡. Retrouvez le code complet sur le repository GitHub.

Hack hack hack

Connectez la roue IKEA LUSTIGT aux Internets a Ă©tĂ© drĂŽlement intĂ©ressant, j’ai Ă©tĂ© surpris que tout ce beau monde s’imbrique correctement et marche du premier coup
 Si vous en avez encore sous le pied, vous pouvez aller encore plus loin :

  • ajouter un feedback sur la roue lorsqu’elle tourne (LED, musique
) ;
  • faire une intĂ©gration plus propre du Photon et de la board RFID sur la roue (👋imprimante 3D) ;
  • trouver d’autres applications !

Si vous montez votre propre roue, envoyez-nous vos photos et applications !

Happy hacking ! 🎈

Continuer la discussion sur Twitter