I'm making a plugin app for my main satellite remote app that adds volume control for several TV types. I only had one person offer to test on Samsung and he says it isn't working. However, I don't see anything wrong in my code. If anyone has a newer model Samsung (internet/network connected) and would be interested in trying my app, please post a message here or send me a PM.
In the meantime, anyone see anything wrong?
Original VBScript code:
Original Python code:
My B4A code:
I can send the compiled APK and/or code if necessary to anyone with a Samsung TV. It is difficult testing code on a device you do not own!
The guy testing for me says the official Samsung remote app works. The code samples above were originally obtained by reverse engineering an iPhone app's network packets.
In the meantime, anyone see anything wrong?
Original VBScript code:
B4X:
Imports System.Net.Sockets
Const mType As String = "drhs_SamsungTV"
Const tvip As String = "1.1.1.1" 'Set a static IP address for your TV and edit this string to match that.
Const tvport As Int32 = 55000 'This is the standard port that the TV listens on. Do not change it.
Const mymac = "00-00-00-00-00-00" ' Enter your HS host MAC address here. This is used for the access control/validation, but not after that AFAIK
Const appstring = "iphone..iapp.samsung" ' What the iPhone app reports
Const tvappstring = "iphone.UN55C8000.iapp.samsung" ' Might need changing to match your TV type
Const remotename = "Homeseer Samsung Remote" ' What gets reported when it asks for permission/also shows in General->Wireless Remote Control menu
Public Sub Main(ByVal Params As Object)
If Params IsNot Nothing Then
Dim tcpClient As New System.Net.Sockets.TcpClient()
tcpClient.Connect(tvip, tvport)
Dim networkStream As NetworkStream = tcpClient.GetStream()
If networkStream.CanWrite Then
Dim Messagepart3 As String = ""
Dim ByteArrayOut() As Byte = StrToByteArray(MessagePart1)
networkStream.Write(ByteArrayOut, 0, ByteArrayOut.Length)
ByteArrayOut = StrToByteArray(MessagePart2)
networkStream.Write(ByteArrayOut, 0, ByteArrayOut.Length)
Dim argv As String() = Params.ToString.Split("|")
If Left(UCase(argv(0)),4) = "KEY_" Then
Dim mp3 As String = Chr(0) & Chr(0) & Chr(0) & Chr(Len(Base64Encode(argv(0)))) & Chr(0) & Base64Encode(argv(0))
MessagePart3 = Chr(0) & Chr(Len(tvappstring)) & Chr(0) & tvappstring & Chr(Len(mp3)) & Chr(0) & mp3
Else
Dim mp3 As String = Chr(1) & Chr(0) & Chr(0) & Chr(Len(Base64Encode(argv(0)))) & Chr(0) & Base64Encode(argv(0))
MessagePart3 = Chr(1) & Chr(Len(tvappstring)) & Chr(0) & tvappstring & Chr(Len(mp3)) & Chr(0) & mp3
End If
ByteArrayOut = StrToByteArray(MessagePart3)
networkStream.Write(ByteArrayOut, 0, ByteArrayOut.Length)
networkStream.Close()
tcpClient.Close()
End If
End If
End Sub
Private Function MessagePart1() As String
'Dim myip As String = hs.GetIPAddress ' Doesn't seem to be really used
Dim myip as String = "2.2.2.2" 'Set your HS Host IP address here
Dim messagepart1x As String = Chr(&H64) & Chr(0) & Chr(Len(Base64Encode(myip))) & Chr(0) & Base64Encode(myip) & Chr(Len(Base64Encode(mymac))) & Chr(0) & Base64Encode(mymac) & Chr(Len(Base64Encode(remotename))) & Chr(0) & Base64Encode(remotename)
Dim part1 As String = Chr(0) & Chr(Len(appstring)) & Chr(0) & appstring & Chr(Len(messagepart1x)) & Chr(0) & messagepart1x
Return part1
End Function
Private Function MessagePart2() As String
Dim messagepart2x As String = Chr(&HC8) & Chr(0)
Dim part2 As String = Chr(0) & Chr(Len(appstring)) & Chr(0) & appstring & Chr(Len(messagepart2x)) & Chr(0) & messagepart2x
Return part2
End Function
Private Function Base64Encode(ByVal InputString As String)
Dim byt As Byte() = System.Text.Encoding.UTF8.GetBytes(InputString)
Return Convert.ToBase64String(byt)
End Function
Private Function StrToByteArray(str As String) As Byte()
Dim ByteArray(Len(str)-1) as Byte
For n As Short = 0 To UBound(ByteArray)
ByteArray(n) = Asc(Mid(str,n + 1,1))
Next
Return ByteArray
End Function
Original Python code:
B4X:
#! /usr/bin/python
# Title: samsungremote.py
# Author: Asif Iqbal
# Date: 05APR2012
# Info: To send remote control commands to the Samsung tv over LAN
# TODO:
import socket
import base64
import time, datetime
#IP Address of TV
tvip = "100.0.0.123"
#IP Address of TV
myip = "100.0.0.112"
#Used for the access control/validation, but not after that AFAIK
mymac = "00-0c-29-3e-b1-4f"
#What the iPhone app reports
appstring = "iphone..iapp.samsung"
#Might need changing to match your TV type
tvappstring = "iphone.UE55C8000.iapp.samsung"
#What gets reported when it asks for permission
remotename = "Python Samsung Remote"
# Function to send keys
def sendKey(skey, dataSock, appstring):
messagepart3 = chr(0x00) + chr(0x00) + chr(0x00) + chr(len(
base64.b64encode(skey))) + chr(0x00) + base64.b64encode(skey);
part3 = chr(0x00) + chr(len(appstring)) + chr(0x00) \
+ appstring + chr(len(messagepart3)) + chr(0x00) + messagepart3
dataSock.send(part3);
# Open Socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((tvip, 55000))
# Key Reference
# Normal remote keys
#KEY_0
#KEY_1
#KEY_2
#KEY_3
#KEY_4
#KEY_5
#KEY_6
#KEY_7
#KEY_8
#KEY_9
#KEY_UP
#KEY_DOWN
#KEY_LEFT
#KEY_RIGHT
#KEY_MENU
#KEY_PRECH
#KEY_GUIDE
#KEY_INFO
#KEY_RETURN
#KEY_CH_LIST
#KEY_EXIT
#KEY_ENTER
#KEY_SOURCE
#KEY_AD #KEY_PLAY
#KEY_PAUSE
#KEY_MUTE
#KEY_PICTURE_SIZE
#KEY_VOLUP
#KEY_VOLDOWN
#KEY_TOOLS
#KEY_POWEROFF
#KEY_CHUP
#KEY_CHDOWN
#KEY_CONTENTS
#KEY_W_LINK #Media P
#KEY_RSS #Internet
#KEY_MTS #Dual
#KEY_CAPTION #Subt
#KEY_REWIND
#KEY_FF
#KEY_REC
#KEY_STOP
# Bonus buttons not on the normal remote:
#KEY_TV
#Don't work/wrong codes:
#KEY_CONTENT
#KEY_INTERNET
#KEY_PC
#KEY_HDMI1
#KEY_OFF
#KEY_POWER
#KEY_STANDBY
#KEY_DUAL
#KEY_SUBT
#KEY_CHANUP
#KEY_CHAN_UP
#KEY_PROGUP
#KEY_PROG_UP
# First configure the connection
ipencoded = base64.b64encode(myip)
macencoded = base64.b64encode(mymac)
messagepart1 = chr(0x64) + chr(0x00) + chr(len(ipencoded)) \
+ chr(0x00) + ipencoded + chr(len(macencoded)) + chr(0x00) \
+ macencoded + chr(len(base64.b64encode(remotename))) + chr(0x00) \
+ base64.b64encode(remotename)
part1 = chr(0x00) + chr(len(appstring)) + chr(0x00) + appstring \
+ chr(len(messagepart1)) + chr(0x00) + messagepart1
sock.send(part1)
messagepart2 = chr(0xc8) + chr(0x00)
part2 = chr(0x00) + chr(len(appstring)) + chr(0x00) + appstring \
+ chr(len(messagepart2)) + chr(0x00) + messagepart2
sock.send(part2)
# Now send the keys as you like, e.g.,
sendKey("KEY_VOLUP",sock,tvappstring)
time.sleep(1)
sendKey("KEY_TOOLS",sock,tvappstring)
time.sleep(1)
sendKey("KEY_RIGHT",sock,tvappstring)
time.sleep(1)
sendKey("KEY_DOWN",sock,tvappstring)
time.sleep(1)
sendKey("KEY_RIGHT",sock,tvappstring)
# Close the socket when done
sock.close()
My B4A code:
B4X:
Sub SendSammy (iCommand As Int)
Dim sCMD As String
Select Case iCommand
Case 1 ' Power Toggle
sCMD = ""
Case 2 ' Power On
sCMD = ""
Case 3 ' Power Off
sCMD = "KEY_POWEROFF"
Case 4 ' Volume Up
sCMD = "KEY_VOLUP"
Case 5 ' Volume Down
sCMD = "KEY_VOLDOWN"
Case 6 ' Mute Toggle
sCMD = "KEY_MUTE"
Case 7 ' Mute On
sCMD = "" ' or "NRC_TV_MUTE_ON-ONOFF"
Case 8 ' Mute Off
sCMD = "" ' or "NRC_TV_MUTE_OFF-ONOFF"
Case 9 ' Select Input
sCMD = "KEY_SOURCE"
End Select
If sCMD = "" Then Return ' Shouldn't happen because we checked earlier for unsupported commands but whatever.....
If VCTest <> 999 Then 'Test
ToastMessageShow ("Samsung Test > Sending command to " & Common.AVRDeviceName & "...", False)
Else 'Real
If VCToast = True Then ToastMessageShow ("Sending command to " & Common.AVRDeviceName & "...", False)
End If
' GET IP
If Common.DeviceIP = "" Then Common.DeviceIP = Common.GetIP
' Get MAC
If Common.DeviceMAC = "" Then Common.DeviceMAC = Common.GetMAC
If Common.Logging Then Log ("IP = " & Common.DeviceIP)
If Common.Logging Then Log ("MAC = " & Common.DeviceMAC)
Dim SamsungAppstring As String = "iphone..iapp.samsung"
If Common.TVName = "" Then Common.TVName = "samsung"
Dim SamsungTVappstring As String = "iphone." & Common.TVName & ".iapp.samsung" ' xxxx = is typically model # I guess. Just try without for now...
Dim SamsungRemoteName As String = "DirecTV Remote Plus"
Common.ForConnectAVRIP = Common.AVRIP
Common.ForConnectAVRPort = Common.AVRPort
Common.ForConnectAVRType = 6 ' Samsung
Common.ForConnectAVRCommand = iCommand
Dim IPEncoded As String = Common.Base64Encode (Common.DeviceIP)
Dim MACEncoded As String = Common.Base64Encode (Common.DeviceMAC)
Dim SRNameEncoded As String = Common.Base64Encode (SamsungRemoteName)
Dim sCMDEncoded As String = Common.Base64Encode (sCMD)
Dim messagepart1x As String = Chr(0x64) & Chr(0) & Chr(IPEncoded.Length) & Chr(0) & IPEncoded & Chr(MACEncoded.Length) & Chr(0) & MACEncoded & Chr(SRNameEncoded.Length) & Chr(0) & SRNameEncoded
Common.SamsungSendString1 = Chr(0) & Chr(SamsungAppstring.Length) & Chr(0) & SamsungAppstring & Chr(messagepart1x.Length) & Chr(0) & messagepart1x
Dim messagepart2x As String = Chr(0xc8) & Chr(0)
Common.SamsungSendString2 = Chr(0) & Chr(SamsungAppstring.Length) & Chr(0) & SamsungAppstring & Chr(messagepart2x.Length) & Chr(0) & messagepart2x ' Said SamsungSendString1 before! Oops
Dim mp3 As String = Chr(0) & Chr(0) & Chr(0) & Chr(sCMDEncoded.Length) & Chr(0) & sCMDEncoded
Common.SamsungSendString3 = Chr(0) & Chr(SamsungTVappstring.Length) & Chr(0) & SamsungTVappstring & Chr(mp3.Length) & Chr(0) & mp3
If Common.ConnectServiceRunning = True AND Common.ConnectServiceConnected = True Then
If Common.ForConnectAVRType <> 6 Then ' Force disconnect and restart the service
Common.SamsungIsInitialized = False
StopService (ConnectAVR):DoEvents
Else
CallSubDelayed (ConnectAVR,"SendCommand")
Return
End If
End If
StartService (ConnectAVR)
End Sub
Sub InitNetInfo
Try
If MyIP.IsInitialized = False Then
MyIP.Initialize (1059,"")
End If
Catch ' Possibly left other app (free or pro) running
If MyIP.IsInitialized = False Then
MyIP.Initialize (1060,"")
End If
End Try
End Sub
Sub GetIP As String
InitNetInfo
Try
DeviceIP = MyIP.GetMyWifiIP ' WiFi IP
Catch
End Try
If DeviceIP <> "" AND DeviceIP <> "127.0.0.1" Then ' WiFi must be on and connected because we have only checked for the WiFiIP
End If
Try
DeviceIP = MyIP.GetMyIP ' Non-WiFi IP
Catch
DeviceIP = ""
End Try
MyIP.Close
Return DeviceIP
End Sub
Sub GetMAC As String
Dim MyWiFi As ABWifi, r As Boolean
r = MyWiFi.ABLoadWifi()
If r = False Then
DeviceMAC = "00:00:00:00:00:00"
Else
DeviceMAC = MyWiFi.ABGetCurrentWifiInfo.MacAddress
End If
Return DeviceMAC
End Sub
Sub Base64Encode (strIn As String) As String
Dim su As StringUtils
Return su.EncodeBase64 (strIn.GetBytes("UTF8"))
End Sub
'Service module
Sub Process_Globals
'These global variables will be declared once when the application starts.
'These variables can be accessed from all modules.
Dim AStreams As AsyncStreams
Dim Socket1 As Socket
Dim OpeningSocket As Boolean
Dim TimerKeepServiceAlive As Timer
Dim AwaitingResponse As Boolean
' For TESTING *******
Dim TestingToasts As Boolean = False
End Sub
Sub Service_Create
TimerKeepServiceAlive.Initialize ("TimerKeepServiceAlive",30000) ' Keep service / connection active for 30 seconds to speed up consecutive commands
End Sub
Sub Service_Start (StartingIntent As Intent)
Common.ConnectServiceRunning = True
Common.ConnectServiceConnected = False
ConnectToSocket
End Sub
Sub Service_Destroy
AStreams.Close
Socket1.Close
AwaitingResponse = False
TimerKeepServiceAlive.Enabled = False
Common.ConnectServiceConnected = False
Common.ConnectServiceRunning = False
Common.SamsungIsInitialized = False
End Sub
Sub TimerKeepServiceAlive_tick
If AwaitingResponse = True Then Return 'We're in the middle of sending a command
TimerKeepServiceAlive.Enabled = False
If Common.Logging = True Then Log ("Socket Service stopped due to inactivity")
StopService ("")
End Sub
Sub ConnectToSocket
TimerKeepServiceAlive.Enabled = True
OpeningSocket = True
If Common.Logging = True Then Log("Attempting connection to " & Common.ForConnectAVRIP & ":" & Common.ForConnectAVRPort)
If TestingToasts = True Then ToastMessageShow ("Attempting connection to " & Common.ForConnectAVRIP & ":" & Common.ForConnectAVRPort, False)
Try
Socket1.Initialize("Socket1")
Socket1.Connect(Common.ForConnectAVRIP, Common.ForConnectAVRPort, 10000) ' changed from 5 to 10 seconds timeout
Catch
End Try
End Sub
Sub Socket1_Connected (Successful As Boolean)
Try
If Successful Then
TimerKeepServiceAlive.Enabled = False: TimerKeepServiceAlive.Enabled = True ' Reset the timer
If Common.Logging = True Then Log("Connected to " & Common.ForConnectAVRIP)
If TestingToasts = True Then ToastMessageShow ("Connected to " & Common.ForConnectAVRIP, True)
Common.ConnectServiceConnected = True
AStreams.Initialize (Socket1.InputStream, Socket1.OutputStream, "AStreams")
DoEvents
SendCommand
End If
OpeningSocket = False
Catch
OpeningSocket = False
Common.ConnectServiceConnected = False
End Try
End Sub
Sub SendCommand
Dim sCMD As String
Select Case Common.ForConnectAVRType
Case 1 ' Advanced HTTP
sCMD = Common.ForPOSTGETRequest
Case 2 ' Denon/Marantz
sCMD = Common.ForPOSTGETRequest
Case 5 ' Panasonic VIERA
sCMD = Common.ForPOSTGETRequest
Case 6 ' Samsung TV
If Common.SamsungIsInitialized = False Then
SendDataToSocket (Common.SamsungSendString1)
SendDataToSocket (Common.SamsungSendString2)
Common.SamsungIsInitialized = True
End If
sCMD = Common.SamsungSendString3
Case Else 'What are we doing here?
StopService ("")
End Select
' Send whatever data we determined we need to send depending on device type...
SendDataToSocket (sCMD)
TimerKeepServiceAlive.Enabled = False:TimerKeepServiceAlive.Enabled = True 'Reset the timer
End Sub
Sub SendDataToSocket (sDataToSend As String)
If AStreams.IsInitialized = False Then
If Common.Logging = True Then Log ("Failed to send data to socket because the stream was not initialized!")
If TestingToasts = True Then ToastMessageShow ("Failed to send data to socket because the stream was not initialized!", True)
Return
End If
If sDataToSend.Length > 0 Then
AwaitingResponse = True
Dim buffer() As Byte
Dim data As String
data = sDataToSend
buffer = data.GetBytes ("UTF8")
AStreams.Write (buffer)
If Common.Logging = True Then Log ("Sending data to socket: " & sDataToSend )
If TestingToasts = True Then ToastMessageShow ("Sending data to socket...", True)
End If
End Sub
Sub AStreams_NewData (Buffer() As Byte)
Dim msg As String
msg = BytesToString(Buffer, 0, Buffer.Length, "UTF8")
'ToastMessageShow(msg, False)
If Common.Logging = True Then Log ("Received: " & msg)
If TestingToasts = True Then ToastMessageShow ("Received: " & msg, True)
If AwaitingResponse = True Then AwaitingResponse = False
End Sub
Sub AStreams_Error
If Common.Logging = True Then Log ("Socket connection error: " & LastException.Message)
ToastMessageShow ("Socket connection error: " & LastException.Message,True)
If AwaitingResponse = True Then AwaitingResponse = False
Common.SamsungIsInitialized = False
End Sub
Sub AStreams_Terminated
If Common.Logging = True Then Log ("Stream terminated")
'If TestingToasts = True Then ToastMessageShow ("Stream terminated",True)
If AwaitingResponse = True Then AwaitingResponse = False
TimerKeepServiceAlive.Enabled = False
StopService ("")
End Sub
I can send the compiled APK and/or code if necessary to anyone with a Samsung TV. It is difficult testing code on a device you do not own!
The guy testing for me says the official Samsung remote app works. The code samples above were originally obtained by reverse engineering an iPhone app's network packets.