Posts: 86
Threads: 10
Joined: Jul 2015
Reputation:
1
Dear friends,
According to this site, it seems that there a possibility to control Panasonic Viera TVs through IP commands.
Since my LUA knowledge is very starter level, can anyone give me a quick example how to send a simple "power off" command through LUA scripting so I can try to move it forward with the rest of the commands?
Thank you all in advance.
Posts: 7764
Threads: 42
Joined: Jun 2015
Reputation:
447
Try these functions, they are untested so might not work at all. You have to parse any XML response manually
Code: function request(host, url, urn, action, args)
local body, http, ltn12, sink, res, err
ltn12 = require('ltn12')
http = require('socket.http')
body = [[<?xml version="1.0" encoding="utf-8"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<s:Body><u:]] .. action .. [[ xmlns:u="urn:]] .. urn .. [[">]] .. args .. [[</u:]] .. action .. [[></s:Body>
</s:Envelope>]]
sink = {}
res, err = http.request({
url = 'http://' .. host .. ':55000/' .. url,
method = 'POST',
headers = {
['soapaction'] = '"urn:' .. urn .. '#' .. action .. '"',
['Content-Length'] = #body,
},
sink = ltn12.sink.table(sink),
source = ltn12.source.string(body),
})
if res then
return table.concat(sink)
else
return nil, err
end
end
function sendkey(host, code)
local args = '<X_KeyEvent>' .. code .. '</X_KeyEvent>'
return request(host, 'nrc/control_0', 'panasonic-com:service:p00NetworkControl:1', 'X_SendKey', args)
end
function getmute(host)
return request(host, 'dmr/control_0', 'schemas-upnp-org:service:RenderingControl:1', 'GetMute', '<InstanceID>0</InstanceID><Channel>Master</Channel>')
end
IP = '192.168.1.2'
log(getmute(IP))
Posts: 86
Threads: 10
Joined: Jul 2015
Reputation:
1
15.03.2016, 14:55
(This post was last modified: 15.03.2016, 15:16 by jetsetter.)
Thank you very much.
I will give it a try and report back.
I have successfully add a user library with those functions and then have send a "NRC_POWER-ONOFF" code to the TV and it worked!! Thank you very much!
I will now try to complete the rest of the commands and - if possible - to create a simple panel to simulate the remote control via the LM visualization!
One last question, since this TV is not powered via a bus-controlable outlet, and also does not support any wake-on-lan functionality, in order to update the TV's "ON" status after I turn it off via the above IP command, is there a way to periodicaly check if a specific IP is alive (via ping?) or a specific domain name is alive (it always register to DHCP as "COM-MID1") in my LAN?
Than you in advance.
Posts: 7764
Threads: 42
Joined: Jun 2015
Reputation:
447
You can use this function to check if given TCP port on your device is accepting connections:
Code: function socketping(ip, port, timeout)
local sock = require('socket').tcp()
sock:settimeout(timeout or 2)
local res, err = sock:connect(ip, port)
sock:close()
return res, err
end
IP = '192.168.1.10'
PORT = 55000
status = socketping(IP, PORT)
Posts: 86
Threads: 10
Joined: Jul 2015
Reputation:
1
16.03.2016, 15:05
Just add this to the rest of TV functions and works great too!
Thank you once more for your support.
My next try will be to control another TV that doesn't have native IP control (no LAN port at all). This will be done through HDMI CEC commands that will be send via Kodi (formerly XBMC media player) running on a RPI, through Kodi's JSON RPC API and a relative Kodi add-on, so I will update with the results and more details upon success...
Thanks!
Posts: 86
Threads: 10
Joined: Jul 2015
Reputation:
1
Just finished successfully also the power-off control of another non-smart TV, through a Kodi media player (running in an RPi) connected to it via HDMI.
If anyone is interested, the code I used is the following:
Code: require('socket.http')
socket.http.TIMEOUT = 5
data1 = socket.http.request('http://KODI-IP-ADDRESS/jsonrpc?request={"jsonrpc":"2.0","method":"Addons.ExecuteAddon","params":{"addonid":"script.json-cec","params":{"command":"toggle"}},"id":1}')
socket.http.TIMEOUT = 5
data2 = socket.http.request('http://KODI-IP-ADDRESS/jsonrpc?request={"jsonrpc":"2.0","method":"Addons.ExecuteAddon","params":{"addonid":"script.json-cec","params":{"command":"standby"}},"id":1}')
Sends two CEC commands to the TV through HDMI. One is for swapping the TV source to the HDMI of KODI, and the second is for putting the TV to standby (the TV should be on this source in order for the standby command to work).
The KODI add-on used for the above script can be found here:
Posts: 85
Threads: 16
Joined: Jun 2016
Reputation:
2
Hello,
I have a Samsung smart tv and i want to control TV through IP commands.
Have you a script or a app for that?
Thanks.
Posts: 92
Threads: 9
Joined: Sep 2015
Reputation:
1
I need for Sony Bravia Android TVs, too!
Posts: 133
Threads: 28
Joined: May 2016
Reputation:
3
Hi,
I wanted to ask if there was already progress?
I would like to control a SamsungTV with a homeLYnk. Is it with the CEC / HDMI adapter? and does the adapter work with space- / homeLYnk's as well?
Posts: 7764
Threads: 42
Joined: Jun 2015
Reputation:
447
Most TVs have limited CEC support (not all functions are supported). Another issue is that some models cannot be turned on with CEC, only turned off. So you need to do so digging before buying an adapter
Posts: 133
Threads: 28
Joined: May 2016
Reputation:
3
thx. I've ordered one Chromecast to test it out like describe's in example section.
Posts: 139
Threads: 44
Joined: Dec 2017
Reputation:
4
(10.03.2016, 14:32)admin Wrote: Try these functions, they are untested so might not work at all. You have to parse any XML response manually
Code: function request(host, url, urn, action, args)
local body, http, ltn12, sink, res, err
ltn12 = require('ltn12')
http = require('socket.http')
body = [[<?xml version="1.0" encoding="utf-8"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<s:Body><u:]] .. action .. [[ xmlns:u="urn:]] .. urn .. [[">]] .. args .. [[</u:]] .. action .. [[></s:Body>
</s:Envelope>]]
sink = {}
res, err = http.request({
url = 'http://' .. host .. ':55000/' .. url,
method = 'POST',
headers = {
['soapaction'] = '"urn:' .. urn .. '#' .. action .. '"',
['Content-Length'] = #body,
},
sink = ltn12.sink.table(sink),
source = ltn12.source.string(body),
})
if res then
return table.concat(sink)
else
return nil, err
end
end
function sendkey(host, code)
local args = '<X_KeyEvent>' .. code .. '</X_KeyEvent>'
return request(host, 'nrc/control_0', 'panasonic-com:service:p00NetworkControl:1', 'X_SendKey', args)
end
function getmute(host)
return request(host, 'dmr/control_0', 'schemas-upnp-org:service:RenderingControl:1', 'GetMute', '<InstanceID>0</InstanceID><Channel>Master</Channel>')
end
IP = '192.168.1.2'
log(getmute(IP))
Now in my region as of 2019 Panasonic have implemented Auth before i can send commands,
i found this ( https://github.com/florianholzapfel/pana...a/issues/9) explaining how it is achieved, but it is python, im not sure where to start to work out how to port it to lua,
I have soap command working to return the iv key my goal is to return the encrypted_payload to send to the tv to make connection.
import binascii
import base64
import hmac, hashlib
from Crypto.Cipher import AES
# Example challenge (which is our IV)
iv = base64.b64decode("mUQdS7/RyJTMsiojPz9i1Q==")
# Get character codes from IV bytes
iv_vals = [ord© for c in iv]
# Initialise key character codes array
key_vals = [0] * 16
# Derive key from IV
i = 0
while i < 16:
key_vals[i] = ~iv_vals[i + 3] & 0xFF
key_vals[i + 1] = ~iv_vals[i + 2] & 0xFF
key_vals[i + 2] = ~iv_vals[i + 1] & 0xFF
key_vals[i + 3] = ~iv_vals[i] & 0xFF
i += 4
# Convert our key character codes to bytes
key = ''.join(chr© for c in key_vals)
# Initialise HMAC key mask (taken from libtvconnect.so)
hmac_key_mask_vals = [ord© for c in binascii.unhexlify("15C95AC2B08AA7EB4E228F811E34D04FA54BA7DCAC9879FA8ACDA3FC244F3854")]
# Initialise HMAC key character codes array
hmac_vals = [0] * 32
# Calculate HMAC key using HMAC key mask and IV
i = 0
while i < 32:
hmac_vals[i] = hmac_key_mask_vals[i] ^ iv_vals[(i + 2) & 0xF]
hmac_vals[i + 1] = hmac_key_mask_vals[i + 1] ^ iv_vals[(i + 3) & 0xF]
hmac_vals[i + 2] = hmac_key_mask_vals[i + 2] ^ iv_vals[i & 0xF]
hmac_vals[i + 3] = hmac_key_mask_vals[i + 3] ^ iv_vals[(i + 1) & 0xF]
i += 4
# Convert our HMAC key character codes to bytes
hmac_key = ''.join(chr© for c in hmac_vals)
# This is our plaintext SOAP argument for the pin code shown on the TV
authinfo = "<X_PinCode>4410</X_PinCode>"
# First 12 bytes are randomised, let's just set them to 0 because it doesn't matter
payload = "000000000000"
# The next 4 bytes contain the plaintext (SOAP arg) length in big endian
n = len(authinfo)
payload += chr(n >> 24)
payload += chr((n >> 16) & 0xFF)
payload += chr((n >> 8) & 0xFF)
payload += chr(n & 0xFF)
# Now we concatenate our payload, which is starting at byte 17 of the payload
payload += authinfo
# Let's encrypt it with AES-CBC! We need to make sure we pad it to a multiple of 16 bytes beforehand
aes = AES.new(key, AES.MODE_CBC, iv)
ciphertext = aes.encrypt(pad(payload))
# Calculate the HMAC-SHA-256 signature of our encrypted payload
sig = hmac.new(hmac_key, ciphertext, hashlib.sha256).digest()
# Concatenate the HMAC signature to the encrypted payload and base64 encode it, and we're done!
encrypted_payload = base64.b64encode(ciphertext + sig)
Posts: 7764
Threads: 42
Joined: Jun 2015
Reputation:
447
For AES functions use library in this post: https://forum.logicmachine.net/showthread.php?tid=2057
encdec libary supports following HMAC functions: - hmacmd5
- hmacsha1
- hmacsha256
- hmacsha384
- hmacsha512
function arguments:
- data
- key
- raw (set to true to get raw binary hmac value, hex otherwise)
Posts: 139
Threads: 44
Joined: Dec 2017
Reputation:
4
(20.01.2020, 08:32)admin Wrote: For AES functions use library in this post: https://forum.logicmachine.net/showthread.php?tid=2057
for Aes functions, what format can the key and hash need to be in ? string, table, byte array? etc,
i have the below it runs with no err but result not correct i think key an iv need to be in a different format?
key = 'u�НJ�z�6���Y+�'
iv = 'b/�~��ss��'
payload = 'some data'
local aes, err = aes:new(key, nil, aes.cipher(256, 'cbc'), iv, nil, 0)
ciphertext = aes.encrypt(payload)
log(ciphertext)
Posts: 7764
Threads: 42
Joined: Jun 2015
Reputation:
447
Here's Python code converted to Lua:
Code: require('encdec')
aes = require('user.aes')
iv = encdec.base64dec('mUQdS7/RyJTMsiojPz9i1Q==')
iv_vals = { iv:byte(1, -1) }
key_vals = {}
for i = 1, 16, 4 do
key_vals[ i ] = bit.band(bit.bnot(iv_vals[ i + 3 ]), 0xFF)
key_vals[ i + 1 ] = bit.band(bit.bnot(iv_vals[ i + 2 ]), 0xFF)
key_vals[ i + 2 ] = bit.band(bit.bnot(iv_vals[ i + 1 ]), 0xFF)
key_vals[ i + 3 ] = bit.band(bit.bnot(iv_vals[ i ]), 0xFF)
end
key = string.char(unpack(key_vals))
hmac_key_mask = lmcore.hextostr('15C95AC2B08AA7EB4E228F811E34D04FA54BA7DCAC9879FA8ACDA3FC244F3854', true)
hmac_key_mask_vals = { hmac_key_mask:byte(1, -1) }
hmac_vals = {}
for i = 1, 32, 4 do
hmac_vals[ i ] = bit.bxor(hmac_key_mask_vals[ i ], iv_vals[ bit.band(i + 1, 0xF) + 1 ])
hmac_vals[ i + 1 ] = bit.bxor(hmac_key_mask_vals[ i + 1 ], iv_vals[ bit.band(i + 2, 0xF) + 1 ])
hmac_vals[ i + 2 ] = bit.bxor(hmac_key_mask_vals[ i + 2 ], iv_vals[ bit.band(i - 1, 0xF) + 1 ])
hmac_vals[ i + 3 ] = bit.bxor(hmac_key_mask_vals[ i + 3 ], iv_vals[ bit.band(i, 0xF) + 1 ])
end
hmac_key = string.char(unpack(hmac_vals))
authinfo = '<X_PinCode>4410</X_PinCode>'
payload = '000000000000'
n = #authinfo
payload = payload .. string.char(bit.band(bit.rshift(n, 24), 0xFF))
payload = payload .. string.char(bit.band(bit.rshift(n, 16), 0xFF))
payload = payload .. string.char(bit.band(bit.rshift(n, 8), 0xFF))
payload = payload .. string.char(bit.band(n, 0xFF))
payload = payload .. authinfo
aes_cbc, err = aes:new(key, nil, aes.cipher(128, 'cbc'), { iv = iv }, nil, 1)
ciphertext = aes_cbc:encrypt(payload)
sig = encdec.hmacsha256(ciphertext, hmac_key, true)
encrypted_payload = encdec.base64enc(ciphertext .. sig)
Posts: 139
Threads: 44
Joined: Dec 2017
Reputation:
4
(14.04.2020, 07:57)admin Wrote: Here's Python code converted to Lua: Thanks @admin
I have it working now im not sure what is the best way to pass variables between functions is, i used storage... is there any way to make variables global and persistant in a user library also is there any improvements i can make to this script, still learning...
To get a pin to display on the tv call function request_pin_code()
once you have the pin displayed on the tv then call function authorise_pin_code('0080') with the pin from the tv, that completes the pairing process, the tv will show message "pairing process complete"
Then you can call send encrypted commands with function, send_key('NRC_POWER-ONOFF') etc
Code: encdec = require('encdec')
aes = require('user.aes')
require('json')
ip = '192.168.1.100'
name = 'My Remote'
URL_CONTROL_NRC = 'nrc/control_0'
URL_CONTROL_DMR = 'dmr/control_0'
URL_CONTROL_NRC_DEF = 'nrc/sdd_0.xml'
URN_RENDERING_CONTROL = 'schemas-upnp-org:service:RenderingControl:1'
URN_REMOTE_CONTROL = 'panasonic-com:service:p00NetworkControl:1'
function request(host, url, urn, action, args)
local body, http, ltn12, sink, res, err
ltn12 = require('ltn12')
http = require('socket.http')
body = [[<?xml version="1.0" encoding="utf-8"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<s:Body><u:]] .. action .. [[ xmlns:u="urn:]] .. urn .. [[">]] .. args .. [[</u:]] .. action .. [[></s:Body>
</s:Envelope>]]
sink = {}
res, err = http.request({
url = 'http://' .. host .. ':55000/' .. url,
method = 'POST',
headers = {
['soapaction'] = '"urn:' .. urn .. '#' .. action .. '"',
['Content-Type'] = 'text/xml; charset=utf-8',
['Content-Length'] = #body,
},
sink = ltn12.sink.table(sink),
source = ltn12.source.string(body),
})
if sink then
-- log(table.concat(sink))
return table.concat(sink)
else
return nil, err
end
end
function encrypt_soap_payload(data, key, hmac_key, iv)
payload = '000000000000'
n = #data
payload = payload .. string.char(bit.band(bit.rshift(n, 24), 0xFF))
payload = payload .. string.char(bit.band(bit.rshift(n, 16), 0xFF))
payload = payload .. string.char(bit.band(bit.rshift(n, 8), 0xFF))
payload = payload .. string.char(bit.band(n, 0xFF))
payload = payload .. data
aes_cbc, err = aes:new(key, nil, aes.cipher(128, 'cbc'), { iv = iv }, nil, 1)
ciphertext = aes_cbc:encrypt(payload)
sig = encdec.hmacsha256(ciphertext, hmac_key, true)
encrypted_payload = encdec.base64enc(ciphertext .. sig)
return encrypted_payload
end
function decrypt_soap_payload(data, key, hmac_key, iv)
aes_cbc, err = aes:new(key, nil, aes.cipher(128, 'cbc'), { iv = iv }, nil, 0)
decrypted = aes_cbc:decrypt(encdec.base64dec(data))
decrypted = string.gsub(string.sub(lmcore.strtohex(decrypted), 33), '%x%x', function(value) return string.char(tonumber(value, 16)) end)
return decrypted
end
function get_session_keys(enc_key)
iv = encdec.base64dec(enc_key)
iv_vals = { iv:byte(1, -1) }
key_vals = {}
for i = 1, 16, 4 do
key_vals[ i ] = iv_vals[ i + 2]
key_vals[ i + 1 ] = iv_vals[ i + 3]
key_vals[ i + 2 ] = iv_vals[ i ]
key_vals[ i + 3 ] = iv_vals[ i+ 1]
end
sesh_key = string.char(unpack(key_vals))
sesh_hmac_key = iv..iv
sesh_iv = iv
return sesh_key, sesh_hmac_key, sesh_iv
end
function request_session_id(app_id, sesh_key, sesh_hmac_key, sesh_iv)
encinfo = encrypt_soap_payload('<X_ApplicationId>' .. app_id .. '</X_ApplicationId>',sesh_key, sesh_hmac_key, sesh_iv)
params = ('<X_ApplicationId>'..app_id..'</X_ApplicationId>'.. '<X_EncInfo>'..encinfo..'</X_EncInfo>' )
sesh_id = request(ip, URL_CONTROL_NRC, URN_REMOTE_CONTROL, 'X_GetEncryptSessionId', params)
return sesh_id
end
function request_pin_code()
pairing_res = request(ip, URL_CONTROL_NRC, URN_REMOTE_CONTROL, 'X_DisplayPinCode', '<X_DeviceName>' .. name .. '</X_DeviceName>')
if pairing_res then
challenge_Key = string.match(pairing_res,'<X_ChallengeKey>(.*)</X_ChallengeKey>')
iv = encdec.base64dec(challenge_Key)
storage.set('IV', iv)
end
end
function authorise_pin_code(pincode)
iv = storage.get('IV')
iv_vals = { iv:byte(1, -1) }
key_vals = {}
for i = 1, 16, 4 do
key_vals[ i ] = bit.band(bit.bnot(iv_vals[ i + 3 ]), 0xFF)
key_vals[ i + 1 ] = bit.band(bit.bnot(iv_vals[ i + 2 ]), 0xFF)
key_vals[ i + 2 ] = bit.band(bit.bnot(iv_vals[ i + 1 ]), 0xFF)
key_vals[ i + 3 ] = bit.band(bit.bnot(iv_vals[ i ]), 0xFF)
end
key = string.char(unpack(key_vals))
hmac_key_mask = lmcore.hextostr('15C95AC2B08AA7EB4E228F811E34D04FA54BA7DCAC9879FA8ACDA3FC244F3854', true)
hmac_key_mask_vals = { hmac_key_mask:byte(1, -1) }
hmac_vals = {}
for i = 1, 32, 4 do
hmac_vals[ i ] = bit.bxor(hmac_key_mask_vals[ i ], iv_vals[ bit.band(i + 1, 0xF) + 1 ])
hmac_vals[ i + 1 ] = bit.bxor(hmac_key_mask_vals[ i + 1 ], iv_vals[ bit.band(i + 2, 0xF) + 1 ])
hmac_vals[ i + 2 ] = bit.bxor(hmac_key_mask_vals[ i + 2 ], iv_vals[ bit.band(i - 1, 0xF) + 1 ])
hmac_vals[ i + 3 ] = bit.bxor(hmac_key_mask_vals[ i + 3 ], iv_vals[ bit.band(i, 0xF) + 1 ])
end
hmac_key = string.char(unpack(hmac_vals))
params = '<X_AuthInfo>' .. encrypt_soap_payload("<X_PinCode>" .. pincode .. "</X_PinCode>", key, hmac_key, iv) .. '</X_AuthInfo>'
authorise_res = request(ip, URL_CONTROL_NRC, URN_REMOTE_CONTROL, 'X_RequestAuth', params)
auth_res = string.match(authorise_res,'<X_AuthResult>(.*)</X_AuthResult>')
decrypted = decrypt_soap_payload(auth_res, key, hmac_key, iv)
app_id = string.match(decrypted,'<X_ApplicationId>(.*)</X_ApplicationId>')
enc_key = string.match(decrypted,'<X_Keyword>(.*)</X_Keyword>')
-- get AES and Hmac keys from x_keyword
sesh_key, sesh_hmac_key, sesh_iv = get_session_keys(enc_key)
-- request session key to be able to send encrypted commands
sesh_id_res = request_session_id(app_id, sesh_key, sesh_hmac_key, sesh_iv)
enc_result = string.match(sesh_id_res,'<X_EncResult>(.*)</X_EncResult>')
enc_result = decrypt_soap_payload(enc_result, sesh_key, sesh_hmac_key, sesh_iv)
--Set session ID and begin sequence number at 1. We have to increment the sequence number upon each successful NRC command.
sesh_id = string.match(enc_result,'<X_SessionId>(.*)</X_SessionId>')
sesh_seq_num = 1
session_keys = json.encode({
SESSION_ID = sesh_id,
SESSION_SEQUENCE_NUMBER = sesh_seq_num,
SESSION_IV = sesh_iv,
SESSION_HMAC_KEY = sesh_hmac_key,
SESSION_KEY = sesh_key,
APP_ID = app_id,
KEY = key,
HMAC_KEY = hmac_key,
IV = iv
})
storage.set('session_keys', session_keys)
return sesh_id, sesh_seq_num, sesh_iv
end
function send_enc_cmd(action, urn, params)
x = storage.get('session_keys')
S_K =json.decode(x)
-- modify sequence number to 8 bits
seq_num = string.format("%08d", S_K.SESSION_SEQUENCE_NUMBER)
encrypted_command = [[<X_SessionId>]] .. S_K.SESSION_ID .. [[</X_SessionId>]]..
[[<X_SequenceNumber>]] .. seq_num ..[[</X_SequenceNumber>]]..
[[<X_OriginalCommand>]] .. [[<u:]].. action .. [[ xmlns:u="urn:]] .. urn .. [[">]] .. params .. [[</u:]] .. action .. [[>]] .. [[</X_OriginalCommand>]]
enc_cmd = encrypt_soap_payload(encrypted_command, S_K.SESSION_KEY, S_K.SESSION_HMAC_KEY, S_K.SESSION_IV)
params = '<X_ApplicationId>'..S_K.APP_ID..'</X_ApplicationId>'.. '<X_EncInfo>'.. enc_cmd..'</X_EncInfo>'
send_enc_cmd_res = request(ip, URL_CONTROL_NRC, URN_REMOTE_CONTROL, 'X_EncryptedCommand', params)
res_err = string.match(send_enc_cmd_res,'<s:Fault>')
-- if send_enc_cmd_res is sucessfull then increment sequence number
if not res_err then
S_K.SESSION_SEQUENCE_NUMBER = S_K.SESSION_SEQUENCE_NUMBER + 1
session_keys = json.encode({
SESSION_ID = S_K.SESSION_ID,
SESSION_SEQUENCE_NUMBER = S_K.SESSION_SEQUENCE_NUMBER, -- increment session sequence number each time command is sucessfull
SESSION_IV = S_K.SESSION_IV,
SESSION_HMAC_KEY = S_K.SESSION_HMAC_KEY,
SESSION_KEY = S_K.SESSION_KEY,
APP_ID = S_K.APP_ID,
KEY = S_K.KEY,
HMAC_KEY = S_K.HMAC_KEY,
IV =S_K.IV
})
storage.set('session_keys', session_keys)
end
return params
end
function send_key(key)
params = send_enc_cmd('X_SendKey', URN_REMOTE_CONTROL, '<X_KeyEvent>'..key..'</X_KeyEvent>')
end
function get_mute()
req_res = request(ip, URL_CONTROL_DMR, URN_RENDERING_CONTROL, 'GetMute', '<InstanceID>0</InstanceID><Channel>Master</Channel>')
mute_level = string.match(req_res,'<CurrentMute>(.*)</CurrentMute>')
return mute_level
end
function get_volume()
req_res = request(ip, URL_CONTROL_DMR, URN_RENDERING_CONTROL, 'GetVolume', '<InstanceID>0</InstanceID><Channel>Master</Channel>')
vol_level = string.match(req_res,'<CurrentVolume>(.*)</CurrentVolume>')
return vol_level
end
function set_mute(state)
request(ip, URL_CONTROL_DMR, URN_RENDERING_CONTROL, 'SetMute', '<InstanceID>0</InstanceID><Channel>Master</Channel><DesiredMute>'.. state .. '</DesiredMute>')
end
function set_volume(level)
request(ip, URL_CONTROL_DMR, URN_RENDERING_CONTROL, 'SetVolume', '<InstanceID>0</InstanceID><Channel>Master</Channel><DesiredVolume>'.. level .. '</DesiredVolume>')
end
Posts: 2
Threads: 0
Joined: Mar 2020
Reputation:
0
24.12.2020, 18:46
(This post was last modified: 27.12.2020, 13:39 by parkerc.)
Hi
id love to test this piece of code on a standard Lua installation, but to do that does anyone know where I could find the required modules/libraries ?
Code: encdec = require('encdec')
aes = require('user.aes')
Is anyone able to post them or direct me to where I can download them ?
Posts: 7764
Threads: 42
Joined: Jun 2015
Reputation:
447
This code requires LuaJIT. It won't work with standard Lua because it does not have FFI library.
Posts: 2
Threads: 0
Joined: Mar 2020
Reputation:
0
27.12.2020, 14:04
(This post was last modified: 27.12.2020, 14:23 by parkerc.)
(25.12.2020, 13:49)admin Wrote: This code requires LuaJIT. It won't work with standard Lua because it does not have FFI library.
Can I assume an alternative Lua library (or libraries) could be used ?
For example to get around the encdec.base64dec() requirement, I used a base64 function/code from here - http://lua-users.org/wiki/BaseSixtyFour and added a specific new function called encdec_base64dec()
Code: -- decoding
function encdec_base64dec(data)
local b = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
data = string.gsub(data, '[^'..b..'=]', '')
return (data:gsub('.', function(x)
if (x == '=') then return '' end
local r,f='',(b:find(x)-1)
for i=6,1,-1 do r=r..(f%2^i-f%2^(i-1)>0 and '1' or '0') end
return r;
end):gsub('%d%d%d?%d?%d?%d?%d?%d?', function(x)
if (#x ~= 8) then return '' end
local c=0
for i=1,8 do c=c+(x:sub(i,i)=='1' and 2^(8-i) or 0) end
return string.char(c)
end))
end
I would really appreciate any guidance on alternatives for other calls such as those below e.g hex to/from string and aes_cbc encrypt/decrypt etc.
Code: lmcore.strtohex(decrypted)
lmcore.hextostr('15C95AC2B08AA7EB4E228F811E34D04FA54BA7DCAC9879FA8ACDA3FC244F3854', true)
aes_cbc:decrypt(encdec.base64dec(data))
aes_cbc:encrypt(payload)
encdec.hmacsha256(ciphertext, hmac_key, true)
Is something like https://github.com/somesocks/lua-lockbox or something similar potentially a viable alternative library?
Posts: 7764
Threads: 42
Joined: Jun 2015
Reputation:
447
For conversion from/to hex you can use this library: https://gist.github.com/yi/01e3ab762838d567e65d
lockbox seems to have all the required functionality (aes128 and hmac).
|