예제 #1
0
    def __init__(self, *subscriber_list, back_plane_ip_address=None,
                 subscriber_port='43125',
                 publisher_port='43124', process_name='ArduinoGateway',
                 event_loop=None, ):
        """
        Set up the gateway for operation

        :param subscriber_list: a tuple or list of subscription topics.
        :param back_plane_ip_address: ip address of backplane or none if local
        :param subscriber_port: backplane subscriber port
        :param publisher_port: backplane publisher port
        :param process_name: name to display on the console
        :param event_loop: optional parameter to pass in an asyncio
                           event loop
        """

        # set the event loop to be used. accept user's if provided
        if event_loop:
            self.event_loop = event_loop
        else:
            self.event_loop = asyncio.get_event_loop()

        # instantiate pymata express to control the arduino
        self.arduino = PymataExpress(loop=self.event_loop)

        # extract pin info from self.arduino
        self.number_of_digital_pins = len(self.arduino.digital_pins)
        self.number_of_analog_pins = len(self.arduino.analog_pins)
        self.first_analog_pin = self.arduino.first_analog_pin

        # Initialize the parent
        super(ArduinoGateway, self).__init__(subscriber_list=subscriber_list,
                                             event_loop=self.event_loop,
                                             back_plane_ip_address=back_plane_ip_address,
                                             subscriber_port=subscriber_port,
                                             publisher_port=publisher_port,
                                             process_name=process_name,
                                             )
예제 #2
0
    def __init__(
            self,
            event_loop=None,
            com_port=None,
            arduino_instance_id=None,
            keep_alive=False,
            log=True,
            bucket_token=20,
            bucket_fill_rate=10,
            **kwargs  # 暂未处理启动提醒
    ):

        # set the event loop to be used. accept user's if provided
        self.event_loop = event_loop
        if not self.event_loop:
            loop = asyncio.new_event_loop()
            asyncio.set_event_loop(loop)
            self.event_loop = loop

        self.log = log
        # instantiate pymata express to control the arduino
        # if user want to pass in a com port, then pass it in
        try:
            if com_port:
                self.arduino = PymataExpress(loop=self.event_loop,
                                             com_port=com_port)
            # if user wants to set an instance id, then pass it in
            elif arduino_instance_id:
                self.arduino = PymataExpress(
                    loop=self.event_loop,
                    arduino_instance_id=arduino_instance_id)
            # default settings
            else:
                self.arduino = PymataExpress(loop=self.event_loop)
        except RuntimeError as e:
            if self.log:
                logging.exception("Exception occurred", exc_info=True)
            raise
        # 正常
        self.connect_status = "connected"
        # extract pin info from self.arduino
        self.number_of_digital_pins = len(self.arduino.digital_pins)
        self.number_of_analog_pins = len(self.arduino.analog_pins)
        self.first_analog_pin = self.arduino.first_analog_pin

        # Initialize the parent
        super().__init__(bucket_token=bucket_token,
                         bucket_fill_rate=bucket_fill_rate,
                         **kwargs)

        self.first_analog_pin = self.arduino.first_analog_pin
        self.keep_alive = keep_alive
예제 #3
0
async def get_board(data: Mapping) -> PymataExpress:
    """Create a Pymata board object."""
    board_data = {}

    if CONF_SERIAL_PORT in data:
        board_data["com_port"] = data[CONF_SERIAL_PORT]
    if CONF_SERIAL_BAUD_RATE in data:
        board_data["baud_rate"] = data[CONF_SERIAL_BAUD_RATE]
    if CONF_ARDUINO_INSTANCE_ID in data:
        board_data["arduino_instance_id"] = data[CONF_ARDUINO_INSTANCE_ID]

    if CONF_ARDUINO_WAIT in data:
        board_data["arduino_wait"] = data[CONF_ARDUINO_WAIT]
    if CONF_SLEEP_TUNE in data:
        board_data["sleep_tune"] = data[CONF_SLEEP_TUNE]

    board_data["autostart"] = False
    board_data["shutdown_on_exception"] = True
    board_data["close_loop_on_shutdown"] = False

    board = PymataExpress(**board_data)

    await board.start_aio()
    return board
예제 #4
0
def main(event_loop, cb=None):
    """
    Processes the joystick analog and digital inputs
    :param event_loop: the event loop to use for execution
    :param cb: an optional async callback to use
    """
    asyncio.set_event_loop(event_loop)
    board = PymataExpress()

    try:
        pin_setup_task = asyncio.gather(
            board.set_pin_mode_analog_input(X_PIN,
                                            callback=x_handler,
                                            differential=DIFFERENTIAL),
            board.set_pin_mode_analog_input(Y_PIN,
                                            callback=y_handler,
                                            differential=DIFFERENTIAL),
            board.set_pin_mode_digital_input_pullup(SW_PIN,
                                                    callback=switch_handler))

        event_loop.run_until_complete(pin_setup_task)

        reporting_task = asyncio.ensure_future(print_vals(cb))

        # Now loop forever printing the recorded values
        # from the handlers (callbacks)
        event_loop.run_until_complete(reporting_task)

    except KeyboardInterrupt:
        # hide the keyboard interrupt
        pass
    finally:

        for task in asyncio.Task.all_tasks():
            task.cancel()

        event_loop.run_until_complete(board.shutdown())

        event_loop.stop()
예제 #5
0

async def digital_in(my_board, pin):
    """
     This function establishes the pin as a
     digital input. Any changes on this pin will
     be reported through the call back function.
     :param my_board: a pymata_express instance
     :param pin: Arduino pin number
     """
    # set the pin mode

    await my_board.set_pin_mode_digital_input_pullup(pin,
                                                     callback=the_callback)

    while True:
        await my_board.digital_read(pin)

        while True:
            await asyncio.sleep(1)


loop = asyncio.get_event_loop()
board = PymataExpress()
try:
    loop.run_until_complete(digital_in(board, 2))
    loop.run_until_complete(board.shutdown())
except KeyboardInterrupt:
    loop.run_until_complete(board.shutdown())
    sys.exit(0)
class ArduinoGateway(GatewayBaseAIO): # 直接回复
    '''
    use TokenBucket to limit message rate(pub) https://github.com/CodeLabClub/codelab_adapter_client_python/blob/master/codelab_adapter_client/utils.py#L25
    '''
    # This class implements the GatewayBase interface adapted for asyncio.
    # It supports Arduino boards, tested with Uno.

    # NOTE: This class requires the use of Python 3.7 or above
    
    NODE_ID = "eim/extension_arduino_uno"
    HELP_URL = "http://adapter.codelab.club/extension_guide/arduino_UNO/"
    WEIGHT = 94
    DESCRIPTION = "将Arduino积木化"
    
    def __init__(self,
                 event_loop=None,
                 com_port=None,
                 arduino_instance_id=None,
                 keep_alive=False,
                 log=True,
                 bucket_token=20,
                 bucket_fill_rate=10,
                 **kwargs # 暂未处理启动提醒
                 ):

        # set the event loop to be used. accept user's if provided
        self.event_loop = event_loop
        if not self.event_loop:
            loop = asyncio.new_event_loop()
            asyncio.set_event_loop(loop)
            self.event_loop = loop

        self.log = log
        # instantiate pymata express to control the arduino
        # if user want to pass in a com port, then pass it in
        try:
            if com_port:
                self.arduino = PymataExpress(loop=self.event_loop,
                                             com_port=com_port)
            # if user wants to set an instance id, then pass it in
            elif arduino_instance_id:
                self.arduino = PymataExpress(
                    loop=self.event_loop,
                    arduino_instance_id=arduino_instance_id)
            # default settings
            else:
                self.arduino = PymataExpress(loop=self.event_loop)
        except RuntimeError as e:
            if self.log:
                logging.exception("Exception occurred", exc_info=True)
            raise
        # 正常
        self.connect_status = "connected"
        # extract pin info from self.arduino
        self.number_of_digital_pins = len(self.arduino.digital_pins)
        self.number_of_analog_pins = len(self.arduino.analog_pins)
        self.first_analog_pin = self.arduino.first_analog_pin

        # Initialize the parent
        super().__init__(bucket_token=bucket_token, bucket_fill_rate=bucket_fill_rate, **kwargs)

        self.first_analog_pin = self.arduino.first_analog_pin
        self.keep_alive = keep_alive

        # self.event_loop.create_task(pub_notification_coroutine)

    def init_pins_dictionary(self):
        """
        This method will initialize the pins dictionary contained
        in gateway base parent class. This method is called by
        the gateway base parent in its init method.

        NOTE: that this a a non-asyncio method.
        """
        report = self.event_loop.run_until_complete(
            self.arduino.get_capability_report())
        x = 0
        pin = 0
        while x < len(report):
            while report[x] != 127:
                mode = report[x]
                if mode == PrivateConstants.INPUT:
                    self.pins_dictionary[pin] = \
                        [GatewayBaseAIO.DIGITAL_INPUT_MODE, 0, False]
                elif mode == PrivateConstants.ANALOG:
                    self.pins_dictionary[pin + self.first_analog_pin] = \
                        [GatewayBaseAIO.ANALOG_INPUT_MODE, 0, False]
                x += 1
            x += 1
            pin += 1
        # set up entry for i2c as pin 200 ( a pseudo pin number)
        self.pins_dictionary[200] = GatewayBaseAIO.DIGITAL_INPUT_MODE

    async def digital_write(self, topic, payload):
        """
        This method performs a digital write
        :param topic: message topic
        :param payload content: {"command": "digital_write", "pin": “PIN”, "value": “VALUE”}
        """
        await self.arduino.digital_write(payload['content']["pin"],
                                         payload['content']['value'])

    async def disable_analog_reporting(self, topic, payload):
        """
        This method disables analog input reporting for the selected pin.
        :param topic: message topic
        :param payload content: {"command": "disable_analog_reporting", "pin": “PIN”, "tag": "TAG"}
        """
        await self.arduino.disable_analog_reporting(payload['content']["pin"])

    async def disable_digital_reporting(self, topic, payload):
        """
        This method disables digital input reporting for the selected pin.

        :param topic: message topic
        :param payload content: {"command": "disable_digital_reporting", "pin": “PIN”, "tag": "TAG"}
        """
        await self.arduino.disable_digital_reporting(payload['content']["pin"])

    async def enable_analog_reporting(self, topic, payload):
        """
        This method enables analog input reporting for the selected pin.
        :param topic: message topic
        :param payload content:  {"command": "enable_analog_reporting", "pin": “PIN”, "tag": "TAG"}
        """
        await self.arduino.enable_analog_reporting(payload['content']["pin"])

    async def enable_digital_reporting(self, topic, payload):
        """
        This method enables digital input reporting for the selected pin.
        :param topic: message topic
        :param payload content: {"command": "enable_digital_reporting", "pin": “PIN”, "tag": "TAG"}
        """
        await self.arduino.enable_digital_reporting(payload['content']["pin"])

    async def i2c_read(self, topic, payload):
        """
        This method will perform an i2c read by specifying the i2c
        device address, i2c device register and the number of bytes
        to read.

        Call set_mode_i2c first to establish the pins for i2c operation.

        :param topic: message topic
        :param payload content: {"command": "i2c_read", "pin": “PIN”, "tag": "TAG",
                         "addr": “I2C ADDRESS, "register": “I2C REGISTER”,
                         "number_of_bytes": “NUMBER OF BYTES”}
        :return via the i2c_callback method
        """

        await self.arduino.i2c_read(payload['content']['addr'],
                                    payload['content']['register'],
                                    payload['content']['number_of_bytes'],
                                    callback=self.i2c_callback)

    async def i2c_write(self, topic, payload):
        """
        This method will perform an i2c write for the i2c device with
        the specified i2c device address, i2c register and a list of byte
        to write.

        Call set_mode_i2c first to establish the pins for i2c operation.

        :param topic: message topic
        :param payload content: {"command": "i2c_write", "pin": “PIN”, "tag": "TAG",
                         "addr": “I2C ADDRESS, "register": “I2C REGISTER”,
                         "data": [“DATA IN LIST FORM”]}
        """
        await self.arduino.i2c_write(payload['content']['addr'],
                                     payload['content']['data'])

    async def play_tone(self, topic, payload):
        """
        This method plays a tone on a piezo device connected to the selected
        pin at the frequency and duration requested.
        Frequency is in hz and duration in milliseconds.

        Call set_mode_tone before using this method.
        :param topic: message topic
        :param payload content: {"command": "play_tone", "pin": “PIN”, "tag": "TAG",
                         “freq”: ”FREQUENCY”, duration: “DURATION”}
        """
        await self.arduino.play_tone(payload['content']['pin'],
                                     payload['content']['freq'],
                                     payload['content']['duration'])

    async def pwm_write(self, topic, payload):
        """
        This method sets the pwm value for the selected pin.
        Call set_mode_pwm before calling this method.
        :param topic: message topic
        :param payload content: {“command”: “pwm_write”, "pin": “PIN”,
                         "tag":”TAG”,
                          “value”: “VALUE”}
        """
        await self.arduino.analog_write(payload['content']["pin"],
                                        payload['content']['value'])

    async def servo_position(self, topic, payload):
        """
        This method will set a servo's position in degrees.
        Call set_mode_servo first to activate the pin for
        servo operation.

        :param topic: message topic
        :param payload content: {'command': 'servo_position',
                         "pin": “PIN”,'tag': 'servo',
                        “position”: “POSITION”}
        """
        await self.arduino.servo_write(payload['content']["pin"],
                                       payload['content']["position"])

    async def set_mode_analog_input(self, topic, payload):
        """
        This method sets a GPIO pin as analog input.
        :param topic: message topic
        :param payload content: {"command": "set_mode_analog_input", "pin": “PIN”, "tag":”TAG” }
        """
        pin = payload['content']["pin"]
        self.pins_dictionary[pin + self.first_analog_pin][GatewayBaseAIO.PIN_MODE] = \
            GatewayBaseAIO.ANALOG_INPUT_MODE
        await self.arduino.set_pin_mode_analog_input(
            pin, self.analog_input_callback)

    async def set_mode_digital_input(self, topic, payload):
        """
        This method sets a pin as digital input.
        :param topic: message topic
        :param payload content: {"command": "set_mode_digital_input", "pin": “PIN”, "tag":”TAG” }
        """
        pin = payload['content']["pin"]
        self.pins_dictionary[pin][
            GatewayBaseAIO.PIN_MODE] = GatewayBaseAIO.DIGITAL_INPUT_MODE
        await self.arduino.set_pin_mode_digital_input(
            pin, self.digital_input_callback)

    async def set_mode_digital_input_pullup(self, topic, payload):
        """
        This method sets a pin as digital input with pull up enabled.
        :param topic: message topic
        :param payload content: message payload
        """
        pin = payload['content']["pin"]
        self.pins_dictionary[pin][
            GatewayBaseAIO.PIN_MODE] = GatewayBaseAIO.DIGITAL_INPUT_PULLUP_MODE
        await self.arduino.set_pin_mode_digital_input_pullup(
            pin, self.digital_input_callback)

    async def set_mode_digital_output(self, topic, payload):
        """
        This method sets a pin as a digital output pin.
        :param topic: message topic
        :param payload content: {"command": "set_mode_digital_output", "pin": PIN, "tag":”TAG” }
        """
        pin = payload['content']["pin"]
        self.pins_dictionary[pin][
            GatewayBaseAIO.PIN_MODE] = GatewayBaseAIO.DIGITAL_OUTPUT_MODE
        await self.arduino.set_pin_mode_digital_output(pin)

    async def set_mode_i2c(self, topic, payload):
        """
        This method sets up the i2c pins for i2c operations.
        :param topic: message topic
        :param payload content: {"command": "set_mode_i2c"}
        """
        self.pins_dictionary[200][
            GatewayBaseAIO.PIN_MODE] = GatewayBaseAIO.I2C_MODE
        await self.arduino.set_pin_mode_i2c()

    async def set_mode_pwm(self, topic, payload):
        """
        This method sets a GPIO pin capable of PWM for PWM operation.
        :param topic: message topic
        :param payload content: {"command": "set_mode_pwm", "pin": “PIN”, "tag":”TAG” }
        """
        pin = payload['content']["pin"]
        self.pins_dictionary[pin][
            GatewayBaseAIO.PIN_MODE] = GatewayBaseAIO.PWM_OUTPUT_MODE
        await self.arduino.set_pin_mode_pwm(pin)

    async def set_mode_servo(self, topic, payload):
        """
        This method establishes a GPIO pin for servo operation.
        :param topic: message topic
        :param payload content: {"command": "set_mode_servo", "pin": “PIN”, "tag":”TAG” }
        """
        pin = payload['content']["pin"]
        self.pins_dictionary[pin][
            GatewayBaseAIO.PIN_MODE] = GatewayBaseAIO.SERVO_MODE
        await self.arduino.set_pin_mode_servo(pin)

    async def set_mode_sonar(self, topic, payload):
        """
        This method sets the trigger and echo pins for sonar operation.
        :param topic: message topic
        :param payload content: {"command": "set_mode_sonar", "trigger_pin": “PIN”, "tag":”TAG”
                         "echo_pin": “PIN”"tag":”TAG” }
        """

        trigger = payload['content']["trigger_pin"]
        echo = payload['content']["echo_pin"]
        self.pins_dictionary[trigger][
            GatewayBaseAIO.PIN_MODE] = GatewayBaseAIO.SONAR_MODE
        self.pins_dictionary[echo][
            GatewayBaseAIO.PIN_MODE] = GatewayBaseAIO.SONAR_MODE

        await self.arduino.set_pin_mode_sonar(trigger,
                                              echo,
                                              cb=self.sonar_callback)

    async def set_mode_stepper(self, topic, payload):
        """
        This method establishes either 2 or 4 GPIO pins to be used in stepper
        motor operation.
        :param topic:
        :param payload content:{"command": "set_mode_stepper", "pins": [“PINS”],
                        "steps_per_revolution": “NUMBER OF STEPS”}
        """
        for pin in payload['content']['pins']:
            self.pins_dictionary[pin][
                GatewayBaseAIO.PIN_MODE] = GatewayBaseAIO.STEPPER_MODE
        await self.arduino.set_pin_mode_stepper(
            payload['content']['steps_per_revolution'],
            payload['content']['pins'])

    async def set_mode_tone(self, topic, payload):
        """
        Establish a GPIO pin for tone operation.
        :param topic:
        :param payload content:{"command": "set_mode_tone", "pin": “PIN”, "tag":”TAG” }
        """
        pin = payload['content']["pin"]
        self.pins_dictionary[pin][
            GatewayBaseAIO.PIN_MODE] = GatewayBaseAIO.TONE_MODE
        await self.arduino.set_pin_mode_tone(pin)

    async def stepper_write(self, topic, payload):
        """
        Move a stepper motor for the specified number of steps.
        :param topic:
        :param payload content: {"command": "stepper_write", "motor_speed": “SPEED”,
                         "number_of_steps":”NUMBER OF STEPS” }
        """
        await self.arduino.stepper_write(payload['content']['motor_speed'],
                                         payload['content']['number_of_steps'])

    # Callbacks
    async def digital_input_callback(self, data):
        """
        Digital input data change reported by Arduino
        :param data:
        :return:
        """
        # data = [pin, current reported value, pin_mode, timestamp]
        self.pins_dictionary[data[0]][GatewayBaseAIO.LAST_VALUE] = data[1]

        message = self.message_template()
        message["payload"]["content"] = {
            'report': 'digital_input',
            'pin': data[0],
            'value': data[1],
            'timestamp': data[3]
        }
        await self.publish(message)

    async def analog_input_callback(self, data):
        # data = [pin, current reported value, pin_mode, timestamp]
        self.pins_dictionary[data[0] + self.arduino.first_analog_pin][
            GatewayBaseAIO.LAST_VALUE] = data[1]
        message = self.message_template()
        message["payload"]["content"] = {
            'report': 'analog_input',
            'pin': data[0],
            'value': data[1],
            'timestamp': data[3]
        }
        await self.publish(message)

    async def i2c_callback(self, data):
        """
        Analog input data change reported by Arduino

        :param data:
        :return:
        """
        # creat a string representation of the data returned
        self.pins_dictionary[200] = data[1]
        report = ', '.join([str(elem) for elem in data])
        message = self.message_template()
        message["payload"]["content"] = {'report': 'i2c_data', 'value': report}
        await self.publish(message)

    async def sonar_callback(self, data):
        """
        Sonar data change reported by Arduino

        :param data:
        :return:
        """
        self.pins_dictionary[data[0]][GatewayBaseAIO.LAST_VALUE] = data[1]
        message = self.message_template()
        message["payload"]["content"] = {
            'report': 'sonar_data',
            'value': data[1]
        }
        await self.publish(message)

    def my_handler(self, tp, value, tb):
        """
        for logging uncaught exceptions
        :param tp:
        :param value:
        :param tb:
        :return:
        """
        self.logger.exception("Uncaught exception: {0}".format(str(value)))

    async def main(self):
        # call the inherited begin method located in banyan_base_aio
        # await self.receive_loop()

        # start the keep alive on the Arduino if enabled
        if self.keep_alive:
            await self.arduino.keep_alive()
        # sit in an endless loop to receive protocol messages
        await self.receive_loop()  # pub_notification should after receive_loop
        # 在此之后才能发送,publisher先建立起来,消息可以后发

    # The following methods and are called
    # by the gateway base class in its incoming_message_processing
    # method. They overwrite the default methods in the gateway_base.

    # noinspection DuplicatedCode
    def run(self):
        # get the event loop
        # this is for python 3.8
        if sys.platform == 'win32':
            asyncio.set_event_loop_policy(
                asyncio.WindowsSelectorEventLoopPolicy())

        try:
            self.event_loop.create_task(
                self.pub_notification('Arduino UNO 已连接',
                                      type="SUCCESS"))
            self.event_loop.run_until_complete(self.main())
            self.logger.debug("arduino thread end")
            self.event_loop.run_until_complete(self.arduino.shutdown())
        except (KeyboardInterrupt, asyncio.CancelledError, RuntimeError):
            pass
예제 #7
0
    def __init__(self,
                 *subscriber_list,
                 back_plane_ip_address=None,
                 subscriber_port='43125',
                 publisher_port='43124',
                 process_name='ArduinoGateway',
                 event_loop=None,
                 keep_alive=False,
                 com_port=None,
                 arduino_instance_id=None,
                 log=False):
        """
        Set up the gateway for operation

        :param subscriber_list: a tuple or list of subscription topics.
        :param back_plane_ip_address: ip address of backplane or none if local
        :param subscriber_port: backplane subscriber port
        :param publisher_port: backplane publisher port
        :param process_name: name to display on the console
        :param event_loop: optional parameter to pass in an asyncio
                           event loop
        :param keep_alive: if True, enable FirmataExpress keep-alives
        :param com_port: force pymata-express to use this comport
        :param arduino_instance: set an arduino instance id that must
                                 be programmed into the FirmataExpress
                                 sketch.
        :param log: enable logging
        """

        # set up logging if requested
        self.log = log
        if self.log:
            fn = str(pathlib.Path.home()) + "/ardgw.log"
            self.logger = logging.getLogger(__name__)
            logging.basicConfig(filename=fn, filemode='w', level=logging.DEBUG)
            sys.excepthook = self.my_handler

        # set the event loop to be used. accept user's if provided
        if event_loop:
            self.event_loop = event_loop
        else:
            self.event_loop = asyncio.get_event_loop()

        the_loop = self.event_loop

        # instantiate pymata express to control the arduino
        # if user want to pass in a com port, then pass it in
        try:
            if com_port:
                self.arduino = PymataExpress(loop=the_loop, com_port=com_port)
            # if user wants to set an instance id, then pass it in
            elif arduino_instance_id:
                self.arduino = PymataExpress(
                    loop=the_loop, arduino_instance_id=arduino_instance_id)
            # default settings
            else:
                self.arduino = PymataExpress(loop=the_loop)
        except RuntimeError:
            if self.log:
                logging.exception("Exception occurred", exc_info=True)
            raise

        # extract pin info from self.arduino
        self.number_of_digital_pins = len(self.arduino.digital_pins)
        self.number_of_analog_pins = len(self.arduino.analog_pins)
        self.first_analog_pin = self.arduino.first_analog_pin

        # Initialize the parent
        super(ArduinoGateway, self).__init__(
            subscriber_list=subscriber_list,
            event_loop=self.event_loop,
            back_plane_ip_address=back_plane_ip_address,
            subscriber_port=subscriber_port,
            publisher_port=publisher_port,
            process_name=process_name,
        )

        self.first_analog_pin = self.arduino.first_analog_pin
        self.keep_alive = keep_alive
예제 #8
0
class ArduinoGateway(GatewayBaseAIO):
    # This class implements the GatewayBase interface adapted for asyncio.
    # It supports Arduino boards, tested with Uno.

    # NOTE: This class requires the use of Python 3.7 or above

    # serial_port = None

    def __init__(self,
                 *subscriber_list,
                 back_plane_ip_address=None,
                 subscriber_port='43125',
                 publisher_port='43124',
                 process_name='ArduinoGateway',
                 event_loop=None,
                 keep_alive=False,
                 com_port=None,
                 arduino_instance_id=None,
                 log=False):
        """
        Set up the gateway for operation

        :param subscriber_list: a tuple or list of subscription topics.
        :param back_plane_ip_address: ip address of backplane or none if local
        :param subscriber_port: backplane subscriber port
        :param publisher_port: backplane publisher port
        :param process_name: name to display on the console
        :param event_loop: optional parameter to pass in an asyncio
                           event loop
        :param keep_alive: if True, enable FirmataExpress keep-alives
        :param com_port: force pymata-express to use this comport
        :param arduino_instance: set an arduino instance id that must
                                 be programmed into the FirmataExpress
                                 sketch.
        :param log: enable logging
        """

        # set up logging if requested
        self.log = log
        if self.log:
            fn = str(pathlib.Path.home()) + "/ardgw.log"
            self.logger = logging.getLogger(__name__)
            logging.basicConfig(filename=fn, filemode='w', level=logging.DEBUG)
            sys.excepthook = self.my_handler

        # set the event loop to be used. accept user's if provided
        if event_loop:
            self.event_loop = event_loop
        else:
            self.event_loop = asyncio.get_event_loop()

        the_loop = self.event_loop

        # instantiate pymata express to control the arduino
        # if user want to pass in a com port, then pass it in
        try:
            if com_port:
                self.arduino = PymataExpress(loop=the_loop, com_port=com_port)
            # if user wants to set an instance id, then pass it in
            elif arduino_instance_id:
                self.arduino = PymataExpress(
                    loop=the_loop, arduino_instance_id=arduino_instance_id)
            # default settings
            else:
                self.arduino = PymataExpress(loop=the_loop)
        except RuntimeError:
            if self.log:
                logging.exception("Exception occurred", exc_info=True)
            raise

        # extract pin info from self.arduino
        self.number_of_digital_pins = len(self.arduino.digital_pins)
        self.number_of_analog_pins = len(self.arduino.analog_pins)
        self.first_analog_pin = self.arduino.first_analog_pin

        # Initialize the parent
        super(ArduinoGateway, self).__init__(
            subscriber_list=subscriber_list,
            event_loop=self.event_loop,
            back_plane_ip_address=back_plane_ip_address,
            subscriber_port=subscriber_port,
            publisher_port=publisher_port,
            process_name=process_name,
        )

        self.first_analog_pin = self.arduino.first_analog_pin
        self.keep_alive = keep_alive

    def init_pins_dictionary(self):
        """
        This method will initialize the pins dictionary contained
        in gateway base parent class. This method is called by
        the gateway base parent in its init method.

        NOTE: that this a a non-asyncio method.
        """
        report = self.event_loop.run_until_complete(
            self.arduino.get_capability_report())
        x = 0
        pin = 0
        while x < len(report):
            while report[x] != 127:
                mode = report[x]
                if mode == PrivateConstants.INPUT:
                    self.pins_dictionary[pin] = \
                        [GatewayBaseAIO.DIGITAL_INPUT_MODE, 0, False]
                elif mode == PrivateConstants.ANALOG:
                    self.pins_dictionary[pin + self.first_analog_pin] = \
                        [GatewayBaseAIO.ANALOG_INPUT_MODE, 0, False]
                x += 1
            x += 1
            pin += 1
        # set up entry for i2c as pin 200 ( a pseudo pin number)
        self.pins_dictionary[200] = GatewayBaseAIO.DIGITAL_INPUT_MODE

    async def main(self):
        # call the inherited begin method located in banyan_base_aio
        await self.begin()

        # start the keep alive on the Arduino if enabled
        if self.keep_alive:
            await self.arduino.keep_alive()

        # sit in an endless loop to receive protocol messages
        while True:
            await self.receive_loop()

    # The following methods and are called
    # by the gateway base class in its incoming_message_processing
    # method. They overwrite the default methods in the gateway_base.

    async def digital_write(self, topic, payload):
        """
        This method performs a digital write
        :param topic: message topic
        :param payload: {"command": "digital_write", "pin": “PIN”, "value": “VALUE”}
        """
        await self.arduino.digital_write(payload["pin"], payload['value'])

    async def disable_analog_reporting(self, topic, payload):
        """
        This method disables analog input reporting for the selected pin.
        :param topic: message topic
        :param payload: {"command": "disable_analog_reporting", "pin": “PIN”, "tag": "TAG"}
        """
        await self.arduino.disable_analog_reporting(payload["pin"])

    async def disable_digital_reporting(self, topic, payload):
        """
        This method disables digital input reporting for the selected pin.

        :param topic: message topic
        :param payload: {"command": "disable_digital_reporting", "pin": “PIN”, "tag": "TAG"}
        """
        await self.arduino.disable_digital_reporting(payload["pin"])

    async def enable_analog_reporting(self, topic, payload):
        """
        This method enables analog input reporting for the selected pin.
        :param topic: message topic
        :param payload:  {"command": "enable_analog_reporting", "pin": “PIN”, "tag": "TAG"}
        """
        await self.arduino.enable_analog_reporting(payload["pin"])

    async def enable_digital_reporting(self, topic, payload):
        """
        This method enables digital input reporting for the selected pin.
        :param topic: message topic
        :param payload: {"command": "enable_digital_reporting", "pin": “PIN”, "tag": "TAG"}
        """
        await self.arduino.enable_digital_reporting(payload["pin"])

    async def i2c_read(self, topic, payload):
        """
        This method will perform an i2c read by specifying the i2c
        device address, i2c device register and the number of bytes
        to read.

        Call set_mode_i2c first to establish the pins for i2c operation.

        :param topic: message topic
        :param payload: {"command": "i2c_read", "pin": “PIN”, "tag": "TAG",
                         "addr": “I2C ADDRESS, "register": “I2C REGISTER”,
                         "number_of_bytes": “NUMBER OF BYTES”}
        :return via the i2c_callback method
        """

        await self.arduino.i2c_read(payload['addr'],
                                    payload['register'],
                                    payload['number_of_bytes'],
                                    callback=self.i2c_callback)

    async def i2c_write(self, topic, payload):
        """
        This method will perform an i2c write for the i2c device with
        the specified i2c device address, i2c register and a list of byte
        to write.

        Call set_mode_i2c first to establish the pins for i2c operation.

        :param topic: message topic
        :param payload: {"command": "i2c_write", "pin": “PIN”, "tag": "TAG",
                         "addr": “I2C ADDRESS, "register": “I2C REGISTER”,
                         "data": [“DATA IN LIST FORM”]}
        """
        await self.arduino.i2c_write(payload['addr'], payload['data'])

    async def play_tone(self, topic, payload):
        """
        This method plays a tone on a piezo device connected to the selected
        pin at the frequency and duration requested.
        Frequency is in hz and duration in milliseconds.

        Call set_mode_tone before using this method.
        :param topic: message topic
        :param payload: {"command": "play_tone", "pin": “PIN”, "tag": "TAG",
                         “freq”: ”FREQUENCY”, duration: “DURATION”}
        """
        await self.arduino.play_tone(payload['pin'], payload['freq'],
                                     payload['duration'])

    async def pwm_write(self, topic, payload):
        """
        This method sets the pwm value for the selected pin.
        Call set_mode_pwm before calling this method.
        :param topic: message topic
        :param payload: {“command”: “pwm_write”, "pin": “PIN”,
                         "tag":”TAG”,
                          “value”: “VALUE”}
        """
        await self.arduino.analog_write(payload["pin"], payload['value'])

    async def servo_position(self, topic, payload):
        """
        This method will set a servo's position in degrees.
        Call set_mode_servo first to activate the pin for
        servo operation.

        :param topic: message topic
        :param payload: {'command': 'servo_position',
                         "pin": “PIN”,'tag': 'servo',
                        “position”: “POSITION”}
        """
        await self.arduino.servo_write(payload["pin"], payload["position"])

    async def set_mode_analog_input(self, topic, payload):
        """
        This method sets a GPIO pin as analog input.
        :param topic: message topic
        :param payload: {"command": "set_mode_analog_input", "pin": “PIN”, "tag":”TAG” }
        """
        pin = payload["pin"]
        self.pins_dictionary[pin + self.first_analog_pin][GatewayBaseAIO.PIN_MODE] = \
            GatewayBaseAIO.ANALOG_INPUT_MODE
        await self.arduino.set_pin_mode_analog_input(
            pin, self.analog_input_callback)

    async def set_mode_digital_input(self, topic, payload):
        """
        This method sets a pin as digital input.
        :param topic: message topic
        :param payload: {"command": "set_mode_digital_input", "pin": “PIN”, "tag":”TAG” }
        """
        pin = payload["pin"]
        self.pins_dictionary[pin][
            GatewayBaseAIO.PIN_MODE] = GatewayBaseAIO.DIGITAL_INPUT_MODE
        await self.arduino.set_pin_mode_digital_input(
            pin, self.digital_input_callback)

    async def set_mode_digital_input_pullup(self, topic, payload):
        """
        This method sets a pin as digital input with pull up enabled.
        :param topic: message topic
        :param payload: message payload
        """
        pin = payload["pin"]
        self.pins_dictionary[pin][
            GatewayBaseAIO.PIN_MODE] = GatewayBaseAIO.DIGITAL_INPUT_PULLUP_MODE
        await self.arduino.set_pin_mode_digital_input_pullup(
            pin, self.digital_input_callback)

    async def set_mode_digital_output(self, topic, payload):
        """
        This method sets a pin as a digital output pin.
        :param topic: message topic
        :param payload: {"command": "set_mode_digital_output", "pin": PIN, "tag":”TAG” }
        """
        pin = payload["pin"]
        self.pins_dictionary[pin][
            GatewayBaseAIO.PIN_MODE] = GatewayBaseAIO.DIGITAL_OUTPUT_MODE
        await self.arduino.set_pin_mode_digital_output(pin)

    async def set_mode_i2c(self, topic, payload):
        """
        This method sets up the i2c pins for i2c operations.
        :param topic: message topic
        :param payload: {"command": "set_mode_i2c"}
        """
        self.pins_dictionary[200][
            GatewayBaseAIO.PIN_MODE] = GatewayBaseAIO.I2C_MODE
        await self.arduino.set_pin_mode_i2c()

    async def set_mode_pwm(self, topic, payload):
        """
        This method sets a GPIO pin capable of PWM for PWM operation.
        :param topic: message topic
        :param payload: {"command": "set_mode_pwm", "pin": “PIN”, "tag":”TAG” }
        """
        pin = payload["pin"]
        self.pins_dictionary[pin][
            GatewayBaseAIO.PIN_MODE] = GatewayBaseAIO.PWM_OUTPUT_MODE
        await self.arduino.set_pin_mode_pwm(pin)

    async def set_mode_servo(self, topic, payload):
        """
        This method establishes a GPIO pin for servo operation.
        :param topic: message topic
        :param payload: {"command": "set_mode_servo", "pin": “PIN”, "tag":”TAG” }
        """
        pin = payload["pin"]
        self.pins_dictionary[pin][
            GatewayBaseAIO.PIN_MODE] = GatewayBaseAIO.SERVO_MODE
        await self.arduino.set_pin_mode_servo(pin)

    async def set_mode_sonar(self, topic, payload):
        """
        This method sets the trigger and echo pins for sonar operation.
        :param topic: message topic
        :param payload: {"command": "set_mode_sonar", "trigger_pin": “PIN”, "tag":”TAG”
                         "echo_pin": “PIN”"tag":”TAG” }
        """

        trigger = payload["trigger_pin"]
        echo = payload["echo_pin"]
        self.pins_dictionary[trigger][
            GatewayBaseAIO.PIN_MODE] = GatewayBaseAIO.SONAR_MODE
        self.pins_dictionary[echo][
            GatewayBaseAIO.PIN_MODE] = GatewayBaseAIO.SONAR_MODE

        await self.arduino.set_pin_mode_sonar(trigger,
                                              echo,
                                              cb=self.sonar_callback)

    async def set_mode_stepper(self, topic, payload):
        """
        This method establishes either 2 or 4 GPIO pins to be used in stepper
        motor operation.
        :param topic:
        :param payload:{"command": "set_mode_stepper", "pins": [“PINS”],
                        "steps_per_revolution": “NUMBER OF STEPS”}
        """
        for pin in payload['pins']:
            self.pins_dictionary[pin][
                GatewayBaseAIO.PIN_MODE] = GatewayBaseAIO.STEPPER_MODE
        await self.arduino.set_pin_mode_stepper(
            payload['steps_per_revolution'], payload['pins'])

    async def set_mode_tone(self, topic, payload):
        """
        Establish a GPIO pin for tone operation.
        :param topic:
        :param payload:{"command": "set_mode_tone", "pin": “PIN”, "tag":”TAG” }
        """
        pin = payload["pin"]
        self.pins_dictionary[pin][
            GatewayBaseAIO.PIN_MODE] = GatewayBaseAIO.TONE_MODE
        await self.arduino.set_pin_mode_tone(pin)

    async def stepper_write(self, topic, payload):
        """
        Move a stepper motor for the specified number of steps.
        :param topic:
        :param payload: {"command": "stepper_write", "motor_speed": “SPEED”,
                         "number_of_steps":”NUMBER OF STEPS” }
        """
        await self.arduino.stepper_write(payload['motor_speed'],
                                         payload['number_of_steps'])

    # Callbacks
    async def digital_input_callback(self, data):
        """
        Digital input data change reported by Arduino
        :param data:
        :return:
        """
        # data = [pin, current reported value, pin_mode, timestamp]
        self.pins_dictionary[data[0]][GatewayBaseAIO.LAST_VALUE] = data[1]
        payload = {
            'report': 'digital_input',
            'pin': data[0],
            'value': data[1],
            'timestamp': data[3]
        }
        await self.publish_payload(payload, 'from_arduino_gateway')

    async def analog_input_callback(self, data):
        # data = [pin, current reported value, pin_mode, timestamp]
        self.pins_dictionary[data[0] + self.arduino.first_analog_pin][
            GatewayBaseAIO.LAST_VALUE] = data[1]
        payload = {
            'report': 'analog_input',
            'pin': data[0],
            'value': data[1],
            'timestamp': data[3]
        }
        await self.publish_payload(payload, 'from_arduino_gateway')

    async def i2c_callback(self, data):
        """
        Analog input data change reported by Arduino

        :param data:
        :return:
        """
        # creat a string representation of the data returned
        self.pins_dictionary[200] = data[1]
        report = ', '.join([str(elem) for elem in data])
        payload = {'report': 'i2c_data', 'value': report}
        await self.publish_payload(payload, 'from_arduino_gateway')

    async def sonar_callback(self, data):
        """
        Sonar data change reported by Arduino

        :param data:
        :return:
        """
        self.pins_dictionary[data[0]][GatewayBaseAIO.LAST_VALUE] = data[1]
        payload = {'report': 'sonar_data', 'value': data[1]}
        await self.publish_payload(payload, 'from_arduino_gateway')

    def my_handler(self, type, value, tb):
        """
        for logging uncaught exceptions
        :param type:
        :param value:
        :param tb:
        :return:
        """
        self.logger.exception("Uncaught exception: {0}".format(str(value)))
예제 #9
0
 You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
 along with this library; if not, write to the Free Software
 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
"""

import asyncio
import sys
from pymata_express.pymata_express import PymataExpress

# This is a demonstration of the tone methods

# retrieve the event loop
loop = asyncio.get_event_loop()

# instantiate pymata express
board = PymataExpress()

try:
    # set a pin's mode for tone operations
    loop.run_until_complete(board.set_pin_mode_tone(3))

    # specify pin, frequency and duration and play tone
    loop.run_until_complete(board.play_tone(3, 1000, 500))
    loop.run_until_complete(asyncio.sleep(2))

    # specify pin and frequency and play continuously
    loop.run_until_complete(board.play_tone_continuously(3, 2000))
    loop.run_until_complete(asyncio.sleep(2))

    # specify pin to turn pin off
    loop.run_until_complete(board.play_tone_off(3))