Voltage monitoring with Python

Voltage monitoring with Python

Sometimes people ask us for help about programming applications involving our devices. For instance, we have been asked for an application able to monitor mains voltage, with a variable sampling rate. Well, why not ? It has been a while since we haven't shown how easy our API is.





The problem
The problem statement is quite simple: the customer wants to monitor the mains voltage and record it in a CSV file. Under normal circumstances the program will take a sample once every 10 seconds, but when a specific event occurs (signaled by a closing contact), the sampling rate must speed up to 10 per second.

The hardware
We need a Yocto-Volt for the mains voltage monitoring, and a Yocto-Knob to read the control switch.

A Yocto-Volt and a  Yocto-Knob
A Yocto-Volt and a Yocto-Knob


The customer wants the application to run on a Raspberry PI. We chose Python as programming language, as it is readily available with all Linux distributions. An important preparatory step is to configure the PI to make sure it will reasonably work with USB 1.1 devices.

The wiring
The wiring


Lets start with Yocto-Volt and Yocto-Knob configuration. We will use the Virtual Hub to give logical names to our devices functions. The AC input of the Yocto-Volt will be named ACinput and the first channel on the Yocto-Knob will be named FreqCmd. This step can be skipped, but the code would be more complex.

To make the code more simpler, we give a logical name to the voltmeter AC input.
To make the code more simpler, we give a logical name to the voltmeter AC input.



Programming
Lets make sure the Yoctopuce python libraries have been downloaded and properly installed. Information on how to do that can be found in any Yoctopuce device documentation.

Now, we need to start our program by including the required Yoctopuce libraries.

from yocto_api import *
from yocto_voltage import *
from yocto_anbutton import *


Then we need to initialise the Yoctopuce API

errmsg=YRefParam()
if YAPI.RegisterHub("usb", errmsg)!= YAPI.SUCCESS:
    sys.exit("init error"+errmsg.value)


Now we need to find the objects matching the Yocto-Volt AC input and Yocto-Knob first channel. For that we will use the logical names we defined with the virtual hub.

# look for the Voltage Sensor called ACinput
sensorAC = YVoltage.FindVoltage('ACinput')
if not(sensorAC.isOnline()):
    sys.exit('No ACsensor Voltage function found')

# look for the anButton called FreqCmd
button = YAnButton.FindAnButton('FreqCmd')
if not(button.isOnline()):
    sys.exit('No FreqCmd AnButton Function found')



Sampling rate control will be handled by a callback. This callback will be invoked each time the switch state has changed.

#register button callback
button.registerValueCallback(buttonChange);


The callback will check if the corresponding input has been closed (pressed) or relased. Then it will update a global variable accordingly. This variable will be used for sampling speed control.

def buttonChange(button,value):
    global SampleFrequency
    if  button.get_isPressed():
        SampleFrequency=10
    else:
        SampleFrequency=0.1



Now the main loop: it has to read the voltage:

voltage = sensorAC.get_currentValue();


... and append it at the end of a CSV file.

logfile = open("voltagelog.csv", "a");
logfile.write(str(sampleTime.day)+'/')
logfile.write(str(sampleTime.month)+'/')
logfile.write(str(sampleTime.year)+' ')
logfile.write(str(sampleTime.hour)+':')
logfile.write(str(sampleTime.minute)+':')
logfile.write(str(sampleTime.second)+'.')
logfile.write(("%03d" % (sampleTime.microsecond/1000))+' , ')
logfile.write(str(voltage)+'\n')
logfile.close()



Last thing to do: wait before taking the next sample. Since the sampling frequency might change at any time, we don't know how long we are supposed to wait, so we have to be a little bit subtle. The waiting loop will permanently check if the elapsed time since the last sample is no longer than the current period. This is probably the more complex part of the program.

 mustwait = True;
 while mustwait:
     YAPI.Sleep(10)
     delta = datetime.datetime.now()-sampleTime;
     if (delta.seconds*1000 + delta.microseconds/1000) > 1000 / SampleFrequency:
         mustwait=False



Done, problem solved. Here is the full source code:

import os,sys
import datetime
from yocto_api import *
from yocto_voltage import *
from yocto_anbutton import *

SampleFrequency = 0.1;

def buttonChange(button,value):
    global SampleFrequency
    if  button.get_isPressed():
        SampleFrequency=10
    else:
        SampleFrequency=0.1

# Setup the API to use local USB devices
errmsg=YRefParam()
if YAPI.RegisterHub("usb", errmsg)!= YAPI.SUCCESS:
    sys.exit("init error"+errmsg.value)

# look for the Voltage Sensor called ACinput
sensorAC = YVoltage.FindVoltage('ACinput')
if not(sensorAC.isOnline()):
    sys.exit('No ACsensor Voltage function found')

# look for the anButton called FreqCmd
button = YAnButton.FindAnButton('FreqCmd')
if not(button.isOnline()):
    sys.exit('No FreqCmd AnButton Function found')

# register button callback
button.registerValueCallback(buttonChange);

print("Running")
while True:
    # make sure the Sensor is still connected
    sys.stdout.write(".")
    sys.stdout.flush()
    if (sensorAC.isOnline()):
        sampleTime = datetime.datetime.now();
        voltage = sensorAC.get_currentValue();
        # write to log file
        logfile = open("voltagelog.csv", "a");
        logfile.write(str(sampleTime.day)+'/')
        logfile.write(str(sampleTime.month)+'/')
        logfile.write(str(sampleTime.year)+' ')
        logfile.write(str(sampleTime.hour)+':')
        logfile.write(str(sampleTime.minute)+':')
        logfile.write(str(sampleTime.second)+'.')
        logfile.write(("%03d" % (sampleTime.microsecond/1000))+' , ')
        logfile.write(str(voltage)+'\n')
        logfile.close()
    else:
        print("Yocto-Volt is offline")
    # wait until for next sample
    mustwait = True;
    while mustwait:
        YAPI.Sleep(10)
        delta = datetime.datetime.now()-sampleTime;
        if (delta.seconds*1000 + delta.microseconds/1000) > 1000/SampleFrequency:
            mustwait=False



Too easy ;-)




1 - funky81 Wednesday,april 17,2013 12H18

I'm interested with this case.
May I know where you put the devices?
Any scheme?

2 - martinm (Yocto-Team)Wednesday,april 17,2013 12H56

I just added a wiring diagram in the article. It's quite simple: you just have to wire the Yocto-volt with the mains and wire a button on the Yocto-Knob.

Yoctopuce, get your stuff connected.