Code by Scott שאול בן ישוע
Verified Commit 0416b30d authored by Sha'ul ben Yeshua's avatar Sha'ul ben Yeshua 🎗
Browse files

added public drivers for HE

parent a048f797
/**
* Copyright 2019 Scott Grayban
*
* 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.
*
* FortrezZ Siren Strobe Alarm
*/
metadata {
definition (
name: "FortrezZ SSA1/SSA2 US",
namespace: "sgrayban",
author: "Scott Grayban",
importUrl: "https://raw.githubusercontent.com/sgrayban/Hubitat-Ports/master/Drivers/FortrezZ/FortrezZ_SSA1-2-US.groovy"
)
{
capability "Actuator"
capability "Switch"
capability "Sensor"
capability "Alarm"
capability "Polling"
capability "Refresh"
command "test"
fingerprint deviceId: "0x1100", inClusters: "0x26,0x71"
fingerprint mfr:"0084", prod:"0313", model:"010B", deviceJoinName: "FortrezZ SSA1US/SSA2 US"
}
preferences {
input "refreshEvery", "enum", title: "Enable auto refresh every XX Minutes", required: false, defaultValue: false, //RK
options: [5:"5 minutes",10:"10 minutes",15:"15 minutes",30:"30 minutes"] //RK
input "locale", "enum", title: "Choose refresh date format", required: true, defaultValue: true, //RK
options: [US:"US MM/DD/YYYY",UK:"UK DD/MM/YYYY"] //RK
input name: "debugOutput", type: "bool", title: "Enable debug logging?", defaultValue: true
input name: "txtEnable", type: "bool", title: "Enable descriptionText logging", defaultValue: true //RK
}
}
def installed() {
log.debug "Installed"
refresh()
}
// App Version *********************************************************************************
def setVersion(){
state.Version = "1.0.1"
state.InternalName = "FortrezzSiren"
sendEvent(name: "DriverAuthor", value: "sgrayban")
sendEvent(name: "DriverVersion", value: state.Version)
sendEvent(name: "DriverStatus", value: state.Status)
}
def updated() {
log.debug "Updated"
log.info "Preferences updated..."
log.warn "Debug logging is: ${debugOutput == true}"
unschedule()
// RK start
if (refreshEvery != null) {
"runEvery${refreshEvery}Minutes"(autorefresh)
log.info "Refresh set for every ${refreshEvery} Minutes"
} else {
runEvery30Minutes (autorefresh)
log.info "Refresh set for every 30 Minutes"
}
if (debugOutput) runIn(1800,logsOff)
state.LastRefresh = new Date().format("YYYY/MM/dd \n HH:mm:ss", location.timeZone)
// RK stop
version()
refresh()
}
def on() {
logDebug "Executing switch.on"
[
zwave.basicV1.basicSet(value: 0xFF).format(),
zwave.basicV1.basicGet().format()
]
}
def off() {
logDebug "Executing switch.off"
[
zwave.basicV1.basicSet(value: 0x00).format(),
zwave.basicV1.basicGet().format()
]
}
def test() {
logDebug "Executing switch.test"
[
zwave.basicV1.basicSet(value: 0xFF).format(),
"delay 3000",
zwave.basicV1.basicSet(value: 0x00).format(),
zwave.basicV1.basicGet().format()
]
}
def strobe() {
logDebug "Executing switch.strobe"
[
zwave.basicV1.basicSet(value: 0x21).format(),
zwave.basicV1.basicGet().format()
]
}
def siren() {
logDebug "Executing switch.siren"
[
zwave.basicV1.basicSet(value: 0x42).format(),
zwave.basicV1.basicGet().format()
]
}
def both() {
logDebug "Executing switch.both"
[
zwave.basicV1.basicSet(value: 0xFF).format(),
zwave.basicV1.basicGet().format()
]
}
def logsOff(){
log.warn "debug logging auto disabled..."
device.updateSetting("debugOutput",[value:"false",type:"bool"])
}
def initialize() {
log.info "initialize"
if (txtEnable) log.info "initialize" //RK
refresh()
}
def autorefresh() {
if (locale == "UK") {
if (debugOutput) log.info "Get last UK Date DD/MM/YYYY"
state.LastRefresh = new Date().format("d/MM/YYYY \n HH:mm:ss", location.timeZone)
sendEvent(name: "LastRefresh", value: state.LastRefresh, descriptionText: "Last refresh performed")
}
if (locale == "US") {
if (debugOutput) log.info "Get last US Date MM/DD/YYYY"
state.LastRefresh = new Date().format("MM/d/YYYY \n HH:mm:ss", location.timeZone)
sendEvent(name: "LastRefresh", value: state.LastRefresh, descriptionText: "Last refresh performed")
}
if (txtEnable) log.info "Executing 'auto refresh'" //RK
refresh()
}
def parse(String description) {
logDebug "parse($description)"
def result = null
def cmd = zwave.parse(description, [0x20: 1])
if (cmd) {
result = createEvents(cmd)
}
logDebug "Parse returned ${result?.descriptionText}"
return result
}
def createEvents(hubitat.zwave.commands.basicv1.BasicReport cmd)
{
def switchValue = cmd.value ? "on" : "off"
def alarmValue
if (cmd.value == 0) {
alarmValue = "off"
}
else if (cmd.value <= 33) {
alarmValue = "strobe"
}
else if (cmd.value <= 66) {
alarmValue = "siren"
}
else {
alarmValue = "both"
}
[
createEvent([name: "switch", value: switchValue, type: "digital", displayed: false]),
createEvent([name: "alarm", value: alarmValue, type: "digital"])
]
}
def zwaveEvent(hubitat.zwave.Command cmd) {
logDebug "UNEXPECTED COMMAND: $cmd"
}
private logDebug(msg) {
if (settings?.debugOutput || settings?.debugOutput == null) {
log.debug "$msg"
}
}
private dbCleanUp() {
unschedule()
state.remove("version")
state.remove("Version")
}
/**
* PING is used by Device-Watch in attempt to reach the Device
* */
def ping() {
logDebug "ping"
zwave.basicV1.basicGet().format()
}
// handle commands
//RK Updated to include last refreshed
def poll() {
if (locale == "UK") {
if (debugOutput) log.info "Get last UK Date DD/MM/YYYY"
state.LastRefresh = new Date().format("d/MM/YYYY \n HH:mm:ss", location.timeZone)
sendEvent(name: "LastRefresh", value: state.LastRefresh, descriptionText: "Last refresh performed")
}
if (locale == "US") {
if (debugOutput) log.info "Get last US Date MM/DD/YYYY"
state.LastRefresh = new Date().format("MM/d/YYYY \n HH:mm:ss", location.timeZone)
sendEvent(name: "LastRefresh", value: state.LastRefresh, descriptionText: "Last refresh performed")
}
if (txtEnable) log.info "Executing 'poll'" //RK
refresh()
}
def refresh() {
logDebug "refresh"
ping()
}
// Check Version ***** with great thanks and acknowlegment to Cobra (github CobraVmax) for his original code **************
def version(){
updatecheck()
schedule("0 0 18 1/1 * ? *", updatecheck) // Cron schedule
// schedule("0 0/1 * 1/1 * ? *", updatecheck) // Test Cron schedule
}
def updatecheck(){
setVersion()
def paramsUD = [uri: "https://sgrayban.github.io/Hubitat-Public/version.json"]
try {
httpGet(paramsUD) { respUD ->
if (txtEnable) log.warn " Version Checking - Response Data: ${respUD.data}" // Troubleshooting Debug Code - Uncommenting this line should show the JSON response from your webserver
def copyrightRead = (respUD.data.copyright)
state.Copyright = copyrightRead
def newVerRaw = (respUD.data.versions.Driver.(state.InternalName))
def newVer = (respUD.data.versions.Driver.(state.InternalName).replace(".", ""))
def currentVer = state.Version.replace(".", "")
state.UpdateInfo = (respUD.data.versions.UpdateInfo.Driver.(state.InternalName))
state.author = (respUD.data.author)
state.icon = (respUD.data.icon)
if(newVer == "NLS"){
state.Status = "<b>** This driver is no longer supported by $state.author **</b>"
log.warn "** This driver is no longer supported by $state.author **"
}
else if(currentVer < newVer){
state.Status = "<b>New Version Available (Version: $newVerRaw)</b>"
log.warn "** There is a newer version of this driver available (Version: $newVerRaw) **"
log.warn "** $state.UpdateInfo **"
}
else if(currentVer > newVer){
state.Status = "<b>You are using a Test version of this Driver (Version: $newVerRaw)</b>"
}
else{
state.Status = "Current"
log.info "You are using the current version of this driver"
}
} // httpGet
} // try
catch (e) {
log.error "Something went wrong: CHECK THE JSON FILE AND IT'S URI - $e"
}
if(state.Status == "Current"){
state.UpdateInfo = "Up to date"
sendEvent(name: "DriverUpdate", value: state.UpdateInfo)
sendEvent(name: "DriverStatus", value: state.Status)
}
else {
sendEvent(name: "DriverUpdate", value: state.UpdateInfo)
sendEvent(name: "DriverStatus", value: state.Status)
}
sendEvent(name: "DriverAuthor", value: "sgrayban")
sendEvent(name: "DriverVersion", value: state.Version)
}
# FortrezZ Siren Strobe Alarm
Product Features
Protect your home with a strobe light and 110db siren.
Choose between 3 modes: siren only, strobe only, or siren and strobe.
Tamper proof feature uses 9V battery backup to sound alarm if power is disconnected.
Works with Hubitat Hub.
Benefits with Hubitat
Control your FortrezZ alarm and other connected devices.
Automate your FortrezZ alarm with Hubitat and set it to turn on when doors or windows are opened unexpectedly, when there’s movement in your home, and much more.
Manage your FortrezZ alarm and other connected devices with the Hubitat Rule Machine.
Technical Information
Model Number: SSA1US, SSA2US
Color: Clear Lens, Red Lens
Dimensions: 1.8" x 4.4" x 4.4"
Weight: 0.5 lb
Protocol: Z-Wave
Power Source: Battery, Wall-Powered
Battery Type: 9V
![SSA1/2](SSA1-2.png)
This diff is collapsed.
/*
Halo Smoke Alarm
Copyright 2016, 2017, 2018, 2019 Hubitat Inc. All Rights Reserved
2019-02-12 2.0.6 maxwell
-update enrollResponse with delay
2018-09-28 maxwell
-initial pub
*/
import hubitat.zigbee.clusters.iaszone.ZoneStatus
metadata {
definition (name: "Halo Smoke Alarm", namespace: "hubitat", author: "Mike Maxwell") {
capability "Configuration"
capability "Switch"
capability "Switch Level"
capability "Color Control"
capability "Relative Humidity Measurement"
capability "Temperature Measurement"
capability "Pressure Measurement"
capability "Smoke Detector"
capability "Carbon Monoxide Detector"
capability "Refresh"
capability "Sensor"
capability "Actuator"
fingerprint inClusters: "0000,0001,0003,0402,0403,0405,0500,0502", manufacturer: "HaloSmartLabs", model: "haloWX", deviceJoinName: "Halo Smoke Alarm"
}
preferences {
input name: "logEnable", type: "bool", title: "Enable debug logging", defaultValue: true
input name: "txtEnable", type: "bool", title: "Enable descriptionText logging", defaultValue: true
}
}
def logsOff(){
log.warn "debug logging disabled..."
device.updateSetting("logEnable",[value:"false",type:"bool"])
}
def updated(){
log.info "updated..."
log.warn "debug logging is: ${logEnable == true}"
log.warn "description logging is: ${txtEnable == true}"
if (logEnable) runIn(1800,logsOff)
}
def installed(){
sendEvent(name:"smoke", value:"clear")
sendEvent(name:"carbonMonoxide", value:"clear")
}
def parse(String description) {
if (logEnable) log.debug "parse: ${description}"
def result = []
if (description?.startsWith("enroll request")) {
List cmds = zigbee.enrollResponse(1200)
result = cmds?.collect { new hubitat.device.HubAction(it, hubitat.device.Protocol.ZIGBEE) }
} else {
if (description?.startsWith("zone status")) {
result = parseIasMessage(description)
} else {
result = parseReportAttributeMessage(description)
}
}
return result
}
private parseReportAttributeMessage(String description) {
def descMap = zigbee.parseDescriptionAsMap(description)
if (logEnable) log.debug "zigbee.parseDescriptionAsMap-read attr: ${descMap}"
def result = []
def cluster = descMap.cluster ?: descMap.clusterId
switch(cluster) {
case "0405":
getHumidityResult(descMap.value)
break
case "0402":
getTemperatureResult(descMap.value)
break
case "0403":
getPressureResult(descMap.value)
break
case "FD00":
getAlarmResult(descMap.data[0])
break
/*
case "FD01": //
log.debug "FD01- cmd:${descMap.command}, data:${descMap.data}"
break
case "FD02": //
//data:[03] ??
log.debug "FD02- cmd:${descMap.command}, data:${descMap.data}"
break
case "0500": //
// cmd:04, data:[00]
log.debug "0500- cmd:${descMap.command}, data:${descMap.data}"
break
*/
case "0006": //switch events
getSwitchResult(descMap.value)
break
case "0008": //level Events
getLevelResult(descMap.value)
break
case "0300": //color events
getColorResult(descMap.value,descMap.attrInt)
break
default :
if (logEnable) log.warn "parseReportAttributeMessage- skip descMap:${descMap}, description:${description}"
break
}
return result
}
private parseIasMessage(String description) {
ZoneStatus zs = zigbee.parseZoneStatus(description)
if (zs.alarm1) getAlarmResult("AL1")
if (zs.alarm2) getAlarmResult("AL2")
if (zs.alarm1 == 0 && zs.alarm2 == 0) getAlarmResult("00")
}
private getAlarmResult(rawValue){
if (rawValue == null) return
def value
def name
def descriptionText = "${device.displayName} "
switch (rawValue) {
case "00": //cleared
if (device.currentValue("smoke") == "detected") {
descriptionText = "${descriptionText} smoke is clear"
sendEvent(name:"smoke", value:"clear",descriptionText:descriptionText)
} else if (device.currentValue("carbonMonoxide") == "detected") {
descriptionText = "${descriptionText} carbon monoxide is clear"
sendEvent(name:"carbonMonoxide", value:"clear",descriptionText:descriptionText)
} else {
descriptionText = "${descriptionText} smoke and carbon monoxide are clear"
sendEvent(name:"smoke", value:"clear")
sendEvent(name:"carbonMonoxide", value:"clear")
}
break
/*
case "04": //Elevated Smoke Detected (pre)
descriptionText = "${descriptionText} smoke was detected (pre alert)"
sendEvent(name:"smoke", value:"detected",descriptionText:"${descriptionText} smoke was detected")
descriptionText = "${descriptionText} smoke was detected (pre alert)"
break
case "07": //Smoke Detected, send again, force state change
sendEvent(name:"smoke", value:"detected",descriptionText:"${descriptionText} smoke was detected", isStateChange: true)
descriptionText = "${descriptionText} smoke was detected"
break
*/
case "09": //Silenced
log.debug "getAlarmResult- Silenced"
break
case "AL1":
descriptionText = "${descriptionText} smoke was detected"
sendEvent(name:"smoke", value:"detected",descriptionText:descriptionText, isStateChange: true)
break
case "AL2":
descriptionText = "${descriptionText} carbon monoxide was detected"
sendEvent(name:"carbonMonoxide", value:"detected",descriptionText:descriptionText, isStateChange: true)
break
default :
descriptionText = "${descriptionText} getAlarmResult- skipped:${value}"
return
}
if (txtEnable) log.info "${descriptionText}"
}
private getHumidityResult(valueRaw){
if (valueRaw == null) return
def value = Integer.parseInt(valueRaw, 16) / 100
def descriptionText = "${device.displayName} RH is ${value}%"
if (txtEnable) log.info "${descriptionText}"
sendEvent(name:"humidity", value:value, descriptionText:descriptionText, unit:"%")
}
private getPressureResult(hex){
if (hex == null) return
def valueRaw = hexStrToUnsignedInt(hex)
def value = valueRaw / 10
def descriptionText = "${device.displayName} pressure is ${value}kPa"
if (txtEnable) log.info "${descriptionText}"
sendEvent(name:"pressure", value:value, descriptionText:descriptionText, unit:"kPa")
}
private getTemperatureResult(valueRaw){
if (valueRaw == null) return
def tempC = hexStrToSignedInt(valueRaw) / 100
def value = convertTemperatureIfNeeded(tempC.toFloat(),"c",2)
def unit = "°${location.temperatureScale}"
def descriptionText = "${device.displayName} temperature is ${value}${unit}"
if (txtEnable) log.info "${descriptionText}"
sendEvent(name:"temperature",value:value, descriptionText:descriptionText, unit:unit)
}
private getSwitchResult(rawValue){
def value = rawValue == "01" ? "on" : "off"
def name = "switch"
if (device.currentValue("${name}") == value){
descriptionText = "${device.displayName} is ${value}"
} else {
descriptionText = "${device.displayName} was turned ${value}"
}
if (txtEnable) log.info "${descriptionText}"
sendEvent(name:name,value:value,descriptionText:descriptionText)
}
private getLevelResult(rawValue){
def unit = "%"
def value = Math.round(Integer.parseInt(rawValue,16) / 2.55)
def name = "level"
if (device.currentValue("${name}") == value){
descriptionText = "${device.displayName} is ${value}${unit}"
} else {
descriptionText = "${device.displayName} was set to ${value}${unit}"
}
if (txtEnable) log.info "${descriptionText}"
sendEvent(name:name,value:value,descriptionText:descriptionText,unit:unit)
}
private getColorResult(rawValue,attrInt){
def unit = "%"
def value = Math.round(Integer.parseInt(rawValue,16) / 2.55)
def name
switch (attrInt){
case 0: //hue
name = "hue"
if (device.currentValue("${name}")?.toInteger() == value){
descriptionText = "${device.displayName} ${name} is ${value}${unit}"
} else {
descriptionText = "${device.displayName} ${name} was set to ${value}${unit}"
}
state.lastHue = rawValue
break
case 1: //sat
name = "saturation"
if (device.currentValue("${name}")?.toInteger() == value){
descriptionText = "${device.displayName} ${name} is ${value}${unit}"
} else {
descriptionText = "${device.displayName} ${name} was set to ${value}${unit}"
}
state.lastSaturation = rawValue
break
default :
return
}
if (txtEnable) log.info "${descriptionText}"
sendEvent(name:name,value:value,descriptionText:descriptionText,unit:unit)
}
def configure() {
log.warn "configure..."
runIn(1800,logsOff)
def cmds = [
//bindings
"zdo bind 0x${device.deviceNetworkId} 1 1 0x0402 {${device.zigbeeId}} {}", "delay 200", //temp
"zdo bind 0x${device.deviceNetworkId} 1 1 0x0403 {${device.zigbeeId}} {}", "delay 200", //pressure
"zdo bind 0x${device.deviceNetworkId} 1 1 0x0405 {${device.zigbeeId}} {}", "delay 200", //hum
"zdo bind 0x${device.deviceNetworkId} 2 1 0x0006 {${device.zigbeeId}} {}", "delay 200",
"zdo bind 0x${device.deviceNetworkId} 2 1 0x0008 {${device.zigbeeId}} {}", "delay 200",
"zdo bind 0x${device.deviceNetworkId} 2 1 0x0300 {${device.zigbeeId}} {}", "delay 200",
//mfr specific
"zdo bind 0x${device.deviceNetworkId} 4 1 0xFD00 {${device.zigbeeId}} {1201}", "delay 200", //appears to be custom alarm
"zdo bind 0x${device.deviceNetworkId} 4 1 0xFD01 {${device.zigbeeId}} {1201}", "delay 200", //hush???
"zdo bind 0x${device.deviceNetworkId} 4 1 0xFD02 {${device.zigbeeId}} {1201}", "delay 200",
//reporting
"he cr 0x${device.deviceNetworkId} 1 0x0402 0x0000 0x29 1 43200 {50}","delay 200", //temp
"he cr 0x${device.deviceNetworkId} 1 0x0405 0x0000 0x21 1 43200 {50}","delay 200", //hum
"he cr 0x${device.deviceNetworkId} 1 0x0403 0x0000 0x29 1 43200 {1}","delay 200", //pressure
//mfr specific reporting
"he cr 0x${device.deviceNetworkId} 0x04 0xFD00 0x0000 0x30 5 120 {} {1201}","delay 200", //alarm
"he cr 0x${device.deviceNetworkId} 0x04 0xFD00 0x0001 0x30 5 120 {} {1201}","delay 200", //alarm
//need to verify ep, st attrib id's 1, and 0
"he cr 0x${device.deviceNetworkId} 0x01 0xFD01 0x0000 0x30 5 120 {} {1201}","delay 200", //hush???
"he cr 0x${device.deviceNetworkId} 0x01 0xFD01 0x0001 0x0A 5 120 {} {1201}","delay 200", //hush???