Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
/**
*
* 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.
*
* Based on on original by Lazcad / RaveTam
* 01/2017 corrected the temperature reading
* 02/2017 added heartbeat to monitor connectivity health of outlet
* 02/2017 added multiattribute tile
* bspranger - renamed to bspranger to remove confusion of a4refillpad
*/
metadata {
definition (name: "Xiaomi Zigbee Outlet", namespace: "bspranger", author: "bspranger") {
capability "Actuator"
capability "Configuration"
capability "Refresh"
capability "Switch"
capability "Temperature Measurement"
attribute "lastCheckin", "string"
}
// simulator metadata
simulator {
// status messages
status "on": "on/off: 1"
status "off": "on/off: 0"
// reply messages
reply "zcl on-off on": "on/off: 1"
reply "zcl on-off off": "on/off: 0"
}
preferences {
//Date & Time Config
input description: "", type: "paragraph", element: "paragraph", title: "DATE & CLOCK"
input name: "dateformat", type: "enum", title: "Set Date Format\n US (MDY) - UK (DMY) - Other (YMD)", description: "Date Format", options:["US","UK","Other"]
input name: "clockformat", type: "bool", title: "Use 24 hour clock?"
}
}
// Parse incoming device messages to generate events
def parse(String description) {
log.debug "Parsing '${description}'"
def value = zigbee.parse(description)?.text
log.debug "Parse: $value"
Map map = [:]
if (description?.startsWith('catchall:')) {
map = parseCatchAllMessage(description)
}
else if (description?.startsWith('read attr -')) {
map = parseReportAttributeMessage(description)
}
else if (description?.startsWith('on/off: ')){
def resultMap = zigbee.getKnownDescription(description)
log.debug "${resultMap}"
map = parseCustomMessage(description)
}
log.debug "Parse returned $map"
// send event for heartbeat
def now = formatDate()
sendEvent(name: "lastCheckin", value: now)
def results = map ? createEvent(map) : null
return results;
}
private Map parseCatchAllMessage(String description) {
Map resultMap = [:]
def cluster = zigbee.parse(description)
log.debug cluster
if (cluster.clusterId == 0x0006 && cluster.command == 0x01){
def onoff = cluster.data[-1]
if (onoff == 1)
resultMap = createEvent(name: "switch", value: "on")
else if (onoff == 0)
resultMap = createEvent(name: "switch", value: "off")
}
return resultMap
}
private Map parseReportAttributeMessage(String description) {
Map descMap = (description - "read attr - ").split(",").inject([:]) { map, param ->
def nameAndValue = param.split(":")
map += [(nameAndValue[0].trim()):nameAndValue[1].trim()]
}
//log.debug "Desc Map: $descMap"
Map resultMap = [:]
if (descMap.cluster == "0001" && descMap.attrId == "0020") {
resultMap = getBatteryResult(convertHexToInt(descMap.value / 2))
}
if (descMap.cluster == "0002" && descMap.attrId == "0000") {
resultMap = createEvent(name: "temperature", value: zigbee.parseHATemperatureValue("temperature: " + (convertHexToInt(descMap.value) / 2), "temperature: ", getTemperatureScale()), unit: getTemperatureScale())
log.debug "Temperature Hex convert to ${resultMap.value}%"
}
else if (descMap.cluster == "0008" && descMap.attrId == "0000") {
resultMap = createEvent(name: "switch", value: "off")
}
return resultMap
}
def off() {
log.debug "off()"
sendEvent(name: "switch", value: "off")
"st cmd 0x${device.deviceNetworkId} 1 6 0 {}"
}
def on() {
log.debug "on()"
sendEvent(name: "switch", value: "on")
"st cmd 0x${device.deviceNetworkId} 1 6 1 {}"
}
def refresh() {
log.debug "refreshing"
[
"st rattr 0x${device.deviceNetworkId} 1 6 0", "delay 500",
"st rattr 0x${device.deviceNetworkId} 1 6 0", "delay 250",
"st rattr 0x${device.deviceNetworkId} 1 2 0", "delay 250",
"st rattr 0x${device.deviceNetworkId} 1 1 0", "delay 250",
"st rattr 0x${device.deviceNetworkId} 1 0 0"
]
}
private Map parseCustomMessage(String description) {
def result
if (description?.startsWith('on/off: ')) {
if (description == 'on/off: 0')
result = createEvent(name: "switch", value: "off")
else if (description == 'on/off: 1')
result = createEvent(name: "switch", value: "on")
}
return result
}
private Integer convertHexToInt(hex) {
Integer.parseInt(hex,16)
}
def formatDate() {
def correctedTimezone = ""
def timeString = clockformat ? "HH:mm:ss" : "h:mm:ss aa"
// If user's hub timezone is not set, display error messages in log and events log, and set timezone to GMT to avoid errors
if (!(location.timeZone)) {
correctedTimezone = TimeZone.getTimeZone("GMT")
log.error "${device.displayName}: Time Zone not set, so GMT was used. Please set up your location in the SmartThings mobile app."
sendEvent(name: "error", value: "", descriptionText: "ERROR: Time Zone not set, so GMT was used. Please set up your location in the SmartThings mobile app.")
}
else {
correctedTimezone = location.timeZone
}
if (dateformat == "US" || dateformat == "" || dateformat == null) {
return new Date().format("EEE MMM dd yyyy ${timeString}", correctedTimezone)
}
else if (dateformat == "UK") {
return new Date().format("EEE dd MMM yyyy ${timeString}", correctedTimezone)
}
else {
return new Date().format("EEE yyyy MMM dd ${timeString}", correctedTimezone)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment