diff --git a/.gitignore b/.gitignore index 0a69710..f9010f8 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,92 @@ .pydevproject *.prefs +.cache/ +.idea/ +Adventures in The Cloud_ Documenting python code using sphinx and github.html +Adventures in The Cloud_ Documenting python code using sphinx and github_files/ +FirmataPlus/libraries/ +__init__.py +__pycache__/ +abtests/ +build/ +creating_sphinx_docs.txt +dist/ +docs/ +documentation/__pycache__/ +documentation/images/Screenshot from 2016-01-05 11-45-39.png +examples/__init__.py +examples/__pycache__/ +examples/adxl345.py +examples/bug.py +examples/callback_example.py +examples/core_sample.py~ +examples/jimmy2.py +examples/mma8452q2.py +examples/mma8452qSave.py +examples/new_blink.py +examples/new_blink2.py +examples/osx_serial.py +examples/prof +examples/prof.txt +examples/rbEncoder.py +examples/rbStandAloneTalk.py +examples/red_bot/ +examples/redbot_accel.py +examples/simpleMotors.py +examples/simple_mult_input.py +examples/sock.py +examples/sock3.py +examples/sonar.py +examples/sparkfun_redbot/MrYLogo.png +examples/sparkfun_redbot/__init__.py +examples/sparkfun_redbot/__pycache__/ +examples/sparkfun_redbot/abc.py +examples/sparkfun_redbot/accel_basic_pymata3.py +examples/sparkfun_redbot/accel_basic_pymata_core.py +examples/sparkfun_redbot/get_page.py +examples/sparkfun_redbot/html/ +examples/sparkfun_redbot/newStandAlone.py +examples/sparkfun_redbot/rbDash.html +examples/sparkfun_redbot/rbStandAlone.py +examples/sparkfun_redbot/rb_accel.py +examples/sparkfun_redbot/redbot.py +examples/sparkfun_redbot/redbot2.py +examples/sparkfun_redbot/redbot_accel.py +examples/sparkfun_redbot/redbot_control.py +examples/sparkfun_redbot/redbot_controller.py +examples/sparkfun_redbot/redbot_dash.py +examples/sparkfun_redbot/sparkfun_experiments/library/__pycache__/ +examples/sparkfun_redbot/test_socket_client.py +examples/test3.py +examples/test3accel.py +examples/tmp102.py +keepAliveCalcs.ods +keepAliveCalcs.xls +Would skip repository pymata-aio.wiki/ +pymata_aio.egg-info/ +pymata_aio/.pymata_core.log +pymata_aio/__pycache__/ +pymata_aio/jimmy2.py +pymata_aio/latching.py +pymata_aio/pymata_aio.html +pymata_aio/pymata_aio.log +pymata_aio/pymata_iot.py~ +talk/ +tcp_stuff.py +test/__pycache__/ +test/all.py +test/buttonTest.py +test/dave.py +test/dave2.py +test/dave3.py +test/dave4.py +test/dave5.py +test/i2c/i2c_write/__pycache__/ +test/keep_alive.py +test/leigh1.py +test/redbot_demo.py +test/testDigitalReporting.py +test/xyz.py +test_allx.py +wiki_Backup/ diff --git a/FirmataPlus/libraries.zip b/FirmataPlus/libraries.zip index d0af3a4..ca101e5 100644 Binary files a/FirmataPlus/libraries.zip and b/FirmataPlus/libraries.zip differ diff --git a/documentation/changelog.md b/documentation/changelog.md index 1001d79..ef7d365 100644 --- a/documentation/changelog.md +++ b/documentation/changelog.md @@ -1,5 +1,16 @@ # Change Log +## Release 2.14 + +26 July 2016 + + +* Arduino Firmware Version information is printed as part of start-up banner +* All FirmataPlus versions were re-baselined against StandardFirmata 2.5.3 +* An additional FirmataPlus variant was created to support AVR 32u4 boards. +* Corrected 2 calls to asyncio.sleep in pymata_serial.py that were missing awaits. These fixes should not affect the performance of the pymata_aio library, and therefore updating to this release from 2.13 is optional. +* Forced txaio (required by autobahn) to an earlier release (2.1.0) to avoid warnings generated in latest version. + ## Release 2.13 21 April 2016 diff --git a/pymata_aio/private_constants.py b/pymata_aio/private_constants.py index 5008e76..5d8cf24 100644 --- a/pymata_aio/private_constants.py +++ b/pymata_aio/private_constants.py @@ -70,7 +70,7 @@ class PrivateConstants: SYSEX_REALTIME = 0x7F # MIDI Reserved for realtime messages # reserved for PyMata - PYMATA_VERSION = "2.13" + PYMATA_VERSION = "2.14" # each byte represents a digital port # and its value contains the current port settings diff --git a/pymata_aio/pymata_core.py b/pymata_aio/pymata_core.py index 4e0ade7..780b638 100644 --- a/pymata_aio/pymata_core.py +++ b/pymata_aio/pymata_core.py @@ -197,13 +197,13 @@ def __init__(self, arduino_wait=2, sleep_tune=0.0001, log_output=False, if self.log_output: log_string = 'pymata_aio Version ' + \ PrivateConstants.PYMATA_VERSION + \ - ' Copyright (c) 2015 Alan Yorinks All rights reserved.' + ' Copyright (c) 2015-2016 Alan Yorinks All rights reserved.' logging.info(log_string) else: print('{}{}{}'.format('\n', 'pymata_aio Version ' + PrivateConstants.PYMATA_VERSION, - '\tCopyright (c) 2015 Alan Yorinks All ' + '\tCopyright (c) 2015-2016 Alan Yorinks All ' 'rights reserved.\n')) sys.stdout.flush() @@ -282,10 +282,21 @@ def start(self): # wait for arduino to go through a reset cycle if need be time.sleep(self.arduino_wait) + # register the get_command method with the event loop # self.loop = asyncio.get_event_loop() self.the_task = self.loop.create_task(self._command_dispatcher()) + # get arduino firmware version and print it + asyncio.ensure_future(self.get_firmware_version()) + + firmware_version = self.loop.run_until_complete(self.get_firmware_version()) + if self.log_output: + log_string = "\nArduino Firmware ID: " + firmware_version + logging.exception(log_string) + else: + print("\nArduino Firmware ID: " + firmware_version) + # get an analog pin map asyncio.ensure_future(self.get_analog_map()) @@ -389,6 +400,14 @@ async def start_aio(self): self.loop = asyncio.get_event_loop() self.the_task = self.loop.create_task(self._command_dispatcher()) + # get arduino firmware version and print it + firmware_version = await self.get_firmware_version() + if self.log_output: + log_string = "\nArduino Firmware ID: " + firmware_version + logging.exception(log_string) + else: + print("\nArduino Firmware ID: " + firmware_version) + # get an analog pin map asyncio.ensure_future(self.get_analog_map()) @@ -710,7 +729,7 @@ async def get_protocol_version(self): :returns: Firmata protocol version """ if self.query_reply_data.get(PrivateConstants.REPORT_VERSION) == '': - await self._send_command(PrivateConstants.REPORT_VERSION) + await self._send_command([PrivateConstants.REPORT_VERSION]) while self.query_reply_data.get( PrivateConstants.REPORT_VERSION) == '': await asyncio.sleep(self.sleep_tune) @@ -1274,8 +1293,20 @@ async def _command_dispatcher(self): logging.exception(ex) else: print(ex) + await self.shutdown() + + await self.serial_port.close() + + print("An exception occurred on the asyncio event loop while receiving data. Invalid message.") - # raise # re-raise exception. + loop = self.loop + for t in asyncio.Task.all_tasks(loop): + t.cancel() + loop.run_until_complete(asyncio.sleep(.1)) + loop.close() + loop.stop() + sys.exit(0) + ''' Firmata message handlers @@ -1783,6 +1814,7 @@ async def _send_command(self, command): :returns: length of data sent """ send_message = "" + for i in command: send_message += chr(i) result = None diff --git a/pymata_aio/pymata_serial.py b/pymata_aio/pymata_serial.py index 8e27a74..6f49320 100644 --- a/pymata_aio/pymata_serial.py +++ b/pymata_aio/pymata_serial.py @@ -48,6 +48,7 @@ def __init__(self, com_port='/dev/ttyACM0', speed=57600, sleep_tune=.001, sys.stdout.flush() self.my_serial = serial.Serial(com_port, speed, timeout=1, writeTimeout=1) + self.com_port = com_port self.sleep_tune = sleep_tune @@ -71,30 +72,40 @@ async def write(self, data): """ # the secret sauce - it is in your future future = asyncio.Future() - + result = None try: result = self.my_serial.write(bytes([ord(data)])) except serial.SerialException: - if self.log_output: - logging.exception('Write exception') - else: - print('Write exception') - loop = asyncio.get_event_loop() - for t in asyncio.Task.all_tasks(loop): - t.cancel() - loop.run_until_complete(asyncio.sleep(.1)) - loop.stop() - loop.close() - self.my_serial.close() - sys.exit(0) - - future.set_result(result) - while True: - if not future.done(): - # spin our asyncio wheels until future completes - asyncio.sleep(self.sleep_tune) - else: - return future.result() + # self.my_serial.close() + # noinspection PyBroadException + try: + await self.close() + future.cancel() + if self.log_output: + logging.exception('Write exception') + else: + print('Write exception') + + loop = asyncio.get_event_loop() + for t in asyncio.Task.all_tasks(loop): + t.cancel() + loop.run_until_complete(asyncio.sleep(.1)) + loop.stop() + loop.close() + self.my_serial.close() + sys.exit(0) + except: # swallow any additional exceptions during shutdown + pass + + if result: + future.set_result(result) + while True: + if not future.done(): + # spin our asyncio wheels until future completes + await asyncio.sleep(self.sleep_tune) + + else: + return future.result() async def readline(self): """ @@ -108,7 +119,7 @@ async def readline(self): while True: if not data_available: if not self.my_serial.inWaiting(): - asyncio.sleep(self.sleep_tune) + await asyncio.sleep(self.sleep_tune) else: data_available = True data = self.my_serial.readline() diff --git a/setup.py b/setup.py index 055add3..02a856f 100644 --- a/setup.py +++ b/setup.py @@ -2,9 +2,9 @@ setup( name='pymata-aio', - version='2.13', + version='2.14', packages=['pymata_aio'], - install_requires=['pyserial==2.7', 'autobahn[asyncio]==0.10.4'], + install_requires=['pyserial==2.7', 'txaio==2.1.0', 'autobahn[asyncio]==0.10.4'], url='https://github.com/MrYsLab/pymata-aio/wiki', download_url='https://github.com/MrYsLab/pymata-aio', license='GNU General Public License v3 (GPLv3)',