I’m attempting to write a LAN edge driver where the device broadcasts a message over UDP whenever its state changes. However, I’m struggling to even get the UDP socket to receive messages when running on the hub. When I run basically the same code locally, it seems to work as I would expect.
Here is my listener code.
local udp = socket.udp()
assert(udp:setoption('broadcast', true)) -- Is this needed just for listening?
assert(udp:settimeout(2))
assert(udp:setsockname('*', 0)) -- Would love to specify port but I can't
local _, p = udp:getsockname() -- Instead, for now, grab the port that was assigned for testing purposes
log.debug('Listening on port ' .. p .. '...')
while true do
local data, ip, port = udp:receivefrom()
log.debug('Received from ' .. tostring(ip) .. ':' .. tostring(port) .. ' ' .. tostring(data))
end
When running on the hub, I only receive a message if I send a UDP message to the hub’s IP address and the generated port. If I send it to the broadcast IP (255.255.255.255) on the generated port, the message doesn’t show up. But, if I run locally on my machine, I get messages sent to either that machine IP or the broadcast IP.
It seems that when running on the hub, broadcast messages are ignored. Is this expected? Am I doing this all wrong?
Bonus question: Is there no way around passing 0 as the port number? Alternatively, is it possible to listen for UDP messages on all ports (this is a reach, I know).
Even more relevant to what you are doing than my web requestor driver is my UPnP control point library. It is on github if you want to take a look at it. UPnP uses the gamut of TCP, UDP and multicast communications so it’s all covered in there.
This is how I create a socket for SSDP-type discovery:
local multicast_ip = "239.255.255.250"
local multicast_port = 1900
local listen_ip = "0.0.0.0"
local listen_port = 0
local s = assert(socket.udp(), "create discovery socket")
assert(s:setsockname(listen_ip, listen_port), "discovery socket setsockname")
Not sure if the broadcast IP you’re trying to use is functional on the hub. The above should work both on hub and off.
My prior code snippet was for sending things out on the multicast address. I realized you probably really want this, which is how to listen on the multicast address:
I really appreciate you taking the time to reply and point me to your library as well as the code snippets you posted. Unfortunately I couldn’t get it to work. I suspect you’re onto something with your comment about not being sure if the broadcast IP is functional on the hub. I don’t really have control over that on the broadcasting device so I can’t address that.
The good news is I was able to accomplish my goal (pushing events to the hub) with a different mechanism that was available.
Again, super thankful for those that chimed in and much love for this community.
Just getting started on Lua to port my old device drivers to Lua. I am building the guts on my Mac and then will move them into device drivers. In doing so, I am having trouble getting UDP broadcast sent out on all interfaces. On my Mac, the code below is only sending it out on loopback but not on en0. Have not tried it on the hub as that is much harder to debug than getting it work on the Mac first.
The above code only transmits on loopback interface, but not on en0 (verified via WireShark). I tried changing setsockname to the IP address on en0, but still no dice.
I have also tried using network-prefix.255 instead of 255.255.255.255 - does not make a difference either.
Similar code written in python on the same machine works just fine! Seems like some Lua specific thing I am not doing right - any help?
I haven’t tried to get any LUA to run on my development machine, so my mileage may differ, but the hub LUA is pretty limited on udp - it must be multicast and NOT broadcast. Here’s a snip of my code to set up to receive and send on multicast:
(global)
local udpSocket = socket.udp()
local multicastIP = "239.192.1.1"
local multicastPort = 2290
(in my handle_discovery for example)
... other code ...
udpSocket = assert(socket.udp(), "recreate the socket")
assert(udpSocket:setoption('reuseaddr', true))
assert(udpSocket:setsockname(multicastIP, multicastPort))
assert(udpSocket:setoption("ip-add-membership", {multiaddr = multicastIP, interface = "0.0.0.0"}), "join multicast group")
assert(udpSocket:settimeout(0))
udpSocket:sendto("DiscoverMotor", multicastIP, multicastPort)
local beginTime = os.time()
while os.time() - beginTime < 20 do
local parseResult, returnIp, returnPort = udpSocket:receivefrom()
if parseResult then
-- handle the result data
end
end
I’ve installed that driver in it’s basic form onto my hub. I’m running it in discovery and it’s not seeing the device I’m wanting to discover. The device is broadcasting UDP messages on port 50222. I’ve modified the watcher.lua cod to setup the socket defs for both multicas and listen (I saw that listen was doing what appeared to be UPD messages) but I’m still not seeing my device show up. Is there any guidance you can provide?
Are you referring to my UPnP driver? If so, UPnP uses port 1900 on multicast IP 239.255.255.250. Sounds like your device is doing something custom, so you’d have to make some changes.
If all you really want is the SSDP (discovery) part of UPnP, then you might want to use this code and modify it for your needs.
Yes, that is what I’m referring to. To give you my use case, I have a personal weather device that broadcasts data on my LAN on port 50222. I’d like to have a listener on my hub pulling that data and parsing it out to populate a virtual weather device in SmartThings, specifically the temperature, humidity, and illuminance capabilities.
As @edleno mentioned above, the hub supports multicast, but I don’t think you can listen for broadcast messages. In the Edge environment, drivers cannot request a specific port. Listening on a multicast address is the one exception to this.
You might want to check with @nayelyz to see if she can find out if there is any way to make this work in an Edge driver, but I don’t think so.
I wonder if that’s why the manufacturer of my personal weather station stuck the “Works With SmartThings” logo on it’s website in 2020. Then took it down a few weeks later. Then said, “SmartThings integration coming soon in 2021”. Then in 2022 said, “SmartThings support coming late 2022”… and now more crickets.
In any regard, I appreciate you taking the time to response and greatly appreciate all the work you have done for this community.
Yes, it is Tempest. I’m doing some fun stuff with the API (not SmartThings related), and got tired of waiting for them to release their own integration they have been promising. I figured I’d use this as an opportunity to dive into the Edge ecosystem. I was hoping to just use the UDP data it broadcasts to update an edge driver, but I guess that isn’t possible. Tempest integrates with Weather Underground, which integrates with SmartThings, but that’s a Groovy integration, so who knows how long that will survive.
If there is anything I can help with, I would love to do so.
I am new to this community, but have been a long time user of SmartThings. I am very new to Edge as I was previously using Groovy for drivers. I am trying to setup your Edge Weather driver to connect SmartThings to PI to my Tempest weather station, but I am having trouble. I have used CoPilot for guidance with my setup, but it keeps stating that I have the wrong driver. It states that you created an Edge Weather V2 driver. Is this correct? If so, how can I access it? I would appreciate your assistance with this as I want to pull in my local forecast data from Tempest into SmartThings for automation.
If you are having problems, I think the first thing to ask is this: This of course requires my edgebridge app running on your Pi. Have you gotten that all set up and running? Have you been able to test it with any other driver to be sure everything is working?
Tell me a little more about the issue you are having. We may need to get logs from either the driver itself (using the SmartThings CLI), or you can also view the edgebridge logs on your Pi.
Thank you Todd for the quick reply. I was worried that AI was leading me down the wrong path since I could not find Edge Weather version 2 anywhere on your GitHub page or on your SmartThings community page. I didn’t think you would have it behind a paywall since you share all your hard work with the broader community which we appreciate. I am not very technical so tried to follow your steps from the original GitHub invitation link to setup the bridge and driver. AI is claiming my edge bridge is running based on a bunch of tests it asked me to run. I am new to PI too as I just recently purchased a device to access my Tempest data since the company never created a direct integration with SmartThings like other brands have. I downloaded your Edgebridge Monitor driver today and the device originally showed as offline in SmartThings, but I was able to fix it. I moved all of your files to the main root folder. I originally created a sub-folder and some files were stored there. I have since deleted the sub-folder so everything is in one place. The Edge Weather device in SmartThings is still not pulling data from my Tempest weather station. I believe I have updated all the settings correctly including the URLs. What do you recommend to fix this issue? I will stop using AI. LOL!!!
I think the easiest thing for you to do now is check the edgebridge log file. Go to the directory on your Pi where you installed it and dump the contents using the command:
cat edgebridge.log
If for some reason it doesn’t exist, paste here the contents of your edgebridge.cfg file:
cat edgebridge.cat
You can also display a continuous output of the log file with this command:
tail -f edgebridge.log
While that is running, try refreshing the device control screen back in the SmartThings app for the whether device you created. You should see a transaction pop up on the edgebridge log.
As an aside, make sure that your Pi is on the same subnet as your SmartThings hub.
It would also be helpful to tell me all the settings values you have configured for the SmartThings weather device (weather source, URLs, proxy server address and type, etc.)
Stand by… I plugged your URL into a test device and the data is causing an error in the driver - seems to be related to one of the values being returned. Let me get back to you. This may require a code fix!