Python Plugin UDP Usage

Python and python framework

Moderator: leecollings

Post Reply
febalci
Posts: 331
Joined: Monday 03 July 2017 19:58
Target OS: NAS (Synology & others)
Domoticz version:
Contact:

Python Plugin UDP Usage

Post 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?
User avatar
Dnpwwo
Posts: 820
Joined: Sunday 23 March 2014 9:00
Target OS: Raspberry Pi / ODroid
Domoticz version: Beta
Location: Melbourne, Australia
Contact:

Re: Python Plugin UDP Usage

Post 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.
The reasonable man adapts himself to the world; the unreasonable one persists to adapt the world to himself. Therefore all progress depends on the unreasonable man. George Bernard Shaw
febalci
Posts: 331
Joined: Monday 03 July 2017 19:58
Target OS: NAS (Synology & others)
Domoticz version:
Contact:

Re: Python Plugin UDP Usage

Post 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.
User avatar
Dnpwwo
Posts: 820
Joined: Sunday 23 March 2014 9:00
Target OS: Raspberry Pi / ODroid
Domoticz version: Beta
Location: Melbourne, Australia
Contact:

Re: Python Plugin UDP Usage

Post 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?
The reasonable man adapts himself to the world; the unreasonable one persists to adapt the world to himself. Therefore all progress depends on the unreasonable man. George Bernard Shaw
febalci
Posts: 331
Joined: Monday 03 July 2017 19:58
Target OS: NAS (Synology & others)
Domoticz version:
Contact:

Re: Python Plugin UDP Usage

Post 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
edog1973
Posts: 1
Joined: Wednesday 14 November 2018 23:21
Target OS: Raspberry Pi / ODroid
Domoticz version:
Contact:

Re: Python Plugin UDP Usage

Post 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.
User avatar
Dnpwwo
Posts: 820
Joined: Sunday 23 March 2014 9:00
Target OS: Raspberry Pi / ODroid
Domoticz version: Beta
Location: Melbourne, Australia
Contact:

Re: Python Plugin UDP Usage

Post 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.
The reasonable man adapts himself to the world; the unreasonable one persists to adapt the world to himself. Therefore all progress depends on the unreasonable man. George Bernard Shaw
Nettime
Posts: 15
Joined: Friday 14 December 2018 9:01
Target OS: Raspberry Pi / ODroid
Domoticz version:
Contact:

Re: Python Plugin UDP Usage

Post 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
User avatar
Dnpwwo
Posts: 820
Joined: Sunday 23 March 2014 9:00
Target OS: Raspberry Pi / ODroid
Domoticz version: Beta
Location: Melbourne, Australia
Contact:

Re: Python Plugin UDP Usage

Post 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.
The reasonable man adapts himself to the world; the unreasonable one persists to adapt the world to himself. Therefore all progress depends on the unreasonable man. George Bernard Shaw
Nettime
Posts: 15
Joined: Friday 14 December 2018 9:01
Target OS: Raspberry Pi / ODroid
Domoticz version:
Contact:

Re: Python Plugin UDP Usage

Post 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
FrancescoS
Posts: 12
Joined: Sunday 19 May 2019 21:16
Target OS: -
Domoticz version:
Contact:

Re: Python Plugin UDP Usage

Post 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
Post Reply

Who is online

Users browsing this forum: No registered users and 1 guest