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)
/*
Iris V2 Keypad
Copyright 2016, 2017, 2018, 2019 Hubitat Inc. All Rights Reserved
2019-04-02 2.0.9 maxwell
-updates for countdown and confirmation sounds
2019-03-05 2.0.7 maxwell
-initial pub
*/
import groovy.json.JsonSlurper
import groovy.json.JsonOutput
metadata {
definition (name: "Iris V2 Keypad(DEV)", namespace: "Hubitat", author: "Mike Maxwell") {
capability "Battery"
capability "Configuration"
capability "Motion Sensor"
capability "Sensor"
capability "Temperature Measurement"
capability "Refresh"
capability "Security Keypad"
capability "Tamper Alert"
capability "Alarm"
capability "Tone"
command "armNight"
command "setArmNightDelay", ["number"]
command "setArmHomeDelay", ["number"]
command "entry" //fired from HSM on system entry
attribute "armingIn", "NUMBER"
command "setPartialFunction"
fingerprint profileId: "0104", inClusters: "0000,0001,0003,0020,0402,0500,0501,0B05,FC04", outClusters: "0019,0501", manufacturer: "CentraLite", model: "3405-L", deviceJoinName: "Iris 3405-L Keypad"
fingerprint profileId: "0104", inClusters: "0000,0001,0003,0020,0402,0500,0501,0B05,FC04,FC05", outClusters: "0019,0501", manufacturer: "CentraLite", model: "3405-L", deviceJoinName: "Iris 3405-L Keypad V2"
}
preferences{
input name: "optEncrypt", type: "bool", title: "Enable lockCode encryption", defaultValue: false, description: ""
input name: "pinOnArmAway", type: "bool", title: "Verify pin to arm away", defaultValue: false, description: ""
input name: "pinOnArmHome", type: "bool", title: "Verify pin to arm home/night", defaultValue: false, description: ""
input ("motionTime", "number", title: "Time in seconds for Motion to become Inactive (Default:10, 0=disabled)", defaultValue: 10, displayDuringSetup: false)
input name: "enablePanic", type: "bool", title: "Enable Panic", defaultValue: false, description: ""
input "refTemp", "decimal", title: "Reference temperature", description: "Enter current reference temperature reading", range: "*..*"
input name: "logEnable", type: "bool", title: "Enable debug logging", defaultValue: true, description: ""
input name: "txtEnable", type: "bool", title: "Enable descriptionText logging", defaultValue: true, description: ""
}
}
def logsOff(){
log.warn "debug logging disabled..."
device.updateSetting("logEnable",[value:"false",type:"bool"])
}
def installed(){
log.warn "installed..."
state.exitDelay = 0
state.entryDelay = 0
state.armNightDelay = 0
state.armHomeDelay = 0
state.armMode = "00"
state.fnPartial = "01"
sendEvent(name:"maxCodes", value:20)
sendEvent(name:"codeLength", value:4)
sendEvent(name:"alarm", value: "off")
sendEvent(name:"securityKeypad", value: "disarmed")
}
def uninstalled(){
return zigbee.command(0x0000,0x00)
}
// New code sgrayban
def motionON() {
if (txtEnable) log.debug "--- Motion Detected (ON)"
sendEvent(name: "motion", value: "active", displayed:true, isStateChange: true)
def motionTimeRun = (settings.motionTime?:0).toInteger()
if (motionTimeRun > 0) {
if (txtEnable) log.debug "--- Will become inactive in $motionTimeRun seconds"
runIn(motionTimeRun, "motionOFF")
}
}
def motionOFF() {
if (txtEnable) log.debug "--- Motion Inactive (OFF)"
sendEvent(name: "motion", value: "inactive", displayed:true, isStateChange: true)
}
// End new code
def parse(String description) {
def resp = []
if (description.startsWith("zone status")) {
def zoneStatus = zigbee.parseZoneStatus(description)
getTamperResult(zoneStatus.tamper)
} else if (description.startsWith("enroll request")) {
resp.addAll(zigbee.enrollResponse(0))
} else {
def descMap = zigbee.parseDescriptionAsMap(description)
if (logEnable) log.debug "descMap: ${descMap}"
def clusterId = descMap.clusterId ?: descMap.cluster
def cmd = descMap.command
switch (clusterId) {
case "0001":
if (descMap.value) {
value = hexStrToUnsignedInt(descMap.value)
getBatteryResult(value)
}
break
case "0501":
if (cmd == "07" && descMap.data.size() == 0) { //get panel status client -> server
if (state.bin == -1) motionON() // sgrayban
resp.addAll(sendPanelResponse(false))
} else if (cmd == "00") {
state.bin = -1
def armRequest = descMap.data[0]
def asciiPin = descMap.data[2..5].collect{ (char)Integer.parseInt(it, 16) }.join()
resp.addAll(sendArmResponse(armRequest,isValidPin(asciiPin, armRequest)))
} else if (cmd == "04") { //panic client -> server
if (enablePanic) resp.addAll(togglePanic())
} else {
if (logEnable) log.info "0501 skipped: ${descMap}"
}
break
case "0402":
if (descMap.value) {
def tempC = hexStrToSignedInt(descMap.value)
getTemperatureResult(tempC)
}
break
default :
if (logEnable) log.info "skipped: ${descMap}, description:${description}"
}
if (resp){
sendHubCommand(new hubitat.device.HubMultiAction(resp, hubitat.device.Protocol.ZIGBEE))
}
}
}
//Security Keypad commands
def beep(){
if (txtEnable) log.debug "Sending beeps"
return "he raw 0x${device.deviceNetworkId} 1 1 0xFC04 {15 4E 10 00 00 00}"
}
def setEntryDelay(delay){
log.trace "setEntryDelay(${delay})"
state.entryDelay = delay != null ? delay.toInteger() : 0
}
def setExitDelay(Map delays){
state.exitDelay = (delays?.awayDelay ?: 0).toInteger()
state.armNightDelay = (delays?.nightDelay ?: 0).toInteger()
state.armHomeDelay = (delays?.homeDelay ?: 0).toInteger()
}
def setExitDelay(delay){
state.exitDelay = delay != null ? delay.toInteger() : 0
}
def setArmNightDelay(delay){
state.armNightDelay = delay != null ? delay.toInteger() : 0
}
def setArmHomeDelay(delay){
state.armHomeDelay = delay != null ? delay.toInteger() : 0
}
def setPartialFunction(mode = null) {
if ( !(mode in ["armHome","armNight"]) ) {
if (txtEnable) log.warn "custom command used by HSM"
} else if (mode in ["armHome","armNight"]) {
state.fnPartial = mode == "armHome" ? "01" : "02"
}
}
def setCodeLength(length){
def descriptionText = "${device.displayName} codeLength set to 4"
if (txtEnable) log.info "${descriptionText}"
sendEvent(name:"codeLength",value:"${4}",descriptionText:descriptionText)
}
def setCode(codeNumber, code, name = null) {
if (!name) name = "code #${codeNumber}"
def lockCodes = getLockCodes()
def codeMap = getCodeMap(lockCodes,codeNumber)
def data = [:]
def value
//verify proposed changes
if (!changeIsValid(codeMap,codeNumber,code,name)) return
if (logEnable) log.debug "setting code ${codeNumber} to ${code} for lock code name ${name}"
if (codeMap) {
if (codeMap.name != name || codeMap.code != code) {
codeMap = ["name":"${name}", "code":"${code}"]
lockCodes."${codeNumber}" = codeMap
data = ["${codeNumber}":codeMap]
if (optEncrypt) data = encrypt(JsonOutput.toJson(data))
value = "changed"
}
} else {
codeMap = ["name":"${name}", "code":"${code}"]
data = ["${codeNumber}":codeMap]
lockCodes << data
if (optEncrypt) data = encrypt(JsonOutput.toJson(data))
value = "added"
}
updateLockCodes(lockCodes)
sendEvent(name:"codeChanged",value:value,data:data, isStateChange: true)
}
def deleteCode(codeNumber) {
def codeMap = getCodeMap(lockCodes,"${codeNumber}")
def result = [:]
if (codeMap) {
lockCodes.each{
if (it.key != "${codeNumber}"){
result << it
}
}
updateLockCodes(result)
def data = ["${codeNumber}":codeMap]
if (optEncrypt) data = encrypt(JsonOutput.toJson(data))
sendEvent(name:"codeChanged",value:"deleted",data:data, isStateChange: true)
}
}
def getCodes(){
updateEncryption()
}
def entry(){
def intDelay = state.entryDelay ? state.entryDelay.toInteger() : 0
if (intDelay) return entry(intDelay)
}
def entry(entranceDelay){
if (entranceDelay) {
def ed = entranceDelay.toInteger()
state.bin = 1
state.delayExpire = now() + (ed * 1000)
state.armingMode = "05" //entry delay
def hexVal = intToHexStr(ed)
runIn(ed + 5 ,clearPending)
return [
"he raw 0x${device.deviceNetworkId} 1 1 0x0501 {19 01 04 05 ${hexVal} 01 01}"
]
}
}
def disarm(exitDelay = null) {
state.armPending = false
state.bin = 1
if (exitDelay == null) sendArmResponse("00",getDefaultLCdata())
else sendArmResponse("00",getDefaultLCdata(),exitDelay.toInteger())
}
def armHome(exitDelay = null) {
if (logEnable) log.debug "armHome(${exitDelay}, armMode:${state.armMode}, armingMode:${state.armingMode})"
if (state.armMode == "01") {
sendPanelResponse(false)
if (logEnable) log.trace "armHome(${exitDelay}) called, already armedHome"
return
}
state.bin = 1
if (exitDelay == null) sendArmResponse("01",getDefaultLCdata())
else sendArmResponse("01",getDefaultLCdata(),exitDelay.toInteger())
}