Les appareils de mesure qui peuvent être connectés directement sur le réseau sont en général très chers, plus de 1000 EUR. Pourtant, de nombreuses applications pourraient en profiter s'ils étaient plus abordables, comme par exemple le suivi d'une expérience commencée sur un coin de table. Nous allons donc vous montrer comment transformer très simplement un Raspberry Pi en un multi-mètre Ethernet très flexible, à l'aide d'un simple script Python. Une solution simple à base de modules USB standards, vidéo à l'appui.
Update: le code source est disponible sur GitHub: https://github.com/yoctopuce-examples/multimeter
Pour faire notre multi-mètre Ethernet, nous allons utiliser
- un Raspberry Pi modèle B, pour la connexion Ethernet (28 EUR)
- un écran OLED Yocto-Display, pour un affichage très lisible (70 EUR)
- une RaspBox, pour l'habillage (12 EUR)
- des capteurs Yoctopuce, par ex. un Yocto-Thermocouple (37 EUR) ou un Yocto-Volt (48 EUR)
- un petit script Python tournant sur le Raspberry Pi pour le contrôle de l'écran (gratuit)
- le logiciel VirtualHub (téléchargeable sur notre site) pour l'accès distant aux mesures (gratuit)
Le prix final dépendra des capteurs que vous utilisez, mais restera très avantageux par rapport à une solution commerciale (dans l'exemple ci-dessus, deux entrées thermocouple plus une mesure de tension avec isolation revient à moins de 200 EUR).
L'assemblage
Rien de compliqué pour cette réalisation puisqu'on utilise que des périphériques USB standards. En faisant 4 petits trous sur la plaque supérieure de la RaspBox, on fixe le Yocto-Display dessous afin qu'il soit protégé. L'écran est raccordé par un câble USB via un connecteur 1.27mm, moins encombrant qu'une fiche micro-B, qui s'adapte à tous nos modules et que nous aurons en vente sur notre shop d'ici quelques jours.
Voilà ce qu'on va réaliser
L'installation
Prenez une image Linux pour Raspberry Pi standard, et vérifiez bien que votre Raspberry Pi est à jour en exécutant "sudo raspi-config" et en sélectionnant "update". Le bug USB du Raspberry Pi n'a toujours pas été complètement fixé, il faut donc s'assurer que votre fichier /boot/cmdline.txt contienne bien l'option dwc_otg.speed=1 et redémarrer. Édit: L'option "dwc_otg.speed" n'est plus nécessaire pour les Raspberry Pi B+ et suivants.
Téléchargez et installez ensuite le VirtualHub de Yoctopuce, qui fournira automatiquement un accès réseau à vos capteurs, pour pouvoir les interroger à distance depuis votre station de travail, et installez la librairie Yoctopuce pour Python yoctopuce via PyPi. C'est tout, il ne reste plus qu'à écrire les quelques lignes de Python pour piloter le tout.
Le code
Pour être le plus pratique possible, le code va détecter à tout moment les modules connectés afin de s'adapter automatiquement à la sonde connectée. Pour ce faire, nous allons partir de l'exemple de programmation par événement fourni dans la librairie Yoctopuce, et le généraliser un peu pour tenir à jour un dictionnaire de sondes disponibles pour l'affichage.
sensors = { }
currentSensor = ""
# add sensor to dictionary when plugged
def deviceArrival(m):
global sensors, currentSensor
for i in range(m.functionCount()):
fctName = m.functionId(i) # eg. "voltage1"
fctType = re.sub("\d+$", "", fctName) # eg. "voltage"
hwId = m.get_serialNumber() + "." + fctName
yocto_mod = getattr(yoctopuce, "yocto_"+fctType.lower(), None)
if(yocto_mod is not None):
className = fctType[0].upper()+fctType[1:]# eg. "Voltage"
YClass = getattr(yocto_mod, "Y"+className)# eg. YVoltage
yFind = getattr(YClass, "Find"+className) # eg. YVoltage.FindVoltage
fct = yFind(hwId)
if getattr(fct, "get_unit", None) is not None:
currentSensor = fct.get_hardwareId()
sensors[currentSensor] = \
{ "name" : fct.get_friendlyName(),
"val" : fct.get_unit() }
fct.registerValueCallback(sensorChanged)
refreshDisplay()
# update display when sensor changes
def sensorChanged(fct,value):
hwId = fct.get_hardwareId()
if hwId in sensors: sensors[hwId]['val'] = value+" "+fct.get_unit()
refreshDisplay()
# remove sensor from dictionary when unplugged
def deviceRemoval(m):
deletePattern = m.get_serialNumber()+"\..*"
deleteList = []
for key in sensors:
if re.match(deletePattern, key): deleteList.append(key)
for key in deleteList:
del sensors[key]
refreshDisplay()
Le code d'affichage ne prend que quelques lignes. Comme il peut y avoir plusieurs senseurs, on garde le nom de la fonction actuellement affichée dans une variable.
display = YDisplay.FirstDisplay()
if display is None:
sys.exit("Display not connected")
display.resetAll()
dispLayer = display.get_displayLayer(1)
dispLayer.hide()
# Update the display value if needed (with double-buffering)
def refreshDisplay():
global currentSensor
if currentSensor not in sensors:
currentSensor = sensors.keys()[-1]
sensor = sensors[currentSensor]
dispLayer.clear()
dispLayer.selectFont("Small.yfm")
dispLayer.drawText(0,0,YDisplayLayer.ALIGN.TOP_LEFT,sensor["name"])
dispLayer.selectFont("Medium.yfm")
dispLayer.drawText(127,28,YDisplayLayer.ALIGN.BOTTOM_RIGHT,sensor["val"])
display.copyLayerContent(1,2)
Pour changer la fonction affichée, on utilise simplement les entrées bouton disponibles sur l'écran. Il n'est même pas indispensable d'y mettre un vrai bouton poussoir en l'occurrence: comme il s'agit d'entrées analogiques avec calibration, il suffira d'effleurer les contacts avec les doigts pour activer les entrées, selon le même principe que le Makey-Makey.
serial = display.get_module().get_serialNumber()
prevButton = YAnButton(serial+".anButton1")
nextButton = YAnButton(serial+".anButton6")
prevButton.set_userData(False) # False = released
nextButton.set_userData(False) # False = released
prevButton.registerValueCallback(buttonPressed);
nextButton.registerValueCallback(buttonPressed);
# Callback whenever a button value changes
def buttonPressed(fct,value):
global currentSensor
if(int(value) > 500): # button is released
fct.set_userData(False)
return
if(fct.get_userData()): # button was already pressed
return
# Button was just pressed, cycle through sensors values
fct.set_userData(True)
delta = (1 if fct.get_hardwareId()[-1] == '1' else -1)
if(delta != 0):
keys = sensors.keys()
idx = len(keys)-1
for i in range(len(keys)):
if keys[i] == currentSensor:
idx = (i+delta+len(keys)) % len(keys)
currentSensor = keys[idx]
refreshDisplay()
Pour le confort d'utilisation, on ajoute une fonction affichable supplémentaire: l'adresse IP du Raspberry Pi. Ça facilite grandement la vie pour ces machines sans écran...
sensors[""] = { "name" : socket.gethostname(),
"val" : findMyIP() }
refreshDisplay()
Voilà pour l'affichage en direct, vous avez maintenant un multi-mètre Ethernet. Comme nous avons mis le VirtualHub, les capteurs peuvent être interrogés à travers le réseau par la même API Yoctopuce, et ce depuis (presque) n'importe quel langage de programmation.
Et, cerise sur le gâteau, vous pouvez en quelques clicks configurer le VirtualHub pour poster automatiquement sur Cosm les valeurs mesurées. Ainsi vous pourrez suivre vos expériences sur votre Smartphone sans même écrire une ligne de code...
Les données peuvent être collectées automatiquement sur Cosm
Le résultat