I am trying to use passing a choice of pins to the raspberry py when creating channels and want to change only the .P(value) when calling the method. For if I call the class in another class I currently have to import all libraries again with the way it is now. Below is code.
import busio
import digitalio
import board
import adafruit_mcp3xxx.mcp3008 as MCP
from adafruit_mcp3xxx.analog_in import AnalogIn
def createChannel(self, channelNumber):
# create the spi bus
spi = busio.SPI(clock=board.SCK, MISO=board.MISO, MOSI=board.MOSI)
# create the cs (chip select)
cs = digitalio.DigitalInOut(board.D22)
# create the mcp object
mcp = MCP.MCP3008(spi, cs)
self.channelNumber = channelNumber
chan = self.channelNumber
chan = AnalogIn(mcp, self.channelNumber)
rawValue = chan.voltage
return rawValue
Then I call it like
sensor = createChannel()
rawValue = sensor.createChannel(MCP.P0)
So when I create another class to use the sensor retrieved data and I call the function I need to import all the libraries again that works with the MCP. I want to call it like this
sensor = createChannel()
rawValue = sensor.createChannel(P0)
But I can not find a way to just change the last part 'MCP.P0') by passing a argument in the call that works.
So when I create the other class I have to do this and import all libraries again
def sensorOne(self):
# create the spi bus
spi = busio.SPI(clock=board.SCK, MISO=board.MISO, MOSI=board.MOSI)
# create the cs (chip select)
cs = digitalio.DigitalInOut(board.D22)
# create the mcp object
mcp = MCP.MCP3008(spi, cs)
#get date and time
outTime = str(datetime.now())
# instance of createSpi class. so if tds sensor is connected to pin 0 you do as below. I will also do ph on pin 2 but comment it out for I am not sure if anyting is connected there yet.
sensor = createChannel()
#get data from sensor on pin 1
outData = sensor.createChannel(MCP.P1)
return outTime, outData
If spacing is not hundred persent please excuse I can not see for I am blind, but the code works just need to try and be able to change just the .P0 to for instance P1 by passing a argument to the call.
Thank you
I think you can define constants P0 to P7 in your module that defines createChannel, and then other files can import those constants from that module instead of getting them from MCP directly. Also, you can just specify a channel with an integer from 0 to 7.
I found some online documentation for adafruit_mcp3xxx.mcp3008. I think it means the channel names like MCP.P0 and MCP.P1 are really just integer values like 0 and 1, respectively.
The ADC chips’ input pins (AKA “channels”) are aliased in this library
as integer variables whose names start with “P” (eg MCP3008.P0 is
channel 0 on the MCP3008 chip). Each module that contains a driver
class for a particular ADC chip has these aliases predefined
accordingly. This is done for code readability and prevention of
erroneous SPI commands.
You can make channel names available to users of your createChannel method by defining constants P0, P1 and so forth in the module that defines createChannel.
## File createChannel.py
import adafruit_mcp3xxx.mcp3008 as MCP
# Alias the channel constants for convenience.
P0 = MCP.P0
P1 = MCP.P1
# etc.
P7 = MCP.P7
class createChannel():
def createChannel(self, channelNumber):
# ... Do stuff with channelNumber.
return channelNumber # Or whatever you need to return.
In another file that wants to use createChannel you can import the channel constants as well as the method. Alternatively, I think you can just access a channel by specifying an integer from 0 to 7.
## Another file.
from createChannel import createChannel, P0, P1, P7
sensor = createChannel()
# Access a single pin.
rawValue = sensor.createChannel(P0)
# Access each pin.
rawBus = [sensor.createChannel(pin) for pin in range(8)]
Related
I wrote code to stream audio as simple as the following.
If no callback is registered (part **) this code works fine.
But I would like to register a play callback to preprocess the streamed data.
How to register a callback function can be found by looking at the python-vlc documentation.
But I can't figure out how to write the callback function.
The second argument to the callback function, samples, is a pointer to the data to be played.
How should I write a callback function at the (*) part with this pointer?
Any reply would be appreciated.
import vlc
import re
import requests
import ctypes
url = "http://serpent0.duckdns.org:8088/kbsfm.pls"
res = requests.get(url)
res.raise_for_status()
# retrieve url
p = re.compile("https://.+")
m = p.search(res.text)
url = m.group()
# AudioPlayCb = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_uint, ctypes.c_int64)
#vlc.CallbackDecorators.AudioPlayCb
def play_callback(opaque, samples, count, pts):
"""
#param data: data pointer as passed to L{libvlc_audio_set_callbacks}() [IN].
#param samples: pointer to a table of audio samples to play back [IN].
#param count: number of audio samples to play back.
#param pts: expected play time stamp (see libvlc_delay()).
"""
# HOW DO I RETURN SOMETHING FROM HERE? (*)
pass
return buffer
instance = vlc.Instance(["--prefetch-buffer-size=2000 --prefetch-read-size=5000 --network-caching=1000"]) #define VLC instance
media = instance.media_new(url)
player = media.player_new_from_media()
player.audio_set_format("f32l", 48000, 2)
# PLAYS WELL WITHOUT THIS LINE (**)
player.audio_set_callbacks(play=play_callback, pause=None, resume=None, flush=None, drain=None, opaque=None)
player.play() #Play the media
c = input()
I wrote the play callback function as below.
I think the buffer_array passed in should be copied to another buffer to play samples.
#vlc.CallbackDecorators.AudioPlayCb
def play_callback(data, samples, count, pts):
bytes_read = count * 4 * 2
buffer_array = ctypes.cast(samples, ctypes.POINTER(ctypes.c_char * bytes_read))
# This code is invalid. To do it right, where should buffer_array be copied to?
buffer = bytearray(bytes_read)
buffer[:] = buffer_array.contents
I'm writing a module for an I2C temperature sensor (TMP117) with cross-compatability being a priority.
The MicroPython implementation is different on BBC Micro:bit and Raspberry Pi Pico - an important difference is how the I2C driver is implemented:
Pico uses the machine class to drive i2c: i2c.writeto
Micro:bit has already defined i2c.write (bundled with from microbit import *) docs
This simple difference in naming is really all that affects compatability!
So far I have shoehorned a working solution so my module tmp117.py is usable on both platforms.
In tmp117.py, when the sensor class is initialised it checks the sysname and declares function pointers self.i2cWrite and self.i2cRead that are assigned the hardware-appropriate definition.
However, I'm quite new to Python and imagine I may have committed many atrocities in doing so by eg. mishandling namespaces or chewing up memory with inappropriate imports. Can anybody comment if this method is appropriate? In terms of scalability, needless imports, namespaces etc.
main.py
# TMP117 minimal example code
from tmp117 import *
from time import sleep
mySensor = tmp117()
while True:
# Read and print the temperature in various units
tempC = mySensor.readTempC() # Celsius
tempStringC = str(tempC) # convert temperature number to string
print("it's " + tempStringC)
sleep(1)
tmp117.py
# A simple class to read temperature from the TMP117 i2c temperature sensor
# Currently only supports reading temperature in C, F, K. Does not support
# alarms.
# This module has been tested with the following development boards:
# • BBC Micro:bit
# • Raspberry Pi Pico (RP2040)
import os
if os.uname().sysname == 'microbit':
from microbit import *
else: # for Raspberry Pi Pico
from machine import I2C
i2c = I2C(0)
print("Running on " + os.uname().sysname)
# Register definitions
REG_TEMPC = b'\x00'
class tmp117(object):
def __init__(self, addr_=0x48, i2c_=i2c):
if os.uname().sysname == 'microbit':
self.i2c = i2c_
self.addr = addr_
self.i2cWrite = self.i2c.write
self.i2cRead = self.i2c.read
else:
self.i2c = i2c_
self.addr = addr_
self.i2cWrite = self.i2c.writeto
self.i2cRead = self.i2c.readfrom
def readTempC(self):
self.i2cWrite(self.addr, REG_TEMPC)
data = self.i2cRead(self.addr, 2) # returns a bytes object
tempDataRaw = int.from_bytes(data, 'big')
# handle negatives (MicroPython int.from_bytes does not support signed conversion (yet)
if tempDataRaw >= 0x8000:
return -256.0 + (tempDataRaw - 0x8000) * 7.8125e-3 # One LSB equals 7.812 mdegC
else:
return tempDataRaw * 7.8125e-3 # One LSB equals 7.812 mdegC
my choice of doing the same thing would be define _PLATFORM variable, set it accordingly and use it later:
import os
if os.uname().sysname == 'microbit':
_PLATFORM = 'microbit'
elif os.uname().sysname == 'rpico': # not sure about real value
_PLATFORM = 'pico'
else:
raise Exception('Unsupported platform')
if _PLATFORM == 'microbit':
from microbit import *
elif _PLATFORM == 'pico': # for Raspberry Pi Pico
from machine import I2C
i2c = I2C(0)
print("Running on {}".format(_PLATFORM)) # <<--- use format() function to save RAM
# Register definitions
REG_TEMPC = b'\x00'
class tmp117(object):
def __init__(self, addr_=0x48, i2c_=i2c):
if _PLATFORM == 'microbit':
self.i2c = i2c_
self.addr = addr_
self.i2cWrite = self.i2c.write
self.i2cRead = self.i2c.read
elif _PLATFORM == 'pico':
self.i2c = i2c_
self.addr = addr_
self.i2cWrite = self.i2c.writeto
self.i2cRead = self.i2c.readfrom
def readTempC(self):
self.i2cWrite(self.addr, REG_TEMPC)
data = self.i2cRead(self.addr, 2) # returns a bytes object
tempDataRaw = int.from_bytes(data, 'big')
# handle negatives (MicroPython int.from_bytes does not support signed conversion (yet)
if tempDataRaw >= 0x8000:
return -256.0 + (tempDataRaw - 0x8000) * 7.8125e-3 # One LSB equals 7.812 mdegC
else:
return tempDataRaw * 7.8125e-3 # One LSB equals 7.812 mdegC
I'm trying to write a device server with PyTango. I created a list of Attributes for the Server. How do I access the value stored in the attributes by the set_value() function?
If I have this attribute for example, how can I retrieve the value?
x_pixel_size = attribute(label = "x pixel size", dtype=float,
display_level = DispLevel.OPERATOR,
unit = 'microns', format='5.2f',
access = AttrWriteType.READ,
doc = 'Size of a single pixel along x-axis
of the detector')
self.x_pixel_size.set_value(720)
I want to retrieve the value 720 from the Attribute x_pixel_size. Is there a way to do this without using additional variables in the server?
Of course it is possible. You can do this in this way:
from PyTango.server import run
from PyTango.server import Device, DeviceMeta
from PyTango.server import attribute, command, device_property
from PyTango import AttrQuality, AttrWriteType, DispLevel
class DeviceClass(Device):
__metaclass__ = DeviceMeta
def init_device(self):
self.x_pixel_size.set_write_value(720)
x_pixel_size = attribute(label = "x pixel size", dtype=float,
display_level = DispLevel.OPERATOR,
unit = 'microns', format='5.2f',
access = AttrWriteType.READ_WRITE,
doc = 'Size of a single pixel along x-axis of the detector')
def write_x_pixel_size(self, value):
pass
def read_x_pixel_size(self):
return self.x_pixel_size.get_write_value()
def main():
run((DeviceClass,))
if __name__ == "__main__":
main()
And you can test it using Python console:
>>> from PyTango import DeviceProxy
>>> dev = DeviceProxy('test/device/1')
>>> dev.x_pixel_size
720.0
>>> dev.x_pixel_size = 550
>>> dev.x_pixel_size
550.0
>>>
If you have any further questions, just ask. But actually I use additional variables for keeping the attribute's value for me.
my problem seem to be similar to This Thread however, while I think I am following the advised method, I still get a PicklingError. When I run my process locally without sending to an IPython Cluster Engine the function works fine.
I am using zipline with IPyhon's notebook, so I first create a class based on zipline.TradingAlgorithm
Cell [ 1 ]
from IPython.parallel import Client
rc = Client()
lview = rc.load_balanced_view()
Cell [ 2 ]
%%px --local # This insures that the Class and modules exist on each engine
import zipline as zpl
import numpy as np
class Agent(zpl.TradingAlgorithm): # must define initialize and handle_data methods
def initialize(self):
self.valueHistory = None
pass
def handle_data(self, data):
for security in data.keys():
## Just randomly buy/sell/hold for each security
coinflip = np.random.random()
if coinflip < .25:
self.order(security,100)
elif coinflip > .75:
self.order(security,-100)
pass
Cell [ 3 ]
from zipline.utils.factory import load_from_yahoo
start = '2013-04-01'
end = '2013-06-01'
sidList = ['SPY','GOOG']
data = load_from_yahoo(stocks=sidList,start=start,end=end)
agentList = []
for i in range(3):
agentList.append(Agent())
def testSystem(agent,data):
results = agent.run(data) #-- This is how the zipline based class is executed
#-- next I'm just storing the final value of the test so I can plot later
agent.valueHistory.append(results['portfolio_value'][len(results['portfolio_value'])-1])
return agent
for i in range(10):
tasks = []
for agent in agentList:
#agent = testSystem(agent,data) ## On its own, this works!
#-- To Test, uncomment the above line and comment out the next two
tasks.append(lview.apply_async(testSystem,agent,data))
agentList = [ar.get() for ar in tasks]
for agent in agentList:
plot(agent.valueHistory)
Here is the Error produced:
PicklingError Traceback (most recent call last)/Library/Python/2.7/site-packages/IPython/kernel/zmq/serialize.pyc in serialize_object(obj, buffer_threshold, item_threshold)
100 buffers.extend(_extract_buffers(cobj, buffer_threshold))
101
--> 102 buffers.insert(0, pickle.dumps(cobj,-1))
103 return buffers
104
PicklingError: Can't pickle <type 'function'>: attribute lookup __builtin__.function failed
If I override the run() method from zipline.TradingAlgorithm with something like:
def run(self, data):
return 1
Trying something like this...
def run(self, data):
return zpl.TradingAlgorithm.run(self,data)
results in the same PicklingError.
then the passing off to the engines works, but obviously the guts of the test are not performed. As run is a method internal to zipline.TradingAlgorithm and I don't know everything that it does, how would I make sure it is passed through?
It looks like the zipline TradingAlgorithm object is not pickleable after it has been run:
import zipline as zpl
class Agent(zpl.TradingAlgorithm): # must define initialize and handle_data methods
def handle_data(self, data):
pass
agent = Agent()
pickle.dumps(agent)[:32] # ok
agent.run(data)
pickle.dumps(agent)[:32] # fails
But this suggests to me that you should be creating the Agents on the engines, and only passing data / results back and forth (ideally, not passing data across at all, or at most once).
Minimizing data transfers might look something like this:
define the class:
%%px
import zipline as zpl
import numpy as np
class Agent(zpl.TradingAlgorithm): # must define initialize and handle_data methods
def initialize(self):
self.valueHistory = []
def handle_data(self, data):
for security in data.keys():
## Just randomly buy/sell/hold for each security
coinflip = np.random.random()
if coinflip < .25:
self.order(security,100)
elif coinflip > .75:
self.order(security,-100)
load the data
%%px
from zipline.utils.factory import load_from_yahoo
start = '2013-04-01'
end = '2013-06-01'
sidList = ['SPY','GOOG']
data = load_from_yahoo(stocks=sidList,start=start,end=end)
agent = Agent()
and run the code:
def testSystem(agent, data):
results = agent.run(data) #-- This is how the zipline based class is executed
#-- next I'm just storing the final value of the test so I can plot later
agent.valueHistory.append(results['portfolio_value'][len(results['portfolio_value'])-1])
# create references to the remote agent / data objects
agent_ref = parallel.Reference('agent')
data_ref = parallel.Reference('data')
tasks = []
for i in range(10):
for j in range(len(rc)):
tasks.append(lview.apply_async(testSystem, agent_ref, data_ref))
# wait for the tasks to complete
[ t.get() for t in tasks ]
And plot the results, never fetching the agents themselves
%matplotlib inline
import matplotlib.pyplot as plt
for history in rc[:].apply_async(lambda : agent.valueHistory):
plt.plot(history)
This is not quite the same code you shared - three agents bouncing back and forth on all your engines, whereas this has on agent per engine. I don't know enough about zipline to say whether that's useful to you or not.
I'm trying to create an audio stream that has a constant audio source (in this case, audiotestsrc) to which I can occasionally add sounds from files (of various formats, that's why I'm using decodebin) through the play_file() method. I use an adder for that purpose. However, for some reason, I cannot add the second sound correctly. Not only does the program play the sound incorrectly, it also completely stops the original audiotestsrc. Here's my code so far:
import gst; import gobject; gobject.threads_init()
pipe = gst.Pipeline()
adder = gst.element_factory_make("adder", "adder")
first_sink = adder.get_request_pad('sink%d')
pipe.add(adder)
test = gst.element_factory_make("audiotestsrc", "test")
test.set_property('freq', 100)
pipe.add(test)
testsrc = test.get_pad("src")
testsrc.link(first_sink)
output = gst.element_factory_make("alsasink", "output")
pipe.add(output)
adder.link(output)
pipe.set_state(gst.STATE_PLAYING)
raw_input('Press key to play sound')
def play_file(filename):
adder_sink = adder.get_request_pad('sink%d')
audiofile = gst.element_factory_make('filesrc', 'audiofile')
audiofile.set_property('location', filename)
decoder = gst.element_factory_make('decodebin', 'decoder')
def on_new_decoded_pad(element, pad, last):
pad.link(adder_sink)
decoder.connect('new-decoded-pad', on_new_decoded_pad)
pipe.add(audiofile)
pipe.add(decoder)
audiofile.link(decoder)
pipe.set_state(gst.STATE_PAUSED)
pipe.set_state(gst.STATE_PLAYING)
play_file('sample.wav')
while True:
pass
Thanks to moch on #gstreamer, I realized that all adder sources should have the same format. I modified the above script so as to have the caps "audio/x-raw-int, endianness=(int)1234, channels=(int)1, width=(int)16, depth=(int)16, signed=(boolean)true, rate=(int)11025" (example) go before every input in the adder.