Ne verrouillez pas votre code sur un nom de modèle!

Ne verrouillez pas votre code sur un nom de modèle!

Depuis le premier jour, la documentation Yoctopuce insiste sur le fait que l'API d'un module Yoctopuce et ses fonctionnalités sont décorrélées à dessein, au point que l'on peut travailler avec des fonctionnalités Yoctopuce sans avoir à se préoccuper du module qui les héberge. Autrement-dit, il n'est pas nécessaire de chercher un module particulier pour utiliser une de ses fonctionnalités. En fait, c'est même assez contre-indiqué...

Avec la généralisation des versions USB-C, on commence à recevoir des emails de clients un peu étonnés de constater que le module USB type-C, qu'ils ont acheté pour remplacer un vieux module au format Micro-B, ne fonctionne pas avec leur application alors qu'on avait promis que les versions USB-C et Micro-B seraient compatibles.

Le problème

A chaque fois, si l'on se penche un peu sur leur code, on remarque immédiatement qu'il est verrouillé d'une manière ou d'une autre sur un nom ou un identifiant de modèle. Car voyez-vous, bien que fonctionnellement identiques, les versions USB-C et Micro-B de chaque module ont un nom et un identifiant de modèle différents. C'est, entre autres, ce qui vous permet de les différencier au moment où vous les achetez...

Ces deux Yocto-Temperature sont 100% compatibles, mais ils n'ont pas le même nom
Ces deux Yocto-Temperature sont 100% compatibles, mais ils n'ont pas le même nom


Raisonnons avec un petit exemple pratique: imaginons que vous ayez un simple Yocto-Temperature utilisé pour mesurer la température ambiante. Vous pourriez être intuitivement tentés d'écrire votre code de surveillance de la température de cette manière:

sensor : YTemperature = None
module : YModule = YModule.FirstModule()
while not (module is None):
 if module.get_productId()=="TMPSENS1":
   serial:str = module.get_serialNumber()
   sensor = YTemperature.FindTemperature(serial+".temperature")
 module =module.nextModule()
if sensor is None : sys.exit("Yocto-Temperature introuvable")
if not sensor.isOnline() : sys.exit("Yocto-Temperature hors ligne")
print("Temperature = %2.1f %s"%(sensor.get_currentValue(),sensor.get_unit()))


Où encore comme ça:

sensor : YTemperature = None
module : YModule = YModule.FirstModule()
while not (module is None):
 if module.get_productName()=="Yocto-Temperature":
   serial:str = module.get_serialNumber()
   sensor = YTemperature.FindTemperature(serial+".temperature")
 module =module.nextModule()
if sensor is None : sys.exit("Yocto-Temperature introuvable")
if not sensor.isOnline() : sys.exit("Yocto-Temperature hors ligne")
print("Temperature = %2.1f %s"%(sensor.get_currentValue(),sensor.get_unit()))


Ces deux bouts de code sont implicitement verrouillés sur un Yocto-Temperature et ne fonctionneront pas avec un Yocto-Temperature-C dont le nom et l'identifiant de modèle sont différents.

La solution bon marché

Si votre code est déjà écrit et que vous devez le corriger en vitesse avant que vos propres clients ne vous sautent à la gorge, vous pouvez vous en tirer à bon compte en modifiant une seule ligne de votre code, qui se mettra alors à fonctionner avec le Yocto-Temperature-C.

sensor : YTemperature = None
module : YModule = YModule.FirstModule()
while not (module is None):
 # correction rapide et un peu honteuse  
 if module.get_productName().startswith("Yocto-Temperature"):
   serial:str = module.get_serialNumber()
   sensor = YTemperature.FindTemperature(serial+".temperature")
 module =module.nextModule()
if sensor is None : sys.exit("Yocto-Temperature introuvable")
if not sensor.isOnline() : sys.exit("Yocto-Temperature hors ligne")
print("Temperature = %2.1f %s"%(sensor.get_currentValue(),sensor.get_unit()))



Notez cependant que ce code, même amélioré, ne vous permettra pas de remplacer vos Yocto-Temperature et Yocto-Temperature-C avec un autre type de capteur de température, comme un Yocto-PT100, alors que l'API est justement pensée pour que cela soit possible.

La solution recommandée

En fait, vous n'avez pas besoin d'écrire du code aussi compliqué. Il est possible et même recommandé de récupérer votre fonction YTemperature sans même faire référence à son module. Si vous êtes sûr qu'il n'y a qu'un seul capteur de température dans votre système vous pouvez vous contenter d'écrire ça:

sensor : YTemperature = YTemperature.FirstTemperature()
if sensor is None : sys.exit("Yocto-Temperature introuvable")
if not sensor.isOnline() : sys.exit("Capteur de température hors ligne")
print("Temperature = %2.1f %s"%(sensor.get_currentValue(),sensor.get_unit()))



Évidement s'il y a plusieurs capteurs du même type dans votre système, c'est un problème parce que vous ne savez pas trop lequel YXxx.FirstXxxx() va vous retourner. C'est particulièrement flagrant dans le cas des capteurs de température qui sont présents dans de nombreux modules.

La solution que Yoctopuce recommande, c'est de donner un nom logique aux fonctions utiles à votre système et d'utiliser ce nom pour les retrouver. Vous pouvez faire ça manuellement avec le VirtualHub:

Configuration d'un nom logique avec le VirtulaHub
Configuration d'un nom logique avec le VirtulaHub


Ou, si vous montez des systèmes à la chaîne, vous pouvez aussi écrire un petit utilitaire qui pré-configure vos modules à chaque fois que vous lui en présentez un, voici un exemple très simplifié qui affecte automatiquement le nom logique "T_ambient" à la fonction temperature de chaque Yocto-Temperature(-C) qu'on connecte à la machine qui le fait tourner. Notez que ce code est, à dessein, lié au nom de modèle.

import sys
from yoctolib.yocto_api import YRefParam, YAPI,YModule
from yoctolib.yocto_temperature import YTemperature

def arrival(m:YModule):
  if m.get_productName().startswith("Yocto-Temperature"):
    serial : str =  m.get_serialNumber()
    feat : YTemperature = YTemperature.FindTemperature(serial+".temperature")
    feat.set_logicalName("T_ambient")
    m.saveToFlash()

errmsg = YRefParam()
if YAPI.RegisterHub("localhost", errmsg) != YAPI.SUCCESS:
  sys.exit("RegisterHub failed: " + errmsg.value)

YAPI.RegisterDeviceArrivalCallback(arrival)
while True:
  YAPI.UpdateDeviceList()
  YAPI.Sleep(100)



Une fois un module configuré de manière adéquate , le code pour retrouver vos fonctions devient trivial

sensor : YTemperature = YTemperature.FindTemperature("T_ambient")
if not sensor.isOnline() : sys.exit("Capteur de température hors ligne)
print("
Temperature = %2.1f %s"%(sensor.get_currentValue(),sensor.get_unit()))



Programmez pour le long terme

Pour conclure, on ne saurait que trop vous encourager à écrire du code qui anticipe le futur. C'est particulièrement important si vous écrivez du logiciel qui sera vendu à des clients qui ne pourront pas le modifier et le recompiler en cas de problème. Enfin, on aimerait insister sur le fait que ce problème a été exacerbé par l'arrivée des versions USB-C, mais il n'est pas nouveau. Yoctopuce crée assez régulièrement des nouvelles versions de ses produits soit parce qu'il y avait la possibilité d'améliorer les performances soit parce que certains composants clefs n'était plus disponibles. Yoctopuce a toujours fait en sorte que ces nouvelles versions sont compatibles avec les anciennes, mais le "problème" des noms et identifiants de modules qui changent était déjà là.

Commenter aucun commentaire Retour au blog












Yoctopuce, get your stuff connected.