· 7 years ago · Dec 21, 2017, 04:40 PM
1import groovy.json.JsonSlurper
2import groovy.json.JsonOutput
3
4metadata {
5 definition (name: "Rompr", namespace: "ngw", author: "Niv Gal Waizer") {
6 capability "Music Player"
7 capability "Switch"
8 capability "Refresh"
9 command "preset1"
10 command "preset2"
11 command "preset3"
12 }
13
14 simulator {
15 // TODO: define status and reply messages here
16 }
17
18 tiles {
19 //main
20 standardTile("status", "device.status", width: 1, height: 1, decoration: "flat") {
21 state "play", label:'Playing', action:"music Player.pause", icon:"st.Electronics.electronics19", nextState:"pause", backgroundColor:"#ffffff"
22 state "stop", label:'Stopped', action:"music Player.play", icon:"st.Electronics.electronics19", nextState:"play", backgroundColor:"#ffffff"
23 state "pause", label:'Paused', action:"music Player.play", icon:"st.Electronics.electronics19", nextState:"play", backgroundColor:"#ffffff"
24 }
25 // Row 1
26 standardTile("nextTrack", "device.status", width: 1, height: 1, decoration: "flat") {
27 state "next", label:'', action:"music Player.nextTrack", icon:"st.sonos.next-btn", backgroundColor:"#ffffff"
28 }
29 standardTile("playpause", "device.status", width: 1, height: 1, decoration: "flat") {
30 state "default", label:'', action:"music Player.play", icon:"st.sonos.play-btn", nextState:"play", backgroundColor:"#ffffff"
31 state "play", label:'', action:"music Player.pause", icon:"st.sonos.pause-btn", nextState:"pause", backgroundColor:"#79b821"
32 state "pause", label:'', action:"music Player.play", icon:"st.sonos.play-btn", nextState:"play", backgroundColor:"#ffffff"
33 }
34 standardTile("previousTrack", "device.status", width: 1, height: 1, decoration: "flat") {
35 state "previous", label:'', action:"music Player.previousTrack", icon:"st.sonos.previous-btn", backgroundColor:"#ffffff"
36 }
37 standardTile("stop", "device.status", width: 1, height: 1, decoration: "flat") {
38 state "stop", label:'', action:"music Player.stop", icon:"st.sonos.stop-btn", backgroundColor:"#ffffff"
39 }
40 // Row 2
41 standardTile("refresh", "capability.refresh", width: 1, height: 1, decoration: "flat") {
42 state ("default", label:"Refresh", action:"refresh.refresh", icon:"st.secondary.refresh")
43 }
44 // Row 3
45 standardTile("mute", "device.mute", inactiveLabel: false, decoration: "flat") {
46 state "unmuted", label:"Mute", action:"music Player.mute", icon:"st.custom.sonos.unmuted", backgroundColor:"#79b821", nextState:"muted"
47 state "muted", label:"Unmute", action:"music Player.unmute", icon:"st.custom.sonos.muted", backgroundColor:"#ffffff", nextState:"unmuted"
48 }
49 controlTile("volume", "device.volume", "slider", width: 1, height: 1) {
50 state "volume", label:'${currentValue}', action:"music Player.setLevel", backgroundColor:"#ffffff"
51 }
52 //multiAttributeTile(name:"file", type: "generic", width: 1, height: 1, decoration: "flat") {
53 // tileAttribute ("device.contactDisplay", key: "PRIMARY_CONTROL") {
54 // attributeState("KCRW", label:'${currentValue}')
55 // attributeState("99FM", label:'${currentValue}')
56 // }
57 //}
58 standardTile("file", "device.contactDisplay", width: 3, height: 1, decoration: "flat") {
59 state "0", label:'${name}'
60 state "1", label:'1'
61 state "2", label:'${name}'
62 state "3", label:'3'
63 }
64 valueTile("error", "device.displayName", width: 1, height: 1, decoration: "flat") {
65 state "default", label:'${name}'
66 }
67 standardTile("preset1", "device.preset1Name", width: 1, height: 1, decoration: "flat") {
68 state "val", label:'1', action:"preset1"
69 }
70 standardTile("preset2", "device.preset1Name", width: 1, height: 1, decoration: "flat") {
71 state "val", label:'2', action:"preset2"
72 }
73 standardTile("preset3", "device.preset1Name", width: 1, height: 1, decoration: "flat") {
74 state "val", label:'3', action:"preset3"
75 }
76 standardTile("switch", "device.switch", width: 1, height: 1, canChangeIcon: true) {
77 state "off", label: '${currentValue}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff"
78 state "on", label: '${currentValue}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#79b821"
79 }
80 main("status")
81 details([
82 "previousTrack","playpause","nextTrack",
83 "preset1","preset2","preset3",
84 "stop","refresh", "error",
85 "mute","volume",
86 "file"
87 ])
88 }
89}
90
91preferences {
92 input("IP", "text", title: "IP", defaultValue:"192.168.1.12", required: false, displayDuringSetup: true)
93 input("Port", "text", title: "Port", defaultValue:"80", required: false, displayDuringSetup: true)
94}
95
96def message(msg){
97 log.debug("***** '${msg}'")
98}
99
100// parse events into attributes
101def parse(String description) {
102 message("Parsing '${description}'")
103 def map = stringToMap(description)
104 if (map.headers && map.body) { //got device info response
105 if (map.body) {
106 def bodyString = new String(map.body.decodeBase64())
107 message("body = $bodyString")
108 def slurper = new JsonSlurper()
109 def result = slurper.parseText(bodyString)
110 if (result.containsKey("volume")) {
111 message("setting volume to ${result.volume}")
112 sendEvent(name: "volume", value: result.volume)
113 }
114 if (result.containsKey("state")) {
115 message("setting state to ${result.state}")
116 sendEvent(name: "status", value: result.state)
117 sendEvent(name: "playpause", value: result.state)
118 }
119 if (result.containsKey("file")) {
120 message("replay said that file is ${result.file}")
121 switch (result.file) {
122 case ~/.*kcrw.*/:
123 message('preset 1 found')
124 sendEvent(name: "file", value: "1")
125 break
126 case ~/.*99fm.*/ :
127 message('preset 3 found')
128 sendEvent(name: "file", value: "3")
129 break
130 default:
131 message('No match to preset')
132 sendEvent(name: "file", value: "0")
133
134 }
135 }
136 if (result.containsKey("playlist")) {
137 def json = new groovy.json.JsonBuilder(result.playlist)
138 message("setting playlist to ${json.toString()}")
139 // sendEvent(name: "playlist",value: json.toString())
140 }
141 if (result.containsKey("error")) {
142 def json = new groovy.json.JsonBuilder(result.error)
143 message("setting error to ${json.toString()}")
144 sendEvent(name: "error",value: json.toString())
145 }
146 }
147 }
148}
149
150def refresh(){
151 executeCommand("[]")
152}
153
154// handle commands
155def on() {
156 message('on')
157 play()
158}
159
160def off() {
161 message('off')
162 stop()
163}
164
165def play() {
166 message("play")
167 executeCommand("[[\"play\"]]")
168}
169
170def pause() {
171 message( "pause" )
172 executeCommand("[[\"pause\"]]")
173}
174
175def stop() {
176 message("stop")
177 executeCommand("[[\"stop\"]]")
178}
179
180def previousTrack() {
181 message('previousTrack')
182 executeCommand("[[\"play\",\"-1\"]]")
183}
184
185def nextTrack() {
186 message('nextTrack')
187 executeCommand("[[\"play\",\"1\"]]")
188}
189
190def setLevel(value) {
191 message("setLevel to '${value}'")
192 //sendEvent(name: "volume", value: value, isStateChange: true)
193 executeCommand("[[\"setvol\",${value}]]")
194}
195
196def mute() {
197 message('mute')
198 executeCommand("[[\"disableoutput\",0]]")
199}
200
201def unmute() {
202 message('unmute')
203 executeCommand("[[\"enableoutput\",0]]")
204}
205
206def preset1() {
207 message('Play preset 1')
208 executeCommand("[[\"playid\",\"1\"]]")
209}
210def preset2() {
211 message('Play preset 2')
212 executeCommand("[[\"playid\",\"2\"]]")
213}
214def preset3() {
215 message('Play preset 3')
216 executeCommand("[[\"playid\",\"3\"]]")
217}
218
219def poll(){
220 refresh()
221}
222
223def createDNI(){
224 if (!settings.IP && !settings.Port) {
225 settings.IP = "192.168.1.12"
226 settings.Port = "80"
227 }
228 def gatewayIPHex = convertIPtoHex(settings.IP)
229 def gatewayPortHex = convertPortToHex(settings.Port)
230 device.deviceNetworkId = "$gatewayIPHex:$gatewayPortHex"
231 message (device.deviceNetworkId)
232}
233
234private get(path){
235 message ("**** Issue GET to: ${settings.IP}:${settings.Port}")
236 createDNI()
237 def headers = [:]
238 headers.put("HOST", "${settings.IP}:${settings.Port}")
239 try {
240 def hubAction = new physicalgraph.device.HubAction([
241 method: "GET",
242 path: path,
243 headers: headers
244 ],
245 device.deviceNetworkId //,
246 //[callback: "hubActionResponse"]
247 )
248 message("${hubAction}")
249 hubAction
250 } catch (e) {
251 message(e.message)
252 }
253}
254
255private executeCommand(command){
256 message ("**** POSTing to: ${settings.IP}:${settings.Port} $command")
257 createDNI()
258 def path = "/player/mpd/postcommand.php"
259 def headers = [:]
260 headers.put("HOST", "${settings.IP}:${settings.Port}")
261 headers.put("Accept", "application/json, text/javascript, */*; q=0.01")
262 def command_in_json = new groovy.json.JsonOutput().toJson(command)
263 message("JSON is ${command_in_json}")
264 try {
265 def hubAction = new physicalgraph.device.HubAction([
266 method: "POST",
267 path: path,
268 headers: headers,
269 body: "${command}"
270 ],
271 device.deviceNetworkId
272 )
273 message("${hubAction}")
274 hubAction
275 } catch (e) {
276 message(e.message)
277 }
278}
279
280private String convertIPtoHex(ipAddress) {
281 String hex = ipAddress.tokenize( '.' ).collect { String.format( '%02x', it.toInteger() ) }.join()
282 return hex
283}
284
285private String convertPortToHex(port) {
286 String hexport = port.toString().format( '%04x', port.toInteger() )
287 return hexport
288}