Skip to content

Instantly share code, notes, and snippets.

@nivw
Created December 6, 2017 00:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nivw/eaf7ace34052c3a917c7aa94161da734 to your computer and use it in GitHub Desktop.
Save nivw/eaf7ace34052c3a917c7aa94161da734 to your computer and use it in GitHub Desktop.
even GET failed
import groovy.json.JsonSlurper
metadata {
definition (name: "Rompr", namespace: "ngw", author: "Niv") {
capability "Music Player"
capability "Refresh"
capability "Switch"
// These strings are comma separated lists of names
attribute "playlists", "json_object"
attribute "speakers", "json_object"
command "play"
command "pause"
}
tiles {
// Row 1
standardTile("nextTrack", "device.status", width: 1, height: 1, decoration: "flat") {
state "next", label:'', action:"music Player.nextTrack", icon:"st.sonos.next-btn", backgroundColor:"#ffffff"
}
standardTile("playpause", "device.status", width: 1, height: 1, decoration: "flat") {
state "default", label:'', action:"play", icon:"st.sonos.play-btn", nextState:"play", backgroundColor:"#ffffff"
state "play", label:'', action:"pause", icon:"st.sonos.pause-btn", nextState:"pause", backgroundColor:"#ffffff"
state "pause", label:'', action:"play", icon:"st.sonos.play-btn", nextState:"play", backgroundColor:"#ffffff"
}
standardTile("previousTrack", "device.status", width: 1, height: 1, decoration: "flat") {
state "previous", label:'', action:"music Player.previousTrack", icon:"st.sonos.previous-btn", backgroundColor:"#ffffff"
}
// Row 2
standardTile("switch", "device.switch", width: 1, height: 1, decoration: "flat", canChangeIcon: true) {
state "on", label:'On', action:"switch.off", icon:"st.Electronics.electronics14", nextState:"off", backgroundColor:"#ffffff"
state "off", label:'Off', action:"switch.on", icon:"st.Electronics.electronics16", nextState:"on", backgroundColor:"#ffffff"
}
standardTile("status", "device.status", width: 1, height: 1, decoration: "flat", canChangeIcon: true) {
state "play", label:'Playing', action:"music Player.pause", icon:"st.Electronics.electronics19", nextState:"pause", backgroundColor:"#ffffff"
state "stop", label:'Stopped', action:"music Player.play", icon:"st.Electronics.electronics19", nextState:"play", backgroundColor:"#ffffff"
state "pause", label:'Paused', action:"music Player.play", icon:"st.Electronics.electronics19", nextState:"play", backgroundColor:"#ffffff"
}
standardTile("mute", "device.mute", inactiveLabel: false, decoration: "flat") {
state "unmuted", label:"Mute", action:"music Player.mute", icon:"st.custom.sonos.unmuted", backgroundColor:"#ffffff", nextState:"muted"
state "muted", label:"Unmute", action:"music Player.unmute", icon:"st.custom.sonos.muted", backgroundColor:"#ffffff", nextState:"unmuted"
}
// Row 3
controlTile("levelSliderControl", "device.level", "slider", height: 1, width: 3, inactiveLabel: false) {
state "level", action:"music Player.setLevel", backgroundColor:"#ffffff"
}
//Row 4
valueTile("currentSong", "device.trackDescription", inactiveLabel: true, height:1, width:3, decoration: "flat") {
state "default", label:'${currentValue}', backgroundColor:"#ffffff"
}
// Row 5
standardTile("refresh", "device.status", inactiveLabel: false, decoration: "flat") {
state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh", backgroundColor:"#ffffff"
}
main "playpause"
details([
"previousTrack","playpause","nextTrack",
"switch","status","mute",
"levelSliderControl",
//"currentSong",
"refresh"
])
}
simulator {
status "play" : "simulator:true, state:'play'"
status "stop" : "simulator:true, state:'stop'"
status "pause" : "simulator:true, state:'pause'"
}
}
preferences {
input("RomprIP", "text", title: "Rompr IP", required: true, displayDuringSetup: true)
input("RomprPort", "text", title: "Rompr Port", required: false, displayDuringSetup: true)
}
// parse events into attributes
def parse(String description) {
log.trace("Parsing $description")
def map = stringToMap(description)
if (map.headers && map.body) { //got device info response
if (map.body) {
def bodyString = new String(map.body.decodeBase64())
log.debug( "body = $bodyString")
def slurper = new JsonSlurper()
def result = slurper.parseText(bodyString)
if (result.containsKey("volume")) {
log.debug( "setting volume to ${result.volume}")
sendEvent(name: "level", value: result.volume)
}
if (result.containsKey("state")) {
log.debug( "setting state to ${result.state}")
sendEvent(name: "state", value: result.state)
}
if (result.containsKey("file")) {
def json = new groovy.json.JsonBuilder(result.file)
log.debug "setting file to ${json.toString()}"
sendEvent(name: "file", value: json.toString())
}
if (result.containsKey("playlist")) {
def json = new groovy.json.JsonBuilder(result.playlist)
log.debug "setting playlist to ${json.toString()}"
sendEvent(name: "playlist",value: json.toString())
}
}
}
}
def updated() {
log.debug("Updating Rompr")
refresh()
}
def updateState() {
log.debug("updateState")
}
def installed() {
// subscribeAction("/subscribe")
refresh()
}
// handle commands
def refresh() {
log.debug "refreshing"
//def address = getCallBackAddress()
//sendCommand("subscribe=$address")
//sendCommand("[]")
get("/")
}
def on() {
log.debug "Turn-on MPD play"
play()
}
def off() {
log.debug "Turn-off play in MPD"
stop()
}
def play() {
log.debug( "Executing play" )
sendCommand("[[\"play\"]]")
//sendEvent(name: "main", value: "playing", isStateChange: true)
}
def pause() {
log.debug( "Executing pause" )
sendCommand("[[\"pause\"]]")
//sendEvent(name: "main", value: "paused", isStateChange: true)
}
def stop() {
log.debug( "Executing 'stop'" )
sendCommand("[[\"stop\"]]")
}
def nextTrack() {
log.debug "Executing 'nextTrack'"
sendCommand("[[\"next\"]]")
}
def setLevel(value) {
log.debug "Executing 'setLevel' to $value"
sendCommand("[[\"setvol\",${value}]]")
}
def mute() {
log.debug "Executing 'mute'"
sendCommand("[[\"disableoutput\",0]]")
}
def previousTrack() {
log.debug "Executing 'previousTrack'"
sendCommand("[[\"play\",\"-1\"]]")
}
def unmute() {
log.debug "Executing 'unmute'"
sendCommand("[[\"enableoutput\",0]]")
}
// Private functions used internally
// Creates Device Network ID in ‘AAAAAAAA:PPPP’ format
private String createDNI(ipaddr, port) {
log.debug("createDNI(${ipaddr}, ${port})")
def hexIp = ipaddr.tokenize('.').collect {
String.format('%02x', it.toInteger())
}.join()
def hexPort = String.format('%04x', port.toInteger())
log.trace("DNI is ${hexIp}:${hexPort}")
return "${hexIp}:${hexPort}"
}
private updateDNI() {
//if (device.deviceNetworkId != state.dni) {
if (settings.RomprPort) {
log.trace("Using port ${settings.RomprPort}")
device.deviceNetworkId = createDNI(settings.RomprIP, settings.RomprPort)
} else {
log.trace('Using port 80')
device.deviceNetworkId = createDNI(settings.RomprIP,80)
}
//}
}
def hubActionResponse(response){
log.debug("Response from host: $device.deviceNetworkId")
log.debug("${response}")
}
private sendCommand(command) {
if (settings.RomprIP) {
def path = "/player/mpd/postcommand.php"
def headers = [:]
log.debug(" IP: $settings.RomprIP")
def host = createDNI(settings.RomprIP,80)
device.deviceNetworkId = host
headers.put("HOST", settings.RomprIP)
def method = "POST"
try {
//sendHubCommand(new physicalgraph.device.HubAction([
def hubAction = new physicalgraph.device.HubAction([
method: method,
path: path,
body: command,
headers: headers],
host,
[callback: "hubActionResponse"]
)
log.debug("Print hubAction: $hubAction")
hubAction
} catch (e) {
log.debug(e.message)
}
} else {
log.error('Missing Rompr IP in prefrence')
}
}
private get(path) {
if (settings.RomprIP) {
def headers = [:]
log.debug(" Get IP: ${settings.RomprIP}${path}")
def host = createDNI(settings.RomprIP,80)
//headers.put("HOST", settings.RomprIP)
def method = "GET"
try {
//sendHubCommand(new physicalgraph.device.HubAction([
def hubAction = new physicalgraph.device.HubAction([
method: method,
path: path,
headers: headers],
host,
[callback: "hubActionResponse"]
)
log.debug("Print hubAction: $hubAction")
hubAction
} catch (e) {
log.debug(e.message)
}
} else {
log.error('Missing Rompr IP in prefrence')
}
}
private getPlaylists() {
log.debug "in getPlaylists!!!"
def path = "/get.html?list=playlists"
def headers = [:]
headers.put("GET", device.deviceNetworkId)
headers.put("Content-Type", "application/x-www-form-urlencoded")
def method = "GET"
def result = new physicalgraph.device.HubAction(
method: method,
path: path,
headers: headers
)
result
}
private getCallBackAddress()
{
device.hub.getDataValue("localIP") + ":" + device.hub.getDataValue("localSrvPortTCP")
}
private subscribeAction(path, callbackPath="") {
def address = device.hub.getDataValue("localIP") + ":" + device.hub.getDataValue("localSrvPortTCP")
def parts = device.deviceNetworkId.split(":")
def ip = convertHexToIP(parts[0])
def port = convertHexToInt(parts[1])
ip = ip + ":" + port
def result = new physicalgraph.device.HubAction(
method: "SUBSCRIBE",
path: path,
headers: [
HOST: ip,
CALLBACK: "<http://${address}/obything>",
NT: "upnp:event",
TIMEOUT: "Second-3600"])
result
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment