Permalink
Browse files

Merge branch 'master' of github.com:tino/pyFirmata

  • Loading branch information...
2 parents 0926d52 + 4016b71 commit 301e6459c4d40abbe524505c50e1f67d9cad4204 @tino committed Oct 19, 2013
Showing with 76 additions and 44 deletions.
  1. +41 −6 README.rst
  2. +2 −3 pyfirmata/__init__.py
  3. +33 −35 pyfirmata/pyfirmata.py
View
@@ -2,16 +2,37 @@
pyFirmata
=========
+pyFirmata is a Python interface for the `Firmata`_ protocol.
+
+.. _Firmata: http://firmata.org
+
+Master tests:
+
+.. image:: https://travis-ci.org/tino/pyFirmata.png?branch=master
+ :target: https://travis-ci.org/tino/pyFirmata
+
+Python 3 tests:
+
+.. image:: https://travis-ci.org/tino/pyFirmata.png?branch=py3
+ :target: https://travis-ci.org/tino/pyFirmata
+
Installation
============
The preferred way to install is with pip_::
pip install pyfirmata
-If you install from source with ``python setup.py install``, don't forget to install ``pyserial`` as well.
+If you install from source with ``python setup.py install``, don't forget to
+install `pyserial`_ as well.::
+
+ git clone https://github.com/tino/pyFirmata
+ cd pyFirmata
+ pip install pyserial
+ python setup.py install
.. _pip: http://www.pip-installer.org/en/latest/
+.. _pyserial:http://pyserial.sourceforge.net/
Usage
=====
@@ -22,15 +43,21 @@ Basic usage::
>>> board = Arduino('/dev/tty.usbserial-A6008rIF')
>>> board.digital[13].write(1)
-To use analog ports, it is probably handy to start an iterator thread. Otherwise the board will keep sending data to your serial, until it overflows::
+To use analog ports, it is probably handy to start an iterator thread.
+Otherwise the board will keep sending data to your serial, until it overflows::
>>> it = util.Iterator(board)
>>> it.start()
>>> board.analog[0].enable_reporting()
>>> board.analog[0].read()
0.661440304938
-If you use a pin more often, it can be worth it to use the ``get_pin`` method of the board. It let's you specify what pin you need by a string, composed of 'a' or 'd' (depending on wether you need an analog or digital pin), the pin number, and the mode ('i' for input, 'o' for output, 'p' for pwm). All seperated by ``:``. Eg. ``a:0:i`` for analog 0 as input, or ``d:3:p`` for digital pin 3 as pwm.::
+If you use a pin more often, it can be worth it to use the ``get_pin`` method
+of the board. It let's you specify what pin you need by a string, composed of
+'a' or 'd' (depending on wether you need an analog or digital pin), the pin
+number, and the mode ('i' for input, 'o' for output, 'p' for pwm). All
+seperated by ``:``. Eg. ``a:0:i`` for analog 0 as input or ``d:3:p`` for
+digital pin 3 as pwm.::
>>> analog_0 = board.get_pin('a:0:i')
>>> analog_0.read()
@@ -41,7 +68,11 @@ If you use a pin more often, it can be worth it to use the ``get_pin`` method of
Board layout
============
-If you want to use a board with a different layout than the standard Arduino, or the Arduino Mega (for wich there exist the shortcut classes ``pyfirmata.Arduino`` and ``pyfirmata.ArduinoMega``), instantiate the Board class with a dictionary as the ``layout`` argument. This is the layout dict for the Mega for example::
+If you want to use a board with a different layout than the standard Arduino,
+or the Arduino Mega (for wich there exist the shortcut classes
+``pyfirmata.Arduino`` and ``pyfirmata.ArduinoMega``), instantiate the Board
+class with a dictionary as the ``layout`` argument. This is the layout dict
+for the Mega for example::
>>> mega = {
... 'digital' : tuple(x for x in range(54)),
@@ -56,5 +87,9 @@ Todo
The next things on my list are to implement the new protocol changes in firmata:
-- Capability Query, which would eliminate the need to instantiate a board with the layout dict, as it will be able to determine the layout itself (http://firmata.org/wiki/Proposals#Capability_Query_.28added_in_version_2.2.29)
-- Pin State Query, which allows it to populate on-screen controls with an accurate representation of the hardware's configuration (http://firmata.org/wiki/Proposals#Pin_State_Query_.28added_in_version_2.2.29)
+- Capability Query, which would eliminate the need to instantiate a board with
+ the layout dict, as it will be able to determine the layout itself
+ (http://firmata.org/wiki/Proposals#Capability_Query_.28added_in_version_2.2.29)
+- Pin State Query, which allows it to populate on-screen controls with an
+ accurate representation of the hardware's configuration
+ (http://firmata.org/wiki/Proposals#Pin_State_Query_.28added_in_version_2.2.29)
@@ -5,10 +5,9 @@
# shortcut classes
-
class Arduino(Board):
"""
- A board that wil set itself up as a normal Arduino.
+ A board that will set itself up as a normal Arduino.
"""
def __init__(self, *args, **kwargs):
args = list(args)
@@ -21,7 +20,7 @@ def __str__(self):
class ArduinoMega(Board):
"""
- A board that wil set itself up as an Arduino Mega.
+ A board that will set itself up as an Arduino Mega.
"""
def __init__(self, *args, **kwargs):
args = list(args)
@@ -60,9 +60,7 @@ class NoInputWarning(RuntimeWarning):
pass
class Board(object):
- """
- Base class for any board
- """
+ """The Base class for any board."""
firmata_version = None
firmware = None
firmware_version = None
@@ -74,7 +72,7 @@ class Board(object):
def __init__(self, port, layout, baudrate=57600, name=None):
self.sp = serial.Serial(port, baudrate)
# Allow 5 secs for Arduino's auto-reset to happen
- # Alas, Firmata blinks it's version before printing it to serial
+ # Alas, Firmata blinks its version before printing it to serial
# For 2.3, even 5 seconds might not be enough.
# TODO Find a more reliable way to wait until the board is ready
self.pass_time(BOARD_SETUP_WAIT_TIME)
@@ -92,19 +90,19 @@ def __str__(self):
return "Board %s on %s" % (self.name, self.sp.port)
def __del__(self):
- '''
+ """
The connection with the a board can get messed up when a script is
closed without calling board.exit() (which closes the serial
connection). Therefore also do it here and hope it helps.
- '''
+ """
self.exit()
def send_as_two_bytes(self, val):
self.sp.write(chr(val % 128) + chr(val >> 7))
def setup_layout(self, board_layout):
"""
- Setup the Pin instances based on the given board-layout. Maybe it will
+ Setup the Pin instances based on the given board layout. Maybe it will
be possible to do this automatically in the future, by polling the
board for its type.
"""
@@ -143,9 +141,7 @@ def setup_layout(self, board_layout):
self.add_cmd_handler(REPORT_FIRMWARE, self._handle_report_firmware)
def add_cmd_handler(self, cmd, func):
- """
- Adds a command handler for a command.
- """
+ """Adds a command handler for a command."""
len_args = len(inspect.getargspec(func)[0])
def add_meta(f):
def decorator(*args, **kwargs):
@@ -161,9 +157,14 @@ def get_pin(self, pin_def):
Returns the activated pin given by the pin definition.
May raise an ``InvalidPinDefError`` or a ``PinAlreadyTakenError``.
- :arg pin_def: Pin definition as described in TODO,
+ :arg pin_def: Pin definition as described below,
but without the arduino name. So for example ``a:1:i``.
+ 'a' analog pin Pin number 'i' for input
+ 'd' digital pin Pin number 'o' for output
+ 'p' for pwm (Pulse-width modulation)
+
+ All seperated by ``:``.
"""
if type(pin_def) == list:
bits = pin_def
@@ -193,9 +194,7 @@ def get_pin(self, pin_def):
return pin
def pass_time(self, t):
- """
- Non-blocking time-out for ``t`` seconds.
- """
+ """Non-blocking time-out for ``t`` seconds."""
cont = time.time() + t
while time.time() < cont:
time.sleep(0)
@@ -227,8 +226,8 @@ def bytes_available(self):
def iterate(self):
"""
Reads and handles data from the microcontroller over the serial port.
- This method should be called in a main loop, or in an
- :class:`Iterator` instance to keep this boards pin values up to date
+ This method should be called in a main loop or in an :class:`Iterator`
+ instance to keep this boards pin values up to date.
"""
byte = self.sp.read()
if not byte:
@@ -269,7 +268,7 @@ def iterate(self):
def get_firmata_version(self):
"""
- Returns a version tuple (major, mino) for the firmata firmware on the
+ Returns a version tuple (major, minor) for the firmata firmware on the
board.
"""
return self.firmata_version
@@ -291,7 +290,7 @@ def servo_config(self, pin, min_pulse=544, max_pulse=2400, angle=0):
self.digital[pin].write(angle)
def exit(self):
- """ Call this to exit cleanly. """
+ """Call this to exit cleanly."""
# First detach all servo's, otherwise it somehow doesn't want to close...
if hasattr(self, 'digital'):
for pin in self.digital:
@@ -313,7 +312,7 @@ def _handle_analog_message(self, pin_nr, lsb, msb):
def _handle_digital_message(self, port_nr, lsb, msb):
"""
Digital messages always go by the whole port. This means we have a
- bitmask wich we update the port.
+ bitmask which we update the port.
"""
mask = (msb << 7) + lsb
try:
@@ -331,7 +330,7 @@ def _handle_report_firmware(self, *data):
self.firmware = two_byte_iter_to_str(data[2:])
class Port(object):
- """ An 8-bit port on the board """
+ """An 8-bit port on the board."""
def __init__(self, board, port_number, num_pins=8):
self.board = board
self.port_number = port_number
@@ -346,7 +345,7 @@ def __str__(self):
return "Digital Port %i on %s" % (self.port_number, self.board)
def enable_reporting(self):
- """ Enable reporting of values for the whole port """
+ """Enable reporting of values for the whole port."""
self.reporting = True
msg = chr(REPORT_DIGITAL + self.port_number)
msg += chr(1)
@@ -356,14 +355,14 @@ def enable_reporting(self):
pin.reporting = True # TODO Shouldn't this happen at the pin?
def disable_reporting(self):
- """ Disable the reporting of the port """
+ """Disable the reporting of the port."""
self.reporting = False
msg = chr(REPORT_DIGITAL + self.port_number)
msg += chr(0)
self.board.sp.write(msg)
def write(self):
- """Set the output pins of the port to the correct state"""
+ """Set the output pins of the port to the correct state."""
mask = 0
for pin in self.pins:
if pin.mode == OUTPUT:
@@ -376,17 +375,15 @@ def write(self):
self.board.sp.write(msg)
def _update(self, mask):
- """
- Update the values for the pins marked as input with the mask.
- """
+ """Update the values for the pins marked as input with the mask."""
if self.reporting:
for pin in self.pins:
if pin.mode is INPUT:
pin_nr = pin.pin_number - self.port_number * 8
pin.value = (mask & (1 << pin_nr)) > 0
class Pin(object):
- """ A Pin representation """
+ """A Pin representation"""
def __init__(self, board, pin_number, type=ANALOG, port=None):
self.board = board
self.pin_number = pin_number
@@ -406,13 +403,13 @@ def _set_mode(self, mode):
self._mode = UNAVAILABLE
return
if self._mode is UNAVAILABLE:
- raise IOError("%s can not be used through Firmata" % self)
+ raise IOError("%s can not be used through Firmata." % self)
if mode is PWM and not self.PWM_CAPABLE:
- raise IOError("%s does not have PWM capabilities" % self)
+ raise IOError("%s does not have PWM capabilities." % self)
if mode == SERVO:
if self.type != DIGITAL:
raise IOError("Only digital pins can drive servos! %s is not"
- "digital" % self)
+ "digital." % self)
self._mode = SERVO
self.board.servo_config(self.pin_number)
return
@@ -432,11 +429,11 @@ def _get_mode(self):
mode = property(_get_mode, _set_mode)
"""
Mode of operation for the pin. Can be one of the pin modes: INPUT, OUTPUT,
- ANALOG, PWM or SERVO (or UNAVAILABLE)
+ ANALOG, PWM. or SERVO (or UNAVAILABLE).
"""
def enable_reporting(self):
- """ Set an input pin to report values """
+ """Set an input pin to report values."""
if self.mode is not INPUT:
raise IOError, "%s is not an input and can therefore not report" % self
if self.type == ANALOG:
@@ -448,7 +445,7 @@ def enable_reporting(self):
self.port.enable_reporting() # TODO This is not going to work for non-optimized boards like Mega
def disable_reporting(self):
- """ Disable the reporting of an input pin """
+ """Disable the reporting of an input pin."""
if self.type == ANALOG:
self.reporting = False
msg = chr(REPORT_ANALOG + self.pin_number)
@@ -460,7 +457,8 @@ def disable_reporting(self):
def read(self):
"""
Returns the output value of the pin. This value is updated by the
- boards :meth:`Board.iterate` method. Value is alway in the range 0.0 - 1.0
+ boards :meth:`Board.iterate` method. Value is always in the range from
+ 0.0 to 1.0.
"""
if self.mode == UNAVAILABLE:
raise IOError, "Cannot read pin %s"% self.__str__()
@@ -476,7 +474,7 @@ def write(self, value):
"""
if self.mode is UNAVAILABLE:
- raise IOError, "%s can not be used through Firmata" % self
+ raise IOError, "%s can not be used through Firmata." % self
if self.mode is INPUT:
raise IOError, "%s is set up as an INPUT and can therefore not be written to" % self
if value is not self.value:

0 comments on commit 301e645

Please sign in to comment.