Send pop-up notification from Vera to Samsung TV

Hi, Samsung SmartTV seems to have the capability to display pop-up notifications. Is there a way we can send notifications of some Vera events (like door sensor triggered) to Samsung TV?

I read about the Samsung TV plug-in (http://forum.micasaverde.com/index.php/topic,7878.0.html) and wonder if that can be a good place for the notification code to reside.

This would be cool… Because for one… I have 3 Samsung TV’s :slight_smile:

I didn’t look at the link yet… Hopefully it is an Http call or something

It’s a UPNP message … I did this at one time when I was playing around … I would have to lookup the details.

I think it was to support Voice Call Alerts.

[quote=“RichardTSchaefer, post:3, topic:179986”]It’s a UPNP message … I did this at one time when I was playing around … I would have to lookup the details.

I think it was to support Voice Call Alerts.[/quote]

I remember some postings on that or with a cable box (maybe they were yours, Richard). I can’t find them now. This would be a killer app.

We have verizon FiOS and noticed that they just put a lot of changes into their box’s latest firmware. Has anyone seen/used their HA piece?

FYI, found some documentation that might help, maybe?

-TC

I’m new to Lua, I gave it a shot but no success yet! I’d appreciate if the Lua Experts out there can correct my errors below.

First, I found this link that talks about a quick way to do pop-up notification on Samsung TV: GitHub - shantanugoel/samsung-messagebox: Send messages to be displayed on screen on Samsung TVs using samsung messagebox service

It was written in Python and I’m trying to convert it to Lua. One of the main things that I wasn’t quite sure, is it indicated that it needs epoch time but yet the python code seemed to be writing out a regular date/time…

Here is my “converted” Lua code:

local socket = require(“socket”)
local host = “192.168.1.1” – TV IP
local port = 52235 – TV port
local tcp = assert(socket.connect(host, port))

tcp:send(“<?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:AddMessage xmlns:u="urn:samsung.com:service:MessageBoxService:1">" … " text/xml" … " 12345" … “” … “SMS” … “Maximum” … “” … “” … os.date(“%Y-%m-%d”) … “” … “” … os.date(“%H:%M:%S”) … “” … “” … “” … “” … “receiver_no” … “” … “” … “receiver” … “” … “” … “” … “” … “sender_no” … “” … “” … “sender” … “” … “” … “” … “testing 123” … “” … “” … " </u:AddMessage>" … " </s:Body>" … “</s:Envelope>”)

tcp:close()
return true

This would be really great to have that functionality with my 2 Samsung TVs. Unfortunately I am not a LUA expert so I cannot help here but I echo the demand for this. It would be a great plugin to have.

+1

The first thing is to clean up the string, so you can see what’s going on. So remove the escaped double quotes, by using single quotes for the string declarations. Also lot’s of strings and the continual concatenation of them chews up memory. It’s far better and more convenient to use a table to assemble the result. Then log it all, so you can see what’s produced - it can then also be checked with a XML validator:

[code]local strTab = {
‘<?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:AddMessage xmlns:u=“urn:samsung.com:service:MessageBoxService:1”>’,
‘text/xml’,
‘12345’,
‘’,
‘SMS’,
‘Maximum’,
‘’,
‘’,
os.date(‘%Y-%m-%d’),
‘’,
‘’,
os.date(‘%H:%M:%S’),
‘’,
‘’,
‘’,
‘’,
‘receiver_no’,
‘’,
‘’,
‘receiver’,
‘’,
‘’,
‘’,
‘’,
‘sender_no’,
‘’,
‘’,
‘sender’,
‘’,
‘’,
‘’,
‘testing 123’,
‘’,
‘’,
‘</u:AddMessage>’,
‘</s:Body>’,
‘</s:Envelope>’
}

local xmlStr = table.concat(strTab,‘\n’)
luup.log(xmlStr)

local socket = require(‘socket’)
local host = ‘192.168.1.1’ – TV IP
local port = 52235 – TV port
local tcp = assert(socket.connect(host, port))

tcp:send(strTab)
tcp:close()

return true[/code]

Then going back to the original code:

Where is the Header?

Thanks a-lurker! I have added the Header section now, and re-structured a code a little bit for easier reading. I also found my socket code was bad last time, so re-wrote based on sample from some other threads.

My outstanding question is still the epoch time, not sure if it matters.

Another dumb question: How can I view the log easily for troubleshooting purposes?

local host = "192.168.1.1"
local port = 52235

local strTab = {
   '<?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:AddMessage xmlns:u="urn:samsung.com:service:MessageBoxService:1">',
   '<MessageType>text/xml</MessageType>',
   '<MessageID>12345</MessageID>',
   '<Message>',
   '<Category>SMS</Category>',
   '<DisplayType>Maximum</DisplayType>',
   '<ReceiveTime>',
   '<Date>',
    os.date('%Y-%m-%d'),
   '</Date>',
   '<Time>',
    os.date('%H:%M:%S'),
   '</Time>',
   '</ReceiveTime>',
   '<Receiver>',
   '<Number>',
   'receiver_no',
   '</Number>',
   '<Name>',
   'receiver',
   '</Name>',
   '</Receiver>',
   '<Sender>',
   '<Number>',
   'sender_no',
   '</Number>',
   '<Name>',
   'sender',
   '</Name>',
   '</Sender>',
   '<Body>',
   'testing 123',
   '</Body>',
   '</Message>',
   '</u:AddMessage>',
   '</s:Body>',
   '</s:Envelope>'
   }

local body = table.concat(strTab)

local length = string.len(body)

local strTabHead = {
   'POST /PMR/control/MessageBoxService HTTP/1.0\r\n', 
   'Content-Type: text/xml; charset="utf-8"\r\n', 
   'HOST: ',
   host,
   '\r\n',
   'Content-Length: ',
   tostring(length),
   '\r\n',
   'SOAPACTION: "uuid:samsung.com:service:MessageBoxService:1#AddMessage"\r\n',
   'Connection: close\r\n',
   '\r\n'
   }

local header = table.concat(strTabHead)

local message = header .. body

local socket = require("socket")
local tcp = socket.tcp()
tcp:settimeout(3)
if (tcp:connect(host, port)) then
   if (tcp:send(message)) then
      luup.log("Sent Successfully")
   else
      luup.log("Error Sending Msg")
   end
else
   luup.log("Error Opening Socket")
end

tcp:close(socket)
return true

Forgot to mention, the code is still NOT WORKING yet. I appreciate any further review of the revised code. Thanks!

I looked into this and while I don’t have it working here is what I found out.

A) the port is incorrect unless you have very old Samsung TV with networking ability. The proper port should be port 55000. You can test this by installing Python on your PC/computer and just run the script. You should get an error 61 with “connection refused” if you don’t use port 55000. With that said it seems like different Samsung models are using different ports which we should plan for if anybody comes up with a proper plugin.
B) This link GitHub - shantanugoel/samsung-messagebox: Send messages to be displayed on screen on Samsung TVs using samsung messagebox service provided you the code but this code doesn’t seem to work
C) If you try this link Samsung TV Remote Control Python Script · GitHub and you alter the settings to match your devices, you should get a message on the TV asking for permission for the IP address trying to access your TV which you have to acknowledge.

I am trying to figure out why the first script doesn’t work while the second script connects. This is not about LUA but more about getting a functional code which works and then get the LUA experts here to maybe help us to bring this to the next level.

I would also very much like to see this feature.

Using the original script from Display Message on Samsung TVs in Python (Samsung MessageBox Service Exploitation) - Shantanu Vs The World ,

I get HTTP/1.1 401 Unauthorized on default port 52235 , and no response on port 55000

Does anyone had progress on it?

I have a series E550 Plasma from 2013
It appears that you need to run the AllShare app on your PC to allow access to the Samsung TV
Once I did that, I was able to port scan the TV from my PC and found a few open ports but nothing that allows a message to be sent. Perhaps my TV is a cheaper model that doesn’t support messaging.

EDIT: I should clarify, the messages were successfully sent using the LUA Code above without any socket errors (for those sockets that were open according to nmap), however, no message was ever displayed on my TV

[quote=“macrho, post:15, topic:179986”]I have a series E550 Plasma from 2013
It appears that you need to run the AllShare app on your PC to allow access to the Samsung TV
Once I did that, I was able to port scan the TV from my PC and found a few open ports but nothing that allows a message to be sent. Perhaps my TV is a cheaper model that doesn’t support messaging.

EDIT: I should clarify, the messages were successfully sent using the LUA Code above without any socket errors (for those sockets that were open according to nmap), however, no message was ever displayed on my TV[/quote]

Macrho, after research a bit at samygo website, the impression I have is that only some firmware versions have the message service included. I live in Brazil, and probably the firmware my TV has doesn’t support it. Bad Samsung :frowning:

That’s a bummer though if u use XBMC:

I’m going to look into this a bit as most of the time my TV is on, I’m running XBMC

Actually… Samsung removed the messagebox service from their TV sets starting with the the D-series models… The B-Series through C-series have it (verified with my UN55C5000), but it E-Series does not (verified with my UN40EH5300).

There is a way to determine if the set supports it or not… send a UPNP SSDP M-SEARCH packet to the multicast broadcast address (239.255.255.250) on port 1900… The TV will respond with the devices/services that it supports… MediaRenderer, AVTransport and RemoteControlReceiver for most models, and additionally either MessageBoxService and/or PersonalMessageReceiver (and I’ve also seen reference to a UPNP PersonalMessageTest for very early models with beta firmware)…

The code to do the SSDP search is:

local STVR_DEV = "urn:samsung.com:device:PersonalMessageReceiver:1"  -- MessageBoxDevice
local STVR_DEV = "urn:samsung.com:device:RemoteControlReceiver:1"  -- remote control device
local STVS_DEV = "urn:samsung.com:device:MainTVServer2:1"   - digital media renderer device
local STVR_SVC = "urn:samsung.com:service:MultiScreenService:1"   - screenshare  - used by Samsung TV app framework
local STVS_SVC = "urn:samsung.com:service:MainTVAgent2:1"    - digital media renderer service
local STVM_SVC = "urn:samsung.com:service:MessageBoxService:1" - MessageBox Service

function doSsdpSearch(searchFilter, retries)
	-- do an ssdp search - get the response and retrieve the SCPD file
	-- returns contents, DeviceURL, DeviceIpAddress, DeviceIpPort
	local count = retries
	local http = require("socket.http")

	debug("doSsdpSearch - Search for '"..searchFilter.."' -------------------------------------------------------")

	local ssdpPacketTable = {
		[1] = "M-SEARCH * HTTP/1.1\r\n",
		[2]= "Host: 239.255.255.250:1900\r\n",
		[3] = "MAN: \"ssdp:discover\"\r\n",
		[4] = "MX: 10\r\n",
		[5] = "ST:"..searchFilter.."\r\n",
		[6] = "CONTENT-LENGTH: 0\r\n",
		[7] = "\r\n"
	}

	local ssdpPacket = table.concat(ssdpPacketTable )
	repeat
		local udp = assert(socket.udp())
		udp:setoption("broadcast",true)
		udp:settimeout(10)
		assert(udp:sendto(ssdpPacket, "239.255.255.250", 1900))
		address = udp:receive()
		udp:close()
		count = count - 1
		debug("doSsdpSearch - Try # ".. (retries - count).." - received '"..(address or "").."'")
	until ( (count == 0) or (address ~= "") )

	if (address ~= "") then
		location = string.match(address, "[Ll][Oo][Cc][Aa][Tt][Ii][Oo][Nn]:%s*(.-)\r?\n")
		debug("doSsdpSearch - received location = '"..(location or "").."'")
		ipAddress = string.match(location,"http%:%/%/(.-)%/")
		if ipAddress ~= nil and string.match(ipAddress, ":") then
			ipPort = string.match(ipAddress, ":(.*)")
			ipAddress = string.match(ipAddress, "(.*):")
		else
			ipPort = "80"
		end
		local contents,response=http.request(location)
		response = string.match(response,"[%s+]?%d+")
		debug("doSsdpSearch - Found device at '"..ipAddress.."' port '"..ipPort.."'")
		return response, contents, location, ipAddress, ipPort
	else
		return "404", "", "", "", ""
	end
end

local searchResponse = doSsdpSearch("*", 5)  -- search for all uPNP devices, try 5 times
searchResponse = doSsdpSearch(STVM_SVC, retries) -- search for the Samsung messageboxservice only - 5 treies

One thing to remember… If you are talking to the uPNP services on a Samsung TV… It only understands SOAP… so you need to speak SOAP to it… If it does not understand what you are asking it, it will (and does) ignore you… MOST malformed requests (passing the headers to luasockets as a string is malformed) are silently ignored.

like this:

function SendSoapRequest(DeviceIpAddress, DeviceIpPort, SERVICE, Soap_URL, soap_action, soap_arguments)
	-- Soap_URL is the control URL for the service you are targeting (obtained from the SCPD file)
	local http = require("socket.http")
	local ltn12 = require"ltn12"

	local h_ds = "\045"
	local h_lt = "\060"
	local h_qm = "\063"
	local h_gt = "\062"
	local h_qt = "\034"						
	local req = h_lt..h_qm.."xml version="..h_qt..'1.0'..h_qt.." encoding="..h_qt..'UTF-8'..h_qt..h_qm..h_gt
	req = req .. h_lt.."s:Envelope s:encodingStyle="..h_qt.."http://schemas.xmlsoap.org/soap/envelope/"..h_qt.." xmlns:s="..h_qt.."http://schemas.xmlsoap.org/soap/envelope/"..h_qt..h_gt
	req = req .. h_lt.."s:Body"..h_gt
	req = req .. h_lt.."u:" .. soap_action .. " xmlns:u="..h_qt.. SERVICE .. h_qt..h_gt
	for aName, aValue in pairs(soap_arguments) do
		req = req .. h_lt .. aName .. h_gt .. aValue .. h_lt.."/" .. aName .. h_gt
	end
	req = req .. h_lt.."/u:" .. soap_action .. h_gt..h_lt.."/s:Body"..h_gt..h_lt.."/s:Envelope"..h_gt

	local reqHeaders = {
		["HOST"] = DeviceIpAddress..":"..DeviceIpPort,
		["USER-AGENT"] = "DLNADOC/1.50 SEC_HHP_MiCasaVerde         /1.0",
		["SOAPACTION"] = h_qt .. SERVICE.."#"..soap_action .. h_qt,
		["Content-Type"] = "text/xml;charset="..h_qt.."utf-8"..h_qt,
		["Content-Length"] = tostring(#req)
	}

	debug("SendSoapRequest - Headers:\n"..print_table(reqHeaders).."\n")
	debug("SendSoapRequest - Request:\n"..req.."\n")

	local respBody = {}
	local rHeaders, rCode, rError = http.request({
		method = "POST",
		url = Soap_URL,
		headers = reqHeaders,
		source = ltn12.source.string(req),
		sink = ltn12.sink.table(respBody)
	})
	if ((rCode == nil) or (rCode == "")) then
		log("SendSoapRequest - Request  FAILED!!")
	end
	if (soap_action:sub(1,3) == "Get") then
		-- if the command is a get command, return the command response (the SCPD file)
		return respBody
	end
end

Good Luck… 8-}

PS: This IS working (well… was working… I slightly modified it to be standalone rather than part of a plugin) code…

@cybrmage,

Thank you so much for such complete information. I installed UPnP inspector in a windows laptop, and could discover that my Brazilian D-series has “TestRCRServices:1” under “RemoteControlReceiver:1”.

It has 3 actions:

RemoveMessage
AddMessage
SendKeyCode

However I could not make the AddMessage work. It has 3 parameters (MessageID, MessageType, Message), and whatever I fill in, I get an response “Fail 402” .

Maybe there is an syntax/rule for those 3 parameters?

Thanks
Ricardo

[quote=“rvendrame, post:19, topic:179986”]@cybrmage,

Thank you so much for such complete information. I installed UPnP inspector in a windows laptop, and could discover that my Brazilian D-series has “TestRCRServices:1” under “RemoteControlReceiver:1”.

It has 3 actions:

RemoveMessage
AddMessage
SendKeyCode

However I could not make the AddMessage work. It has 3 parameters (MessageID, MessageType, Message), and whatever I fill in, I get an response “Fail 402” .

Maybe there is an syntax/rule for those 3 parameters?

Thanks
Ricardo[/quote]

Nope. The remote control receiver is for sending remote control codes via IP… From what I can find in the documentation from Samsung, the “AddMessage” and “RemoveMessage” commands have not (or will never be) implemented in the firmware post early C-Series.

Also, people on the SamyGo forums have verified that the code to implement the messagebox service does not exist in the firmware.