Skip to content

Commit

Permalink
Merge pull request SmartThingsCommunity#4154 from SmartThingsCommunit…
Browse files Browse the repository at this point in the history
…y/staging

Rolling up staging to production for deploy
  • Loading branch information
workingmonk authored Apr 9, 2019
2 parents 4f81441 + 7e3434d commit 9efdab3
Show file tree
Hide file tree
Showing 10 changed files with 297 additions and 11 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
/**
* Copyright 2019 SmartThings
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
* for the specific language governing permissions and limitations under the License.
*
*/

metadata {
definition (name: "Glentronics Connection Module", namespace: "smartthings", author: "SmartThings") {
capability "Sensor"
capability "Water Sensor"
capability "Battery"
capability "Power Source"
capability "Health Check"

fingerprint mfr:"0084", prod:"0093", model:"0114", deviceJoinName: "Glentronics Connection Module"
}

tiles (scale: 2){
multiAttributeTile(name: "water", type: "generic", width: 6, height: 4) {
tileAttribute("device.water", key: "PRIMARY_CONTROL") {
attributeState("dry", icon: "st.alarm.water.dry", backgroundColor: "#ffffff")
attributeState("wet", icon: "st.alarm.water.wet", backgroundColor: "#00A0DC")
}
}
valueTile("battery", "device.battery", inactiveLabel: true, decoration: "flat", width: 2, height: 2) {
state "battery", label: 'Backup battery: ${currentValue}%', unit: ""
}
valueTile("powerSource", "device.powerSource", width: 2, height: 1, inactiveLabel: true, decoration: "flat") {
state "powerSource", label: 'Power Source: ${currentValue}', backgroundColor: "#ffffff"
}
main "water"
details(["water", "battery", "powerSource"])
}
}

def parse(String description) {
def result
if (description.startsWith("Err")) {
result = createEvent(descriptionText:description, displayed:true)
} else {
def cmd = zwave.parse(description)
if (cmd) {
result = zwaveEvent(cmd)
}
}
log.debug "Parse returned: ${result.inspect()}"
return result
}

def installed() {
//There's no possibility for initial poll, so to avoid empty fields, assuming everything is functioning correctly
sendEvent(name: "battery", value: 100, unit: "%")
sendEvent(name: "water", value: "dry")
sendEvent(name: "powerSource", value: "mains")
sendEvent(name: "checkInterval", value: 2 * 60 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID, offlinePingable: "1"])
}

def ping() {
response(zwave.versionV1.versionGet().format())
}

def getPowerEvent(event) {
if (event == 0x02) {
createEvent(name: "powerSource", value: "battery", descriptionText: "Pump is powered with backup battery")
} else if (event == 0x03) {
createEvent(name: "powerSource", value: "mains", descriptionText: "Pump is powered with AC mains")
} else if (event == 0x0B) {
createEvent(name: "battery", value: 1, unit: "%", descriptionText: "Backup battery critically low")
} else if (event == 0x0D) {
createEvent(name: "battery", value: 100, unit: "%", descriptionText: "Backup battery is fully charged")
}
}

def getManufacturerSpecificEvent(cmd) {
if (cmd.event == 3) {
if (cmd.eventParameter[0] == 0) {
createEvent(name: "water", value: "dry", descriptionText: "Water alarm has been cleared")
} else if (cmd.eventParameter[0] == 2) {
createEvent(name: "water", value: "wet", descriptionText: "High water alarm")
}
}
}

def zwaveEvent(physicalgraph.zwave.commands.notificationv3.NotificationReport cmd) {
log.debug "NotificationReport: ${cmd}"
if (cmd.notificationType == 8) {
getPowerEvent(cmd.event)
} else if (cmd.notificationType == 9) {
getManufacturerSpecificEvent(cmd)
}
}

def zwaveEvent(physicalgraph.zwave.commands.versionv1.VersionReport cmd) {
createEvent(descriptionText: "Device has responded to ping()")
}

def zwaveEvent(physicalgraph.zwave.Command cmd) {
log.warn "Unhandled command: ${cmd}"
createEvent(descriptionText: "Unhandled event came in")
}
27 changes: 25 additions & 2 deletions devicetypes/smartthings/mobile-presence.src/mobile-presence.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,30 @@ metadata {
}

def parse(String description) {
def name = parseName(description)
def value = parseValue(description)

/*
* When 'not present' event received (left case)
* -> If occupancy value is not 'unoccupied', occupancy value should be 'unoccupied' before posting 'not present'
* When 'occupied' event received (inside case)
* -> If presence value is not 'present', presence value should be 'present' before posting 'occupied'
*/
switch(value) {
case "not present":
if (device.currentState("occupancy") != "unoccupied") sendEvent(generateEvent("occupancy: 0"))
break
case "occupied":
if (device.currentState("presence") != "present") sendEvent(generateEvent("presence: 1"))
break
}

sendEvent(generateEvent(description))
}

private generateEvent(String description) {
log.debug "description: $description"
def value = parseValue(description)
def name = parseName(description)
def linkText = getLinkText(device)
def descriptionText = parseDescriptionText(linkText, value, description)
def handlerName = getState(value)
Expand All @@ -57,7 +79,8 @@ def parse(String description) {
isStateChange: isStateChange,
displayed: displayed(description, isStateChange)
]
log.debug "Parse returned $results.descriptionText"
log.debug "GenerateEvent returned $results.descriptionText"

return results
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,4 @@
#==============================================================================

# Chinese
'''Motion Sensor'''.zh-cn=人体传感器 Samsung Connect (IM6001-MTP)
'''Motion Sensor'''.zh-cn=人体传感器
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,4 @@
#==============================================================================

# Chinese
'''Multipurpose Sensor'''.zh-cn=门窗传感器 Samsung Connect (IM6001-MPP)
'''Multipurpose Sensor'''.zh-cn=门窗传感器
Original file line number Diff line number Diff line change
Expand Up @@ -145,10 +145,10 @@ def ping() {

def configure() {
log.debug "configure"
sendEvent(name: "checkInterval", value:6 * 60 * 60 + 2 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID, offlinePingable: "1"])
Integer minReportTime = 0
Integer maxReportTime = 180
Integer reportableChange = null
sendEvent(name: "checkInterval", value: maxReportTime * 2 + 10 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID, offlinePingable: "1"])
return refresh() + zigbee.enrollResponse() + zigbee.configureReporting(zigbee.POWER_CONFIGURATION_CLUSTER, 0x0021, DataType.UINT8, 30, 21600, 0x10) +
zigbee.configureReporting(zigbee.IAS_ZONE_CLUSTER, zigbee.ATTRIBUTE_IAS_ZONE_STATUS, DataType.BITMAP16, minReportTime, maxReportTime, reportableChange)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@
# under the License.

# Chinese
'''A60 Dim Bulb'''.zh-cn=智能球泡灯 Samsung Connect
'''A60 Dim Bulb'''.zh-cn=智能球泡灯
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@
# under the License.

# Chinese
'''Switch 1'''.zh-cn=智能墙面开关(单火线二路版) Samsung Connect (T21W2Z) 1
'''Switch 1'''.zh-cn=智能墙面开关(单火线二路版) 1
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
/**
*
* Copyright 2019 SmartThings
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
* for the specific language governing permissions and limitations under the License.
*/
import physicalgraph.zigbee.zcl.DataType

metadata {
definition(name: "ZigBee Window Shade", namespace: "smartthings", author: "SmartThings", ocfDeviceType: "oic.d.blind", mnmn: "SmartThings", vid: "generic-shade") {
capability "Actuator"
capability "Configuration"
capability "Refresh"
capability "Window Shade"
capability "Health Check"
capability "Switch Level"

command "pause"

fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0102", outClusters: "0019", model: "E2B0-KR000Z0-HA", deviceJoinName: "SOMFY Blind Controller/eZEX" // SY-IoT201-BD
}


tiles(scale: 2) {
multiAttributeTile(name:"windowShade", type: "generic", width: 6, height: 4) {
tileAttribute("device.windowShade", key: "PRIMARY_CONTROL") {
attributeState "open", label: 'Open', action: "close", icon: "http://www.ezex.co.kr/img/st/window_open.png", backgroundColor: "#00A0DC", nextState: "closing"
attributeState "closed", label: 'Closed', action: "open", icon: "http://www.ezex.co.kr/img/st/window_close.png", backgroundColor: "#ffffff", nextState: "opening"
attributeState "partially open", label: 'Partially open', action: "close", icon: "http://www.ezex.co.kr/img/st/window_open.png", backgroundColor: "#d45614", nextState: "closing"
attributeState "opening", label: 'Opening', action: "pause", icon: "http://www.ezex.co.kr/img/st/window_open.png", backgroundColor: "#00A0DC", nextState: "partially open"
attributeState "closing", label: 'Closing', action: "pause", icon: "http://www.ezex.co.kr/img/st/window_close.png", backgroundColor: "#ffffff", nextState: "partially open"
}
}
standardTile("contPause", "device.switch", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
state "pause", label:"", icon:'st.sonos.pause-btn', action:'pause', backgroundColor:"#cccccc"
}
standardTile("refresh", "device.refresh", inactiveLabel: false, decoration: "flat", width: 2, height: 1) {
state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh"
}
valueTile("shadeLevel", "device.level", width: 4, height: 1) {
state "level", label: 'Shade is ${currentValue}% up', defaultState: true
}
controlTile("levelSliderControl", "device.level", "slider", width:2, height: 1, inactiveLabel: false) {
state "level", action:"switch level.setLevel"
}

main "windowShade"
details(["windowShade", "contPause", "shadeLevel", "levelSliderControl", "refresh"])
}
}

private getCLUSTER_WINDOW_COVERING() { 0x0102 }
private getATTRIBUTE_POSITION_LIFT() { 0x0008 }

private List<Map> collectAttributes(Map descMap) {
List<Map> descMaps = new ArrayList<Map>()

descMaps.add(descMap)

if (descMap.additionalAttrs) {
descMaps.addAll(descMap.additionalAttrs)
}

return descMaps
}

// Parse incoming device messages to generate events
def parse(String description) {
log.debug "description:- ${description}"
if (description?.startsWith("read attr -")) {
Map descMap = zigbee.parseDescriptionAsMap(description)
if (descMap?.clusterInt == CLUSTER_WINDOW_COVERING && descMap.value) {
log.debug "attr: ${descMap?.attrInt}, value: ${descMap?.value}, decValue: ${Integer.parseInt(descMap.value, 16)}, ${device.getDataValue("model")}"
List<Map> descMaps = collectAttributes(descMap)
def liftmap = descMaps.find { it.attrInt == ATTRIBUTE_POSITION_LIFT }
if (liftmap) {
if (liftmap.value == "64") { //open
sendEvent(name: "windowShade", value: "open")
sendEvent(name: "level", value: "100")
} else if (liftmap.value == "00") { //closed
sendEvent(name: "windowShade", value: "closed")
sendEvent(name: "level", value: "0")
} else {
sendEvent(name: "windowShade", value: "partially open")
sendEvent(name: "level", value: zigbee.convertHexToInt(attr.value))
}
}
}
}
}

def close() {
log.info "close()"
zigbee.command(CLUSTER_WINDOW_COVERING, 0x01)
}

def open() {
log.info "open()"
zigbee.command(CLUSTER_WINDOW_COVERING, 0x00)
}

def setLevel(data) {
log.info "setLevel()"
zigbee.command(CLUSTER_WINDOW_COVERING, 0x05, zigbee.convertToHexString(data, 2))
}

def pause() {
log.info "pause()"
zigbee.command(CLUSTER_WINDOW_COVERING, 0x02)
}

/**
* PING is used by Device-Watch in attempt to reach the Device
* */
def ping() {
return refresh()
}

def refresh() {
log.info "refresh()"
def cmds = zigbee.readAttribute(CLUSTER_WINDOW_COVERING, ATTRIBUTE_POSITION_LIFT)
return cmds
}

def configure() {
// Device-Watch allows 2 check-in misses from device + ping (plus 2 min lag time)
log.info "configure()"
sendEvent(name: "checkInterval", value: 2 * 60 * 60 + 2 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
log.debug "Configuring Reporting and Bindings."
zigbee.configureReporting(CLUSTER_WINDOW_COVERING, ATTRIBUTE_POSITION_LIFT, DataType.UINT8, 0, 600, null)
}
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,9 @@ def fanEvents(physicalgraph.zwave.Command cmd) {
def value = (cmd.value ? "on" : "off")
def result = [createEvent(name: "switch", value: value)]
result << createEvent(name: "level", value: cmd.value == 99 ? 100 : cmd.value)
result << createEvent(name: "fanSpeed", value: Math.round(cmd.value/33))
def fan_level = Math.ceil(cmd.value/33) as int
// if (cmd.value < 33 && cmd.value >= 1) fan_level = 1 //sometimes we get "1" when the device is on low
result << createEvent(name: "fanSpeed", value: fan_level)
return result
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ metadata {
fingerprint mfr:"0086", prod:"0003", model:"0084", deviceJoinName: "Aeotec Nano Switch 1"
fingerprint mfr:"0086", prod:"0103", model:"0084", deviceJoinName: "Aeotec Nano Switch 1"
fingerprint mfr: "0000", cc: "0x5E,0x25,0x27,0x32,0x81,0x71,0x60,0x8E,0x2C,0x2B,0x70,0x86,0x72,0x73,0x85,0x59,0x98,0x7A,0x5A", ccOut:"0x82", ui:"0x8700", deviceJoinName: "Aeotec Nano Switch 1"
fingerprint mfr: "027A", prod: "A000", model: "A004", deviceJoinName: "Zooz ZEN Power Strip"
fingerprint mfr: "027A", prod: "A000", model: "A003", deviceJoinName: "Zooz Double Plug"
}

tiles(scale: 2){
Expand Down Expand Up @@ -140,15 +142,28 @@ private createMeterEventMap(cmd) {
eventMap
}

// cmd.endPoints includes the USB ports but we don't want to expose them as child devices since they cannot be controlled so hardcode to just include the outlets
def zwaveEvent(physicalgraph.zwave.commands.multichannelv3.MultiChannelEndPointReport cmd, ep = null) {
if(!childDevices) {
addChildSwitches(cmd.endPoints)
if (isZoozZenStripV2()) {
addChildSwitches(5)
} else if (isZoozDoublePlug()) {
addChildSwitches(2)
} else {
addChildSwitches(cmd.endPoints)
}
}
response([
resetAll(),
refreshAll()
resetAll(),
refreshAll()
])
}
def isZoozZenStripV2() {
zwaveInfo.mfr.equals("027A") && zwaveInfo.model.equals("A004")
}
def isZoozDoublePlug() {
zwaveInfo.mfr.equals("027A") && zwaveInfo.model.equals("A003")
}

def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.ManufacturerSpecificReport cmd, ep = null) {
def mfr = Integer.toHexString(cmd.manufacturerId)
Expand Down

0 comments on commit 9efdab3

Please sign in to comment.