ondrej1024 / crelay

Controlling different relay cards for home automation with a Linux software
GNU General Public License v2.0
81 stars 31 forks source link

Support for multiple relay cards (command line interface only) #5

Closed a-shevtsov closed 7 years ago

a-shevtsov commented 8 years ago

I've added a new optional switch -s that can be used to specify which relay card one wants to control. The code supporting Web UI has been updated too but it has no effect since serial variable is set to NULL there.

ondrej1024 commented 8 years ago

Thanks a lot for your contribution. I appreciate your work to improve crelay. I looked at your patch and I think it should be improved before merging it.

First of all I noticed that the patch addresses only the Sainsmart relays. That's not a real issue, we can start from there. But the handling of multiple cards I had in mind was somewhat different. The basic idea is to provide an interface to the user which is a simple as possible. Using the serial number of the relay is not simple enough. How can the user know the serial number?

So the basic idea is that the cards detection function doesn't stop at the first card it finds but tries to find all of them. Then is can assign simple increasing card numbers (1, 2, ...) to each card which the user can choose from the command line. Or, alternatively we could increase the relay numbers across different cards. Let's say card 1 has relays 1 to 4, card 2 has relays 5 to 8 and so on. This way the user just specifies the relay number as before and no additional parameter is needed. And of course, also the Web Gui should show the relays on all detected cards.

This approach makes things very simple for the user, but the implementation might not be trivial.

a-shevtsov commented 8 years ago

Sorry, I was too busy trying to make my two SainSmart relay controllers work and forgot to make the right changes to make the other controllers work. I'll fix that. A user can get the serial number from lsusb -v output. Here is a diff of the output of the two identical SainSmart cards:

1c1 < Bus 003 Device 002: ID 0403:6001 Future Technology Devices International, Ltd FT232 USB-Serial (UART) IC

Bus 004 Device 002: ID 0403:6001 Future Technology Devices International, Ltd FT232 USB-Serial (UART) IC 15c15 < iSerial 3 A6008d7P

iSerial 3 A6008cD5

Only bus/device numbers and serial numbers are different. Android Debug Bridge command line tool uses the same approach, if you are working with one phone there is no need to specify its serial number, but if you control multiple phones connected to a PC them you have to specify the serial number of a phone you want to talk to.

With your approach there is going to be a management overhead in the following case: let's say somebody had three identical controllers but after some time the second controller has to be moved to another PC, then all the relay numbers of the third controller will change and these changes have to be reflected everywhere where these numbers had been specified.

As discussed on Ask Ubuntu one can track where a certain USB device is connected to but it seems to be more cumbersome than using serial numbers.

Anyway, this is just a suggestion, if there is a better way to work with multiple identical relay controllers I would be all for it.

a-shevtsov commented 8 years ago

I've added implementation for serial number support in Conrad and HID API code but could not test it since I don't have these controllers handy. GPIO is different so I haven't done anything there.

ondrej1024 commented 8 years ago

Thanks again for your efforts to improve crelay. I had a quick look at your modifications and it looks very good. I will test the different relay card types (need to find some time), although I have only one card for each type. But by specifying the serial number I should be able to see if it works as expected.

I think you have a point in using the serial number with respect to my approach I explained earlier. It will certainly be good to be able to address a specific card with its serial. My approach can always be added later. So it is probably also very handy for the user to have a modified behaviour of the -i option for card identification and print a list of all detected cards, including their serial numbers. Then lsusb would not need to be used.

ondrej1024 commented 8 years ago

Sorry, I accidentally closed this, hit the wrong button.

a-shevtsov commented 8 years ago

Good idea about listing the cards with their serial number. I just realized I forgot to make changes in get_relay_conrad_4chan and set_relay_conrad_4chan function. Will fix this later today.

ondrej1024 commented 8 years ago

I have tested the serial number feature with the 3 relay cards I have here (1 Conrad, 1 Sainsmart and 1 HID API). With all 3 cards attached I can correctly address each card with its serial number. Unfortunately I cannot test the case with more than 1 card for each type. I had to modify the serial number detection for the HID API card, because this is working differently from the others. The iSerial property is actually not defined for these cards as can be seen from lsusb: iManufacturer 1 www.dcttech.com iProduct 2 USBRelay2 iSerial 0 Instead the cards Id (or serial) can be retrieved with the same method that reads the relay states.

I have merged your code to the multiplecards_experimental branch in my repository and added the HID API fix.

ondrej1024 commented 8 years ago

Now we only need to fix the -i option. I have to think about what the best way is to implement this. I'm not sure if the detect_relay_card() function should be modified or if its better to add a new function for detecting all connected cards.

Kepedize commented 8 years ago

What a great lib! Does this thread means I can connect to multiple cards concurrently?

ondrej1024 commented 8 years ago

Yes, if you use the multiplecards_experimental branch, you can already try the multiple cards support. It works for all supported relay cards. However the implementation is not complete yet because you first need to find out the serial number of your card (with lsusb command). This information will have to be supplied by crelay itself. Also the multiple cards support for the Web GUI needs to be added before this feature is released officially.

Kepedize commented 8 years ago

Thanks A lot! btw Did you know your library also detects Deditec i/o cards? it's not mentioned in code/docs but it does, and it's easier to use then the Manufacturer's drivers... So, anyway, let's say I want to use the daemon and parse the text result to get current state for all relays on both cards. can you please point this 'ere noob to steps I need to take, having pulled "multiplecards_experimental" branch?

ondrej1024 commented 8 years ago

Maybe there is some confusion here, so let's get a few things straight

  1. crelay is not a library but a standalone program. I actually did consider providing also a library version which you could include into your own projects, but didn't have time to do so. Might happen in the future.
  2. If you use crelay in daemon mode you get only the WebGUI and HTTP API but not the command line output.
  3. In order to read current relay states using e.g. a script you would use the crelay command line tool.

So once you have pulled the "multiplecards_experimental" branch you would build and install the crelay command as explained in the documentation. Then you need to find out the serial numbers for your cards. You can do that with the Linux lsusb -v command, checking the iSerial property of your cards.

ondrej1024 commented 8 years ago

Then you can check the relay state of each relay by using this command: crelay -s <card serial> <relay number>

or just type crelay which will print the help text, pretty easy, I think.

Kepedize commented 8 years ago

understood! great, thanks

ondrej1024 commented 8 years ago

@khilman: can you please check if the Sainsmart 16 channel control module provides a serial number with the lsusb command?

khilman commented 8 years ago

Doesn't look like it, at least not in iSerial.

Bus 003 Device 069: ID 0416:5020 Winbond Electronics Corp. Device Descriptor: bLength 18 bDescriptorType 1 bcdUSB 1.10 bDeviceClass 0 (Defined at Interface level) bDeviceSubClass 0 bDeviceProtocol 0 bMaxPacketSize0 8 idVendor 0x0416 Winbond Electronics Corp. idProduct 0x5020 bcdDevice 0.00 iManufacturer 1 Nuvoton iProduct 2 HID Transfer iSerial 0 bNumConfigurations 1 Configuration Descriptor: bLength 9 bDescriptorType 2 wTotalLength 41 bNumInterfaces 1 bConfigurationValue 1 iConfiguration 0 bmAttributes 0xc0 Self Powered MaxPower 100mA Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 0 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 3 Human Interface Device bInterfaceSubClass 0 No Subclass bInterfaceProtocol 0 None iInterface 0 HID Device Descriptor: bLength 9 bDescriptorType 33 bcdHID 1.10 bCountryCode 0 Not supported bNumDescriptors 1 bDescriptorType 34 Report wDescriptorLength 27 Report Descriptor: (length is 27) Item(Global): Usage Page, data= [ 0x01 ] 1 Generic Desktop Controls Item(Local ): Usage, data= [ 0x00 ] 0 Undefined Item(Main ): Collection, data= [ 0x01 ] 1 Application Item(Global): Logical Minimum, data= [ 0x00 ] 0 Item(Global): Logical Maximum, data= [ 0xff ] 255 Item(Local ): Usage Minimum, data= [ 0x01 ] 1 Pointer Item(Local ): Usage Maximum, data= [ 0x08 ] 8 Multi-Axis Controller Item(Global): Report Count, data= [ 0x40 ] 64 Item(Global): Report Size, data= [ 0x08 ] 8 Item(Main ): Input, data= [ 0x02 ] 2 Data Variable Absolute No_Wrap Linear Preferred_State No_Null_Position Non_Volatile Bitfield Item(Local ): Usage Minimum, data= [ 0x01 ] 1 Pointer Item(Local ): Usage Maximum, data= [ 0x08 ] 8 Multi-Axis Controller Item(Main ): Output, data= [ 0x02 ] 2 Data Variable Absolute No_Wrap Linear Preferred_State No_Null_Position Non_Volatile Bitfield Item(Main ): End Collection, data=none Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x84 EP 4 IN bmAttributes 3 Transfer Type Interrupt Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 1 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x05 EP 5 OUT bmAttributes 3 Transfer Type Interrupt Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 1 Device Status: 0x0000 (Bus Powered)

ondrej1024 commented 8 years ago

@khilman: OK, thanks. Then I guess the serial number is handled as with the other HID compatible cards. There it is send in the same buffer as the relay states. Can you print the whole 16 bytes buffer we get when requesting the relay states? From this we might figure out if there is a serial number. Do you have by any chance more than one card we can use to test?

khilman commented 8 years ago

Since these are always USB devices, why not use the USB bus ID (portname) as the unique ID?

Unfortunately, I only have one of these, so can't compare two different ones. Anyways, here's a dump of the buffer for an on and an off command:

$ ./crelay 16 on CRELAY: Sain16 USB: portname=0003:0045:00, relay=16, state=ON DBG: msg D2 0E 11 11 11 11 11 11 11 11 48 49 44 43 80 02 DBG: msg C3 0E 00 81 00 00 00 00 00 00 48 49 44 43 6A 02

$ ./crelay 16 off CRELAY: Sain16 USB: portname=0003:0045:00, relay=16, state=OFF DBG: msg D2 0E 11 11 11 11 11 11 11 11 48 49 44 43 80 02 DBG: msg C3 0E 00 01 00 00 00 00 00 00 48 49 44 43 EA 01

ondrej1024 commented 8 years ago

The bus Id could change when unplugging and plugging in the card again and depends on other devices being connected. So in order to be sure to talk to the correct card it was chosen to use the serial number which should be unique. The USB HID relay cards send their serial number in the same buffer where the current relay state is send. So you need to insert the debug print code after the hid_read() function in get_mask(), line 177:

printf("DBG: msg "); for (i=0; i<sizeof(hid_msg_t); i++) printf("%02X ", *(((uint8*)hid_msg)+i)); printf("\n");

Then we can see the whole buffer we have received from the card by reading the current relay state.

khilman commented 8 years ago

Here's what I get in the buffer right after the hid_read() in get_mask():

DBG: msg D2 0B 0A 00 AA 00 00 00 00 00 00 00 00 00 00 00

ondrej1024 commented 8 years ago

Thanks for testing. Looks like there is not much in the response buffer, apart from the relay states. I will try to contact Sainsmart and see if I can get some information from them.

ondrej1024 commented 8 years ago

I thought it would be worth a try to ask the Sainsmart customer support but this is all I got:

Dear Customer,

We're sorry for any inconvenience this may have caused you. but we do not have the technical documentation as you request. All we have is the link we provide at our product page. Hope you could understand.

Have a wonderful day.

Best regards,

So I guess I will just have a wonderful day now :smirk:

sabroe commented 7 years ago

Hi, I too would love to see multiple cards supported. Otherwise I am very please too see things just work. I had two USB 8x relay boards connected - a Sainsmart and a Chinese HID controlled board. Tried the "-i" option as the first action and noted, that one board only could be controlled.

As for the reference to boards through USB, I have some opinions:

Having the option to refer to boards through either serial number or some /dev location and depending upon the board, would be of great value. It is preferable that identifiers used can be viewed, inspected and manipulated with existing commandline tools.

+1 to the support for multiple relay cards.

ondrej1024 commented 7 years ago

@sabroe, command line support for multiple relay cards is already available in the multiplecards_experimental branch. Please test and let me know if it works with your cards.

I wanted to implement also the WebGUI and HTTP API support for multiple cards but it is not trivial and I don't have time for it now. So if there are no issues with the command line support I might release this in the next days as a new version of crelay.

Then we need to see if card selection via serial is sufficient or if it also needs to be USB port based.

Please send me your feedback.

ondrej1024 commented 7 years ago

Multiple cards support (CLI only) is now officially released on the master branch.