Open farmio opened 3 years ago
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. https://github.com/calimero-project
@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 https://github.com/kistlin/xknx/commit/c6f70a662d0507b79f0f1c2c083bfa59dab63725
Branch feature/add_usb_interface_support
examples/usb
As a USB interface I used the Siemens OCI702 USB - KNX Serviceinterface.
Sending bytes from a recorded valid KNX frame, seems to work. Also parsing of a USB HID frame into a more meaningful object seems straight forward. I feel comfortable in the lower parts of the communication.
@farmio do you know where in the specification I find information on the application layer? I got in my view a non-trivial KNX device, which has lots of KNX objects in the manual. I would be interested how these objects map to actual bytes on a lower level.
And maybe a description (reference to a document) of the workflow of typical first steps. For example assigning an address to a device. What bytes do we need to send? So that I don't have to reverse everything.
Hi!
For Application layer information I'd look at 03_03_07 Application Layer v01.06.02 AS
- in xknx we have the xknx.telegram.apci
module for the different services. This can be passed to a xknx.telegram.Telegram
object as payload
. See https://github.com/XKNX/xknx/blob/main/xknx/knxip/cemi_frame.py for how we use it to encode/decode a Telegram
object to and from KNX/IP. Afaik USB doesn't necessarily use CEMI-Frames so you maybe would have to add the USB-pendant for this.
To map KNX group objects to bytes you need to know the used DPT and decode it accordingly. See the xknx.dpt
module. We use xknx.device
to abstract that.
If what you are looking for is to reprogram the device, I'm afraid I can't help you. Afaik this is vendor/device specific.
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 KNXonUSB (AN0037)
for KNX over USB. Maybe you'll have to requeset it from KNXA (my.knx.org support ticket).
Ok, maybe back to focusing on integrating USB support.
What helped me was document 03_06_03 EMI_IMI v01.03.03 AS.pdf
in combination with this image
in
09_03 Basic and System Components - Couplers v01.03.03 AS.pdf
.
There in the KNX USB Transfer Protocol Body
is the cEMI/EMI1/EMI2 frame. And from your comment and the code, xknx implements atm. only the cEMI frame right?
If I look for example in 03_06_03 EMI_IMI v01.03.03 AS.pdf
chapter 4.1.5.3.3 L_Data.req
.
This is the higher level interpretation of the
KNX USB Transfer Protocol Body
.
So the integration in a perfect world would then be, receive USB packets on a defined interface and concatenate the data packets together. Once a complete frame is received, check what frame type it is and pass it on to the already existing xknx implementation.
All the higher levels are transport independant, as it should be. Am I missing something?
Yes sounds reasonable. The L_Data.req example here is a CEMI Frame - so this is what you get by creating a xknx.telegram.Telegram
and encapsule it in a cemi frame xknx.knxip.cemi_frame.CEMIFrame
(with CEMIFrame.init_from_telegram
or setting the telegram
property).
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_frame.to_knx()
to your payload - this should make your whole KNX USB Transfer Protocol Body.
To parse received frames pass the KNX USB Transfer Protocol Body (cut the header) to CEMIFrame.from_knx()
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 KNXIPInterface
or USBInterface
object, depending on the ConnectionConfig
passed in, is instantiated.
To test this integration I created a ConnectionConfigUSB
.
The changes in xknx/xknx.py
are pretty minimal.
@@ -114,14 +116,19 @@ class XKNX:
async def start(self) -> None:
"""Start XKNX module. Connect to KNX/IP devices and start state updater."""
self.task_registry.start()
- self.knxip_interface = KNXIPInterface(
- self, connection_config=self.connection_config
- )
- logger.info(
- "XKNX v%s starting %s connection to KNX bus.",
- VERSION,
- self.connection_config.connection_type.name.lower(),
- )
+ if isinstance(self.connection_config, ConnectionConfig):
+ self.knxip_interface = KNXIPInterface(
+ self, connection_config=self.connection_config
+ )
+ logger.info(
+ "XKNX v%s starting %s connection to KNX bus.",
+ VERSION,
+ self.connection_config.connection_type.name.lower(),
+ )
+ if isinstance(self.connection_config, ConnectionConfigUSB):
+ self.knxip_interface = USBInterface(self, connection_config=self.connection_config)
+ logger.info("XKNX start logging on USB device (idVendor: 0x%04x, idProduct: 0x%04x)",
+ self.connection_config.idVendor, self.connection_config.idProduct)
await self.knxip_interface.start()
await self.telegram_queue.start()
if self.start_state_updater:
The switch example with USB would look like this. Only the instantiation of XKNX needs a change.
...
async def main():
xknx = XKNX(connection_config=ConnectionConfigUSB(USBVendorId.SIEMENS_OCI702, USBProductId.SIEMENS_OCI702))
await xknx.start()
switch = Switch(xknx, name="TestOutlet", group_address="1/1/11")
...
All the existing code with default initialization would still work as expected.
Sure for an initial proof of concept implementation this sounds reasonable.
Later we can always rename knxip_interface
to knx_interface
and maybe consolidate the ConnectionConfig classes somehow so the KNXInterface class handles connections to IP and USB in the io
module.
To communicate with xknx devices it just needs to register as an xknx.io.Interface
subclass at xknx.knxip_interface.interface
(so send_telegram
is called, and register the callback xknx.knxip_interface.telegram_received
to put received GroupValue* telegrams into xknx.telegrams
asyncio.Queue.
Is there a tunnelling-like ConnectRequest - ConnectResponse process in USB or is it connectionless?
In 09_03 Basic and System Components - Couplers v01.03.03 AS.pdf
it says
For communication between a tool on a PC and a KNX device connected to the KNX network, KNX frames are tunnelled on the USB link using one of the EMI formats.
The time-out for a KNX tunnelling is 1 s. This is, a KNX USB Interface Device shall be able to receive a tunnelling frame, transmit it on the KNX medium and send the local confirmation back to the tool within 1 s.
This is a recommended value which shall be complied to under normal bus load.
Figure 21 – Device Feature Service
...
For a possible use, please refer to the features proposed in 3.5.3.3 “Device features” below.
Please note that only the Device Feature Get service is confirmed by a Device Feature Response service. The Device Feature Set- and the Device Feature Info services shall not be answered by the receiver.
...
The time-out for the Device Feature Get service is 1 s. This is, a KNX USB Interface Device shall reply with a Device Feature Response frame within 1 s.
For me the relevant parts sound like request/response only. Or just sending something.
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 03_06_03 EMI_IMI v01.03.03 AS.pdf
During treatment of a request that is not yet confirmed to the cEMI client, the cEMI Server shall accept a new request from the cEMI client. This is used e.g. for management requests (see clause 4.1.7) during an L_Data.req/L_Data.con cycle.
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 09_03 Basic and System Components - Couplers v01.03.03 AS.pdf
Discovery and self-description mechanisms on USB level are not in the scope of this clause as well as mechanisms for configuring and establishing of a communication link between the USB host (PC) and the KNX USB Interface Device. These mechanisms are managed by the USB host protocol. Please refer to the corresponding USB specification documents.
And the USB HID specification defines that
The USB Core Specification defines the HID class code. The bInterfaceClass member of an Interface descriptor is always 3 for HID class devices.
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 https://github.com/XKNX/xknx/issues/323 (and the link there if you speak German) for the L_Data.con flow control. This was just recently added to xknx. Worked before with the rate_limiter but now we can be (I hope) sure we never flood the receivers buffers even on high Bus load (or disabled rate_limit).
Yes the reference in your ticket to 4.1.5.1 Flow Control
in 03_06_03 EMI_IMI v01.03.03 AS.pdf
seems to indicate, that we should wait for a con.
cEMI Client To keep the flow control for Data Link Layer services as simple as possible (this allows a simple flow control state machine in the cEMI client), it is recommended that: • a cEMI client sends a new Data Link Layer request only when the confirmation of the preceding request is received, or • a request-to-confirmation timeout is recognised; the recommended time-out for the cEMI client is 3 seconds. A cEMI client shall at any time be able to accept an indication message from the cEMI Server.
FYI your assumption in the forum about the meaning of con
was right, by accident I read that part. 03_03_04 Transport Layer v01.02.02 AS.pdf
Every communication mode shall provide specific Transport Layer Service Access Points (TSAPs) accessible via different Transport Layer services. Each of these services shall consists of three service primitives, the
request
(req
), theconfirm
(con
) and theindication
(ind
).
And just for me, we are speaking about this, so that a possible USB implementation doesn't make the same mistake? :) Also do you consider a refactoring so we don't have twice the logic and twice the tests for the same problem? Or not yet?
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 :).
Also do you consider a refactoring so we don't have twice the logic and twice the tests for the same problem? Or not yet?
Not yet, since not every sent telegram needs this (eg. when using routing).
The confirmation waiting function is currently not more than
https://github.com/XKNX/xknx/blob/0.18.15/xknx/io/tunnel.py#L282-L296
(you wouldn't need the Tunnelling
class since no ACK is required)
I hoped to just put a received telegram into the queue an we are good :).
I think this will work fine. 👍
Hey! Small update for
Also do you consider a refactoring so we don't have twice the logic and twice the tests for the same problem? Or not yet?
I did move some code in #841 that may ease the implementation of a USB-Tunnel (using the _Tunnel
class. USB seems very similar to what is needed for TCP tunnels). Its not perfect as it still has some IP-specific attributes, but I guess its a start.
Marvin is working on a refactoring of the ConnectionConfig
class - we'd like to use separate Dataclasses for the connection types with some minor config validation baked into it - let's see.
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. Put the script in the B.4. Plugin folders and it should work. Maybe you have to select the protocol in the GUI.
Hi kistlin,
I' am trying to use your USB implementation of xknx. When I use your example_usb.py I get:
INFO:xknx.log:XKNX start logging on USB device (idVendor: 0x0908, idProduct: 0x02dc)
WARNING:xknx.usb:TODO: load libusb dll on Windows
INFO:xknx.usb:found 1 device(s)
INFO:xknx.usb:device 1
INFO:xknx.usb: manufacturer : Siemens (idVendor: 0x0908)
INFO:xknx.usb: product : OCI702 KNX Interface (idProduct: 0x02dc)
INFO:xknx.usb: serial_number : 00FD10D01DB7
DEBUG:xknx.telegram:<Telegram direction="Outgoing" source_address="0.0.0" destination_address="1/1/11" payload="<GroupValueWrite value="<DPTBinary value="True" />" />" />
DEBUG:xknx.state_updater:StateUpdater stopping
DEBUG:xknx.telegram:<Telegram direction="Outgoing" source_address="0.0.0" destination_address="1/1/11" payload="<GroupValueWrite value="<DPTBinary value="False" />" />" />
DEBUG:xknx.log:Stopping TelegramQueue```
It seems to find the USB KNX Interface and passes the telegram. I have a BUS Monitor running in ETS 6 with an older Siemens OCI700 Interface, but there I don't receive any Telegram. Is the problem that I have a Warning "load libusb dll"?
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 USBClient.send_telegram
in xknx/io/usb_client.py
.
Hi there, i changed a bit the code of @kistlin for using my usb iface of jung:
util.py
class USBVendorId(IntEnum):
""" Vendor ID's """
SIEMENS_OCI702 = 0x0908
JUNG_2130USBREG = 0x135e
class USBProductId(IntEnum):
""" Product ID's """
SIEMENS_OCI702 = 0x02dc
JUNG_2130USBREG = 0X0023
......
example_switch.py
........
async def main():
#xknx = XKNX(connection_config=ConnectionConfigUSB(usb_util.USBVendorId.SIEMENS_OCI702, usb_util.USBProductId.SIEMENS_OCI702))
xknx = XKNX(connection_config=ConnectionConfigUSB(usb_util.USBVendorId.JUNG_2130USBREG, usb_util.USBProductId.JUNG_2130USBREG))
await xknx.start()
#switch = Switch(xknx, name="TestOutlet", group_address="1/1/11")
switch = Light(xknx, name="TestOutlet", group_address_switch="1/2/30")
await switch.set_on()
await asyncio.sleep(10)
await switch.set_off()
await xknx.stop()
if __name__ == "__main__":
asyncio.run(main())
and i have similar output like @mikimikeCH
DEBUG:asyncio:Using selector: EpollSelector
INFO:xknx.log:XKNX start logging on USB device (idVendor: 0x135e, idProduct: 0x0023)
INFO:xknx.usb:found 1 device(s)
INFO:xknx.usb:device 1
INFO:xknx.usb: manufacturer : ALBRECHT JUNG GMBH & CO. KG (idVendor: 0x135e)
INFO:xknx.usb: product : KNX-USB Data Interface (idProduct: 0x0023)
INFO:xknx.usb: serial_number : None
DEBUG:xknx.telegram:<Telegram direction="Outgoing" source_address="0.0.0" destination_address="1/2/30" payload="<GroupValueWrite value="<DPTBinary value="True" />" />" />
DEBUG:xknx.state_updater:StateUpdater stopping
DEBUG:xknx.telegram:<Telegram direction="Outgoing" source_address="0.0.0" destination_address="1/2/30" payload="<GroupValueWrite value="<DPTBinary value="False" />" />" />
DEBUG:xknx.log:Stopping TelegramQueue
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 list[Telegram]
from a received Telegram - to answer incoming request-response queries directly (for management).
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 made a project 2 years ago that translate http to KNX frames using a raspi and a kberry. For it I needed to build cemi frames but embedded in ft1.2 protocol. I suppose for usb the ft1.2 protocoll is also needed, not only the cemi frames: https://drive.google.com/file/d/1-B_LsezclvBC3x42pkxy9pLOOp0ll1YZ/view?usp=drivesdk
I mean I was commuticating with the kberry over tty serial port and usb is also serial. I suppose xknx access the bus over network layer but serial connection succeed over link layer I think and the frame needs the ft1.2 protocoll for it so far I understand
Take a look to apendixE (this time English): https://www.google.com/url?q=https://weinzierl.de/images/download/documents/baos/knx_baos_binary_protocol_v2_0.pdf&sa=U&ved=2ahUKEwjSiJHE6v34AhVagv0HHfhnBwAQFnoECAAQAg&usg=AOvVaw0yEF3lHYytLXW9xje22UoO
Or maybe am I confusing things? Ft1.2 is for uart. The question is if the usb interface transforms dataframe to uart itsself? Aka. Embeds the cemi in a ft1.2 alone?
Eg. Calimero lists FT1.2 and KNX USB as separate protocols. https://github.com/calimero-project/calimero-core
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) https://www.knx.org/wAssets/docs/downloads/Marketing/Flyers/KNX-Development-Solutions/KNX-Development-Solutions_en.pdf
I had some success to write to a KNX Device Programmingmode On/Off and Restart all those commands worked.
DEBUG:xknx.log:sending: <Telegram direction="Outgoing" source_address="0.0.0" destination_address="0.2.220" payload="<PropertyValueWrite object_index="0" property_id="54" count="1" start_index="1" data="01" />" />
DEBUG:xknx.log:write 64 bytes: 01131800080010010300001100b06002b402dc0603d7003610010100000000000000000000000000000000000000000000000000000000000000000000000000
WARNING:xknx.log:Error: KNX bus did not respond in time (2 secs) to payload request for: 0.2.220
DEBUG:xknx.telegram:<Telegram direction="Outgoing" source_address="0.0.0" destination_address="0.2.220" payload="<PropertyValueWrite object_index="0" property_id="54" count="1" start_index="1" data="00" />" />
DEBUG:xknx.log:sending: <Telegram direction="Outgoing" source_address="0.0.0" destination_address="0.2.220" payload="<PropertyValueWrite object_index="0" property_id="54" count="1" start_index="1" data="00" />" />
DEBUG:xknx.log:write 64 bytes: 01131800080010010300001100b06002b402dc0603d7003610010000000000000000000000000000000000000000000000000000000000000000000000000000```
I think there is a problem in reading the response from the Bus, because i allways get this warning:
WARNING:xknx.log:Error: KNX bus did not respond in time (2 secs) to payload request for: 0.2.220
Hello @mikimikeCH
yes that is because receiving is not implemented yet. But good to hear that sending works.
To be able to do reads and writes simultaneously, I have to look into how this can be done safely with pyusb. Async operations get discussed but are not implemented yet, mentioned earlier.
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.
There is also the issue pyusb/pyusb#301 which talks about sending/receiving at the same time.
Because async operations might take a while, I tend to use threads. But I first have to check, that it is safe to do so.
Do we explicitly need pyusb or would pyserial-asyncio or something like that do as well?
I guess wrapping the communication in a thread would also work - due to HA specific reasons we even already do that optionally with our IP interfaces.
There are now threads that send and receive.
A non-obvious thing was in CEMIFrame
when using from_knx
on the object. It was default initialized with outgoing direction and then I ended up in a message loop :). This could be changed to a @classmethod
and ask for the direction and other required information. Unless I understood that wrong :D.
Currently the USB implementation does not handle receiving fragmented messages. This will be next.
Yes right, CEMIFrame does not have a direction attribute - this is added to our Telegram abstraction when creating them. See https://github.com/XKNX/xknx/blob/9aa172c8f3e8df4fcf5f5f41f30559a7b456cbd9/xknx/io/routing.py#L76
Improvements of this system would be welcome 😉 (would need to be a standard method as it needs lot of self.
)
For the fragmented frames have a look at the TCP transport - it has to handle these too, maybe you can use these methods: https://github.com/XKNX/xknx/blob/9aa172c8f3e8df4fcf5f5f41f30559a7b456cbd9/xknx/io/transport/tcp_transport.py#L77
Calimero maintains a list of Usb VendorID and ProductIDs. Maybe this can be useful to do some kind of auto-discovery? For a HA context this would have to go in the manifest.json
afaik, but maybe you can/want to use it in xknx as I have seen there is an Enum containing 2 now.
https://github.com/calimero-project/calimero-core/blob/master/resources/knxUsbVendorProductIds
Currently I changed the USB device search. If one passes no arguments to ConnectionConfigUSB
like in the updated version of examples/usb/example_light.py
, then the ported list from Calimero is searched. If it finds multiple devices, the first one is used. If vendor and product id are passed, a specific search is performed. Further adaptions should be rather easy.
Now the ConnectionConfigUSB
during instantiation is merely used to tell which connection to use, TCP/IP or USB.
Another issue is, when I attached the KNX USB device for the first time I get a cEMI message code xknx can't handle.
M_PropInfo.ind = F7h (03_06_03 EMI_IMI v01.03.03 AS.pdf
)
There is no code to handle this yet.
I'm not sure what you mean by HA context and manifest.json. You mean vendor and product id would go into the manifest.json? And these then would be read out of there and xknx configured accordingly?
I'm not sure what you mean by HA context and manifest.json. You mean vendor and product id would go into the manifest.json? And these then would be read out of there and xknx configured accordingly?
Yes exactly. Home Assistant has its own USB discovery methods based on matching vendor and product id in any manifest.json. This discovery happens even when the knx integration (and therefore xknx) is not even configured or loaded. As a result we could use these to create a ConnectionConfigUSB
and start xknx.
See https://developers.home-assistant.io/docs/creating_integration_manifest#usb
The M_PropInfo should be easy to add so it can be handled - if we even need to handle it. https://github.com/XKNX/xknx/blob/9aa172c8f3e8df4fcf5f5f41f30559a7b456cbd9/xknx/knxip/knxip_enum.py#L53
4.1.7.3.6 M_PropInfo.ind
The M_PropInfo.ind message shall be applied by the management server to send an event notification to the management client, e.g. about a changed management Property value.
After reception of the M_PropInfo.ind, the management client shall check whether the contained data is relevant to one or more of the management procedures it supports. If so, these procedures shall be called with the received data. If no, the message shall be ignored.
M_PropInfo.ind shall always be an unconfirmed service.
Seems save to not do much about that 🤣
@farmio yeah, I added the message type and just ignore it.
In addition I configured a KNX device that has a push button and sends temperature measurements.
I can receive the messages over USB and decode them. The temperature comes as two byte float and with DPTTemperature
the conversion is fine.
So it is looking better and better. The next step is to add some long overdue unit tests. And maybe a better look at sending telegrams.
Hi @kistlin 👋!
I do have a USB Interface available for testing now and would like to help push this forward.
Unfortunately on my system I do have problems getting your current branch working. I did install libusb
beforehand, but get
ERROR:xknx.usb:Could not detach kernel driver: [Errno 13] Access denied (insufficient permissions)
this may be a macOS specific problem though so I'll see if I have more luck in a Linux VM or something in the coming days. It seems to be able to find and get infos from the device at least.
Ad https://github.com/XKNX/xknx/issues/581#issuecomment-1003399838
Also do you consider a refactoring so we don't have twice the logic and twice the tests for the same problem? Or not yet?
This is now done in #1137 - so you'd only have to pass and handle CEMIFrame
instances, no Telegram
anymore. See https://github.com/XKNX/xknx/blob/915344c0ff2c57b47ed314657b26a7e0cab4adc0/xknx/io/knxip_interface.py#L433-L441
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.
They mention to use HIDAPI and the Cython binding
. Maybe a migration is required to get it to work.
If you can, you could try on Windows or Linux first. To run some basic tests. And then either of us could look into making it work on a Mac. I have one and I see the same error.
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 https://github.com/libusb/libusb/issues/1014
Looking at libusb documenation it even recommends to use the hidapi
rather than libusb directly. https://github.com/libusb/libusb/wiki/FAQ#user-content-Does_libusb_support_USB_HID_devices which also has up-to-date python bindings which look quite promising.
I think I'll take a stab on testing these.
Ok. Then I'll leave it up to you for now :). It might also simplify the code around USB.
Allright! I have copied your branch to https://github.com/XKNX/xknx/tree/usb-interface-support
@kistlin Feel free to open a (draft-)PR against main
🙂
So I did some testing on Windows 10 and had no luck - even with different drivers.
libusb1 times out with usb:Operation not supported or unimplemented on this platform
whereas libusb0 ´[Errno None] b'libusb0-dll:err [claim_interface] could not claim interface 0, invalid configuration 0\n'´
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 🤣
So I did some testing on Windows 10 and had no luck - even with different drivers. libusb1 times out with
usb:Operation not supported or unimplemented on this platform
libusb1 whereas libusb0 ´[Errno None] b'libusb0-dll:err [claim_interface] could not claim interface 0, invalid configuration 0\n'´
libusb0 Can you give me a hint of how to get that running on Windows? What are the right drivers?
Did you see _get_usb_backend
in xknx\usb\util.py
?
It expects libusb1 to be at C:\Windows\System32\libusb-1.0.dll
or you can set it with an environment variable XKNX_LIBUSB
.
Yeah all these quirks. But HID might help.
Yes I saw that and changed the path to my .DLL that was provided by libusb_package
and also a downloaded version from libusb.info.
I'm a Windows noob - I probably forgot something obvious.
If that doesn't help then it was me probably using Zadig
and install WinUSB
for my usb device.
I just had to remove that, else hidapi
would no longer find my device.
I would say let's forget about pyusb/libusb
and just use hidapi
. Too many inconveniences.
@farmio
I quickly hacked some hidapi
support in. You might try it on your system. It's in my branch under usb-interface-support
.
Using the monitor example I don't get what I expect. But running the switch example, it seems to communicate.
I did also try Zadig 🤣 Ok, just tested your branch - hidapi doesn't raise any errors on macOS and Windows - so that's good. But it also doesn't actually send anything to the bus - so thats to improve 😬
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
hidapitester --vidpid 135e/0022 --open --send-output 1,0x13,0x09,0x00,0x08,0x00,0x01,0x0F,0x01,00,00,01 --read-input
Opening device, vid/pid: 0x135E/0x0022
Writing output report of 64-bytes...wrote 64 bytes:
01 13 09 00 08 00 01 0F 01 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Reading 64-byte input report 0, 250 msec timeout...read 64 bytes:
01 13 0B 00 08 00 03 0F 02 00 00 01 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Closing device
it looks to me that my interface doesn't support CEMI, but only EMI1 😭
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