A listening Plug-In

Hi…

Does something already exist within Vera, or perhaps in people’s own libraries - that allows you to just listen for any incoming messages that are being sent to Vera ? Perhaps on a particular port , if you wanted to be specific and send it to Vera that way ?

The reason for asking is because I’ve got some sensors where I can configure them to send a json file of information somewhere to be processed - I just need to give them the address/port number ?

If not, Is this a luup.register_handler sort of thing , or something else? Input/intercept etc.

As it sounds like a standard sort of task, I’m just curious if there was a ‘listening node’ where anything it received is recorded as a variable that you can then watch, and process it as you need to.

Sounds as though you might gain what you want by inspecting Vera’s LuaUPnP Log, simply by going to the following address on your home network:

http://<vera_ip_here>/cgi-bin/cmh/log.sh?Device=LuaUPnP

Hi, thanks for responding, I haven’t actually set anything up or sent anything to Vera yet. At the moment I’m just trying to understand what to do and where I would exactly send things… Once I’ve done that, I totally agree - the logs are my friend :slight_smile:

Roger that. I’m sure someone more knowledgeable will chime in with a purpose-built solution for you to try, but in the meantime, don’t discount Reactor or SiteSensor plug-ins, since both can accept JSON responses.

How you’d shoe-horn those incoming messages into either isn’t readily clear to me, but suffice to say they both have robust message handling features built-in.

I’m not sure of the correct terminology, but I’m looking to having something in place on Vera to receive/accept data from an external push, much of what I have is a pull/poll type action.

Before I embark on another adventure in Lua programming, (Lua Socket) just curious if there was something built in. I believe the following link is the sort of thing I’d need to do, but with Vera’s various Lua quirks I thought it best to check :slight_smile:

https://wiki.dragino.com/index.php?title=Lua_Socket

1 Like

Hi @parkerc ,

The Vera does not have anything build in out of the box for this. You will have to create a plugin. You may be able to use the incoming functionality http://wiki.micasaverde.com/index.php/Luup_Plugins_ByHand.

One plugin using that is this one GitHub - reneboer/Vera-Dutch-Smartmeter: Vera plug-in to read Dutch Smartmeter. Have a look at the I_SmartMeter.xml and L_SmaerMeter.lua.

Cheers Rene

Cheers @reneboer

I couldn’t seen anything within the Dutch plugin that was specific to Lua sockets, did you? Either way, I worked ok this last night and while there were a few options, I’ve got this running on my Rasp Pi at the moment, listening for anything incoming

-- A Lua listening TCP  server 
local socket = require 'socket'
local server = socket.tcp()
server:bind('*',51425)
server:listen(32)
local ip, port = server:getsockname()
local localip, _ = socket.dns.toip(socket.dns.gethostname()) -- want host IP, not 127.0.0.1??

print("This is the IP and port to commect to " .. ip ..":".. port)
print("Below is what's being received by the server....")

while 1 do
  local client = server:accept()
  client:settimeout(20)
  print(client:getpeername()) -- shows IP and port
  print("Connecting client = " ..client:getpeername()) -- only shows IP,  no port, why ???
  local line, err = client:receive()
  if not err then client:send(line .. "\n") end
  print("Client's message = " ..line)
  client:close()
end

And now the other client part…

-- A Lua TCP  client
local host, port = "192.168.102.37", 41565
local socket = require("socket")
local tcp = assert(socket.tcp())
tcp:connect(host, port);
tcp:send("hello the world\n");
while true do
    local s, status, partial = tcp:receive()
    print(s or partial)
print(status)
    if status == "closed" then break end
end
tcp:close()

My Lua listening server reports the following…

pi@raspberrypi:/ $ lua /home/pi/Documents/listen_vera_server.lua
This is the IP and port to commect to 0.0.0.0:57673
Below is what's being received by the server....
192.168.102.107 49478   inet
Connecting client = 192.168.102.107
Client's message = hello the world

Now for my questions/ challenges / next steps with the above (so far) :slight_smile: .

  1. I tried to set this up so the server always use the same port, but every time I stop it from running (CTRL+Z) and then run it again, it gives me a new port no.? Now, Is that due to the port not being closed and it has to open another one instead ? If so is there a cleaner way to stop/restart?

  2. It seems I have to put a \n (new line) at the end of any string I send via the client, otherwise it times out. It can send a json like this "tcp:send(‘{“type”: “Event”, “userId”: 0, “userName”: “Joe”, “roomName”: “Living Room”, “sensorId”: “98072D0B9B71”, “event”: {“name”: “RoomEntry”, “inControl”: true}}\n’)

  3. As this TCP server will needs to be able to receive Http posts from another server, i’m not sure how the server will needs to change to accommodate that … ?

Ok, I’m trying to test my ‘Lua listening server’ with the following http post.

local http = require("socket.http")
local ltn12 = require("ltn12")

function sendRequest()
local path = "http://192.168.102.37:57673"
  local payload = [[ {"type": "Event", "userId": 0, "userName": "Joe", "roomName": "Living Room", "sensorId": "98072D0B9B72", "event": {"name": "RoomEntry", "inControl": true}} ]]
  local response_body = { }

  local res, code, response_headers, status = http.request
  {
    url = path,
    method = "POST",
    headers =
    {
      ["Content-Type"] = "application/json",
      ["Content-Length"] = payload:len()
    },
    source = ltn12.source.string(payload),
    sink = ltn12.sink.table(response_body)
  }
  print('Response: = ' .. table.concat(response_body))
  print('res = ' .. res .. ' code = ' .. code .. ' response_headers = ' .. tostring(response_headers) .. ' status = ' .. tostring(status))
end

sendRequest()

But rather than see the json appear, the server is reporting the following each time I try to send anything.

Connecting client = 192.168.102.22
Client's message = POST / HTTP/1.1
192.168.102.22  46681   inet
Connecting client = 192.168.102.22
Client's message = POST / HTTP/1.1
192.168.102.22  46686   inet
Connecting client = 192.168.102.22
Client's message = POST / HTTP/1.1
192.168.102.22  46690   inet
Connecting client = 192.168.102.22
Client's message = POST / HTTP/1.1

Does anyone know why I’m not seeing the json payload and instead getting “POST / HTTP/1.1”

Hi Parker,

Are you looking for something in a plugin, or just some Lua code to run on a Vera? Using just a socket would create a blocking situation and the Vera Luup engine will not like that at all. What I did for some plugins, is read from the socket non-blocking and have a luup.delay check every second. See the wsAPI module here for an example vera-Harmony-Hub/L_Harmony.lua at master · reneboer/vera-Harmony-Hub · GitHub.

On your result, an HTTP request terminates every line with a new line and your code stops reading after the first line. I think it can work, if you look for a double new line char. One pair for the end of the header, one pair for the end of the html payload. Not an 100% solid solution, but may get you going.

Cheers Rene

Thanks @reneboer

I think my ideal solution would be just a generic listening plugin, one where I could http.post anything to it, and then based on an initial string match , or something similar will store it as a variable and then from there, Vera who will be watching, can do something with it.

Looking at your wsAPI function (280 lines?) it looks impressive, but sadly way way beyond my Lua abilities. Is that entire function a stand-alone websock set up ?

As I will have little to no control over the http-posts that’ll be sent to me, is there something I change change on the Lua listening server side to be more accommodating and accept more?

Hi Parker,

The wsAPI function is a simplified websocket driver that does all what is needed for the Harmony communications. You could used bits that check for a message on the socket and then read from the socket and add it to what you already have. But you would need to make a non-blocking poller inside the plugin as well. This is also in the Harmony plugin.

There are some other ways of doing this as well. For example the original Sonos plugin has a script to listen and then relays this to the plugin incoming handler. Also rigpapa created a socket proxy function that does the same and has details here GitHub - toggledbits/sockproxyd: A socket proxy for Vera/openLuup systems.

This does go beyond a straight forward plugin development indeed.

Cheers Rene