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
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
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.
Programming
Lets make sure the
Now, we need to start our program by including the required Yoctopuce libraries.
from yocto_voltage import *
from yocto_anbutton import *
Then we need to initialise the Yoctopuce API
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.
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.
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.
global SampleFrequency
if button.get_isPressed():
SampleFrequency=10
else:
SampleFrequency=0.1
Now the main loop: it has to read the voltage:
... and append it at the end of a CSV file.
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.
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 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 ;-)