Advertisement
erocm123

Inovelli 2-Channel Smart Plug NZW37

Jan 12th, 2019
195
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 17.71 KB | None | 0 0
  1. /**
  2. *
  3. * Inovelli 2-Channel Smart Plug NZW37
  4. *
  5. * github: Eric Maycock (erocm123)
  6. * Date: 2018-06-05
  7. * Copyright Eric Maycock
  8. *
  9. * Includes all configuration parameters and ease of advanced configuration.
  10. *
  11. * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
  12. * in compliance with the License. You may obtain a copy of the License at:
  13. *
  14. * http://www.apache.org/licenses/LICENSE-2.0
  15. *
  16. * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
  17. * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
  18. * for the specific language governing permissions and limitations under the License.
  19. *
  20. *
  21. * 2018-06-05: Switching back to child device configuration
  22. * 2018-04-09: Changed back to use encapsulation commands and removed child device references
  23. * 2018-03-27: Adapted for Hubitat.
  24. */
  25.  
  26. metadata {
  27. definition(name: "Inovelli 2-Channel Smart Plug NZW37", namespace: "InovelliUSA", author: "Eric Maycock") {
  28. capability "Actuator"
  29. capability "Sensor"
  30. capability "Switch"
  31. capability "Polling"
  32. capability "Refresh"
  33. capability "Health Check"
  34. capability "PushableButton"
  35. capability "Configuration"
  36.  
  37. attribute "lastActivity", "String"
  38. attribute "lastEvent", "String"
  39.  
  40. command "setAssociationGroup", ["number", "enum", "number", "number"] // group number, nodes, action (0 - remove, 1 - add), multi-channel endpoint (optional)
  41. command "childOn"
  42. command "childOff"
  43. command "childRefresh"
  44.  
  45. fingerprint mfr: "015D", prod: "0221", model: "251C"
  46. fingerprint mfr: "0312", prod: "B221", model: "251C"
  47. fingerprint deviceId: "0x1001", inClusters: "0x5E,0x85,0x59,0x5A,0x72,0x60,0x8E,0x73,0x27,0x25,0x86"
  48. fingerprint deviceId: "0x1001", inClusters: "0x5E,0x25,0x27,0x85,0x8E,0x59,0x55,0x86,0x72,0x5A,0x73,0x70,0x5B,0x9F,0x60,0x6C,0x7A"
  49. fingerprint deviceId: "0x1001", inClusters: "0x5E,0x25,0x27,0x85,0x8E,0x59,0x55,0x86,0x72,0x5A,0x73,0x70,0x5B,0x60,0x6C"
  50. }
  51.  
  52. simulator {}
  53.  
  54. preferences {
  55. input "autoOff1", "number", title: "Auto Off Channel 1\n\nAutomatically turn switch off after this number of seconds\nRange: 0 to 32767", description: "Tap to set", required: false, range: "0..32767"
  56. input "autoOff2", "number", title: "Auto Off Channel 2\n\nAutomatically turn switch off after this number of seconds\nRange: 0 to 32767", description: "Tap to set", required: false, range: "0..32767"
  57. input "ledIndicator", "enum", title: "LED Indicator\n\nTurn LED indicator on when switch is:\n", description: "Tap to set", required: false, options:[["0": "On"], ["1": "Off"], ["2": "Disable"]], defaultValue: "0"
  58. input description: "1 pushed - Button 2x click", title: "Button Mappings", displayDuringSetup: false, type: "paragraph", element: "paragraph"
  59. input description: "Use the \"Z-Wave Association Tool\" SmartApp to set device associations. (Firmware 1.02+)\n\nGroup 2: Sends on/off commands to associated devices when switch is pressed (BASIC_SET).", title: "Associations", displayDuringSetup: false, type: "paragraph", element: "paragraph"
  60. }
  61.  
  62. tiles {
  63. multiAttributeTile(name: "switch", type: "lighting", width: 6, height: 4, canChangeIcon: true) {
  64. tileAttribute("device.switch", key: "PRIMARY_CONTROL") {
  65. attributeState "off", label: '${name}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff", nextState: "turningOn"
  66. attributeState "on", label: '${name}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#00a0dc", nextState: "turningOff"
  67. attributeState "turningOff", label: '${name}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff", nextState: "turningOn"
  68. attributeState "turningOn", label: '${name}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#00a0dc", nextState: "turningOff"
  69. }
  70. }
  71.  
  72. standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
  73. state "default", label: "", action: "refresh.refresh", icon: "st.secondary.refresh"
  74. }
  75.  
  76. valueTile("lastActivity", "device.lastActivity", inactiveLabel: false, decoration: "flat", width: 4, height: 1) {
  77. state "default", label: 'Last Activity: ${currentValue}',icon: "st.Health & Wellness.health9"
  78. }
  79.  
  80. valueTile("icon", "device.icon", inactiveLabel: false, decoration: "flat", width: 4, height: 1) {
  81. state "default", label: '', icon: "https://inovelli.com/wp-content/uploads/Device-Handler/Inovelli-Device-Handler-Logo.png"
  82. }
  83. }
  84. }
  85. def parse(String description) {
  86. def result = []
  87. def cmd = zwave.parse(description)
  88. if (cmd) {
  89. result += zwaveEvent(cmd)
  90. log.debug "Parsed ${cmd} to ${result.inspect()}"
  91. } else {
  92. log.debug "Non-parsed event: ${description}"
  93. }
  94.  
  95. def now
  96. if(location.timeZone)
  97. now = new Date().format("yyyy MMM dd EEE h:mm:ss a", location.timeZone)
  98. else
  99. now = new Date().format("yyyy MMM dd EEE h:mm:ss a")
  100. sendEvent(name: "lastActivity", value: now, displayed:false)
  101.  
  102. return result
  103. }
  104.  
  105. def zwaveEvent(hubitat.zwave.commands.basicv1.BasicReport cmd, ep = null) {
  106. log.debug "BasicReport ${cmd} - ep ${ep}"
  107. if (ep) {
  108. def event
  109. childDevices.each {
  110. childDevice ->
  111. if (childDevice.deviceNetworkId == "$device.deviceNetworkId-ep$ep") {
  112. childDevice.sendEvent(name: "switch", value: cmd.value ? "on" : "off")
  113. }
  114. }
  115. if (cmd.value) {
  116. event = [createEvent([name: "switch", value: "on"])]
  117. } else {
  118. def allOff = true
  119. childDevices.each {
  120. childDevice ->
  121. if (childDevice.deviceNetworkId != "$device.deviceNetworkId-ep$ep")
  122. if (childDevice.currentState("switch").value != "off") allOff = false
  123. }
  124. if (allOff) {
  125. event = [createEvent([name: "switch", value: "off"])]
  126. } else {
  127. event = [createEvent([name: "switch", value: "on"])]
  128. }
  129. }
  130. return event
  131. }
  132. }
  133.  
  134. def zwaveEvent(hubitat.zwave.commands.basicv1.BasicSet cmd) {
  135. log.debug "BasicSet ${cmd}"
  136. def result = createEvent(name: "switch", value: cmd.value ? "on" : "off", type: "digital")
  137. def cmds = []
  138. cmds << encap(zwave.switchBinaryV1.switchBinaryGet(), 1)
  139. cmds << encap(zwave.switchBinaryV1.switchBinaryGet(), 2)
  140. //return [result, response(commands(cmds))] // returns the result of reponse()
  141. return response(commands(cmds)) // returns the result of reponse()
  142. }
  143.  
  144. def zwaveEvent(hubitat.zwave.commands.switchbinaryv1.SwitchBinaryReport cmd, ep = null) {
  145. log.debug "SwitchBinaryReport ${cmd} - ep ${ep}"
  146. if (ep) {
  147. def event
  148. def childDevice = childDevices.find {
  149. it.deviceNetworkId == "$device.deviceNetworkId-ep$ep"
  150. }
  151. if (childDevice) childDevice.sendEvent(name: "switch", value: cmd.value ? "on" : "off")
  152. if (cmd.value) {
  153. event = [createEvent([name: "switch", value: "on"])]
  154. } else {
  155. def allOff = true
  156. childDevices.each {
  157. n->
  158. if (n.deviceNetworkId != "$device.deviceNetworkId-ep$ep" && n.currentState("switch").value != "off") allOff = false
  159. }
  160. if (allOff) {
  161. event = [createEvent([name: "switch", value: "off"])]
  162. } else {
  163. event = [createEvent([name: "switch", value: "on"])]
  164. }
  165. }
  166. return event
  167. } else {
  168. def result = createEvent(name: "switch", value: cmd.value ? "on" : "off", type: "digital")
  169. def cmds = []
  170. cmds << encap(zwave.switchBinaryV1.switchBinaryGet(), 1)
  171. cmds << encap(zwave.switchBinaryV1.switchBinaryGet(), 2)
  172. return [result, response(commands(cmds))] // returns the result of reponse()
  173. }
  174. }
  175.  
  176. def zwaveEvent(hubitat.zwave.commands.multichannelv3.MultiChannelCmdEncap cmd) {
  177. log.debug "MultiChannelCmdEncap ${cmd}"
  178. def encapsulatedCommand = cmd.encapsulatedCommand([0x32: 3, 0x25: 1, 0x20: 1])
  179. if (encapsulatedCommand) {
  180. zwaveEvent(encapsulatedCommand, cmd.sourceEndPoint as Integer)
  181. }
  182. }
  183.  
  184. def zwaveEvent(hubitat.zwave.commands.manufacturerspecificv2.ManufacturerSpecificReport cmd) {
  185. log.debug "ManufacturerSpecificReport ${cmd}"
  186. def msr = String.format("%04X-%04X-%04X", cmd.manufacturerId, cmd.productTypeId, cmd.productId)
  187. log.debug "msr: $msr"
  188. updateDataValue("MSR", msr)
  189. }
  190.  
  191. def zwaveEvent(hubitat.zwave.commands.centralscenev1.CentralSceneNotification cmd) {
  192. createEvent(buttonEvent(cmd.sceneNumber, (cmd.sceneNumber == 2? "held" : "pushed"), "physical"))
  193. }
  194.  
  195. def buttonEvent(button, value, type = "digital") {
  196. sendEvent(name:"lastEvent", value: "${value != 'pushed'?' Tap '.padRight(button+1+5, '▼'):' Tap '.padRight(button+1+5, '▲')}", displayed:false)
  197. [name: value, value: button, isStateChange:true]
  198. }
  199.  
  200. def zwaveEvent(hubitat.zwave.Command cmd) {
  201. // This will capture any commands not handled by other instances of zwaveEvent
  202. // and is recommended for development so you can see every command the device sends
  203. log.debug "Unhandled Event: ${cmd}"
  204. }
  205.  
  206. def on() {
  207. log.debug "on()"
  208. commands([
  209. zwave.switchAllV1.switchAllOn(),
  210. encap(zwave.basicV1.basicGet(), 1),
  211. encap(zwave.basicV1.basicGet(), 2)
  212. ])
  213. }
  214.  
  215. def off() {
  216. log.debug "off()"
  217. commands([
  218. zwave.switchAllV1.switchAllOff(),
  219. encap(zwave.basicV1.basicGet(), 1),
  220. encap(zwave.basicV1.basicGet(), 2)
  221. ])
  222. }
  223.  
  224. def childOn(String dni) {
  225. log.debug "childOn($dni)"
  226. def cmds = []
  227. commands([
  228. encap(zwave.basicV1.basicSet(value: 0xFF), channelNumber(dni)),
  229. encap(zwave.basicV1.basicGet(), channelNumber(dni))
  230. ])
  231. }
  232.  
  233. def childOff(String dni) {
  234. log.debug "childOff($dni)"
  235. def cmds = []
  236. commands([
  237. encap(zwave.basicV1.basicSet(value: 0x00), channelNumber(dni)),
  238. encap(zwave.basicV1.basicGet(), channelNumber(dni))
  239. ])
  240. }
  241.  
  242. def childRefresh(String dni) {
  243. log.debug "childRefresh($dni)"
  244. def cmds = []
  245. cmds << new hubitat.device.HubAction(command(encap(zwave.basicV1.basicGet(), channelNumber(dni))), hubitat.device.Protocol.ZWAVE)
  246. cmds
  247. }
  248.  
  249. def poll() {
  250. log.debug "poll()"
  251. commands([
  252. encap(zwave.basicV1.basicGet(), 1),
  253. encap(zwave.basicV1.basicGet(), 2),
  254. ])
  255. }
  256.  
  257. def refresh() {
  258. log.debug "refresh()"
  259. commands([
  260. encap(zwave.basicV1.basicGet(), 1),
  261. encap(zwave.basicV1.basicGet(), 2),
  262. ])
  263. }
  264.  
  265. def ping() {
  266. log.debug "ping()"
  267. refresh()
  268. }
  269.  
  270. def installed() {
  271. refresh()
  272. }
  273.  
  274. def configure() {
  275. log.debug "configure()"
  276. def cmds = initialize()
  277. commands(cmds)
  278. }
  279.  
  280. def updated() {
  281. if (!state.lastRan || now() >= state.lastRan + 2000) {
  282. log.debug "updated()"
  283. state.lastRan = now()
  284. def cmds = initialize()
  285. commands(cmds)
  286. } else {
  287. log.debug "updated() ran within the last 2 seconds. Skipping execution."
  288. }
  289. }
  290.  
  291. def initialize() {
  292. log.debug "initialize()"
  293. if (!childDevices) {
  294. createChildDevices()
  295. } else if (device.label != state.oldLabel) {
  296. childDevices.each {
  297. if (it.label == "${state.oldLabel} (CH${channelNumber(it.deviceNetworkId)})") {
  298. def newLabel = "${device.displayName} (CH${channelNumber(it.deviceNetworkId)})"
  299. it.setLabel(newLabel)
  300. }
  301. }
  302. state.oldLabel = device.label
  303. }
  304. sendEvent(name: "checkInterval", value: 3 * 60 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID, offlinePingable: "1"])
  305. sendEvent(name: "numberOfButtons", value: 1, displayed: true)
  306. def cmds = processAssociations()
  307. cmds << zwave.configurationV1.configurationSet(scaledConfigurationValue: ledIndicator!=null? ledIndicator.toInteger() : 0, parameterNumber: 1, size: 1)
  308. cmds << zwave.configurationV1.configurationGet(parameterNumber: 1)
  309. cmds << zwave.configurationV1.configurationSet(scaledConfigurationValue: autoOff1!=null? autoOff1.toInteger() : 0, parameterNumber: 2, size: 2)
  310. cmds << zwave.configurationV1.configurationGet(parameterNumber: 2)
  311. cmds << zwave.configurationV1.configurationSet(scaledConfigurationValue: autoOff2!=null? autoOff2.toInteger() : 0, parameterNumber: 3, size: 2)
  312. cmds << zwave.configurationV1.configurationGet(parameterNumber: 3)
  313. return cmds
  314. }
  315.  
  316. def zwaveEvent(hubitat.zwave.commands.configurationv2.ConfigurationReport cmd) {
  317. log.debug "${device.displayName} parameter '${cmd.parameterNumber}' with a byte size of '${cmd.size}' is set to '${cmd.configurationValue}'"
  318. }
  319.  
  320. private encap(cmd, endpoint) {
  321. if (endpoint) {
  322. zwave.multiChannelV3.multiChannelCmdEncap(destinationEndPoint: endpoint).encapsulate(cmd)
  323. } else {
  324. cmd
  325. }
  326. }
  327.  
  328. private command(hubitat.zwave.Command cmd) {
  329. if (state.sec) {
  330. zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format()
  331. } else {
  332. cmd.format()
  333. }
  334. }
  335.  
  336. private commands(commands, delay = 1000) {
  337. delayBetween(commands.collect {
  338. command(it)
  339. }, delay)
  340. }
  341.  
  342. private channelNumber(String dni) {
  343. dni.split("-ep")[-1] as Integer
  344. }
  345. private void createChildDevices() {
  346. state.oldLabel = device.label
  347. for (i in 1..2) {
  348. addChildDevice("Switch Child Device", "${device.deviceNetworkId}-ep${i}", [completedSetup: true, label: "${device.displayName} (CH${i})",
  349. isComponent: false, componentName: "ep$i", componentLabel: "Channel $i"
  350. ])
  351. }
  352. }
  353.  
  354. def setDefaultAssociations() {
  355. def smartThingsHubID = zwaveHubNodeId.toString().format( '%02x', zwaveHubNodeId )
  356. state.defaultG1 = [smartThingsHubID]
  357. state.defaultG2 = [smartThingsHubID]
  358. state.defaultG3 = []
  359. }
  360.  
  361. def setAssociationGroup(group, nodes, action, endpoint = null){
  362. log.debug nodes
  363. log.debug action
  364. if (!state."desiredAssociation${group}") {
  365. state."desiredAssociation${group}" = nodes
  366. } else {
  367. switch (action) {
  368. case 0:
  369. state."desiredAssociation${group}" = state."desiredAssociation${group}" - nodes
  370. break
  371. case 1:
  372. log.debug nodes
  373. state."desiredAssociation${group}" = state."desiredAssociation${group}" + nodes
  374. break
  375. }
  376. }
  377. }
  378.  
  379. def processAssociations(){
  380. def cmds = []
  381. setDefaultAssociations()
  382. def associationGroups = 5
  383. if (state.associationGroups) {
  384. associationGroups = state.associationGroups
  385. } else {
  386. log.debug "Getting supported association groups from device"
  387. cmds << zwave.associationV2.associationGroupingsGet()
  388. }
  389. for (int i = 1; i <= associationGroups; i++){
  390. if(state."actualAssociation${i}" != null){
  391. if(state."desiredAssociation${i}" != null || state."defaultG${i}") {
  392. def refreshGroup = false
  393. ((state."desiredAssociation${i}"? state."desiredAssociation${i}" : [] + state."defaultG${i}") - state."actualAssociation${i}").each {
  394. log.debug "Adding node $it to group $i"
  395. cmds << zwave.associationV2.associationSet(groupingIdentifier:i, nodeId:Integer.parseInt(it,16))
  396. refreshGroup = true
  397. }
  398. ((state."actualAssociation${i}" - state."defaultG${i}") - state."desiredAssociation${i}").each {
  399. log.debug "Removing node $it from group $i"
  400. cmds << zwave.associationV2.associationRemove(groupingIdentifier:i, nodeId:Integer.parseInt(it,16))
  401. refreshGroup = true
  402. }
  403. if (refreshGroup == true) cmds << zwave.associationV2.associationGet(groupingIdentifier:i)
  404. else log.debug "There are no association actions to complete for group $i"
  405. }
  406. } else {
  407. log.debug "Association info not known for group $i. Requesting info from device."
  408. cmds << zwave.associationV2.associationGet(groupingIdentifier:i)
  409. }
  410. }
  411. return cmds
  412. }
  413.  
  414. void zwaveEvent(hubitat.zwave.commands.associationv2.AssociationReport cmd) {
  415. def temp = []
  416. if (cmd.nodeId != []) {
  417. cmd.nodeId.each {
  418. temp += it.toString().format( '%02x', it.toInteger() ).toUpperCase()
  419. }
  420. }
  421. state."actualAssociation${cmd.groupingIdentifier}" = temp
  422. log.debug "Associations for Group ${cmd.groupingIdentifier}: ${temp}"
  423. updateDataValue("associationGroup${cmd.groupingIdentifier}", "$temp")
  424. }
  425.  
  426. def zwaveEvent(hubitat.zwave.commands.associationv2.AssociationGroupingsReport cmd) {
  427. log.debug "Supported association groups: ${cmd.supportedGroupings}"
  428. state.associationGroups = cmd.supportedGroupings
  429. createEvent(name: "groups", value: cmd.supportedGroupings)
  430. }
  431.  
  432. void zwaveEvent(hubitat.zwave.commands.versionv1.VersionReport cmd) {
  433. log.debug cmd
  434. if(cmd.applicationVersion && cmd.applicationSubVersion) {
  435. def firmware = "${cmd.applicationVersion}.${cmd.applicationSubVersion.toString().padLeft(2,'0')}"
  436. state.needfwUpdate = "false"
  437. sendEvent(name: "status", value: "fw: ${firmware}")
  438. updateDataValue("firmware", firmware)
  439. }
  440. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement