/* ===== HUBITAT INTEGRATION VERSION =====================================================
UpNp Media Player and MainTVAgent Discovery
This is a test application to discover UPnP devices related to Media Player
as well as Samsung devices with MainTvAgent2. It does a discovery process
and then identifies the devices by name, IP, and Port into two state:
Media Player and MainTvAgent2
===== HUBITAT INTEGRATION VERSION =======================================================*/
//import org.json.JSONObject
def appVersion() { return "TEST" }
def appName() { return "UPnP TV Test" }
definition(
name: "UPnP Identification",
namespace: "davegut",
author: "Dave Gutheinz",
description: "Application to identify Media Players.",
category: "Convenience",
iconUrl: "",
iconX2Url: "",
singleInstance: true,
importUrl: ""
)
preferences {
page(name: "mainPage")
page(name: "discovery")
}
// ===== Page Definitions =====
def mainPage() {
logInfo("mainPage")
setInitialStates()
ssdpSubscribe()
def page1 = "0. Turn on devices you wish to check for at least 1 minute.\n"
page1 += "1. Press 'Next' to find UPnP devices.\n"
page1 += "2. When done, open the App info page (gear icon), Application States.\n"
page1 += " I need the devices data from the states section.\n"
return dynamicPage(
name: "mainPage",
title: "UPnP Identification",
nextPage: "discovery",
install: false,
uninstall: true){
section(page1) {}
}
}
def discovery() {
logInfo("discovery")
def devices = state.devices
def devList = ""
devices.each {
devList += "${it}\n\n"
}
ssdpDiscover()
def text2 = "Allow at least two minutes to discover your devices\n\r\n\r"
return dynamicPage(
name: "discovery",
title: "Device Discovery",
nextPage: "",
refreshInterval: 10,
install: true,
uninstall: true){
section("Allow at least 2 minutes for discovery") {
paragraph "UPnP Devices Discovery Data"
paragraph ""
}
}
}
// ===== Start up Functions =====
def setInitialStates() {
state.ssdpDevices = [:]
state.devices = [:]
}
def installed() { initialize() }
def updated() { initialize() }
def initialize() { unschedule() }
// ===== Device Discovery =====
void ssdpSubscribe() {
logInfo("ssdpSubscribe")
unsubscribe()
subscribe(location, "ssdpTerm.urn:schemas-upnp-org:device:MediaRenderer:1", ssdpHandler)
subscribe(location, "ssdpTerm.urn:samsung.com:device:MainTVServer2:1", ssdpHandler)
}
void ssdpDiscover() {
logInfo("ssdpDiscover")
sendHubCommand(new hubitat.device.HubAction("lan discovery urn:schemas-upnp-org:device:MediaRenderer:1", hubitat.device.Protocol.LAN))
pauseExecution(1000)
sendHubCommand(new hubitat.device.HubAction("lan discovery urn:samsung.com:device:MainTVServer2:1", hubitat.device.Protocol.LAN))
pauseExecution(1000)
getDevData()
}
def ssdpHandler(evt) {
def parsedEvent = parseLanMessage(evt.description)
def ip = convertHexToIP(parsedEvent.networkAddress)
def path = parsedEvent.ssdpPath
def port = convertHexToInt(parsedEvent.deviceAddress)
def key = "${ip}:${path}${port}"
def devices = state.devices
device = [:]
device["dni"] = parsedEvent.mac
device["ip"] = ip
devices << ["${parsedEvent.mac}": device]
logInfo("ssdpHandler: found device dni = ${parsedEvent.mac}")
def ssdpDevices = state.ssdpDevices
ssdpDevice = [:]
ssdpDevice["ip"] = ip
ssdpDevice["port"] = port
ssdpDevice["path"] = path
ssdpDevices << ["${key}": ssdpDevice]
}
def getDevData() {
def ssdpDevices = state.ssdpDevices
ssdpDevices.each {
logInfo("getDeviceData: path = ${it.value.ip}:${it.value.port}${it.value.path}")
sendCmd(it.value.path, it.value.ip, it.value.port, "addDeviceData")
pauseExecution(300)
}
}
void addDeviceData(resp) {
def devices = state.devices
def device = devices.find { it.key == resp.mac }
if (device) {
def type = resp.xml.device.deviceType
def port = convertHexToInt(resp.port)
device.value << [manufacturer: "${resp.xml.device.manufacturer.text()}"]
def services = resp.xml.device.serviceList.service
services.each {
if (it.serviceType.text() == "urn:samsung.com:service:MainTVAgent2:1") {
device.value << [tvPort: "${port}",
tvUrn: "${it.serviceType.text()}",
tvPath: "${it.controlURL.text()}"]
} else if (it.serviceType.text() == "urn:schemas-upnp-org:service:AVTransport:1") {
device.value << [avPort: "${port}",
avUrn: "${it.serviceType.text()}",
avPath: "${it.controlURL.text()}"]
} else if (it.serviceType.text() == "urn:schemas-upnp-org:service:RenderingControl:1") {
device.value << [rcPort: "${port}",
rcUrn: "${it.serviceType.text()}",
rcPath: "${it.controlURL.text()}"]
}
}
}
logInfo("addDeviceData: found data for device ${resp.mac}")
}
private sendCmd(command, deviceIP, devicePort, action){
def host = "${deviceIP}:${devicePort}"
sendHubCommand(new hubitat.device.HubAction("""GET ${command} HTTP/1.1\r\nHOST: ${host}\r\n\r\n""",
hubitat.device.Protocol.LAN, host, [callback: action]))
}
def logWarn(message) {
log.warn "${appName()} ${appVersion()}: ${message}"
}
def logInfo(message) {
log.info "${appName()} ${appVersion()}: ${message}"
}
// ----- Utility Functions SHOULD DISAPPEAR-----
private Integer convertHexToInt(hex) {
Integer.parseInt(hex,16)
}
private String convertHexToIP(hex) {
[convertHexToInt(hex[0..1]),convertHexToInt(hex[2..3]),convertHexToInt(hex[4..5]),convertHexToInt(hex[6..7])].join(".")
}