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.

Panasonic Viera TV IP control
#16
(14.04.2020, 07:57)admin Wrote: Here's Python code converted to Lua:
 Thanks @admin
I have it working now  Smile  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
Reply


Messages In This Thread
Panasonic Viera TV IP control - by jetsetter - 29.02.2016, 11:54
RE: Panasonic Viera TV IP control - by admin - 10.03.2016, 14:32
RE: Panasonic Viera TV IP control - by admin - 16.03.2016, 08:25
RE: Panasonic Viera TV IP control - by andeug - 10.10.2016, 14:41
RE: Panasonic Viera TV IP control - by Habib - 08.04.2018, 11:32
RE: Panasonic Viera TV IP control - by admin - 08.04.2018, 11:58
RE: Panasonic Viera TV IP control - by Habib - 08.04.2018, 13:37
RE: Panasonic Viera TV IP control - by admin - 20.01.2020, 08:32
RE: Panasonic Viera TV IP control - by admin - 14.04.2020, 07:57
RE: Panasonic Viera TV IP control - by benanderson_475 - 17.04.2020, 03:55
RE: Panasonic Viera TV IP control - by admin - 25.12.2020, 13:49
RE: Panasonic Viera TV IP control - by admin - 28.12.2020, 07:46
RE: Panasonic Viera TV IP control - by admin - 06.04.2021, 05:43
RE: Panasonic Viera TV IP control - by admin - 06.04.2021, 09:39

Forum Jump: