예제 #1
0
def main():
    print('Single R421A08 relay board example\n')

    # Create relay_modbus object
    _modbus = relay_modbus.Modbus(serial_port=SERIAL_PORT, verbose=False)

    # Open serial port
    try:
        _modbus.open()
    except relay_modbus.SerialOpenException as err:
        print(err)
        sys.exit(1)

    # Create relay board object
    board = relay_boards.R421A08(_modbus,
                                 address=address,
                                 board_name=board_name,
                                 verbose=False)

    # Print board info
    print_relay_board_info(board)

    # Control some relays
    relay_control(board)

    print('Done')
    def test_crc(self):
        modbus_test = relay_modbus.Modbus(self._serial_port, verbose=False)
        modbus_test.open()

        self.assertListEqual(modbus_test.crc([]), [0xFF, 0xFF])
        self.assertListEqual(modbus_test.crc([0x00]), [0xBF, 0x40])
        self.assertListEqual(modbus_test.crc([0x12, 0x34, 0x56, 0x67]), [0x3A, 0xD8])
        self.assertListEqual(modbus_test.crc([0x12, 0x34, 0x56, 0x67, 0x3A, 0xD8]), [0x00, 0x00])
    def test_send_verbose(self):
        modbus_verbose = relay_modbus.Modbus(self._serial_port, verbose=True)
        modbus_verbose.open()

        with captured_output() as (out, err):
            modbus_verbose.send([0x01, 0x06, 0x00, 0x01, 0x01, 0x00])
            output = out.getvalue().strip()
            self.assertEqual(output, 'TX  8 Bytes:  01 06 00 01 01 00 D9 9A')
def main():
    print('Multiple R421A08 relay boards example\n')

    # ----------------------------------------------------------------------------------------------
    # Create relay_modbus object
    _modbus = relay_modbus.Modbus(serial_port=SERIAL_PORT, verbose=False)

    # Open serial port
    try:
        _modbus.open()
    except relay_modbus.SerialOpenException as err:
        print(err)
        sys.exit(1)

    # ----------------------------------------------------------------------------------------------
    # Create relay board object with on address 1
    relays_kitchen = relay_boards.R421A08(_modbus,
                                          address=1,
                                          board_name='Kitchen')

    # Create second relay board object on address 2
    relays_living_room = relay_boards.R421A08(_modbus,
                                              address=1,
                                              board_name='Living room')

    # ----------------------------------------------------------------------------------------------
    # Print board info
    print_relay_board_info(relays_kitchen)
    print_relay_board_info(relays_living_room)

    # ----------------------------------------------------------------------------------------------
    # Control relays kitchen
    print('Relay board #{} relay 1 on'.format(relays_kitchen.address))
    relays_kitchen.on(1)
    print('Relay board #{} relays 2, 3 and 7 on'.format(
        relays_kitchen.address))
    relays_kitchen.on_multi([2, 3, 7])
    print('Relay board #{} status:'.format(relays_kitchen.address))
    relays_kitchen.print_status_all()
    time.sleep(2)

    # ----------------------------------------------------------------------------------------------
    # Control relays living room
    print('Relay board #{} toggle relay 8'.format(relays_living_room.address))
    relays_living_room.toggle(8)
    print('Relay board #{} status:'.format(relays_kitchen.address))
    relays_living_room.print_status_all()
    time.sleep(2)

    # ----------------------------------------------------------------------------------------------
    # Control relays kitchen and living room
    print('Relay board #{} all off'.format(relays_kitchen.address))
    relays_kitchen.off_all()
    print('Relay board #{} all off'.format(relays_living_room.address))
    relays_living_room.off_all()

    print('Done')
    def test_send_receive(self):
        modbus_test = relay_modbus.Modbus(self._serial_port, verbose=False)
        modbus_test.open()

        tx_data = [0x01, 0x06, 0x00, 0x01, 0x01, 0x00]

        modbus_test.send(tx_data)
        rx_data = modbus_test.receive(len(tx_data))

        self.assertListEqual(tx_data, rx_data[:len(tx_data)])
    def test_send_receive_no_append_crc(self):
        modbus_test = relay_modbus.Modbus(self._serial_port, verbose=False)
        modbus_test.open()

        tx_data = [0x01, 0x06, 0x00, 0x01, 0x02, 0x00, 0xD9, 0x6A]

        modbus_test.send(tx_data, append_crc_to_frame=False)
        rx_data = modbus_test.receive(len(tx_data))

        self.assertListEqual(tx_data, rx_data)
    def test_transfer_timeout(self):
        modbus_test = relay_modbus.Modbus(self._serial_port, verbose=False)
        modbus_test.open()

        with captured_output() as (out_, err_):
            errmsg = None
            try:
                modbus_test.transfer([0x01], rx_length=100)
            except relay_modbus.TransferException as err:
                errmsg = str(err)
            self.assertEqual(errmsg, 'RX error: Receive timeout')
예제 #8
0
def modbus_cmd_monitor(args):
    """
        MODBUS monitor command: Print receiving frames on the serial console.
    :param args: Commandline arguments
    :return: None
    """

    # Create MODBUS object
    _modbus = relay_modbus.Modbus(args.serial_port, baud_rate=args.baudrate)
    _modbus.open()

    # Start monitoring
    _modbus.monitor_start(args.address)
    def test_monitor(self):
        modbus_send = relay_modbus.Modbus(self._serial_port)
        modbus_monitor = relay_modbus.Modbus(self._serial_port_monitor)

        modbus_send.open()
        modbus_monitor.open()

        for address in [0, self._address]:
            with captured_output() as (out, err):
                # Start monitor
                modbus_monitor.monitor_start(address, blocking=False)

                # Send message
                modbus_send.send([0x01, 0x06, 0x00, 0x01, 0x01, 0x00])

                # Wait some time to process the frame
                time.sleep(0.1)

                # Stop monitor
                modbus_monitor.monitor_stop()

                if address == 0:
                    msg_start = 'Monitor receiving frames from all addresses.'
                else:
                    msg_start = 'Monitor receiving frames from address {} only.'.format(address)

                # Check stdout
                output = out.getvalue().strip()
                self.assertEqual(output,
                                 '{}\n'
                                 'Press CTRL+C to abort.\n'
                                 'RX 16 Bytes:  01 06 00 01 01 00 D9 9A 01 06 00 01 01 00 D9 9A'.
                                 format(msg_start))

                # Wait for test completion
                time.sleep(0.05)
예제 #10
0
def modbus_cmd_send(args):
    """
        MODBUS send command
    :param args: Commandline arguments
    :return: None
    """

    # Create MODBUS object
    _modbus = relay_modbus.Modbus(args.serial_port,
                                  baud_rate=args.baudrate,
                                  verbose=True)
    try:
        _modbus.open()
    except relay_modbus.SerialOpenException:
        print_stderr('Error: Cannot open serial port: ' + args.serial_port)
        sys.exit(1)

    tx_data = None
    try:
        tx_str = args.frame

        # Replace characters, for example:
        #   ':010600010100D99A' -> '010600010100D99A'
        #   '0x01, 0x06, 0x00, 0x01, 0x01, 0x00, 0xD9, 0x9A' -> '01 06 00 01 01 00 D9 9A'
        for c in ['0x', ':', ',', ' ']:
            tx_str = tx_str.replace(c, '')

        # Insert space every 2 characters, for example:
        #   '010600010100D99A' -> '01 06 00 01 01 00 D9 9A'
        tx_str = ' '.join(a + b for a, b in zip(tx_str[::2], tx_str[1::2]))

        # Split data in ints, for example:
        #   [0x01, 0x06, 0x00, 0x01, 0x01, 0x00, 0xD9, 0x9A]
        tx_data = [int(i, 16) for i in tx_str.split(' ')]
    except ValueError:
        print('Incorrect send argument. Expecting --send formats like:')
        print('  ":010600010100"')
        print('  "01 06 00 01 01 00"')
        print('  "0x01, 0x06, 0x00, 0x01, 0x01, 0x00"')
        print('Note: CRC bytes can be omitted.')
        sys.exit(1)

    # Send and receive MODBUS frame
    _modbus.transfer(tx_data, not args.no_append_crc, rx_length=0)
    def __init__(self, parent, settings_file=None):
        frmRelays.__init__(self, parent)

        # Protect events when closing window
        self.closing_window = False

        # Set window size and minimum window size
        self.SetSize(wx.Size(580, 650))
        self.SetMinSize(wx.Size(580, 650))

        # Set application icon
        ico_path = resource_path('images/relay.ico')
        if ico_path:
            self.m_relay_icon = wx.Icon(ico_path)
            self.SetIcon(self.m_relay_icon)
        self.SetTitle('R421A08 Relay Control')

        # Create taskbar icon
        self.m_taskbar_icon = CustomTaskBarIcon(self, self.m_relay_icon)

        # Create MODBUS object
        self.m_relay_modbus = relay_modbus.Modbus()

        # Refresh serial ports
        self.OnRefreshPortsClick(None)
        self.m_menuItemDisconnect.Enable(False)

        # Load settings from file when available
        self.m_settings_file = settings_file
        self.m_panel_changed = False
        if self.m_settings_file and os.path.exists(self.m_settings_file):
            self.load_settings(self.m_settings_file)
        else:
            # Create default relay panel
            self.new_relay_panel()

            # Disable controls on relay panel
            self.disable_relay_panels()

            # Disable relay menu
            self.disable_relay_menu()

        self.m_notebook.Bind(wx.EVT_CONTEXT_MENU, self.OnContext)
예제 #12
0
    def __init__(self, parent, serial_port=None):
        frmModbus.__init__(self, parent)

        # Set default serial port
        self._serial_port = serial_port

        # Set application icon
        ico_path = resource_path('images/modbus.ico')
        if os.path.exists(ico_path):
            self.SetIcon(wx.Icon(ico_path))

        # Initialize control states
        self.controls_disconnect()

        # Create MODBUS object
        self._modbus = relay_modbus.Modbus()

        # Transmit / receive frame counter
        self.frame_count = 0

        # Create MODBUS receive thread
        self._modbus_receive_thread = ModbusReceiveThread(
            self._modbus, self.append_log)
        self._modbus_receive_thread.daemon = True
        self._modbus_receive_thread.start()

        # Load serial ports
        self.OnBtnRefreshClick(None)

        if self._serial_port:
            # Open default serial port
            self.OnBtnConnectDisconnect()
            self.m_cmbCommand.SetFocus()
        else:
            # Set default status bar text
            self.m_statusBar.SetStatusText(
                'Select a serial port and click Open')
    def CreateObjects(self, serial_port, address):
        # Check argument types
        assert type(serial_port) == str
        assert type(address) == int

        # Create MODBUS object and open serial port
        self.m_relay_modbus = relay_modbus.Modbus(serial_port)
        try:
            self.m_relay_modbus.open()
        except relay_modbus.SerialOpenException as err:
            wx.MessageBox(str(err), u'Failure', style=wx.OK | wx.ICON_STOP)
            sys.exit(1)

        # Create relay board object
        self.m_relay_board = relay_boards.R421A08(self.m_relay_modbus)
        if address < 0 or address >= self.m_relay_board.num_addresses:
            wx.MessageBox(u'Invalid address {}'.format(address), u'Failure',
                          style=wx.OK | wx.ICON_STOP)
            sys.exit(1)
        self.m_relay_board.address = address

        # Set window title
        self.SetTitle(u'{} address {}'.format(self.m_relay_modbus.serial_port,
                                              self.m_relay_board.address))
예제 #14
0
def argument_parser(args):
    """
        Argument parser
    :param args: Commandline arguments
    :return: None
    """

    # ----------------------------------------------
    # Description and help strings
    description = \
        'Python script to control a 8 Channel RS485 MODBUS RTU relay board type R421A08.'

    help_serial_port = \
        'Serial port (such as COM1 or /dev/ttyUSB0)'

    help_address = \
        'Address of the board [0..{}] (Set DIP switches)'.format(R421A08_NUM_ADDRESSES - 1)

    help_relays = \
        'Relay numbers [1..{}] or * for all relays'.format(R421A08_NUM_RELAYS)

    # ----------------------------------------------------------------------------------------------
    # Create argument parser
    _parser = argparse.ArgumentParser(description=description)

    # Serial port argument is always required
    _parser.add_argument('serial_port',
                         metavar='<SERIAL_PORT>',
                         type=str,
                         help=help_serial_port)

    # Address argument is always required
    _parser.add_argument('address',
                         metavar='<ADDRESS>',
                         type=arg_check_address,
                         help=help_address)

    # ----------------------------------------------------------------------------------------------
    # Create sub command arguments
    _subparsers = _parser.add_subparsers(help='Relay command')

    # Create status argument
    _parser_status = _subparsers.add_parser('status', help='Read status')
    _parser_status.add_argument('relays',
                                metavar='<RELAYS>',
                                nargs='*',
                                default=['*'],
                                type=arg_check_relay,
                                help=help_relays)
    _parser_status.add_argument('-v',
                                '--verbose',
                                action='store_true',
                                help='Print verbose')
    _parser_status.set_defaults(func=relay_cmd_status)

    # Create poll argument
    # _parser_poll = _subparsers.add_parser('poll', help='Poll status')
    # _parser_poll.add_argument('relays', metavar='<RELAYS>', nargs='*', default=['*'],
    #                           type=arg_check_relay, help=help_relays)
    # _parser_poll.add_argument('-i', '--interval', type=int, help='Poll interval in seconds')
    # _parser_poll.add_argument('-v', '--verbose', action='store_true', help='Print verbose')
    # _parser_poll.set_defaults(func=relay_cmd_poll)

    # Create on argument
    _parser_on = _subparsers.add_parser('on', help='On')
    _parser_on.add_argument('relays',
                            metavar='<RELAYS>',
                            nargs='*',
                            type=arg_check_relay,
                            help=help_relays)
    _parser_on.add_argument('-v',
                            '--verbose',
                            action='store_true',
                            help='Print verbose')
    _parser_on.set_defaults(func=relay_cmd_on)

    # Create off argument
    _parser_off = _subparsers.add_parser('off', help='Off')
    _parser_off.add_argument('relays',
                             metavar='<RELAYS>',
                             nargs='*',
                             type=arg_check_relay,
                             help=help_relays)
    _parser_off.add_argument('-v',
                             '--verbose',
                             action='store_true',
                             help='Print verbose')
    _parser_off.set_defaults(func=relay_cmd_off)

    # Create toggle argument
    _parser_toggle = _subparsers.add_parser('toggle', help='Toggle')
    _parser_toggle.add_argument('relays',
                                metavar='<RELAYS>',
                                nargs='*',
                                type=arg_check_relay,
                                help=help_relays)
    _parser_toggle.add_argument('-v',
                                '--verbose',
                                action='store_true',
                                help='Print verbose')
    _parser_toggle.set_defaults(func=relay_cmd_toggle)

    # Create latch argument
    _parser_latch = _subparsers.add_parser('latch', help='Latch')
    _parser_latch.add_argument('relays',
                               metavar='<RELAYS>',
                               nargs='*',
                               type=arg_check_relay,
                               help=help_relays)
    _parser_latch.add_argument('-v',
                               '--verbose',
                               action='store_true',
                               help='Print verbose')
    _parser_latch.set_defaults(func=relay_cmd_latch)

    # Create momentary argument
    _parser_latch = _subparsers.add_parser('momentary', help='Momentary')
    _parser_latch.add_argument('relays',
                               metavar='<RELAYS>',
                               nargs='*',
                               type=arg_check_relay,
                               help=help_relays)
    _parser_latch.add_argument('-v',
                               '--verbose',
                               action='store_true',
                               help='Print verbose')
    _parser_latch.set_defaults(func=relay_cmd_momentary)

    # Create delay argument
    _parser_moment = _subparsers.add_parser('delay', help='Delay')
    _parser_moment.add_argument('relays',
                                metavar='<RELAYS>',
                                nargs='*',
                                type=arg_check_relay,
                                help=help_relays)
    _parser_moment.add_argument(
        '-d',
        '--delay',
        type=arg_check_delay,
        default=2,
        help='Delay (1..255 seconds) Default: 2 seconds')
    _parser_moment.add_argument('-v',
                                '--verbose',
                                action='store_true',
                                help='Print verbose')
    _parser_moment.set_defaults(func=relay_cmd_delay)

    # ----------------------------------------------------------------------------------------------
    # Parse arguments
    _args = None
    try:
        _args = _parser.parse_args(args)

        # Check required arguments
        for argument in ['serial_port', 'address', 'relays', 'verbose']:
            if argument not in _args:
                raise AttributeError()
    except AttributeError:
        _parser.print_help()
        sys.exit(0)

    # Create relay_modbus object
    _modbus = relay_modbus.Modbus(_args.serial_port, verbose=_args.verbose)
    try:
        _modbus.open()
    except serial.SerialException:
        print_stderr('Error: Cannot open serial port: ' + args.serial_port)
        sys.exit(1)

    # Create relay board object
    _relay_board = relay_boards.R421A08(_modbus,
                                        address=_args.address,
                                        verbose=_args.verbose)

    _args.func(_args, relay_boards=_relay_board)
    def test_crc_invalid_type(self):
        modbus_test = relay_modbus.Modbus(self._serial_port, verbose=False)
        modbus_test.open()

        self.assertRaises(AssertionError, modbus_test.crc, 0x00)
    def test_modbus_check_properties(self):
        modbus_test = relay_modbus.Modbus(self._serial_port, verbose=False)
        modbus_test.open()

        self.assertEqual(modbus_test.serial_port, self._serial_port)
        self.assertEqual(modbus_test.baudrate, 9600)
    def test_send_no_data(self):
        modbus_test = relay_modbus.Modbus(self._serial_port, verbose=False)
        modbus_test.open()

        self.assertRaises(AssertionError, modbus_test.send, None)
# Required: Configure serial port, for example:
#   On Windows: 'COMx'
#   On Linux:   '/dev/ttyUSB0'
SERIAL_PORT = 'COM3'


def check(retval):
    if not retval:
        sys.exit(1)


if __name__ == '__main__':
    print('Getting started R421A08 relay board\n')

    # Create MODBUS object
    _modbus = relay_modbus.Modbus(serial_port=SERIAL_PORT)

    # Open serial port
    try:
        _modbus.open()
    except relay_modbus.SerialOpenException as err:
        print(err)
        sys.exit(1)

    # Create relay board object
    board = relay_boards.R421A08(_modbus, address=1)

    print('Status all relays:')
    check(board.print_status_all())
    time.sleep(1)
    def test_crc_no_argument(self):
        modbus_test = relay_modbus.Modbus(self._serial_port, verbose=False)
        modbus_test.open()

        self.assertRaises(TypeError, modbus_test.crc)