Compare commits

..

1 Commits

2 changed files with 232 additions and 173 deletions

View File

@@ -18,10 +18,9 @@ metadata {
capability "Sensor"
capability "Smoke Detector" //attributes: smoke ("detected","clear","tested")
capability "Temperature Measurement" //attributes: temperature
attribute "tamper", "enum", ["active", "inactive"]//capability "Tamper Alert"// <- yields "java.lang.RuntimeException: Metadata Error: Capability 'Tamper Alert' not found" error
attribute "heatAlarm", "enum", ["overheat", "inactive"]
attribute "tamper", "enum", ["detected", "clear"]
attribute "heatAlarm", "enum", ["overheat detected", "clear", "rapid temperature rise", "underheat detected"]
fingerprint deviceId: "0x0701", inClusters: "0x5E, 0x86, 0x72, 0x5A, 0x59, 0x85, 0x73, 0x84, 0x80, 0x71, 0x56, 0x70, 0x31, 0x8E, 0x22, 0x9C, 0x98, 0x7A", outClusters: "0x20, 0x8B"
fingerprint deviceId: "0x0701", inClusters: "0x5E, 0x86, 0x72, 0x5A, 0x59, 0x85, 0x73, 0x84, 0x80, 0x71, 0x56, 0x70, 0x31, 0x8E, 0x22, 0x9C, 0x98, 0x7A"
}
simulator {
//battery
@@ -51,7 +50,7 @@ metadata {
input description: "Please consult Fibaro Smoke Sensor operating manual for advanced setting options. You can skip this configuration to use default settings",
title: "Advanced Configuration", displayDuringSetup: true, type: "paragraph", element: "paragraph"
input "smokeSensorSensitivity", "enum", title: "Smoke Sensor Sensitivity", options: ["High","Medium","Low"], defaultValue: "${smokeSensorSensitivity}", displayDuringSetup: true
input "zwaveNotificationStatus", "enum", title: "Notifications Status", options: ["disabled","casing opened","exceeding temperature threshold","all notifications"],
input "zwaveNotificationStatus", "enum", title: "Notifications Status", options: ["disabled","casing opened","exceeding temperature threshold", "lack of Z-Wave range", "all notifications"],
defaultValue: "${zwaveNotificationStatus}", displayDuringSetup: true
input "visualIndicatorNotificationStatus", "enum", title: "Visual Indicator Notifications Status",
options: ["disabled","casing opened","exceeding temperature threshold", "lack of Z-Wave range", "all notifications"],
@@ -62,47 +61,44 @@ metadata {
input "temperatureReportInterval", "enum", title: "Temperature Report Interval",
options: ["reports inactive", "5 minutes", "15 minutes", "30 minutes", "1 hour", "6 hours", "12 hours", "18 hours", "24 hours"], defaultValue: "${temperatureReportInterval}", displayDuringSetup: true
input "temperatureReportHysteresis", "number", title: "Temperature Report Hysteresis", description: "Available settings: 1-100 C", range: "1..100", displayDuringSetup: true
input "temperatureThreshold", "number", title: "Overheat Temperature Threshold", description: "Available settings: 1-100 C", range: "1..100", displayDuringSetup: true
input "temperatureThreshold", "number", title: "Overheat Temperature Threshold", description: "Available settings: 0 or 2-100 C", range: "0..100", displayDuringSetup: true
input "excessTemperatureSignalingInterval", "enum", title: "Excess Temperature Signaling Interval",
options: ["5 minutes", "15 minutes", "30 minutes", "1 hour", "6 hours", "12 hours", "18 hours", "24 hours"], defaultValue: "${excessTemperatureSignalingInterval}", displayDuringSetup: true
input "lackOfZwaveRangeIndicationInterval", "enum", title: "Lack of Z-Wave Range Indication Interval",
options: ["5 minutes", "15 minutes", "30 minutes", "1 hour", "6 hours", "12 hours", "18 hours", "24 hours"], defaultValue: "${lackOfZwaveRangeIndicationInterval}", displayDuringSetup: true
}
tiles (scale: 2){
multiAttributeTile(name:"FGSD", type: "lighting", width: 6, height: 4){
multiAttributeTile(name:"smoke", type: "lighting", width: 6, height: 4){
tileAttribute ("device.smoke", key: "PRIMARY_CONTROL") {
attributeState("clear", label:"CLEAR", icon:"st.alarm.smoke.clear", backgroundColor:"#ffffff")
attributeState("detected", label:"SMOKE", icon:"st.alarm.smoke.smoke", backgroundColor:"#e86d13")
attributeState("tested", label:"TEST", icon:"st.alarm.smoke.test", backgroundColor:"#e86d13")
attributeState("replacement required", label:"REPLACE", icon:"st.alarm.smoke.test", backgroundColor:"#FFFF66")
attributeState("unknown", label:"UNKNOWN", icon:"st.alarm.smoke.test", backgroundColor:"#ffffff")
}
tileAttribute("device.tamper", key:"SECONDARY_CONTROL") {
attributeState("active", label:'tamper active', backgroundColor:"#53a7c0")
attributeState("inactive", label:'tamper inactive', backgroundColor:"#ffffff")
}
tileAttribute ("device.battery", key: "SECONDARY_CONTROL") {
attributeState "battery", label:'Battery: ${currentValue}%', unit:"%"
}
}
valueTile("battery", "device.battery", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
state "battery", label:'${currentValue}% battery', unit:"%"
}
valueTile("temperature", "device.temperature", inactiveLabel: false, width: 2, height: 2) {
state "temperature", label:'${currentValue}°',
backgroundColors:[
[value: 31, color: "#153591"],
[value: 44, color: "#1e9cbb"],
[value: 59, color: "#90d2a7"],
[value: 74, color: "#44b621"],
[value: 84, color: "#f1d801"],
[value: 95, color: "#d04e00"],
[value: 96, color: "#bc2323"]
]
}
valueTile("heatAlarm", "device.heatAlarm", inactiveLabel: false, width: 2, height: 2) {
state "inactive", label:'TEMPERATURE OK', backgroundColor:"#ffffff"
state "overheat", label:'OVERHEAT DETECTED', backgroundColor:"#bc2323"
valueTile("temperature", "device.temperature", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
state "temperature", label:'${currentValue}°', unit:"C"
}
valueTile("heatAlarm", "device.heatAlarm", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
state "clear", label:'TEMPERATURE OK', backgroundColor:"#ffffff"
state "overheat detected", label:'OVERHEAT DETECTED', backgroundColor:"#ffffff"
state "rapid temperature rise", label:'RAPID TEMP RISE', backgroundColor:"#ffffff"
state "underheat detected", label:'UNDERHEAT DETECTED', backgroundColor:"#ffffff"
}
valueTile("tamper", "device.tamper", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
state "clear", label:'NO TAMPER', backgroundColor:"#ffffff"
state "detected", label:'TAMPER DETECTED', backgroundColor:"#ffffff"
}
main "FGSD"
details(["FGSD","temperature", "battery", "heatAlarm"])
main "smoke"
details(["smoke","temperature"])
}
}
@@ -121,7 +117,7 @@ def parse(String description) {
"If you are unable to control it via SmartThings, you must remove it from your network and add it again.")
} else if (description != "updated") {
log.debug "parse() >> zwave.parse(description)"
def cmd = zwave.parse(description, [0x31: 5, 0x5A: 1, 0x71: 3, 0x72: 2, 0x84: 1, 0x86: 1, 0x8B: 1, 0x9C: 1])
def cmd = zwave.parse(description, [0x31: 5, 0x71: 3, 0x84: 1])
if (cmd) {
result = zwaveEvent(cmd)
}
@@ -130,41 +126,15 @@ def parse(String description) {
return result
}
//security
def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) {
setSecured()
def encapsulatedCommand = cmd.encapsulatedCommand([0x31: 5, 0x5A: 1, 0x71: 3, 0x84: 1, 0x9C: 1])
if (encapsulatedCommand) {
log.debug "command: 98 (Security) 81(SecurityMessageEncapsulation) encapsulatedCommand: $encapsulatedCommand"
zwaveEvent(encapsulatedCommand)
} else {
log.warn "Unable to extract encapsulated cmd from $cmd"
createEvent(descriptionText: cmd.toString())
}
}
//crc16
def zwaveEvent(physicalgraph.zwave.commands.crc16encapv1.Crc16Encap cmd)
{
def versions = [0x31: 5, 0x72: 2, 0x86: 1, 0x8B: 1]
def version = versions[cmd.commandClass as Integer]
def ccObj = version ? zwave.commandClass(cmd.commandClass, version) : zwave.commandClass(cmd.commandClass)
def encapsulatedCommand = ccObj?.command(cmd.command)?.parse(cmd.data)
if (!encapsulatedCommand) {
log.debug "Could not extract command from $cmd"
} else {
zwaveEvent(encapsulatedCommand)
}
}
def zwaveEvent(physicalgraph.zwave.commands.versionv1.VersionReport cmd) {
log.info "Executing zwaveEvent 86 (VersionV1): 12 (VersionReport) with cmd: $cmd"
def version = "${cmd.applicationVersion}.${cmd.applicationSubVersion}"
updateDataValue("version", fw)
def text = "$device.displayName: firmware version: $version, Z-Wave version: ${cmd.zWaveProtocolVersion}.${cmd.zWaveProtocolSubVersion}"
def fw = "${cmd.applicationVersion}.${cmd.applicationSubVersion}"
updateDataValue("fw", fw)
def text = "$device.displayName: firmware version: $fw, Z-Wave version: ${cmd.zWaveProtocolVersion}.${cmd.zWaveProtocolSubVersion}"
createEvent(descriptionText: text, isStateChange: false)
}
def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) {
def map = [ name: "battery", unit: "%" ]
if (cmd.batteryLevel == 0xFF) {
@@ -191,6 +161,18 @@ def zwaveEvent(physicalgraph.zwave.commands.applicationstatusv1.ApplicationRejec
createEvent(displayed: true, descriptionText: "$device.displayName rejected the last request")
}
def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) {
setSecured()
def encapsulatedCommand = cmd.encapsulatedCommand([0x31: 5, 0x71: 3, 0x84: 1])
if (encapsulatedCommand) {
log.debug "command: 98 (Security) 81(SecurityMessageEncapsulation) encapsulatedCommand: $encapsulatedCommand"
zwaveEvent(encapsulatedCommand)
} else {
log.warn "Unable to extract encapsulated cmd from $cmd"
createEvent(descriptionText: cmd.toString())
}
}
def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityCommandsSupportedReport cmd) {
log.info "Executing zwaveEvent 98 (SecurityV1): 03 (SecurityCommandsSupportedReport) with cmd: $cmd"
setSecured()
@@ -217,31 +199,18 @@ def zwaveEvent(physicalgraph.zwave.commands.notificationv3.NotificationReport cm
if (cmd.notificationType == 7) {
switch (cmd.event) {
case 0:
result << createEvent(name: "tamper", value: "inactive", displayed: false)
result << createEvent(name: "tamper", value: "clear", displayed: false)
break
case 3:
result << createEvent(name: "tamper", value: "active", descriptionText: "$device.displayName casing was opened")
result << createEvent(name: "tamper", value: "detected", descriptionText: "$device.displayName casing was opened")
break
}
} else if (cmd.notificationType == 1) { //Smoke Alarm (V2)
log.debug "notificationv3.NotificationReport: for Smoke Alarm (V2)"
result << smokeAlarmEvent(cmd.event)
} else if (cmd.notificationType == 4) { // Heat Alarm (V2)
} else if (cmd.notificationType == 4) { // Heat Alarm (V2)
log.debug "notificationv3.NotificationReport: for Heat Alarm (V2)"
result << heatAlarmEvent(cmd.event)
} else if (cmd.notificationType == 8) {
if (cmd.event == 0x0A) {
def map = [:]
map.name = "battery"
map.value = 1
map.unit = "%"
map.displayed = true
result << createEvent(map)
}
} else if (cmd.notificationType == 9) {
if (cmd.event == 0x01) {
result << createEvent(descriptionText: "Warning: $device.displayName system hardware failure", isStateChange: true)
}
} else {
log.warn "Need to handle this cmd.notificationType: ${cmd.notificationType}"
result << createEvent(descriptionText: cmd.toString(), isStateChange: false)
@@ -252,7 +221,7 @@ def zwaveEvent(physicalgraph.zwave.commands.notificationv3.NotificationReport cm
def smokeAlarmEvent(value) {
log.debug "smokeAlarmEvent(value): $value"
def map = [name: "smoke"]
if (value == 2) {
if (value == 1 || value == 2) {
map.value = "detected"
map.descriptionText = "$device.displayName detected smoke"
} else if (value == 0) {
@@ -261,6 +230,9 @@ def smokeAlarmEvent(value) {
} else if (value == 3) {
map.value = "tested"
map.descriptionText = "$device.displayName smoke alarm test"
} else if (value == 4) {
map.value = "replacement required"
map.descriptionText = "$device.displayName replacement required"
} else {
map.value = "unknown"
map.descriptionText = "$device.displayName unknown event"
@@ -271,12 +243,18 @@ def smokeAlarmEvent(value) {
def heatAlarmEvent(value) {
log.debug "heatAlarmEvent(value): $value"
def map = [name: "heatAlarm"]
if (value == 2) {
map.value = "overheat"
if (value == 1 || value == 2) {
map.value = "overheat detected"
map.descriptionText = "$device.displayName overheat detected"
} else if (value == 0) {
map.value = "inactive"
map.value = "clear"
map.descriptionText = "$device.displayName heat alarm cleared (no overheat)"
} else if (value == 3 || value == 4) {
map.value = "rapid temperature rise"
map.descriptionText = "$device.displayName rapid temperature rise"
} else if (value == 5 || value == 6) {
map.value = "underheat detected"
map.descriptionText = "$device.displayName underheat detected"
} else {
map.value = "unknown"
map.descriptionText = "$device.displayName unknown event"
@@ -296,14 +274,12 @@ def zwaveEvent(physicalgraph.zwave.commands.wakeupv1.WakeUpNotification cmd) {
//Only ask for battery if we haven't had a BatteryReport in a while
if (!state.lastbatt || (new Date().time) - state.lastbatt > 24*60*60*1000) {
log.debug("Device has been configured sending >> batteryGet()")
cmds << zwave.batteryV1.batteryGet()
cmds << zwave.securityV1.securityMessageEncapsulation().encapsulate(zwave.batteryV1.batteryGet()).format()
cmds << "delay 1200"
}
cmds << zwave.sensorAlarmV1.sensorAlarmGet(sensorType: 0)
cmds << zwave.sensorAlarmV1.sensorAlarmGet(sensorType: 1)
cmds << zwave.sensorAlarmV1.sensorAlarmGet(sensorType: 4)
log.debug("Device has been configured sending >> wakeUpNoMoreInformation()")
cmds << zwave.wakeUpV1.wakeUpNoMoreInformation()
result << response(commands(cmds,500)) //tell device back to sleep
cmds << zwave.wakeUpV1.wakeUpNoMoreInformation().format()
result << response(cmds) //tell device back to sleep
}
result
}
@@ -341,26 +317,8 @@ def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.ManufacturerS
log.debug "After device is securely joined, send commands to update tiles"
result << zwave.batteryV1.batteryGet()
result << zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 0x01)
//always send wakeUpNoMoreInformation as secure (at this point "secured" property is not set)
[[descriptionText:"${device.displayName} MSR report"], response(commands(result, 500) << "delay 1000" << secure(zwave.wakeUpV1.wakeUpNoMoreInformation()))]
}
def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.DeviceSpecificReport cmd) {
log.debug "deviceIdData: ${cmd.deviceIdData}"
log.debug "deviceIdDataFormat: ${cmd.deviceIdDataFormat}"
log.debug "deviceIdDataLengthIndicator: ${cmd.deviceIdDataLengthIndicator}"
log.debug "deviceIdType: ${cmd.deviceIdType}"
if (cmd.deviceIdType == 1 && cmd.deviceIdDataFormat == 1) {//serial number in binary format
String serialNumber = "h'"
cmd.deviceIdData.each{ data ->
serialNumber += "${String.format("%02X", data)}"
}
updateDataValue("serialNumber", serialNumber)
log.debug "${device.displayName} - serial number: ${serialNumber}"
}
result << zwave.wakeUpV1.wakeUpNoMoreInformation()
[[descriptionText:"${device.displayName} MSR report"], response(commands(result, 5000))]
}
def zwaveEvent(physicalgraph.zwave.commands.associationv2.AssociationReport cmd) {
@@ -374,37 +332,6 @@ def zwaveEvent(physicalgraph.zwave.commands.associationv2.AssociationReport cmd)
result
}
def zwaveEvent(physicalgraph.zwave.commands.sensoralarmv1.SensorAlarmReport cmd) {
def map = [:]
switch (cmd.sensorType) {
case 0:
map.name = "tamper"
map.value = cmd.sensorState == 0xFF ? "active" : "inactive"
map.descriptionText = cmd.sensorState == 0xFF ? "$device.displayName casing was opened" : ""
break
case 1:
map.name = "smoke"
map.value = cmd.sensorState == 0xFF ? "detected" : "clear"
map.descriptionText = cmd.sensorState == 0xFF ? "$device.displayName detected smoke" : "$device.displayName is clear (no smoke)"
break
case 4:
map.name = "heatAlarm"
map.value = cmd.sensorState == 0xFF ? "overheat" : "inactive"
map.descriptionText = cmd.sensorState == 0xFF ? "$device.displayName overheat detected" : "$device.displayName heat alarm cleared (no overheat)"
break
}
createEvent(map)
}
def zwaveEvent(physicalgraph.zwave.commands.timeparametersv1.TimeParametersGet cmd) {
log.info "Executing zwaveEvent 8B (TimeParametersV1) : 02 (TimeParametersGet) with cmd: $cmd"
def nowCal = Calendar.getInstance(TimeZone.getTimeZone("UTC"))
//Time Parameters are requested by an un-encapsulated frame
response(zwave.timeParametersV1.timeParametersReport(year: nowCal.get(Calendar.YEAR), month: (nowCal.get(Calendar.MONTH) + 1), day: nowCal.get(Calendar.DAY_OF_MONTH),
hourUtc: nowCal.get(Calendar.HOUR_OF_DAY), minuteUtc: nowCal.get(Calendar.MINUTE), secondUtc: nowCal.get(Calendar.SECOND)).format())
}
def zwaveEvent(physicalgraph.zwave.Command cmd) {
log.warn "General zwaveEvent cmd: ${cmd}"
createEvent(descriptionText: cmd.toString(), isStateChange: false)
@@ -433,7 +360,7 @@ def configure() {
}
//3. Z-Wave notification status: 0-all disabled (default), 1-casing open enabled, 2-exceeding temp enable
if (zwaveNotificationStatus && zwaveNotificationStatus != "null"){
request += zwave.configurationV1.configurationSet(parameterNumber: 2, size: 1, scaledConfigurationValue: zwaveNotificationOptionValueMap[zwaveNotificationStatus] ?: 0)
request += zwave.configurationV1.configurationSet(parameterNumber: 2, size: 1, scaledConfigurationValue: notificationOptionValueMap[zwaveNotificationStatus] ?: 0)
}
//4. Visual indicator notification status: 0-all disabled (default), 1-casing open enabled, 2-exceeding temp enable, 4-lack of range notification
if (visualIndicatorNotificationStatus && visualIndicatorNotificationStatus != "null") {
@@ -475,16 +402,7 @@ def configure() {
//12. get temperature reading from device
request += zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 0x01)
//13. set association group
request += zwave.associationV2.associationSet(groupingIdentifier:1, nodeId:[zwaveHubNodeId])
//14. get version
request += zwave.versionV1.versionGet()
//15. get serial number
request += zwave.manufacturerSpecificV2.deviceSpecificGet()
commands(request) + ["delay 1000", command(zwave.wakeUpV1.wakeUpNoMoreInformation())]
commands(request) + ["delay 10000", zwave.wakeUpV1.wakeUpNoMoreInformation().format()]
}
}
@@ -500,42 +418,24 @@ private def getTimeOptionValueMap() { [
"reports inactive" : 0,
]}
private def getZwaveNotificationOptionValueMap() { [
"disabled" : 0,
"casing opened" : 1,
"exceeding temperature threshold" : 2,
"all notifications" : 3
]}
private def getNotificationOptionValueMap() { [
"disabled" : 0,
"casing opened" : 1,
"exceeding temperature threshold" : 2,
"lack of Z-Wave range" : 4,
"all notifications" : 7
"disabled" : 0,
"casing opened" : 1,
"exceeding temperature threshold" : 2,
"lack of Z-Wave range" : 4,
"all notifications" : 7,
]}
private command(physicalgraph.zwave.Command cmd) {
def secureClasses = [0x20, 0x5A, 0x70, 0x71, 0x84, 0x85, 0x8E, 0x9C]
if (isSecured() && secureClasses.find{ it == cmd.commandClassId }) {
if (isSecured()) {
log.info "Sending secured command: ${cmd}"
secure(cmd)
zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format()
} else {
log.info "Sending unsecured command: ${cmd}"
crc16(cmd)
cmd.format()
}
}
private secure(physicalgraph.zwave.Command cmd) {
zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format()
}
private crc16(physicalgraph.zwave.Command cmd) {
//zwave.crc16encapV1.crc16Encap().encapsulate(cmd).format()
"5601${cmd.format()}0000"
}
private commands(commands, delay=200) {
log.info "inside commands: ${commands}"
delayBetween(commands.collect{ command(it) }, delay)
@@ -552,4 +452,4 @@ private setSecured() {
}
private isSecured() {
getDataValue("secured") == "true"
}
}

View File

@@ -0,0 +1,159 @@
/**
* InfluxdbShipper
*
* Copyright 2016 Prune - prune@lecentre.net
*
* 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.
*
* Description :
* This application listen to sensors and send the result metric to an Influxdb 0.9.x or newer server.
* It is NOT compatible with Influxdb 0.8.x
*
* Check Influxdb docs at
* https://docs.influxdata.com/influxdb/v0.10/introduction/
*
* Usage :
* select sensors you want to monitor
* enter your InfluxDB URL with full informations :
*
* <host>:<port>
*
* Ex : www.myserver.ca:8086/write
*
* It is strongly encouraged to use HTTPS and a login/password as your Influxdb server need to be open to the world
*/
definition(
name: "InfluxdbShipper",
namespace: "Prune",
author: "Prune",
description: "stream metrics to Influxdb",
category: "My Apps",
iconUrl: "http://lkhill.com/wp/wp-content/uploads/2015/10/influxdb-logo.png",
iconX2Url: "http://lkhill.com/wp/wp-content/uploads/2015/10/influxdb-logo.png",
iconX3Url: "http://lkhill.com/wp/wp-content/uploads/2015/10/influxdb-logo.png")
preferences {
section("Log devices...") {
input "temperatures", "capability.temperatureMeasurement", title: "Temperatures", required:false, multiple: true
input "humidity", "capability.relativeHumidityMeasurement", title: "Humidity", required:false, multiple: true
input "contacts", "capability.contactSensor", title: "Doors open/close", required: false, multiple: true
input "motions", "capability.motionSensor", title: "Motions", required: false, multiple: true
input "presence", "capability.presenceSensor", title: "Presence", required: false, multiple: true
input "switches", "capability.switch", title: "Switches", required: false, multiple: true
input "energy", "capability.energyMeter", title: "Energy", required: false, multiple: true
input "smoke", "capability.smokeDetector", title: "Smoke", required: false, multiple: true
}
section ("Influxdb URL...") {
input "influxdb_url", "text", title: "Influxdb URL"
input "influxdb_proto", "enum", title: "Protocol (http or https)", options: ["HTTP", "HTTPS"]
input "influxdb_db", "text", title: "Influxdb DB"
input "influxdb_login", "text", title: "Influxdb Login"
input "influxdb_password", "password", title: "Influxdb Password"
}
}
def installed() {
initialize()
}
def updated() {
unsubscribe()
initialize()
}
def initialize() {
/*subscribe(temperatures, "temperature", handleTemperatureEvent)
subscribe(contacts, "contact", handleContactEvent)
subscribe(accelerations, "acceleration", handleAccelerationEvent)
subscribe(motions, "motion", handleMotionEvent)
subscribe(presence, "presence", handlePresenceEvent)
subscribe(switches, "switch", handleSwitchEvent)
log.debug "Done subscribing to events"
*/
//log.debug "temperatures: ${temperatures[0].name} = ${temperatures[0].currentState("temperature").value}"
// Send data every 5 mins
runEvery5Minutes(updateCurrentStats)
}
/*
Push data to Influx
*/
def updateCurrentStats() {
//log.debug "Logging to Influxdb ${influxdb_url}"
// Builds the URL that will be sent to Influxdb
def full_url = "${influxdb_proto}://${influxdb_url}/write?db=${influxdb_db}"
if (influxdb_login != "") {
full_url += "&u=${influxdb_login}&p=${influxdb_password}"
}
def full_body=""
temperatures.eachWithIndex{ val, idx ->
def sensorName = val.displayName.replaceAll(" ",'\\\\ ')
full_body += "temp,sensor=${sensorName} value=${val.currentState("temperature").value} \n"
}
contacts.eachWithIndex{ val, idx ->
def sensorName = val.displayName.replaceAll(" ",'\\\\ ')
// 0=closed, 1=open
def contactState = val.currentState("contact").value == "open" ? 1 : 0
full_body += "contact,sensor=${sensorName} value=${contactState} \n"
}
humidity.eachWithIndex{ val, idx ->
def sensorName = val.displayName.replaceAll(" ",'\\\\ ')
full_body += "humidity,sensor=${sensorName} value=${val.currentState("humidity").value} \n"
}
motions.eachWithIndex{ val, idx ->
def sensorName = val.displayName.replaceAll(" ",'\\\\ ')
// 0=no motion, 1=motion detected
def motionState = val.currentState("motion").value == "active" ? 1 : 0
full_body += "motion,sensor=${sensorName} value=${motionState} \n"
}
presence.eachWithIndex{ val, idx ->
def sensorName = val.displayName.replaceAll(" ",'\\\\ ')
// 0=no presence, 1=present
def presenceState = val.currentState("presence").value == "present" ? 1 : 0
full_body += "presence,sensor=${sensorName} value=${presenceState} \n"
}
switches.eachWithIndex{ val, idx ->
def sensorName = val.displayName.replaceAll(" ",'\\\\ ')
// 0=off, 1=on
def switchState = val.currentState("switch").value == "on" ? 1 : 0
full_body += "switch,sensor=${sensorName} value=${switchState} \n"
}
energy.eachWithIndex{ val, idx ->
def sensorName = val.displayName.replaceAll(" ",'\\\\ ')
full_body += "energy,sensor=${sensorName} value=${val.currentState("energy").value} \n"
}
smoke.eachWithIndex{ val, idx ->
def sensorName = val.displayName.replaceAll(" ",'\\\\ ')
// 0="clear" 1="detected" 2="tested"
def smokeState = val.currentState("smoke").value == "detected" ? 1 : 0
full_body += "smoke,sensor=${sensorName} value=${smokeState} \n"
}
def params = [
uri: full_url,
body: full_body
]
try {
// Make the HTTP request using httpGet()
log.debug "Calling $params"
httpPost(params) { resp -> // This is how we define the "return data". Can also use $it.
log.debug "response data: ${resp.data}"
}
} catch (e) {
log.error "something went wrong: $e"
}
}