Need help on adding new device handler

I found a code that work with Control4 dimmer with ST (aurthor is pstuart). After I copy and paste in the device type handler, I hit the create and I get the following error:
Org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed: script15008727050552120483763.groovy: 27: expecting ‘}’, found ‘:’ @ line 27, column 34. 25 fingerprint endpointId: “01”, profileId: “0104”, deviceId: “0101”, inClusters: “0000 0003 0004 0005 0006 0008 000A” ^ 1 error
I double check that I copy everything. Please help. Thanks.

  1. Please ensure that you are pasting Device Type Handler code into My Device Handlers, not My SmartApps.

  2. Please paste or link to the entire text of the code. We can’t debug unless we see the context!!!

2 Likes

Thanks for the response. I double check and I did paste it to the Create New Device Handler. I following is the code:
1 /**
2 * ps_Control4_Dimmer_ZigbeeHA
3 *
4 * Copyright 2014 patrick@patrickstuart.com
5 *
6 * Licensed under the Apache License, Version 2.0 (the “License”); you may not use this file except
7 * in compliance with the License. You may obtain a copy of the License at:
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
12 * on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
13 * for the specific language governing permissions and limitations under the License.
14 *
15 */
16 metadata {
17 definition (name: “ps_Control4_Dimmer_ZigbeeHA”, namespace: “ps”, author: "patrick@patrickstuart.com") {
18 capability "Switch Level"
19 capability "Actuator"
20 capability "Switch"
21 capability "Configuration"
22 capability "Refresh"
23 capability "Polling"
24

25 fingerprint endpointId: “01”, profileId: “0104”, deviceId: “0101”, inClusters: "0000 0003 0004 0005 0006 0008 000A"
26 fingerprint endpointId: “C4”, profileId: “C25D”, deviceId: “0101”, inClusters: "0001"
27
28 }
29
30 preferences {
31 input(“OnSpeed”, “text”, title:“Turn On Speed”, description: “Please enter the speed at which the dimmer turns on”, defaultValue:“1500”, required: true, displayDuringSetup: true)
32 input(“OffSpeed”, “text”, title:“Turn Off Speed”, description: “Please enter the speed at which the dimmer turns off”, defaultValue:“1500”, required: true, displayDuringSetup: true)
33 input(“DefaultOnValue”, “text”, title:“Default On Value”, description: “Please enter the default value you want ST to turn on to, in case the last dimmed value is lost.”, defaultValue:“75”, required: true, displayDuringSetup: true)
34
35 }
36 simulator {
37 // status messages
38 status “on”: "on/off: 1"
39 status “off”: "on/off: 0"
40

41 // reply messages
42 reply “zcl on-off on”: "on/off: 1"
43 reply “zcl on-off off”: "on/off: 0"
44
45 command "test"
46 command "getClusters"
47 }
48

49 tiles {
50 standardTile(“switch”, “device.switch”, width: 1, height: 1, canChangeIcon: true) {
51 state “off”, label: ‘${name}’, action: “switch.on”, icon: “st.switches.switch.off”, backgroundColor: “#ffffff"
52 state “on”, label: ‘${name}’, action: “switch.off”, icon: “st.switches.switch.on”, backgroundColor: “#79b821"
53 }
54 standardTile(“refresh”, “device.switch”, inactiveLabel: false, decoration: “flat”) {
55 state “default”, label:””, action:“refresh.refresh”, icon:"st.secondary.refresh"
56 }
57 controlTile(“levelSliderControl”, “device.level”, “slider”, height: 1, width: 2, inactiveLabel: false) {
58 state “level”, action:"switch level.setLevel"
59 }
60 valueTile(“level”, “device.level”, inactiveLabel: false, decoration: “flat”) {
61 state “level”, label: 'Level ${currentValue}%'
62 }
63

64 main([“switch”])
65 details([“switch”, “levelSliderControl”, “level”, “refresh”])
66 }
67 }
68

69 def parse(String description) {
70 //log.trace description
71 if (description?.startsWith(“catchall: C25”)) {
72 def msg = zigbee.parse(description)
73 //log.trace msg
74 def payloadhex = description.tokenize(" ").last()
75 def payload = payloadhex.decodeHex()
76 def x = ""
77 payload.each() { x += it as char }
78
79 //log.debug "Payload is $x"
80
81 if(x.contains(“sa c4.dm.cc 00 01”))
82 {
83 def result = createEvent(name: “switch”, value: “on”)
84 log.debug "Parse returned ${result?.descriptionText}"
85 return result
86 }
87 if(x.contains(“sa c4.dm.cc 00 00”))
88 {
89 def result = createEvent(name: “switch”, value: “off”)
90 log.debug "Parse returned ${result?.descriptionText}"
91 return result
92 }
93 if(x.contains(“sa c4.dm.cc 00 02”))
94 {
95 log.debug "Double Tap Top"
96 }
97 if(x.contains(“sa c4.dm.cc 01 02”))
98 {
99 log.debug "Double Tap Bottom"
100 }
101 if(x.contains(“sa c4.dm.cc 00 03”))
102 {
103 log.debug "Triple Tap Top"
104 }
105 if(x.contains(“sa c4.dm.cc 01 03”))
106 {
107 log.debug "Triple Tap Bottom"
108 }
109 if(x.contains(“sa c4.dm.t0c”) || x.contains(“sa c4.dm.b0c”)) {
110 log.debug “switch is dimming $x"
111 def l = convertHexToInt(x.tokenize(” ").last().split())
112 log.debug l
113 def i = Math.round(l)
114 sendEvent( name: “level”, value: i )
115 }
116
117 }
118
119 if (description?.startsWith(“read attr”)) {
120 //log.debug "Read Attr found"
121 //def descMap = parseDescriptionAsMap(description)
122 //log.debug descMap
123 //log.debug description[-2…-1]
124 def i = Math.round(convertHexToInt(description[-2…-1]) / 256 * 100 )
125
126 sendEvent( name: “level”, value: i )
127 }
128 }
129

130 def test() {
131 /*
132 def cmd = []
133 cmd << "zcl global send-me-a-report 1 0x20 0x20 600 3600 {0100}"
134 cmd << "delay 500"
135 cmd << "send 0x${device.deviceNetworkId} 1 6"
136 cmd << "delay 1000"
137 cmd
138 */
139 //'zcl on-off on’
140 log.debug "$OnSpeed onspeed $OffSpeed offspeed $DefaultOnValue defaultOnValue $state.lastOnValue is state.lastonvalue"
141 }
142

143 def getClusters() {
144 log.debug "getClusters hit $device.deviceNetworkId"
145 //"st rattr 0x${device.deviceNetworkId} 4 6 0x01"
146 "zdo active 0x${device.deviceNetworkId}"
147 }
148

149 def on() {
150 log.debug "on()"
151 sendEvent(name: “switch”, value: “on”)
152
153 //"st cmd 0x${device.deviceNetworkId} 1 6 1 {}"
154
155 //get level in UI
156 def value = device.currentValue(“level”)
157 if (value == 0) { value = state.lastOnValue
158 log.debug "Value is $value"
159 }
160 def level = new BigInteger(Math.round(value * 255 / 100).toString()).toString(16)
161 //log.debug level
162
163 def speed = OnSpeed //.toString().padLeft(4, ‘0’)
164 log.debug speed
165 "st cmd 0x${device.deviceNetworkId} 1 8 4 {${level} ${speed} }"
166 }
167

168 def off() {
169 log.debug "off()"
170 //state.lastOnValue = device.currentValue(“level”)
171 sendEvent(name: “switch”, value: “off”)
172 //"st cmd 0x${device.deviceNetworkId} 1 6 0 {}"
173 def speed = OffSpeed.toString().padLeft(4, ‘0’)
174 log.debug speed
175 "st cmd 0x${device.deviceNetworkId} 1 8 4 {00 ${speed} }"
176 }
177

178 def refresh() {
179 [
180 “st rattr 0x${device.deviceNetworkId} 1 6 0”, “delay 100”,
181 "st rattr 0x${device.deviceNetworkId} 1 8 0"
182 ]
183 }
184

185 def poll(){
186 log.debug "Poll is calling refresh"
187 refresh()
188 }
189

190 def setLevel(value) { setLevel(value,“0500”) }
191

192 def setLevel(value, speed) {
193 log.debug value
194 log.debug speed //.toString().padLeft(4, ‘0’)
195 state.lastOnValue = value
196 speed = speed.toString().padLeft(4, ‘0’)
197 log.trace "setLevel($value)"
198
199 def cmds = []
200 if (value < 8.0) {
201 log.debug "Value equals 0?"
202 sendEvent(name: “switch”, value: “off”)
203
204 cmds << "st cmd 0x${device.deviceNetworkId} 1 8 4 {00 0500}"
205 //cmds << "st cmd 0x${device.deviceNetworkId} 1 6 0 {}"
206 }
207 else if (device.latestValue(“switch”) == “off”) {
208 sendEvent(name: “switch”, value: “on”)
209 }
210

211 sendEvent(name: “level”, value: value)
212 def level = new BigInteger(Math.round(value * 255 / 100).toString()).toString(16)
213 cmds << "st cmd 0x${device.deviceNetworkId} 1 8 4 {${level} ${speed} }"
214 cmds
215 }
216

217 //def setLevel(value) {
218
219 //}
220

221

222 def configure() {
223

224 String zigbeeId = swapEndianHex(device.hub.zigbeeId)
225 log.debug "Confuguring Reporting and Bindings."
226 def configCmds = [
227

228 //Switch Reporting
229 “zcl global send-me-a-report 6 0 0x10 0 3600 {01}”, “delay 500”,
230 “send 0x${device.deviceNetworkId} 1 1”, “delay 1000”,
231

232 //Level Control Reporting
233 “zcl global send-me-a-report 8 0 0x20 5 3600 {0010}”, “delay 200”,
234 “send 0x${device.deviceNetworkId} 1 1”, “delay 1500”,
235

236 “zdo bind 0x${device.deviceNetworkId} 1 1 6 {${device.zigbeeId}} {}”, “delay 1500”,
237 “zdo bind 0x${device.deviceNetworkId} 1 1 8 {${device.zigbeeId}} {}”, “delay 500”,
238 ]
239 return configCmds + refresh() // send refresh cmds as part of config
240 }
241

242 def uninstalled() {
243

244 log.debug "uninstalled()"
245 response(“zcl rftd”)
246
247 }
248

249 private getEndpointId() {
250 //log.debug "Device.endpoint is $device.endpointId"
251 new BigInteger(device.endpointId, 16).toString()
252 }
253

254 private hex(value, width=2) {
255 def s = new BigInteger(Math.round(value).toString()).toString(16)
256 while (s.size() < width) {
257 s = “0” + s
258 }
259 s
260 }
261

262 private Integer convertHexToInt(hex) {
263 Integer.parseInt(hex,16)
264 }
265

266

267 private String swapEndianHex(String hex) {
268 reverseArray(hex.decodeHex()).encodeHex()
269 }
270

271 private byte[] reverseArray(byte[] array) {
272 int i = 0;
273 int j = array.length - 1;
274 byte tmp;
275 while (j > i) {
276 tmp = array[j];
277 array[j] = array[i];
278 array[i] = tmp;
279 j–;
280 i++;
281 }
282 return array
283 }
284

285 def parseDescriptionAsMap(description) {
286 (description - “read attr - “).split(”,”).inject([:]) { map, param ->
287 def nameAndValue = param.split(":")
288 map += [(nameAndValue[0].trim()):nameAndValue[1].trim()]
289 }
290 }

Any idea?

paging @pstuart

Just a really basic question, to be sure before trying this. Are you including the line numbers when you paste the code in?

1 Like

Please don’t paste my code in these forums. Provide a link to the github. As stated above, it appears you did not grab the raw text.

Sometimes the IDE is stupid, create a blank device type and then paste the code into that.

1 Like

Thanks for the help. It works great. I am really new at this and don’t even know I need to copy the raw code. I am sorry to post @pstuart code.
Although I am able to create the new device handler, I am not able to pair the control4 switch. That will be a separate subject, I will post it at the other thread for my question. Hopefully @pstuart will help.