Page 1 of 1

Python Plugin UDP Usage

Posted: Saturday 27 January 2018 16:53
by febalci
Hi All,

Trying to write a Xiaomi PM2.5 AQI Sensor Plugin. It works with UDP connection. Domoticz Stable 3.8153 doesn't work with this it gives 'Transport directive ignored', so i tried it with 3.8833 Beta:

Code: Select all

self.miioConn = Domoticz.Connection(Name="miioUDP", Transport="UDP/IP", Protocol="None", Address=Parameters["Address"], Port=Parameters["Port"])
self.miioConn.Send(self.hellopackage)
So, this end the required hello package in UDP to Xiaomi 2.5. And from wireshark i see that it is sending back the response UDP package, however i cannot receive or see this package in the plugin. So i sense i have to enter:

Code: Select all

self.miioConn.Listen()
somewhere, however as far as i understand, the plugin framework doesn't send and listen at the same time for UDP packages. Is there a way to use the plugin framework work like TCP/IP-None way, can send and receive UDP datagrams per ip/port?

Re: Python Plugin UDP Usage

Posted: Monday 29 January 2018 10:26
by Dnpwwo
@febalci,

As you know, UDP is not quite the same as TCP and in the plugin framework I did not try to pretend it is.

Have a look at the "UDP Discovery.py" example that ships as a part of Domoticz shows how to listen for incoming UDP. To send messages just create another Connection and Send it. The UDP implementation allows sharing of UDP ports so nothing will complain.

For example, in onStart:

Code: Select all

  def onStart(self):
    self.miioConn = Domoticz.Connection(Name="miioUDP", Transport="UDP/IP", Protocol="None", Address=Parameters["Address"], Port=Parameters["Port"])
    self.miioConn.Listen()
    helloConn = Domoticz.Connection(Name="hello", Transport="UDP/IP", Protocol="None", Address=Parameters["Address"], Port=Parameters["Port"])
    helloConn.Send(self.hellopackage)
could do the trick.

Incoming data will be seen in "onMessage" as usual.

Re: Python Plugin UDP Usage

Posted: Monday 29 January 2018 10:37
by febalci
Dear @Dnpwwo,

i solved my current problem using an extra module in the same plugin directory and using socket connection in that module: https://github.com/febalci/DomoticzXiaomiPM2.5 I tried using 2 connections as you suggested but it didn't worked, maybe since both connections refer to the same destination IP and port. It didn't give any errors, i can send the hellopackage and receive the response (found out using wireshark), however the plugin and onmessage does not receive the hellopackage response from the module.Might be because 2 connections create 2 different outgoing udp ports, domoticz sends the UDP datagram hellopackage from port 52310, but waits for a response on port 52311... Anyway, i will try it again with some changes, for future users who may request to do the same thing.

Re: Python Plugin UDP Usage

Posted: Tuesday 30 January 2018 10:16
by Dnpwwo
@febalci,

Glad you found a solution, that's the important thing :)

The port difference shouldn't be the problem (because there is no connection). Could you post a screenshot of wireshark packet capture and your test plugin?

Re: Python Plugin UDP Usage

Posted: Tuesday 30 January 2018 17:08
by febalci
Dear @dnpwwo,

Working on 2 UDP connectons here is the log file:

Code: Select all

 2018-01-30 19:01:13.391 (test) Debug log level set to: 'true'.
2018-01-30 19:01:13.391 (test) Creating device 'Miio AQI'.
2018-01-30 19:01:13.393 (test) Device created.
2018-01-30 19:01:13.393 (test) 'HardwareID':'2'
2018-01-30 19:01:13.393 (test) 'HomeFolder':'/config/plugins/Xiaomi/'
2018-01-30 19:01:13.393 (test) 'Version':'0.9.0'
2018-01-30 19:01:13.393 (test) 'Author':'febalci'
2018-01-30 19:01:13.393 (test) 'Name':'test'
2018-01-30 19:01:13.393 (test) 'Address':'192.168.1.86'
2018-01-30 19:01:13.393 (test) 'Port':'54321'
2018-01-30 19:01:13.393 (test) 'Key':'XiaomiPM'
2018-01-30 19:01:13.393 (test) 'Mode6':'Debug'
2018-01-30 19:01:13.393 (test) 'DomoticzVersion':'3.8833'
2018-01-30 19:01:13.393 (test) 'DomoticzHash':'60050638'
2018-01-30 19:01:13.393 (test) 'DomoticzBuildTime':'2018-01-19 15:22:13'
2018-01-30 19:01:13.393 (test) Device count: 1
2018-01-30 19:01:13.394 (test) Device: 1 - ID: 1, Name: 'test - Miio AQI', nValue: 0, sValue: ''
2018-01-30 19:01:13.394 (test) Device ID: '1'
2018-01-30 19:01:13.394 (test) Device Name: 'test - Miio AQI'
2018-01-30 19:01:13.394 (test) Device nValue: 0
2018-01-30 19:01:13.394 (test) Device sValue: ''
2018-01-30 19:01:13.394 (test) Device LastLevel: 0
2018-01-30 19:01:13.401 (test) Protocol set to: 'None'.
2018-01-30 19:01:13.401 (test) Protocol set to: 'None'.
2018-01-30 19:01:13.401 (test) Transport set to: 'UDP/IP', 192.168.1.86:54321.
2018-01-30 19:01:13.403 PluginSystem: Starting I/O service thread.
2018-01-30 19:01:13.404 (test) Listen directive received, action initiated successfully.
2018-01-30 19:01:13.404 (test) Transport set to: 'UDP/IP', 192.168.1.86:54321 for 'miioConnection2'.
2018-01-30 19:01:13.404 (test) Sending 32 bytes of data:
2018-01-30 19:01:13.404 (test) 21 31 00 20 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff !1..����������������
2018-01-30 19:01:13.404 (test) ff ff ff ff ff ff ff ff ff ff ff ff .. .. .. .. .. .. .. .. ������������
2018-01-30 19:01:13.404 (test) Heartbeat interval set to: 30. 
So i see the message going out. But no response.

Here is the wireshark log:

Code: Select all

38	8.505739	192.168.1.54	192.168.1.86	UDP	74	56575→54321 Len=32
0000   78 11 dc 8b b3 19 98 e0 d9 9a 51 df 08 00 45 00
0010   00 3c 3f f9 00 00 3f 11 b7 db c0 a8 01 36 c0 a8
0020   01 56 dc ff d4 31 00 28 a9 3e 21 31 00 20 ff ff
0030   ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0040   ff ff ff ff ff ff ff ff ff ff

39	8.513941	192.168.1.86	192.168.1.54	UDP	74	54321→56575 Len=32
0000   98 e0 d9 9a 51 df 78 11 dc 8b b3 19 08 00 45 00
0010   00 3c 03 9f 00 00 ff 11 34 35 c0 a8 01 56 c0 a8
0020   01 36 d4 31 dc ff 00 28 d8 2a 21 31 00 20 00 00
0030   00 00 04 79 f2 0b 00 00 0c dd 9d e5 5e dd 1b ac
0040   47 45 77 36 4e cd e7 43 c0 b5
So i got the response back.

Here is the related part of the test plugin:

Code: Select all

class BasePlugin:

    miioConn = None
    miioConn2 = None
 
    hellopackage = b'\x21\x31\x00\x20\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'


    def __init__(self):
        #self.var = 123
        return

    def onStart(self):

        if Parameters["Mode6"] == "Debug":
            Domoticz.Debugging(1)

        if (len(Devices) == 0):
            Domoticz.Device(Name="Miio AQI", Unit=1, TypeName="Air Quality", Used=1).Create()
        Domoticz.Debug("Device created.")
        DumpConfigToLog()

        self.miioConn = Domoticz.Connection(Name="miioConnection", Transport="UDP/IP", Protocol="None", Address=Parameters["Address"], Port=Parameters["Port"])   
        self.miioConn2 = Domoticz.Connection(Name="miioConnection2", Transport="UDP/IP", Protocol="None", Address=Parameters["Address"], Port=Parameters["Port"])   

        self.miioConn.Listen()

        self.miioConn2.Send(self.hellopackage)
        Domoticz.Heartbeat(30)
It never goes to onMessage... Btw domoticz version is 3.8833

Re: Python Plugin UDP Usage

Posted: Wednesday 14 November 2018 23:51
by edog1973
Sorry for hijacking the thread, but I'm currently dealing with exactly the same issue. I can send UDP packets and can see the responses arriving using Wireshark, but am not receiving the response messages to the Plugin. Unfortunatly, febalci's solution of using socket would not work for my situation as significant time could pass between sending and receiving the packets.

The solution of using two Connections does not currently work. The listening connection listens on port X that is specified on creation. The sending connection uses a random source port when sending. The host receiving the packet will then send a response packet to the source port of the sending connection. The listening connection needs to listen on the sending connections source port.

It seems that in order to make this work we would need to: a) have a method of determining the random source source port when sending or b) a way to specify the source port when sending a UDP packet

Thank you in advance for your help.

Re: Python Plugin UDP Usage

Posted: Sunday 25 November 2018 13:38
by Dnpwwo
@edog1973,

Not sure I understand why you think know or settig the source port would help. The source port is normally irrelevant with UDP. I've seen issues where Windows filters out UDP traffic but not Linux.

Can wireshark see the outbound traffic from Domoticz and the responses coming back? If you post your code I can have a look to see if I can make any suggestions.

Re: Python Plugin UDP Usage

Posted: Saturday 02 November 2019 17:05
by Nettime
Bumping this as I ran into the same problem.
I need to be able to set the source port ie:
self.udpConn = Domoticz.Connection(Name="ADAM 6xxx", Transport="UDP/IP",
Protocol="None",Address="192.168.1.131",
SourcePort = Parameters["Port"] ,Port=Parameters["Port"])

I'm using a fixed IP and not broadcast so ports matter.
When using 2 Connections the Adam module will reply to the randomized source port and not Parameters["Port"])
Using one Connection is not possible as the reply is sent before the port had time to switch over to "Listen"
Which seems to be the same problem as @edog1973 and probably the original poster.

Is it doable to add a "SourcePort" parameter?
Regards Nettime

Re: Python Plugin UDP Usage

Posted: Monday 04 November 2019 22:20
by Dnpwwo
@Nettime,

I think I see the confusion here.

UDP is connectionless, so it is impossible to send and recieve on the same connection because there is no connection. Adding a SourcePort wouldn't help on that basis.

You need to create a UDP connection object that "listens" for incoming messages first but use a completely different UDP connection object to send messages.

This is not a restriction of the plugin framework but just the way UDP/IP works. Happy to have a look if you post your code.

Re: Python Plugin UDP Usage

Posted: Wednesday 13 November 2019 9:49
by Nettime
I do not belive I'm confused. Yes there is no Connection but there is a localport and I need to send and receive on the same port.
Using Domoticz.Connection it sends on a random free port and the module will reply to that random port and the reply will get lost.
The module replies per default to the remote port it got the message from instead of the port it receives on.
In other words the Communication is not done by "broadcast" on a predetermined broadcast port which seems to be your angle?

It works with socket.socket that sends on the same local port as the remote port
The destination IP address and port number are encapsulated in each UDP packet. These two numbers together uniquely identify the recipient and are used by the underlying operating system to deliver the packet to a specific process (application). Each UDP packet also contains the sender's IP address and port number.
/Nettime

Re: Python Plugin UDP Usage

Posted: Thursday 09 April 2020 8:13
by FrancescoS
Hi,

same problem here.

I 100% agree with Nettime, this is limitation of this UDP implementation,
I hope someone will fix it.

BestRegards