-
-
Notifications
You must be signed in to change notification settings - Fork 108
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for USB Knx Interfaces #581
Comments
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Please make sure to update to the latest version of xknx (or Home Assistant) and check if that solves the issue. Let us know if that works for you by adding a comment 👍 This issue has now been marked as stale and will be closed if no further activity occurs. Thank you for your contributions. |
For the not yet so familiar ones like myself. The specification can be downloaded for free from KNX Specifications. A free account can be created and then the mentioned item has to be put in the basket. After the order is placed (free again) you can download the specification. KNX uses the USB HID device class. For those that want to just have a quick look, here are some online resources. KNX protocol description C++ implementation of the USB interface USB HID specification
To talk to KNX USB devices there are different possibilities. The python library pyusb uses libusb and there is activity trying to integrate it into asyncio in pyusb/pyusb#63. There is also the python library hidapi which is more HID specific. @farmio, do you already have thoughts on how to integrate all this? |
Hi 👋! If one is more comfortable in looking at Java there is also the Calimero project having Knx USB support. @kistlin I personally do not have any thoughts on how to implement this, nor any plans to do it myself. If you like to do it, you are very welcome! Feel free to join the xknx Discord Server if you want to chat about implementation details. |
For now I have done some isolated work in the examples folder. It can be found in the following commit kistlin@c6f70a6 As a USB interface I used the Siemens OCI702 USB - KNX Serviceinterface. Sending bytes from a recorded valid KNX frame, seems to work. @farmio do you know where in the specification I find information on the application layer? And maybe a description (reference to a document) of the workflow of typical first steps. |
Hi! For Application layer information I'd look at To map KNX group objects to bytes you need to know the used DPT and decode it accordingly. See the Assigning an address to a device is currently not supported from xknx. There is currently a PR open for this. From https://www.cs.hs-rm.de/~werntges/proj/knxusb/KSC2005-LinuxUSB.pdf I read there is an Application note |
Yes sounds reasonable. The L_Data.req example here is a CEMI Frame - so this is what you get by creating a telegram = Telegram(
destination_address=GroupAddress("1/0/15"),
payload=GroupValueWrite(DPTBinary(0)),
)
)
cemi = CEMIFrame.init_from_telegram(xknx, telegram, code=CEMIMessageCode.L_DATA_REQ, src_addr=xknx.own_address) Then append cemi = CEMIFrame(xknx)
try:
cemi.from_knx(raw[header_length:])
except UnsupportedCEMIMessage as err:
logger.warning("CEMI not supported: %s", err)
# handle error (see eg https://github.com/XKNX/xknx/blob/main/xknx/knxip/routing_indication.py) As far as I know Cemi support is mandatory, EMI1 adn EMI2 are optional, so going with Cemi schould be fine. |
What do you think of an integration where a To test this integration I created a
The switch example with USB would look like this. Only the instantiation of XKNX needs a change.
All the existing code with default initialization would still work as expected. |
Sure for an initial proof of concept implementation this sounds reasonable. To communicate with xknx devices it just needs to register as an Is there a tunnelling-like ConnectRequest - ConnectResponse process in USB or is it connectionless? |
Yes it seems no TunnelingACK is sent on USB, which is good. I guess L_DATA.con confirmation CEMI frames will be received (and should be waited for) just like on IP Tunneling? Is it possible to identify a USB device as KNX interface? see https://wiki.debian.org/HowToIdentifyADevice/USB do they share some common device protocol or class or description? |
As for the first question, the only thing I found atm. is in 4.1.5.1 Flow Control
Which indicates that the server could receive multiple requests, but I guess it makes it easier to implement (maybe?) if we just wait on the response first. To the second question in 3 KNX USB Interface3.1 Introduction3.1.1 Scope
And the USB HID specification defines that 4.1 The HID Class
So in my understanding there is no real possibility to scan the USB devices and be sure it is a KNX device. A possibility is to enumerate all HID devices and check for a known set of vendor/product id's. These would probably grow over time. |
See #323 (and the link there if you speak German) for the L_Data.con flow control. |
Yes the reference in your ticket to 4.1.5.1 Flow Control
FYI your assumption in the forum about the meaning of 1.1 Communication Modes
And just for me, we are speaking about this, so that a possible USB implementation doesn't make the same mistake? :) Because for now I focused on the sending of a telegram. I hoped to just put a received telegram into the queue an we are good :). |
Not yet, since not every sent telegram needs this (eg. when using routing).
I think this will work fine. 👍 |
Hey! Small update for
I did move some code in #841 that may ease the implementation of a USB-Tunnel (using the Marvin is working on a refactoring of the |
Hello, recently I wasn't that active. I'll try to take a look into the changes next week. And if one of you is working with KNX over USB, I have commited a Wireshark KNX USB dissector. This helped me big time in quickly understanding the message flow. |
Hi kistlin, I' am trying to use your USB implementation of xknx. When I use your example_usb.py I get:
|
Hello @mikimikeCH, as long as it finds the device the warning shouldn't matter that much. I just didn't run it on Windows yet. The bigger problem is that the implementation is not in a usable state. I never finished it. I don't have an actual setup that works, just the programmer as you have. And I ran out of holidays :). Are you familiar with debugging? Else you could follow the code and look where sending fails. If it even reaches |
Hi there,
and i have similar output like @mikimikeCH
Let´s find time for debugging... Also a rebase with main is needed from the branch of @kistlin , there are small conflicts |
@Golpe82 I pushed changes that integrate the existing implementation into the current main of XKNX. And some minor changes. When I now run the example my KNX interface at least blinks :). Does not mean it works yet. |
Oh that is great! Still looking forward to having support for USB from xknx directly 😃 We did some changes allowing to directly return Unfortunately we still have no perfectly clean separation of (OSI)Layers - so I guess there will still be some duplicated code in USB and IP branches... If one of you has any direct questions regarding implementation details or such, don't hesitate to join our Discord server! 👍 |
Hi, I was playing a bit today. |
I mean I was commuticating with the kberry over tty serial port and usb is also serial. |
Take a look to apendixE (this time English): Or maybe am I confusing things? |
Eg. Calimero lists FT1.2 and KNX USB as separate protocols. I couldn't find any mention of "FT1.2" in the Knx specifications pdfs 🧐 |
ok, so far i understand ft1.2 is only for TP/KNX BAOS Module 830 of Weinzierl (also kberry) |
Hi @farmio If i remember right i had to "Install a device filter" when i wanted to access my USB-KNX Interface from Python. Maybe on macOS you have to do it as well. |
Hey @farmio, great to hear. A few weeks back I added a bunch of unit tests for assembling/splitting frames. I would also like to get an initial merge soon. I switched regularly between Windows and Linux, but not on a Mac. On Linux you shouldn't forget udev rules if you want to use it as normal user and Windows should work once the right drivers are installed. But that problem looks similar to pyusb/pyusb#208. If you can, you could try on Windows or Linux first. To run some basic tests. |
So after searching the web for some hours I think it is a limitation / security feature of macOS that can't be worked around that easily. See libusb/libusb#1014 I think I'll take a stab on testing these. |
Ok. Then I'll leave it up to you for now :). |
Allright! I have copied your branch to https://github.com/XKNX/xknx/tree/usb-interface-support |
So I did some testing on Windows 10 and had no luck - even with different drivers. libusb1DEBUG:asyncio:Using proactor: IocpProactor
INFO:xknx.log:XKNX start logging on USB device (idVendor: 0x0000, idProduct: 0x0000)
INFO:xknx.log:XKNX v2.2.0 starting tunneling connection to KNX bus.
INFO:xknx.usb:found 1 device(s)
INFO:xknx.usb:device 1
INFO:xknx.usb: manufacturer : Gira Giersiepen GmbH & Co. KG (idVendor: 0x135e)
INFO:xknx.usb: product : KNX-USB Data Interface (idProduct: 0x0022)
INFO:xknx.usb: serial_number : None
INFO:root:Using device:
DEVICE ID 135e:0022 on Bus 002 Address 008 =================
bLength : 0x12 (18 bytes)
bDescriptorType : 0x1 Device
bcdUSB : 0x110 USB 1.1
bDeviceClass : 0x0 Specified at interface
bDeviceSubClass : 0x0
bDeviceProtocol : 0x0
bMaxPacketSize0 : 0x8 (8 bytes)
idVendor : 0x135e
idProduct : 0x0022
bcdDevice : 0x103 Device 1.03
iManufacturer : 0x1 Gira Giersiepen GmbH & Co. KG
iProduct : 0x2 KNX-USB Data Interface
iSerialNumber : 0x0
bNumConfigurations : 0x1
CONFIGURATION 1: 50 mA ===================================
bLength : 0x9 (9 bytes)
bDescriptorType : 0x2 Configuration
wTotalLength : 0x29 (41 bytes)
bNumInterfaces : 0x1
bConfigurationValue : 0x1
iConfiguration : 0x0
bmAttributes : 0x80 Bus Powered
bMaxPower : 0x19 (50 mA)
INTERFACE 0: Human Interface Device ====================
bLength : 0x9 (9 bytes)
bDescriptorType : 0x4 Interface
bInterfaceNumber : 0x0
bAlternateSetting : 0x0
bNumEndpoints : 0x2
bInterfaceClass : 0x3 Human Interface Device
bInterfaceSubClass : 0x0
bInterfaceProtocol : 0x0
iInterface : 0x0
ENDPOINT 0x81: Interrupt IN ==========================
bLength : 0x7 (7 bytes)
bDescriptorType : 0x5 Endpoint
bEndpointAddress : 0x81 IN
bmAttributes : 0x3 Interrupt
wMaxPacketSize : 0x40 (64 bytes)
bInterval : 0x2
ENDPOINT 0x2: Interrupt OUT ==========================
bLength : 0x7 (7 bytes)
bDescriptorType : 0x5 Endpoint
bEndpointAddress : 0x2 OUT
bmAttributes : 0x3 Interrupt
wMaxPacketSize : 0x40 (64 bytes)
bInterval : 0x2
DEBUG:xknx.usb:Operation not supported or unimplemented on this platform
DEBUG:xknx.telegram:<Telegram direction="Outgoing" source_address="0.0.0" destination_address="5/1/20" payload="<GroupValueRead />" />
DEBUG:xknx.log:sending: <Telegram direction="Outgoing" source_address="0.0.0" destination_address="5/1/20" payload="<GroupValueRead />" />
DEBUG:xknx.log:write 64 bytes: 0113130008000b010300001100bce000002914010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Exception in thread USBSendThread:
Traceback (most recent call last):
File "C:\Users\meti\AppData\Local\Programs\Python\Python310\lib\threading.py", line 1009, in _bootstrap_inner
self.run()
File "c:\Users\meti\dev\xknx\xknx\usb\usb_send_thread.py", line 39, in run
self.usb_device.write(hid_frame.to_knx())
File "c:\Users\meti\dev\xknx\xknx\usb\util.py", line 209, in write
write_count = self._ep_out.write(data)
File "C:\Users\meti\AppData\Local\Programs\Python\Python310\lib\site-packages\usb\core.py", line 408, in write
return self.device.write(self, data, timeout)
File "C:\Users\meti\AppData\Local\Programs\Python\Python310\lib\site-packages\usb\core.py", line 989, in write
return fn(
File "C:\Users\meti\AppData\Local\Programs\Python\Python310\lib\site-packages\usb\backend\libusb1.py", line 855, in intr_write
return self.__write(self.lib.libusb_interrupt_transfer,
File "C:\Users\meti\AppData\Local\Programs\Python\Python310\lib\site-packages\usb\backend\libusb1.py", line 938, in __write
_check(retval)
File "C:\Users\meti\AppData\Local\Programs\Python\Python310\lib\site-packages\usb\backend\libusb1.py", line 602, in _check
raise USBTimeoutError(_strerror(ret), ret, _libusb_errno[ret])
usb.core.USBTimeoutError: [Errno 10060] Operation timed out
WARNING:xknx.log:Error: KNX bus did not respond in time (2.0 secs) to GroupValueRead request for: 5/1/20
Value: None - took 2.008 seconds
DEBUG:xknx.state_updater:StateUpdater stopping
DEBUG:xknx.log:Stopping TelegramQueue
DEBUG:xknx.log:stopping thread USBSendThread
DEBUG:xknx.log:stopping thread USBReceiveThread
DEBUG:xknx.log:USBSendThread stopped
DEBUG:xknx.log:USBReceiveThread stopped whereas libusb0 ´[Errno None] b'libusb0-dll:err [claim_interface] could not claim interface 0, invalid configuration 0\n'´ libusb0DEBUG:asyncio:Using proactor: IocpProactor
INFO:xknx.log:XKNX start logging on USB device (idVendor: 0x0000, idProduct: 0x0000)
INFO:xknx.log:XKNX v2.3.0 starting tunneling connection to KNX bus.
ERROR:xknx.usb:No USB backend found. Set XKNX_LIBUSB environment variable pointing to libusb-1.0.dll or install it to C:\Windows\System32
INFO:xknx.usb:found 1 device(s)
INFO:xknx.usb:device 1
INFO:xknx.usb: manufacturer : Gira Giersiepen GmbH & Co. KG (idVendor: 0x135e)
INFO:xknx.usb: product : KNX-USB Data Interface (idProduct: 0x0022)
INFO:xknx.usb: serial_number : None
INFO:root:Using device:
DEVICE ID 135e:0022 on Bus 000 Address 001 =================
bLength : 0x12 (18 bytes)
bDescriptorType : 0x1 Device
bcdUSB : 0x110 USB 1.1
bDeviceClass : 0x0 Specified at interface
bDeviceSubClass : 0x0
bDeviceProtocol : 0x0
bMaxPacketSize0 : 0x8 (8 bytes)
idVendor : 0x135e
idProduct : 0x0022
bcdDevice : 0x103 Device 1.03
iManufacturer : 0x1 Gira Giersiepen GmbH & Co. KG
iProduct : 0x2 KNX-USB Data Interface
iSerialNumber : 0x0
bNumConfigurations : 0x1
CONFIGURATION 1: 50 mA ===================================
bLength : 0x9 (9 bytes)
bDescriptorType : 0x2 Configuration
wTotalLength : 0x29 (41 bytes)
bNumInterfaces : 0x1
bConfigurationValue : 0x1
iConfiguration : 0x0
bmAttributes : 0x80 Bus Powered
bMaxPower : 0x19 (50 mA)
INTERFACE 0: Human Interface Device ====================
bLength : 0x9 (9 bytes)
bDescriptorType : 0x4 Interface
bInterfaceNumber : 0x0
bAlternateSetting : 0x0
bNumEndpoints : 0x2
bInterfaceClass : 0x3 Human Interface Device
bInterfaceSubClass : 0x0
bInterfaceProtocol : 0x0
iInterface : 0x0
ENDPOINT 0x81: Interrupt IN ==========================
bLength : 0x7 (7 bytes)
bDescriptorType : 0x5 Endpoint
bEndpointAddress : 0x81 IN
bmAttributes : 0x3 Interrupt
wMaxPacketSize : 0x40 (64 bytes)
bInterval : 0x2
ENDPOINT 0x2: Interrupt OUT ==========================
bLength : 0x7 (7 bytes)
bDescriptorType : 0x5 Endpoint
bEndpointAddress : 0x2 OUT
bmAttributes : 0x3 Interrupt
wMaxPacketSize : 0x40 (64 bytes)
bInterval : 0x2
DEBUG:xknx.usb:is_kernel_driver_active
WARNING:xknx.log:[Errno None] b'libusb0-dll:err [claim_interface] could not claim interface 0, invalid configuration 0\n'
DEBUG:xknx.telegram:<Telegram direction="Outgoing" source_address="0.0.0" destination_address="5/1/20" payload="<GroupValueRead />" />
DEBUG:xknx.cemi:Outgoing CEMI: <CEMIFrame code="L_DATA_REQ" src_addr="IndividualAddress("0.0.0")" dst_addr="GroupAddress("5/1/20")" flags="1011110011100000" tpci="TDataGroup()" payload="<GroupValueRead />" />
DEBUG:xknx.log:sending: <CEMIFrame code="L_DATA_REQ" src_addr="IndividualAddress("0.0.0")" dst_addr="GroupAddress("5/1/20")" flags="1011110011100000" tpci="TDataGroup()" payload="<GroupValueRead />" />DEBUG:xknx.log:write 64 bytes: 0113130008000b010300001100bce000002914010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Exception in thread USBSendThread:
Traceback (most recent call last):
File "C:\Users\meti\AppData\Local\Programs\Python\Python310\lib\threading.py", line 1009, in _bootstrap_inner
self.run()
File "c:\Users\meti\dev\xknx\xknx\usb\usb_send_thread.py", line 33, in run
self.usb_device.write(hid_frame.to_knx())
File "c:\Users\meti\dev\xknx\xknx\usb\util.py", line 214, in write
write_count = self._ep_out.write(data)
File "C:\Users\meti\AppData\Local\Programs\Python\Python310\lib\site-packages\usb\core.py", line 408, in write
return self.device.write(self, data, timeout)
File "C:\Users\meti\AppData\Local\Programs\Python\Python310\lib\site-packages\usb\core.py", line 986, in write
intf, ep = self._ctx.setup_request(self, endpoint)
File "C:\Users\meti\AppData\Local\Programs\Python\Python310\lib\site-packages\usb\core.py", line 113, in wrapper
return f(self, *args, **kwargs)
File "C:\Users\meti\AppData\Local\Programs\Python\Python310\lib\site-packages\usb\core.py", line 229, in setup_request
self.managed_claim_interface(device, intf)
File "C:\Users\meti\AppData\Local\Programs\Python\Python310\lib\site-packages\usb\core.py", line 113, in wrapper
return f(self, *args, **kwargs)
File "C:\Users\meti\AppData\Local\Programs\Python\Python310\lib\site-packages\usb\core.py", line 178, in managed_claim_interface
self.backend.claim_interface(self.handle, i)
File "C:\Users\meti\AppData\Local\Programs\Python\Python310\lib\site-packages\usb\backend\libusb0.py", line 447, in _check
raise USBError(errmsg, ret)
usb.core.USBError: [Errno None] b'libusb0-dll:err [claim_interface] could not claim interface 0, invalid configuration 0\n'
WARNING:xknx.log:[Errno None] b'libusb0-dll:err [claim_interface] could not claim interface 0, invalid configuration 0\n'
WARNING:xknx.log:Error: KNX bus did not respond in time (2.0 secs) to GroupValueRead request for: 5/1/20
Value: None - took 2.002 seconds
DEBUG:xknx.state_updater:StateUpdater stopping
WARNING:xknx.log:[Errno None] b'libusb0-dll:err [claim_interface] could not claim interface 0, invalid configuration 0\n'
WARNING:xknx.log:L_DATA_CON Data Link Layer confirmation timed out for <CEMIFrame code="L_DATA_REQ" src_addr="IndividualAddress("0.0.0")" dst_addr="GroupAddress("5/1/20")" flags="1011110011100000" tpci="TDataGroup()" payload="<GroupValueRead />" />
DEBUG:xknx.log:Stopping TelegramQueue
DEBUG:xknx.log:stopping thread USBSendThread
DEBUG:xknx.log:stopping thread USBReceiveThread
DEBUG:xknx.log:USBSendThread stopped
DEBUG:xknx.log:USBReceiveThread stopped Can you give me a hint of how to get that running on Windows? What are the right drivers? I'll refactor to use CEMIFrame instead of Telegram meanwhile - but I guess this will be more straight forward if I could test it. Edit: under Ubuntu VM I don't get the UDEV rule working. But with sudo, at least I don't get any error, the interface gets found and according to logs it seems a telegram is sent. Nothing hits the bus though 🫤 USB is simple and reliable, they said 🤣 |
Did you see Yeah all these quirks. But HID might help. |
Yes I saw that and changed the path to my .DLL that was provided by |
If that doesn't help then it was me probably using I would say let's forget about |
@farmio |
I did also try Zadig 🤣 |
Ok, so unfortunately it seems it's more work to get this running with my interface than I thought... according to this Device Feature Get - Response
it looks to me that my interface doesn't support CEMI, but only EMI1 😭 |
We should probably implement a Device Feature Get - Response cycle on start - raising an error if the device doesn't support CEMI or do a Device Feature Set if it supports more than CEMI. Currently the thread-encapsulation is not great... we call Also, do you think it is possible to do send and receive in a single thread? I could imagine something like this to work (untested pseudo code) self._usb_device.set_nonblocking(True)
while self._is_active.is_set():
if self.out_queue.qsize(): # Return the approximate size of the queue (not reliable!). <- not reliable doesn't sound promising
self.usb_device.write(self.out_queue.get_nowait()) # maybe `try: except Empty:` - maybe even without qsize test
usb_data = self._usb_device.read()
if usb_data:
self._knx_to_telegram.process(usb_data) |
Implementing a feature check makes sense. True Alternatives to check out could also be: Or janus
|
hence the As stated in the SO answer: Maybe a call to loop.call_soon_threadsafe could probably do it too. xknx/xknx/io/knxip_interface.py Line 514 in e031588
|
True. But then the thread would be needlessly spinning. Yes |
Did you see that in a data sheet? I tried to quickly look it up but couldn't find anything. So maybe yours supports more too, it just defaults to EMI1? |
I just looked up the datasheet of my Gira 107000 USB interface (here in german). As expected there is no word about EMI or CEMI 🫥 I should have been more verbose about that output of The response was a If multiple types were supported it would require to set the preferred type before further communication. See §3.5.3.3.2 |
Hi all, is there any progress on supporting USB interfaces? |
@martinmoravek afaik, none apart from what you can read here in this issue or see here https://github.com/XKNX/xknx/tree/usb-interface-support I don't have a cemi compatible usb interface, so I moved to different topics again for now. Feel free to chime in if you like. |
As to me, in recent times I did not invest time worth mentioning. And it is not planned in the near future. Maybe a few days within the next two to three months. The current state is
The last part is holding me up currently.
But it didn't seem to fix it. So I'm currently when I work on it comparing some captures. After querying and setting the EMI type to use, I see a lot of M_PropRead.req/M_PropWrite.req. @martinmoravek if you are willing to test things or even develop that would be welcome. I only have one USB programmer and one KNX device. So no real variety to say with confidence if it works or not. |
Since #1210 we should be able to decode these M_Prop messages, and there is also a module for decoding property ids 😃 |
Ok thanks for the information. And in the document it was right at the end of And while at it. The So the next steps would be to integrate
and after that start normal communication. |
@kistlin not sure if I am able to develop (never ever developed in python, only c/c++, sql), but testing is no problem (I have usb, ip as well as rs232 interface). with some advice and help to get the dev environment running I might try some dev as well |
Setting up a dev env is straightforward. Provided you have a supported version of Python (>=3.9) installed, it should suffice to clone the repo, switch the branch and install dependencies (see root Readme). RS232 is out of scope imho (it's not even supported by ETS anymore 😬). |
@martinmoravek Additional steps before you install dependencies are creating a virtual environment. This prevents you from globally installing packages which will lead to version conflicts of packages, when you work on multiple projects. To create one you can run And every time you launch a new terminal activate it with
You can also add as a second remote my fork https://github.com/kistlin/xknx. Works happens on After you created your environment and installed the packages as mentioned in the README.md you can try and run
and already check if you see something happening. (you might want to change KNX address to match your setup) |
Hi @farmio, what's the status of this issue and https://github.com/XKNX/xknx/tree/usb-interface-support? What's missing to get this done and upstream? |
I just tried to merge recent main to usb-interface-support here https://github.com/rnixx/xknx/tree/rnixx-usb-interface-support knx_hid_helper_test.TestKNXtoCEMI.test_process fails now, looks like some new information from CEMIMessageCode is considered in the meantime. Either test frames have improper format or some hid related special handling is missing. |
@rnixx Hi 👋!
Tbh I don't remember the exact last state of this, but you may read it in the previous comments. It didn't work on my interface at all since it doesn't support CEMI, so this would be needed to check and raise an exception (or translate CEMI to EMI1 if this is possible). I don't know if anyone is still working on this. |
It would be nice to support USB interfaces in addition to KNX/IP.
Next to supporting users that don't own IP Interfaces Xknx could be used as USB - IP bridge in the future.
See KNX specification 9 - 3: Basic System and Components - Couplers §3 KNX USB Interface
The text was updated successfully, but these errors were encountered: