This forum uses cookies
This forum makes use of cookies to store your login information if you are registered, and your last visit if you are not. Cookies are small text documents stored on your computer; the cookies set by this forum can only be used on this website and pose no security risk. Cookies on this forum also track the specific topics you have read and when you last read them. Please confirm that you accept these cookies being set.

a better KODI handler
#1
How to make a handler that interacts with KODI. 
Data can be send to kodi on port 9090 (or another port you configured) using a raw connection with putty.

My goal:
- send command to kodi, for example i can send this command: { "jsonrpc": "2.0", "id": 1, "method": "Application.SetVolume", "params": { "volume": 53 } }
- receive executed events from kodi, for example i receive this command: {"jsonrpc":"2.0","method":"GUI.OnScreensaverDeactivated","params":{"data":{"shuttingdown":false},"sender":"xbmc"}}
- receive commands from my lm/hl over udp and send them to kodi

I like to have this all in one handler. I have already a piece of code that works, but its to slow. It waits on udp command and that interrups my receiving events.

Maybe using copas or something solved the issue, but how? Smile

kodiHandler("192.168.x.x","9090","12007")
Code:
-- library
function kodiHandler(iServer,iPort,sendPort)
 -- first call
 if not ready then
   require('socket')
   require('json')
    
   lastdatareceived = nil
   ready = true
 end
 
 -- client connected
 if connected then
   while true do
     char, err = client:receive(1)
     -- error while receiving, closed socket
     if err == 'closed' then
         connected = false
       sleep(1)
       break
     end
       
     if char ~= nil then
       lastdatareceived = os.time()
       warningclosed = true
       warningfailed = true
       warningerrors = true
       warningtimeou = true
       
                table.insert(buffer, char)
       tmpbuf = table.concat(buffer)
       if ( json.pdecode(tmpbuf) ) then
         data = tmpbuf
         parse(data)
         buffer = {}
       end
     else
       now = os.time()
       deltatime = now - lastdatareceived
     end
       
     -- receive incoming send requests
         msg, ip, port = sendServer:receivefrom()
            if msg then
       -- send command
       --log("send: "..msg)
       client:send(msg)
            end
     
     --[[ clear not complete buffer
     if deltatime > 10 and #buffer > 0 then
       log( #buffer )
       buffer = {}
       lastdatareceived = os.time()
     end
     -]]
   end
   
   -- first call or previously disconnected
 else
   -- close previous connection when disconnected
   if client then
     client:close()
     client = nil
   end
   if sendServer then
     sendServer:close()
     sendServer = nil
   end
   
   -- create tcp client
   client = socket.tcp()
   client:settimeout(5)
   connected, err = client:connect(iServer, iPort)
   
   -- connect ok, reset buffer
   if connected then
     lastdatareceived = os.time()
     warningclosed = true
     warningfailed = true
     warningerrors = true
     warningtimeou = true
     --log('[KODI-client] connection ok: '..iServer)
     buffer = {}
     
     -- create udp server to receive incoming send requests
            if not sendServer then
              sendServer = socket.udp()
              sendServer:setsockname('*', sendPort)
              sendServer:settimeout(0.1)
            end
     
     sleep(5)
     
     -- send initial command
     --client:send( '{"jsonrpc": "2.0", "method": "Player.PlayPause", "params": { "playerid": 0 }, "id": 1}' )
     
   
     -- error while connecting,
   else
            --log(err)
     if warningfailed then log('[KODI-client] connection failed (conn): '.. err) end
     warningfailed = false
     sleep(5)
   end
 end
 
 -- incoming command parser
 function parse(data)
   -- log other info, not mapped, if useful
   --log("data received: "..data)
   --log(json.pdecode(data))
 end
end
Reply
#2
Use this as a starting point, it uses non-blocking socket.select() so UDP won't interfere. The only blocking part is TCP re-connection. There's no need to close/open local UDP server each time.

Code:
if not sockets then
  require('socket')

  clientip = '192.168.1.xx'
  clientport = 9090
  serverport = 12007

  udpserver = socket.udp()
  udpserver:setsockname('127.0.0.1', serverport)
  udpserver:settimeout(0)

  sockets = { udpserver }

  function tcpconnect()
    local tcpclient = socket.tcp()
    tcpclient:settimeout(1)

    if tcpclient:connect(clientip, clientport) then
      tcpclient:settimeout(0)
    else
      tcpclient:close()
      tcpclient = nil
      os.sleep(1)
    end

    return tcpclient
  end

  function reconnect()
    repeat
      tcpclient = tcpconnect()
    until tcpclient

    sockets[ 2 ] = tcpclient
  end

  function errhandler()
    tcpclient:close()
    reconnect()
  end

  function clienthandler()
    while true do
      local char, err = tcpclient:receive(1)

      if char then
        ...
      else
        if err == 'closed' then
          errhandler()
        end

        break
      end
    end
  end

  function serverhandler()
    local msg = udpserver:receive()
    if tcpclient then
      tcpclient:send(msg)
    end
  end

  reconnect()
end

res = socket.select(sockets, nil, 1)

if res then
  if res[ tcpclient ] then
    clienthandler()
  end

  if res[ udpserver ] then
    serverhandler()
  end
end
Reply
#3
yes, that works great!
Reply
#4
Hi did you manage to have a feedback from Kodi ? for instance having a feedback when the film is finished to open the shutters and tun on the light etc ... ?

thanks
Reply
#5
(02.05.2019, 07:53)gilles38 Wrote: Hi did you manage to have a feedback from Kodi ? for instance having a feedback when the film is finished to open the shutters and tun on the light etc ... ?

thanks

edit this code and call a function in the main script:

Code:
-- incoming command parser
  function parse(data)
    -- log other info, not mapped, if useful
    --log("data received: "..data)
    --log(json.pdecode(data))
  end
Reply
#6
(06.05.2019, 15:27)gjniewenhuijse Wrote:
(02.05.2019, 07:53)gilles38 Wrote: Hi did you manage to have a feedback from Kodi ? for instance having a feedback when the film is finished to open the shutters and tun on the light etc ... ?

thanks

edit this code and call a function in the main script:

Code:
-- incoming command parser
  function parse(data)
    -- log other info, not mapped, if useful
    --log("data received: "..data)
    --log(json.pdecode(data))
  end

thanks Wink

I finally add an addon to Kodi called "callback" that allow you to launch script on a specific action in Kodi.
in my case it update a group address Smile
Reply


Forum Jump: