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.

Kodi UDP control
#1
Hello,

Please find below a script to control Kodi over UDP.
I does simulate a full remote, so you can control the behaviour with remote.xml inside kodi.

Please check http://kodi.wiki/view/list_of_built-in_functions for the list of commands

To install it, just copy the script into a user librairy, then use kodi_button and kodi_action in your event script.

Some example :
kodi_button("R1","select")
kodi_action("Action(PlayPause)")
kodi_button("R1","up",0,1,1)
kodi_button("R1","up",1,0,1)

Code:
--[[ Librairy : Kodi UDP control
Author : Matthieu Bouthors

Command reference http://kodi.wiki/view/list_of_built-in_functions

Change IP with your kodi server.
Verified with Kodi v16 and v17
This is a partial implementation, full implementation in python : https://github.com/xbmc/xbmc/blob/master/tools/EventClients/lib/python/xbmcclient.py

Some example :
kodi_button("R1","select")
kodi_action("Action(PlayPause)")
kodi_button("R1","up",0,1,1)
kodi_button("R1","up",1,0,1)
]]--


kodi_destination_IP = "192.168.1.1"
kodi_destination_port = "9777"

--conversion function
function int_to_raw_string(raw_integer,length)
 local value = raw_integer
 local str = ""
 for i=1,length do
   str = string.char(value % 256)  .. str
   value = math.floor(value / 256)
 end
 return str
end
 
-- execute kodi action
function kodi_action(action)
 -- load namespace
 local socket = require("socket")
 -- create a new UDP object
 local udp = assert(socket.udp())
 
 --headers
--[[

 -----------------------------
 | -H1 Signature ("XBMC")    | - 4  x CHAR                4B
 | -H2 Version (eg. 2.0)     | - 2  x UNSIGNED CHAR       2B
 | -H3 PacketType            | - 1  x UNSIGNED SHORT      2B
 | -H4 Sequence number       | - 1  x UNSIGNED LONG       4B
 | -H5 No. of packets in msg | - 1  x UNSIGNED LONG       4B
 | -H6 Payload size
 | -H7 Client's unique token | - 1  x UNSIGNED LONG       4B
 | -H8 Reserved              | - 10 x UNSIGNED CHAR      10B
 |---------------------------|
 | -P1 payload               | -
 -----------------------------  
]]--
 
 
 
 local action_type = "\x02"
 local payload =  action_type .. action .. "\x00"
 
 local version_maj = "\x02"
 local version_min = "\x00"
 
 local PT_ACTION = "\x00\x0A"
 local seq_num = "\x00\x00\x00\x01"
 local max_seq = "\x00\x00\x00\x01"
 local payload_size = string.len(payload)
 local unique_id = "LM01"
 local reserved = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
 
 header = "XBMC" .. version_maj .. version_min .. PT_ACTION .. seq_num .. max_seq .. int_to_raw_string(payload_size,2) .. unique_id .. reserved
   
 -- contact host
 assert(udp:sendto(header .. payload,kodi_destination_IP, kodi_destination_port))
end

-- simulate kodi button press
function kodi_button(map,name,release,repeating,queue)
 -- load namespace
 local socket = require("socket")
 -- create a new UDP object
 local udp = assert(socket.udp())
 
 --headers
--[[

 -----------------------------
 | -H1 Signature ("XBMC")    | - 4  x CHAR                4B
 | -H2 Version (eg. 2.0)     | - 2  x UNSIGNED CHAR       2B
 | -H3 PacketType            | - 1  x UNSIGNED SHORT      2B
 | -H4 Sequence number       | - 1  x UNSIGNED LONG       4B
 | -H5 No. of packets in msg | - 1  x UNSIGNED LONG       4B
 | -H6 Payload size
 | -H7 Client's unique token | - 1  x UNSIGNED LONG       4B
 | -H8 Reserved              | - 10 x UNSIGNED CHAR      10B
 |---------------------------|
 | -P1 payload               | -
 -----------------------------  
 
       """
       Keyword arguments:
  repeating -- this key press should repeat until released (default: 0)
                 Note that queued pressed cannot repeat.
       down -- if this is 1, it implies a press event, 0 implies a release
               event. (default: 1)
       queue -- a queued key press means that the button event is
                executed just once after which the next key press is
                processed. It can be used for macros. Currently there
                is no support for time delays between queued presses.
                (default: 0)
       map_name -- a combination of map_name and button_name refers to a
                   mapping in the user's Keymap.xml or Lircmap.xml.
                   map_name can be one of the following:
                   "KB" => standard keyboard map ( <keyboard> section )
                   "XG" => xbox gamepad map ( <gamepad> section )
                   "R1" => xbox remote map ( <remote> section )
                   "R2" => xbox universal remote map ( <universalremote>
                           section )
                   "LI:devicename" => LIRC remote map where 'devicename' is the
                   actual device's name
       button_name -- a button name defined in the map specified in map_name.
                      For example, if map_name is "KB" refering to the
                      <keyboard> section in Keymap.xml then, valid
                      button_names include "printscreen", "minus", "x", etc.
       amount -- unimplemented for now; in the future it will be used for
                 specifying magnitude of analog key press events
       """  
]]--
 
 local kodi_BT_USE_NAME   = 0x01
 local kodi_BT_DOWN       = 0x02
 local kodi_BT_UP         = 0x04
 local kodi_BT_USE_AMOUNT = 0x08
 local kodi_BT_QUEUE      = 0x10
 local kodi_BT_NO_REPEAT  = 0x20
 local kodi_BT_VKEY       = 0x40
 local kodi_BT_AXIS       = 0x80
 local kodi_BT_AXISSINGLE = 0x00

 local flags = kodi_BT_USE_NAME
 
 if (release == 1) then
   flags = flags + kodi_BT_UP
 else
   flags = flags + kodi_BT_DOWN
 end
 
 if (not repeating) then
   flags = flags + kodi_BT_NO_REPEAT
 end
 
 if (queue) then
   flags = flags + kodi_BT_QUEUE
 end
 
 local payload = "\x00\x00" .. int_to_raw_string(flags,2) .. "\x00\x00" .. map .. "\x00" .. name .. "\x00"
 
 local kodi_version_maj = "\x02"
 local kodi_version_min = "\x00"
 
 local kodi_PT_BUTTON = "\x00\x03"

 local seq_num = "\x00\x00\x00\x01"
 local max_seq = "\x00\x00\x00\x01"
 local payload_size = string.len(payload)
 local kodi_unique_id = "LM01"
 local kodi_reserved = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
 
 header = "XBMC" .. kodi_version_maj .. kodi_version_min .. kodi_PT_BUTTON .. seq_num .. max_seq .. "\x00" .. string.char(payload_size) .. kodi_unique_id .. kodi_reserved

 -- contact host
 assert(udp:sendto(header .. payload,kodi_destination_IP, kodi_destination_port))
end

Best regards,
Matt
Reply
#2
Nice, thanks for sharing!
Reply


Forum Jump: