pir8ped
Posts: 56
Joined: Thu Dec 31, 2015 10:27 am

Using Java to control usb 16 channel relay board

Tue May 30, 2023 5:21 am

Hi,

I want to control a 16 channel relay board via USB, using something like this: https://www.amazon.co.uk/Oumij-Multi-Fu ... B07YQWJDYL

I can't find a straight forward way to communicate with the USB connection using Java. Can anyone help?

I'm surprised this approach isn't more common. I've previously used a board full of transistors and resistors to connect the pi to the relay board inputs, running an irrigation system.

Image

It worked for a few years, but in the end Image

I suspect the fire was caused by a 12v power supply overheating, but I can only guess what went wrong as there isn't much evidence left. It might not have been the board.

But anyway, rebuilding this system, I'd very much like to reduce the number of wires if possible, so connecting the pi to the relay board via USB seems an obvious simplification.

Thanks.

knute
Posts: 897
Joined: Thu Oct 23, 2014 12:14 am
Location: Texas

Re: Using Java to control usb 16 channel relay board

Tue May 30, 2023 10:47 pm

Have you tried writing to the device as if it were a file?

What is the message you have to send to turn a relay on or off?

On second thought, that might not work. If I can find my USB extension cable I'll hook up a couple of Pis and see if I can get it to work.

ame
Posts: 7815
Joined: Sat Aug 18, 2012 1:21 am
Location: New Zealand

Re: Using Java to control usb 16 channel relay board

Wed May 31, 2023 1:47 am

It's undoubtedly a USB serial device, so plug it in, determine the device id, and open it. Then the protocol is described in the Amazon product page:

Note:
A0 01 01 A2 Open the First Way
A0 01 00 A1 Closes the First Way
A0 02 01 A2 Opens the Second Way
A0 02 00 A1 Closes the Second Way
A0 03 01 A2 Opens the 3rd Way
A0 03 00 A1 Closes the 3rd Way
A0 04 01 A2 Opens the 4rd Way
A0 04 00 A1 Closes the 4rd Way
A0 05 01 A2 Opens the 5th Way
A0 05 00 A1 Closes the 5th Way
A0 06 01 A2 Opens the 6rd Way
A0 06 00 A1 Closes the 6rd Way
A0 07 01 A2 Opens the 7rd Way
A0 07 00 A1 Closes the 7rd Way
etc.

So, basically write A0 0n 01 A2 or A0 0n 00 A1 to turn device n on or off. It's not clear if it's an ASCII string or a series of bytes, but a bit of experimentation or Googling will determine that.
Oh no, not again.

pir8ped
Posts: 56
Joined: Thu Dec 31, 2015 10:27 am

Re: Using Java to control usb 16 channel relay board

Wed May 31, 2023 5:30 am

I haven't received the device yet - if it's just like writing to a file, it should be no problem. It's on order. I'll give it a whirl next week.

Thanks

pir8ped
Posts: 56
Joined: Thu Dec 31, 2015 10:27 am

Re: Using Java to control usb 16 channel relay board

Wed Jun 07, 2023 1:42 pm

I have my usb device, and I've had a go at controlling it, using usb4java. I'm having a problem with permission to access the device. I've been following the advice written here: https://unix.stackexchange.com/question ... -in-libusb

I can't access the device:

javax.usb.UsbPlatformException: USB error 3: Can't open device Bus 001 device 007: ID 1a86:7523: Access denied (insufficient permissions)

I'm sure I've got the right device:

Code: Select all

Device Descriptor:
  bLength                 18
  bDescriptorType          1
  bcdUSB                1.10
  bDeviceClass           255 Vendor-specific
  bDeviceSubClass          0
  bDeviceProtocol          0
  bMaxPacketSize0          8
  idVendor            0x1a86
  idProduct           0x7523
  bcdDevice             2.64
  iManufacturer            0
  iProduct                 2
  iSerial                  0
  bNumConfigurations       1
I've tried making a file /etc/udev/rules.d/99-localusb.rules containing the text:

SUBSYSTEM=="usb", ATTR{idVendor}=="1a86", ATTR{idProduct}=="7523", MODE="0666"

Didn't help. That page I was referring to sometimes mentioned the folder /etc/udev/rules.d/ and sometimes /lib/udev/rules.d/

I don't know which was the correct folder to use, so I've put a file called 99-localusb.rules in each of them.

I've also look at /lib/udev/rules.d/50-udev-default.rules referred to at the top of that page. I was hoping to change all the usb devices to 0666, since I am the only user of the rasp pi. I was hoping to see the line:

# 'libusb' device nodes
SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", MODE="0664"

and change it to

# 'libusb' device nodes
SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", MODE="0666"

but a note at the top of the file points out that it isn't so useful to edit the file as it will be over-written on updating. And also, even as an experiment, I couldn't try it as that line doesn't exist in my /lib/udev/rules.d/50-udev-default.rules file.

What I do have in that file is:

SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", IMPORT{builtin}="usb_id", IMPORT{builtin}="hwdb --subsystem=usb", GOTO="default_hwdb_imported"
ENV{MODALIAS}!="", IMPORT{builtin}="hwdb --subsystem=$env{SUBSYSTEM}"
LABEL="default_hwdb_imported"

So it looks like the advice on that page, aimed for linux users, isn't appropriate for Raspian.

Can anyone tell me how to set the permissions for my device on the pi please?

pir8ped
Posts: 56
Joined: Thu Dec 31, 2015 10:27 am

Re: Using Java to control usb 16 channel relay board

Wed Jun 07, 2023 2:03 pm

OK, got over that hump:

Made the file /etc/udev/rules.d/50-localusb.rules containing the text:

SUBSYSTEMS=="usb", ATTR{idVendor}=="1a86", ATTR{idProduct}=="7523", GROUP="dialout", MODE="0666"


Then

sudo udevadm control --reload ; sudo udevadm trigger

And the Access denied notice went away.

Still not working. There seems to be an issue with configuring the device, but at least, I now have the permission to access it.

User avatar
rpdom
Posts: 22369
Joined: Sun May 06, 2012 5:17 am
Location: Chelmsford, Essex, UK

Re: Using Java to control usb 16 channel relay board

Wed Jun 07, 2023 2:25 pm

pir8ped wrote:
Wed Jun 07, 2023 2:03 pm
Made the file /etc/udev/rules.d/50-localusb.rules
Yes, that's the correct location for user configuration changes like that. The /lib or /usr/lib location is for the system default files supplied with the installed software.
Unreadable squiggle

pir8ped
Posts: 56
Joined: Thu Dec 31, 2015 10:27 am

Re: Using Java to control usb 16 channel relay board

Thu Jun 08, 2023 11:21 am

I optimistically had the usb controller attached to the relay board, but no relays were switching.

So I've been messing about with the controller without attaching it to the relay board.

It takes a 5v supply, and when this is connected, all the terminals read 5v. I think that must be right - the relay board is marked 'Low level trigger', so I'm assuming that when the controller is sent a command to one of its channel to switch a relay, the 5v is dropped.

Anyway, I run the code, and see no change in the voltage readings of the controller terminals. There's no indication of it having received the command, no LED flashes. The output from the code suggests the command is sent OK.

I'm stumped! Any suggestions? Here's the code I've been running:

Code: Select all

private String usbDeviceName = "usb-1a86_USB_Serial-if00-port0";
	private static short VENDOR_ID = 0x1a86;
	private static short PRODUCT_ID = 0x7523;
	static UsbDevice relayBoardUSBConnector = null;
	static UsbPipe pipe;

	static String test = "A0 01 01 A2";

	public static void main(String[] args) {
		try {
			System.out.println("*****  Starting Program *****");
			relayBoardUSBConnector = findDevice(UsbHostManager.getUsbServices().getRootUsbHub(), VENDOR_ID, PRODUCT_ID);
		} catch (Exception ex) {
			System.err.println(ex.toString());
		}
		try {
			if (relayBoardUSBConnector != null) {
				UsbDeviceDescriptor desc = relayBoardUSBConnector.getUsbDeviceDescriptor();
				System.out.println("desc=" + desc);
				claimTheInterface(relayBoardUSBConnector);
				sendSomeBytes();
			}
		} catch (SecurityException | UsbException | UsbNotActiveException | UsbDisconnectedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			try {
				pipe.close();
			} catch (UsbNotActiveException | UsbNotOpenException | UsbDisconnectedException | UsbException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

	public static UsbDevice findDevice(UsbHub hub, short vendorId, short productId) {
		for (UsbDevice device : (List<UsbDevice>) hub.getAttachedUsbDevices()) {
			UsbDeviceDescriptor desc = device.getUsbDeviceDescriptor();
			if (desc.idVendor() == vendorId && desc.idProduct() == productId)
				return device;
			if (device.isUsbHub()) {
				device = findDevice((UsbHub) device, vendorId, productId);
				if (device != null)
					return device;
			}
		}
		return null;
	}

	private static void sendSomeBytes() {

		int sent;
		try {
			sent = pipe.syncSubmit(test.getBytes());
			System.out.println(sent + " bytes sent");
		} catch (UsbNotActiveException | UsbNotOpenException | IllegalArgumentException | UsbDisconnectedException
				| UsbException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public static void claimTheInterface(UsbDevice device)
			throws UsbClaimException, UsbNotActiveException, UsbDisconnectedException, UsbException {


		UsbConfiguration configuration = device.getActiveUsbConfiguration();
		System.out.println("configuration.toString()=" + configuration.toString());

		System.out.println("listing interfaces=");
		List<UsbInterface> usbInterfaces = device.getActiveUsbConfiguration().getUsbInterfaces();
		for (Iterator iterator = usbInterfaces.iterator(); iterator.hasNext();) {
			UsbInterface usbInterface = (UsbInterface) iterator.next();
			System.out.println("usbInterface.toString()=" + usbInterface.toString());
		}

		UsbInterface iface = configuration.getUsbInterface((byte) 0);
		System.out.println("iface.toString()=" + iface.toString());
		// this allows us to steal the lock from the kernel
		iface.claim(usbInterface -> true);
		final List<UsbEndpoint> endpoints = iface.getUsbEndpoints();
		for (Iterator iterator = endpoints.iterator(); iterator.hasNext();) {
			UsbEndpoint usbEndpoint = (UsbEndpoint) iterator.next();
			System.out.println("usbEndpoint.toString()=" + usbEndpoint.toString());
		}
		// The first endpoint seems to work, the other 2 cause the app to hang.
		pipe = endpoints.get(0).getUsbPipe();
		System.out.println("here");
		pipe.open();
		System.out.println("here2");
	}

And the output:

Code: Select all

pi@raspberrypi:~ $ java -cp /home/pi/Tester.jar usb.Tester
*****  Starting Program *****
desc=Device Descriptor:
  bLength                 18
  bDescriptorType          1
  bcdUSB                1.10
  bDeviceClass           255 Vendor-specific
  bDeviceSubClass          0
  bDeviceProtocol          0
  bMaxPacketSize0          8
  idVendor            0x1a86
  idProduct           0x7523
  bcdDevice             2.64
  iManufacturer            0
  iProduct                 2
  iSerial                  0
  bNumConfigurations       1

configuration.toString()=USB configuration 01
listing interfaces=
usbInterface.toString()=USB interface 00
iface.toString()=USB interface 00
usbEndpoint.toString()=org.usb4java.javax.Endpoint@1855c9a
usbEndpoint.toString()=org.usb4java.javax.Endpoint@1084709
usbEndpoint.toString()=org.usb4java.javax.Endpoint@24f60b
here
here2
11 bytes sent

ame
Posts: 7815
Joined: Sat Aug 18, 2012 1:21 am
Location: New Zealand

Re: Using Java to control usb 16 channel relay board

Thu Jun 08, 2023 11:24 am

Here's a Python version you could try:
https://gist.github.com/RJ/7acba5b06a03 ... id=3618532
Oh no, not again.

pir8ped
Posts: 56
Joined: Thu Dec 31, 2015 10:27 am

Re: Using Java to control usb 16 channel relay board

Thu Jun 08, 2023 2:54 pm

It's been a while since I used Python, but that code you linked to showed a byte[] being sent to the device like this:

close_relay_cmd = [0xA0, 0x01, 0x01, 0xA2]
ep.write(close_relay_cmd)

What I was sending in Java was a String:

String test = "A0 01 01 A2";

and then sending that as a byte[]. Not smart!

What got it working as sending

byte[] testOpenByte = { (byte)0xA0, 0x01, 0x00, (byte)0xA1};
byte[] testCloseByte = {(byte) 0xA0, 0x01, 0x01, (byte) 0xA2};

So thanks v much for the help. I've now just got to go from the bashed together test code to some reasonable code to fit into my app.

Return to “Java”