Measuring devices which you can directly connect to the network are usually very expensive, more than 1'000 Euros. However, numerous applications, such as monitoring an experiment started on a napkin, could benefit from them if they were more affordable. We are going to show you therefore how to very easily transform a Raspberry Pi into a very flexible Ethernet multimeter, with the help of a simple Python script. A simple solution based on standard USB modules, demonstrated in a video.
Update: the source code is now available on GitHub: https://github.com/yoctopuce-examples/multimeter
To make our Ethernet multimeter, we used:
- a Raspberry Pi, model B, for the Ethernet connection (28 EUR)
- a Yocto-Display OLED screen, for a very readable display (70 EUR)
- a RaspBox, to protect the Raspberry Pi (12 EUR)
- Yoctopuce sensors, e.g. a Yocto-Thermocouple (37 EUR) or a Yocto-Volt (48 EUR)
- a small Python script running on the Raspberry Pi to control the screen (free)
- the VirtualHub software (downloadable from our web site), for remote access to the measures (free)
The final price depends on the sensors you use, but it remains very attractive compared to a commercial solution (in the above example, you can have two thermocouple inputs and a tension measure with isolation for less than 200 EUR).
Assembling
Nothing complex, as we only use standard USB devices. We make 4 small holes on the top plate of the RaspBox so we can fix the Yocto-Display below it to protect it. The screen is connect with a USB cable through a 1.27mm connector, more compact than a micro-B plug. This connector adapts to all our modules and will be available in our shop in a few days.
Here is what we are going to build
Installing
Take a standard Linux image for Raspberry Pi, and check that your Raspberry Pi is up-to-date by running "sudo raspi-config" and by selecting "update". The USB bug on the Raspberry Pi is still not completely fixed, so make sure that your /boot/cmdline.txt file contains the dwc_otg.speed=1 option. Then restart. Edit: The "dwc_otg.speed" option is no more needed on Raspberry Pi B+ and later models.
Then, download and install the Yoctopuce VirtualHub, which automatically provides network access to your sensors so that you can query them remotely from your workstation, and install the Yoctopuce for Python using PyPi . That's it. We only need to write a few lines of Python to drive it all.
Coding
To be as easy to use as possible, the code repeatedly detects connected modules to automatically adapt to the connected probe. To do so, we start from the event programming example provided in the Yoctopuce library and generalize it somewhat to keep an up-to-date dictionary of available probes.
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()
The display code is only a few lines long. As you can have several sensors, we keep the name of the function currently displayed in a 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)
To change the displayed function, we simply use the button inputs available on the screen. You don't even need to add a real push button: as they are analog inputs with calibration, you only need to lightly touch the contacts with your fingers to activate the inputs, following the principle of the 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()
For ease of use, we add a displayable function: the IP address of the Raspberry Pi. This greatly simplifies life for these machines without screen ...
sensors[""] = { "name" : socket.gethostname(),
"val" : findMyIP() }
refreshDisplay()
We are done for direct display, you now have an Ethernet multimeter. As we installed the VirtualHub, you can query the sensors remotely through the same Yoctopuce API, from any programming language.
And, icing on the cake, you only need a few clicks to configure the VirtualHub to automatically post the measured values on Cosm. Thus, you can follow your experiments on your Smartphone without writing any additional line of code...
Data can be collected on Cosm automatically
The result