Cette semaine, nous vous présentons la version bêta de notre nouvelle librairie de programmation Python. Il s'agit d'une refonte complète, qui met à profit les évolutions du langage Python de ces dernières années.
La version originale de notre librairie de programmation Python a été écrite il y a 13 ans, à une époque où Python 2.7 était encore la norme. Pour accéder aux modules Yoctopuce, nous avions choisi d'utiliser - comme pour beaucoup de langages - notre librairie dynamique écrite en C. Bien que nous fournissions cette librairie dynamique précompilée pour la plupart des architectures et systèmes d'exploitation, certaines architectures comme MIPSel ne sont pas supportées.
Depuis lors, le langage Python a beaucoup évolué et de nouvelles fonctionnalités qui présentent un réel intérêt pour l'utilisateur ont fait leur apparition, notamment le typage et la programmation asynchrone. Comme Python est l'un des langages les plus prisés par les utilisateurs Yoctopuce, nous avons décidé de réécrire complètement notre librairie pour permettre aux utilisateurs d'exploiter pleinement ces nouvelles fonctionnalités et pour supprimer toutes les dépendances externe.
Vous pourrez utiliser cette nouvelle librairie avec n'importe quel Python à partir de la version 3.8. Les versions plus anciennes ne supportent malheureusement pas la syntaxe typée, mais ne vous inquiétez pas: nous continuerons à maintenir la version originale pour supporter les anciennes machines et les applications existantes. Les deux versions de la librairie seront disponibles en parallèle.
Installation
La librairie est disponible depuis PyPi, depuis GitHub et naturellement depuis notre site web.
Contrairement à l'ancienne librairie Python, cette version est prévue dès le départ pour être utilisée comme un package PyPi. Le nom du package est yoctolib et on peut l'installer à l'aide de la commande suivante :
pip install yoctolib
Une fois installée, on peut inclure les fichiers de la librairie en utilisant le nom de package yoctolib.
from yoctolib.yocto_relay import YRelay
Si vous avez téléchargé la librairie depuis GitHub ou depuis notre site web, vous pouvez installer la librairie à l'aide de l'option -e et du chemin de la librairie Yoctopuce.
Par exemple, le code suivant télécharge la librairie depuis GitHub et l'installe dans la liste des packages disponibles :
~/test $ git clone https://github.com/yoctopuce/yoctolib_typedpython.git ~/test $ pip install -e ~/test/yoctolib_typedpython
Enfin, si vous ne désirez pas du tout utiliser pip, il est toujours possible de copier les fichiers sources dans le répertoire de votre projet et de les référencer directement.
Les nouveautés
Maintenant que nous avons vu comment installer et inclure la librairie, regardons les nouveautés de cette version.
Le typage
Cette librairie utilise le typage Python. L'utilisation du typage en Python améliore la lisibilité du code et permet de détecter des erreurs avant l’exécution de l'application.
Tout le code de la librairie est typé, ce qui vous permet de détecter plus facilement les erreurs dans le code qui interagit avec notre API.
Le typage permet de détecter des erreurs directement depuis l'IDE
Si vous n'utilisez pas de typage dans votre application, ce n'est pas grave. Le code fonctionnera de manière identique, mais votre IDE aura plus de difficultés à détecter les erreurs.
Programmation asynchrone
Tout comme en JavaScript, TypeScript et C#, Python supporte désormais la programmation asynchrone avec les mots-clés async et await qui permettent de gérer efficacement plusieurs flots d'exécutions parallèles sans recourir aux threads.
Pour rappel, le mot-clé async permet de déclarer une fonction asynchrone et le mot-clé await permet d'appeler cette fonction de manière asynchrone, c'est-à-dire en autorisant d'autres tâches à s'exécuter entre temps si nécessaire, jusqu'au terme de l'exécution de la fonction asynchrone. Cette syntaxe offre donc la possibilité d'exécuter plusieurs tâches en parallèle dans un interpréteur Python. Pour plus de détails, nous vous invitons à lire la page de documentation de Python dédiée à ce sujet.
L'utilisation de code asynchrone en Python est assez récente mais gagne rapidement en popularité car elle permet d'avoir de meilleures performances sur des petites machines.
En interne, notre nouvelle librairie est basée sur des fonctions asynchrones en utilisant async/await. Cependant, pour ne pas imposer à tous les utilisateurs d'adopter le code asynchrone, la librairie expose également une interface synchrone 100% compatible avec notre librairie originale. Cette version synchrone est en réalité un wrapper autour de la version asynchrone, permettant ainsi une utilisation "à l'ancienne" en mode synchrone.
Pour utiliser la version synchrone, il suffit d'inclure les fichiers yocto_xxxxxx.py dans votre application comme par le passé. Par exemple, voici la version synchrone d'un programme qui liste les modules connectés en local :
def main():
errmsg = YRefParam()
if YAPI.RegisterHub("localhost", errmsg) != YAPI.SUCCESS:
print("YAPI.RegisterHub : " + str(errmsg))
return
print('Device list:')
module = YModule.FirstModule()
while module is not None:
serial = module.get_serialNumber()
product_name = module.get_productName()
print(serial + ' (' + product_name + ')')
module = module.nextModule()
YAPI.FreeAPI()
if __name__ == '__main__':
main()
Pour utiliser la version asynchrone de la librairie, il faut utiliser les fichiers yocto_xxxxxx_aio.py, et les mots-clés async/await.
Voici la version asynchrone du même programme :
from yoctolib.yocto_api_aio import YRefParam, YAPI, YModule
async def main():
errmsg = YRefParam()
if await YAPI.RegisterHub("localhost", errmsg) != YAPI.SUCCESS:
print("YAPI.RegisterHub : " + str(errmsg))
return
print('Device list:')
module = YModule.FirstModule()
while module is not None:
serial = await module.get_serialNumber()
product_name = await module.get_productName()
print(serial + ' (' + product_name + ')')
module = module.nextModule()
await YAPI.FreeAPI()
if __name__ == '__main__':
asyncio.run(main(), debug=False)
Comme on peut le voir, le code est très similaire. Il faut simplement ajouter await aux appels de fonctions asynchrones. Pour savoir si une fonction est asynchrone, il faut consulter la documentation de notre librairie ou le code source, mais grâce au typage, 99 % du temps votre IDE devrait vous avertir si vous avez oublié un await. En général, nos fonctions sont asynchrones à l'exception des méthodes FindXXX(), FirstXXX(), et nextXXX().
Les limitations
L'accès aux ports USB
Les plus attentifs auront remarqué que dans notre exemple nous avons utilisé YAPI.RegisterHub("localhost") à la place du traditionnel YAPI.RegisterHub("usb"). La raison est que cette librairie ne prend pas en charge l'accès direct aux ports USB pour l'instant.
Tout comme les librairies JavaScript, TypeScript, PHP et Java, il faut installer VirtualHub pour accéder aux ports USB. La procédure pour installer VirtualHub est expliquée dans cet article.
Cette limitation est liée au fait que cette librairie est écrite à 100 % en Python et que la VM Python ne permet pas d’accéder directement aux périphériques USB. Nous avons quelques idées pour contourner cette limitation, mais à l'heure actuelle, l’utilisation de VirtualHub est la meilleure solution.
Le Datalogger
Nous sommes en train de repenser l'utilisation du DataLogger pour qu'il soit plus efficace sur des machines avec très peu de RAM, mais cette version n'est pas encore disponible. Par conséquent, l'utilisation du DataLogger n'est pas encore supportée dans cette version, mais cette limitation est temporaire.
Conclusion
Cette nouvelle librairie est encore en bêta test, donc il est possible qu'il y ait encore quelques bugs. Elle est toutefois utilisable et activement testée en interne.
Le focus de cette version est d'avoir une librairie plus efficace sur de très petites machines. La nouvelle API asynchrone permet aussi d'intégrer plus facilement nos modules dans des logiciels asynchrones.
Comme d'habitude, si vous avez des problèmes ou des suggestions, n'hésitez pas à nous en faire part soit sur GitHub ou par email.