Stéphane.
AutomationArchivé

MyGlassBox — un miroir connecté, du prototype au produit

Quatre mois pour porter un miroir sans tain au stade du produit : Raspberry Pi en kiosque, point d’accès Wi-Fi embarqué, back-office PHP et applications mobiles. Ce qui a tenu, ce qui n’aurait pas dû.

Technologies employées

  • Raspberry Pi
  • Raspbian
  • PHP 5
  • MySQL
  • Apache
  • hostapd
  • dnsmasq
  • Midori
  • Matchbox
  • Android
  • iOS
  • jQuery

D’octobre 2016 à février 2017, j’ai tenté de transformer une idée en produit : un miroir sans tain doublé d’un écran, qui affiche la météo, les messages, les rappels et les photos qu’on lui envoie depuis un téléphone. Pas seulement le code — le matériel, l’image système, les applications mobiles, la brochure, l’étude de coûts et le modèle économique. Le projet s’est arrêté avant la commercialisation. Ce qui reste est un objet qui fonctionnait vraiment, une architecture réseau dont je suis toujours satisfait, et une poignée de décisions que je regarde aujourd’hui avec beaucoup moins d’indulgence.

L’objet

Une glace sans tain devant une dalle d’écran : là où l’écran est noir, on voit son reflet ; là où il affiche du blanc, le texte traverse la glace et semble flotter dans le miroir. Tout l’effet tient dans ce contraste, et donc dans une interface presque entièrement noire.

Glace sans tain montée dans un cadre d’aluminium noir, posée à la verticale sur un bloc de mousse blanche ; un ruban de LED adhésif court le long du bord inférieur intérieur.
Le prototype de novembre 2016, encore sur sa mousse d’emballage. Le ruban de LED collé au bord inférieur sert d’alerte visuelle : le miroir peut prévenir sans rien afficher.

Derrière la glace : un Raspberry Pi, un module L298N pour piloter le ruban de LED, un capteur de température et d’humidité, un capteur tactile capacitif collé au dos de la vitre, deux haut-parleurs, une clé Wi-Fi et une alimentation commune répartie par bornes à levier.

Plan de câblage : au centre un Raspberry Pi et le brochage complet de son connecteur GPIO, relié à un module L298N, un capteur tactile, un capteur de température, deux haut-parleurs, un ruban de LED RVB, une dalle d’écran en HDMI et une alimentation secteur répartie par bornes à levier.
Le plan de câblage du produit, celui qui servait à monter un exemplaire. C’est ce document — et pas le code — qui a le plus servi à l’assemblage.

Le problème que personne ne voit dans une démo

Un miroir connecté est vendu à un particulier, donc installé derrière une box Internet. Aucune adresse publique, aucun port ouvert, aucune redirection à demander au client — un produit grand public ne peut pas exiger que l’acheteur configure son routeur.

Or le back-office doit pouvoir agir dessus : régler le volume, couper le son, redémarrer, lancer une vidéo. Comment commander un appareil qu’on ne peut pas joindre ?

Canal de commande du miroir MyGlassBoxL’application mobile agit sur le back-office, qui écrit une commande dans une colonne de la base de données. Le miroir, installé derrière une box domestique, ne reçoit aucune connexion : il interroge le serveur, reçoit la commande et l’exécute dans son navigateur. La commande stockée est une chaîne de JavaScript.applicationAndroid · iOSback-officePHP · sessiontable t_system01colonne « command »une chaîne JavaScriptmiroirRaspberry Pi · Midoriderrière une boxécriventinterrogerenvoie la commande<script> … </script>exécuté par le navigateurvolume, coupure du son, redémarrage, lecture vidéo
Aucune connexion entrante vers le miroir : c’est lui qui interroge le serveur. Ce qui transite est du JavaScript stocké en base, réinjecté tel quel dans la page.

La réponse retenue inverse le sens : le miroir interroge le serveur, jamais l’inverse. Le back-office se contente d’écrire la commande dans une colonne d’une table, et le miroir la récupère à son rythme. C’est la bonne réponse, et c’est encore celle que je donnerais aujourd’hui — le principe est exactement celui d’un agent qui tire sa configuration depuis un point central.

Un ordre aurait dû être un mot dans une liste fermée — volume:70, reboot — que le miroir traduit lui-même en action. Le code livré transportait le comportement au lieu de transporter l’intention. C’est la différence entre une commande et une injection, et elle tient dans le vocabulaire employé.

Le point d’accès embarqué

La décision dont je suis le plus satisfait ne concerne pas l’application, mais le premier démarrage.

À la sortie du carton, le miroir n’a aucun réseau, aucun clavier et un écran qu’on ne peut pas toucher. Il démarre donc son propre point d’accès Wi-Fi, nommé MYGLASSBOX- suivi de quatre caractères aléatoires, avec hostapd et dnsmasq, un serveur DHCP sur une plage de quatre adresses et un nom local résolu sur le Pi lui-même. L’acheteur s’y connecte depuis son téléphone, ouvre une page, saisit les identifiants de sa box, et le miroir bascule sur le réseau domestique.

C’est un mécanisme d’appairage classique aujourd’hui ; en 2016, dans un projet mené seul, en avoir vu la nécessité reste ce dont je suis le plus content.

L’affichage : un navigateur en kiosque

Il n’y a pas d’application graphique. Le miroir affiche une page web servie en local, dans un navigateur sans aucun ornement.

ÉlémentChoix retenuCe qu’il apportait
Gestionnaire de fenêtresMatchboxAucune décoration, aucune barre : la page occupe la dalle
NavigateurMidoriLéger, suffisant pour du DOM et de l’AJAX sur un Pi
CurseurunclutterLe pointeur disparaît — un miroir n’a pas de souris
Entrées simuléesxdotool, xautomationRejouer une frappe pour relancer l’affichage
ServeurApache et PHP en localLa page est servie par la machine qui l’affiche
Sonmpg321Lecture des musiques et des radios sans interface

Chaque bloc de l’écran est un petit script PHP interrogé séparément : un pour la météo, un pour la température, un pour les messages, un pour les rappels. La page les rappelle en boucle et remplace le fragment correspondant. Découpage sommaire, mais il a une vertu réelle : la panne d’un bloc n’emporte pas l’écran. Si la météo ne répond pas, le reste continue de s’afficher.

Ce qui n’allait pas

Le code de 2017 comporte des défauts que je ne laisserais passer sur aucune revue aujourd’hui, et il vaut mieux les nommer.

Les identifiants de la base sont écrits en clair dans chaque fichier, et recopiés d’un fichier à l’autre — le même script ouvre parfois trois connexions successives avec les mêmes paramètres répétés à l’identique. Une inclusion partagée existait pourtant déjà dans le projet ; elle n’a pas été utilisée partout.

Les requêtes sont construites par concaténation. L’adresse e-mail et l’identifiant de l’appareil arrivent de la session ou de l’URL et sont insérés directement dans le SQL. Les requêtes préparées existaient en PHP 5 depuis des années ; je ne les ai pas employées.

L’authentification tient dans un jeton passé en paramètre d’URL, comparé à une valeur unique lue en base — la même pour tous les appareils. Un identifiant d’appareil dans l’adresse suffisait ensuite à désigner le compte associé.

Le déploiement passait par un FTP en clair, dont les identifiants figurent dans le script d’installation exécuté sur chaque miroir. Le même script élargit les droits du serveur web au maximum et lui accorde sudo sans mot de passe.

Le produit autour du code

La partie que je sous-estimais complètement en commençant, c’est tout ce qui n’est pas du code. Sur quatre mois, une bonne moitié du temps y est passée : étude des coûts de fabrication, grille tarifaire, contrat de vente, politique de conservation des données, choix du nom commercial, brochure, visuels pour les deux magasins d’applications, préparation d’une campagne de financement participatif, et deux applications mobiles empaquetées.

Le modèle économique visé était celui qu’on appelle hardmium : vendre l’objet à prix coûtant ou presque, parce que sa vraie fonction est de rendre un service qui, lui, fidélise. J’avais noté à l’époque le risque principal de ce modèle — que l’objet soit détourné de son service — et c’est bien ce qui rendait l’équation fragile pour un miroir dont la valeur perçue reste celle d’un meuble.

Le projet s’est arrêté là, avant la mise en vente. Un prototype fonctionnel, une chaîne complète, et pas de marché démontré.

Enseignements

  1. Un appareil vendu à un particulier vit derrière une box : il tire sa configuration, il ne la reçoit pas. Le principe reste valable, c’est sa mise en œuvre qui était fautive.
  2. Une commande doit transporter une INTENTION prise dans une liste fermée, jamais un comportement exécutable. Écrire du JavaScript en base, c’est confondre les deux.
  3. Prévoir l’appairage avant le réseau : un point d’accès embarqué au premier démarrage est ce qui rend un objet connecté installable par son acheteur.
  4. Découper l’affichage en fragments indépendants évite qu’une source défaillante n’efface tout l’écran — la seule vertu du découpage sommaire de l’époque.
  5. Savoir qu’une rustine est une rustine ne la rend pas acceptable : mes propres commentaires signalaient les droits trop larges, et j’ai livré quand même.
  6. Sur un projet de produit, le code n’est qu’une moitié du travail. L’autre moitié — coûts, contrat, données, distribution — décide autant du résultat.

Ce projet est le plus ambitieux que j’aie mené seul, et le seul qui soit allé jusqu’à la brochure et au plan de financement. Il n’a pas trouvé son marché, mais c’est lui qui m’a fait passer du code à l’exploitation : un objet posé chez quelqu’un doit démarrer sans moi, se raccorder sans moi, se réparer sans moi, et ne pas devenir une porte d’entrée chez son propriétaire. Ces quatre exigences décrivent assez bien ce que je fais aujourd’hui.