SmartThings Community

GroveStreams SmartThings QuickStart

If you are using the queuing version of the SmartApp, then I’ve modified it to drop the queue on a PUT error:

This is to avoid the huge data I/O explosion I had when my uploads to GroveStreams started failing:

Here’s an initial version of my ‘InfluxDB Logger’ SmartApp… https://github.com/codersaur/SmartThings

Hope it’s of some use. I will be creating a blog soon, and will write up some tutorials on how to setup InfluxDB and Grafana to use the data. Best to give me a few weeks though… :sweat_smile:

I’m quite pleased with it all now though. In conjunction with my Evohome (Connect) SmartApp I’m getting some great graphs of my home heating behaviour and enery usage. Here’s a quick example:

[Updated with a better chart showing periods of heating and optimisation]

HTH

Z

1 Like

… and after a week of learning Wordpress, here’s my first blog post!! :blush:

It’s a walk-through of how to set up InfluxDB and Grafana, and use my InfluxDB Logger SmartApp to get data from SmartThings.

It covers only basic graphs for now, but I aim to follow it up with details for the more-advanced graphs I’ve managed to put together soon.

I’m concious this thread is about GroveStreams, so I’ve started a new thread about InfluxDB and Grafana over here: SmartThings Data Visualisation using InfluxDB and Grafana

z.

1 Like

Hi, @JasonBSteele.
I managed to blow the 5Mb data allowance on GroveStream in one day – 78Mb!

I used the SmartApp at https://www.grovestreams.com/developers/getting_started_smartthings.html

Should I be using a different version ““This version does not include any queuing or buffering logic to attempt to prevent exceeding the free usage limits””. Where do I find that? Does OP mean original post??? If so, that’s the version I used.

Any help appreciated.

@Cheth Yes OP means Original Post. Other’s in this thread have created solutions which queue the data going to GroveStreams to throttle it so that usage limits don’t get blown. I’m not currently using any of these but the are snippets of code in the thread that can be used to overwrite the code from the OP. I think there is another GroveStreams thread somewhere which may also have links to code. Sorry I couldn’t be of more help!

How do I add illuminance Mesurment to groveStreams?

I edited CyborgMaster smart app and added illuminance. The app allowed
me to select zooZ sensor that had illuminance Mesurment, but it didn’t show
up in Observation Studio.

SmartApp:[code]
definition(name: “GroveStreams w Light”,
namespace: “CyborgMaster”,
author: “NathanEdit”,
description: “Log to GroveStreams”,
category: “My Apps”,
iconUrl: “https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience.png”,
iconX2Url: “https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience@2x.png”,
iconX3Url: “https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience@2x.png”)

preferences {
section(“Log devices…”) {
input(“temperatures”, “capability.temperatureMeasurement”,
title: “Temperatures”, required:false, multiple: true)
input(“humidities”, “capability.relativeHumidityMeasurement”,
title: “Humidities”, required:false, multiple: true)
input(“thermostats”, “capability.thermostat”,
title: “Thermostats”, required: false, multiple: true)
input(“illuminance”, “capability.illuminanceMeasurement”,
title: “Illuminance”, required:false, multiple: true)
input(“contacts”, “capability.contactSensor”,
title: “Doors open/close”, required: false, multiple: true)
input(“accelerations”, “capability.accelerationSensor”,
title: “Accelerations”, 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(“batteries”, “capability.battery”,
title: “Batteries”, required: false, multiple: true)
}

section (“GroveStreams Feed PUT API key…”) {
input “channelKey”, “text”, title: “API key”
}
}

def installed() {
initialize()
}

def updated() {
log.debug "Updating…"
unsubscribe()
unschedule()
initialize()
}

def initialize() {
subscribe(temperatures, “temperature”, handleTemperatureEvent)
subscribe(humidities, “humidity”, handleHumidityEvent)
subscribe(illuminance, “illuminance”, handleIlluminanceEvent)
subscribe(thermostats, “thermostatOperatingState”, handleThermostatOperatingStateEvent)
subscribe(contacts, “contact”, handleContactEvent)
subscribe(accelerations, “acceleration”, handleAccelerationEvent)
subscribe(motions, “motion”, handleMotionEvent)
subscribe(presence, “presence”, handlePresenceEvent)
subscribe(switches, “switch”, handleSwitchEvent)
subscribe(batteries, “battery”, handleBatteryEvent)
if (atomicState.queue == null) {
log.debug "Initializing queue"
atomicState.queue = []
}
if (atomicState.lock == null) {
log.debug "Initializing lock"
atomicState.lock = []
}
schedule(“27 * * * * ?”, processQueue)
}

def handleTemperatureEvent(evt) {
queueValue(evt) { it.toString() }
}

def handleHumidityEvent(evt) {
queueValue(evt) { it.toString() }
}

def handleilluminanceEvent(evt) {
queueValue(evt) { it.toString() }
}

def handleThermostatOperatingStateEvent(evt) {
queueValue(evt) { it == “idle” ? “false” : “true” }
}

def handleBatteryEvent(evt) {
queueValue(evt) { it.toString() }
}

def handleContactEvent(evt) {
queueValue(evt) { it == “open” ? “true” : “false” }
}

def handleAccelerationEvent(evt) {
queueValue(evt) { it == “active” ? “true” : “false” }
}

def handleMotionEvent(evt) {
queueValue(evt) { it == “active” ? “true” : “false” }
}

def handlePresenceEvent(evt) {
queueValue(evt) { it == “present” ? “true” : “false” }
}

def handleSwitchEvent(evt) {
queueValue(evt) { it == “on” ? “true” : “false” }
}

private queueValue(evt, Closure convert) {
def jsonPayload = [compId: evt.displayName, streamId: evt.name, data: convert(evt.value), time: now()]
log.debug “Appending to queue ${jsonPayload}”

synchronized(atomicState.lock) {
def queue = atomicState.queue
queue << jsonPayload
atomicState.queue = queue
}

log.debug “Queue ${atomicState.queue}”
}

def processQueue() {
log.debug "Processing queue"
def url = "https://grovestreams.com/api/feed?api_key=${channelKey}"
def header = [“X-Forwarded-For”: location.id]
if (atomicState.queue != null && atomicState.queue.size() > 0) {
synchronized(atomicState.lock) {
log.debug "Events: ${atomicState.queue}"
try {
httpPutJson([“uri”: url, “header”: header, “body”: atomicState.queue]) {
response ->
if (response.status != 200 ) {
log.debug “GroveStreams logging failed, status = ${response.status}”
} else {
log.debug "GroveStreams accepted event(s)"
atomicState.queue = []
}
}
} catch(e) {
def errorInfo = "Error sending value: ${e}"
log.error errorInfo
if (e instanceof groovyx.net.http.ResponseParseException) {
log.debug "Simple parse error, events were still accepted. Clearing queue"
atomicState.queue = []
}
}
}
}
}[/code]

zooZ Device Handler:

[code] metadata {
definition (name: “zooZ Sensor 1.2 - Temperature”, namespace: “robertvandervoort”, author: “Robert Vandervoort”) {
capability "Motion Sensor"
capability "Acceleration Sensor"
capability "Temperature Measurement"
capability "Relative Humidity Measurement"
capability "Illuminance Measurement"
capability "Configuration"
capability "Sensor"
capability “Battery”

    // RAW Description: 0 0 0x0701 0 0 0 e 0x5E 0x98 0x86 0x72 0x5A 0x85 0x59 0x73 0x80 0x71 0x31 0x70 0x84 0x7A   										 
	attribute "tamper", "enum", ["detected", "clear"]
	fingerprint deviceId: "0x0701", inClusters: "0x5E,0x86,0x72,0x59,0x85,0x73,0x71,0x84,0x80,0x31,0x70,0x5A,0x98,0x7A"
	}

/* simulator {
status “no motion” : "command: 9881, payload: 00300300"
status “motion” : "command: 9881, payload: 003003FF"
status “clear” : " command: 9881, payload: 0071050000000007030000"
status “tamper” : “command: 9881, payload: 007105000000FF07030000”

    for (int i = 0; i <= 100; i += 20) {
		status "temperature ${i}F": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate(
			new physicalgraph.zwave.Zwave().sensorMultilevelV2.sensorMultilevelReport(
            	scaledSensorValue: i,
                precision: 2,
                sensorType: 1,
                scale: 1
			)
		).incomingMessage()
	}
	for (int i = 0; i <= 100; i += 20) {
		status "RH ${i}%": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate(
			new physicalgraph.zwave.Zwave().sensorMultilevelV2.sensorMultilevelReport(
            	scaledSensorValue: i,
                sensorType: 5
        	)
		).incomingMessage()
	}
	for (int i in [0, 1, 2, 8, 12, 16, 20, 24, 30, 64, 82, 100, 200, 500, 1000]) {
		status "illuminance ${i}%": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate(
			new physicalgraph.zwave.Zwave().sensorMultilevelV2.sensorMultilevelReport(
            scaledSensorValue: i,
            sensorType: 3
            )
		).incomingMessage()
	}
	for (int i in [0, 5, 10, 15, 50, 99, 100]) {
		status "battery ${i}%": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate(
			new physicalgraph.zwave.Zwave().batteryV1.batteryReport(
            batteryLevel: i
            )
		).incomingMessage()
	}
	status "low battery alert": new physicalgraph.zwave.Zwave().securityV1.securityMessageEncapsulation().encapsulate(
			new physicalgraph.zwave.Zwave().batteryV1.batteryReport(
        	batteryLevel: 255
        	)
		).incomingMessage()
	status "wake up": "command: 8407, payload:"
}

*/
tiles (scale: 2) {
multiAttributeTile(name:“main”, type:“generic”, width:6, height:4) {
tileAttribute(“device.temperature”, key: “PRIMARY_CONTROL”) {
attributeState “temperature”,label:’${currentValue}°’, precision:2, backgroundColors:[
[value: 32, color: “#153591”],
[value: 44, color: “#1e9cbb”],
[value: 59, color: “#90d2a7”],
[value: 74, color: “#44b621”],
[value: 84, color: “#f1d801”],
[value: 92, color: “#d04e00”],
[value: 98, color: “#bc2323”]
]
}
tileAttribute(“device.humidity”, key: “SECONDARY_CONTROL”) {
attributeState “humidity”,label:‘RH ${currentValue} %’, precision:2
}
}
standardTile(“motion”,“device.motion”, width: 2, height: 2) {
state “active”,label:‘motion’,icon:“st.motion.motion.active”,backgroundColor:"#53a7c0"
state “inactive”,label:‘no motion’,icon:“st.motion.motion.inactive”,backgroundColor:"#ffffff"
}
valueTile(“humidity”,“device.humidity”, width: 2, height: 2) {
state “humidity”,label:‘RH ${currentValue}%’, precision:2
}
valueTile(“illuminance”,“device.illuminance”, width: 2, height: 2) {
state “luminosity”,label:‘LIGHT ${currentValue}%’, precision:2
}
standardTile(“acceleration”, “device.acceleration”, width: 2, height: 2) {
state(“active”, label:‘tamper’, icon:“st.motion.acceleration.active”, backgroundColor:"#ff0000")
state(“inactive”, label:‘clear’, icon:“st.motion.acceleration.inactive”, backgroundColor:"#00ff00")
}
valueTile(“battery”, “device.battery”, decoration: “flat”, width: 2, height: 2) {
state “battery”, label:’${currentValue}% battery’
}
main([“main”])
details([“main”,“humidity”,“illuminance”,“motion”,“acceleration”,“battery”])
}
preferences {
input “debugOutput”, “boolean”,
title: “Enable debug logging?”,
defaultValue: false,
displayDuringSetup: true
input “LEDbehavior”, “enum”,
title: “LED Behavior”,
options: [“LED Off”, “Breathing”, “Quick Blink on Temp/PIR”],
defaultValue: “Quick Blink on Temp/PIR”,
required: false,
displayDuringSetup: false
input “tempoffset”, “number”,
title: “Reporting threshold for temp”,
description: “Enter a value 1-50 changing reporting threshold for temp. Represents 0.1 degree increments.”,
range: “1…50”,
defaultValue: 50,
required: false,
displayDuringSetup: false
input “humidityoffset”, “number”,
title: “Reporting threshold for humidity”,
description: “Report when change occurs from 1%-50% RH)”,
range: “1…50”,
defaultValue: 1,
required: false,
displayDuringSetup: false
input “luminanceoffset”, “number”,
title: “Reporting threshold for Luminance”,
description: “valid values from 5% to 50%”,
range: “5…50”,
defaultValue: 5,
required: false,
displayDuringSetup: false
input “PIRsensitivity”, “number”,
title: “PIR motion sensitivity”,
description: “A value from 1-7, from high to low sensitivity (1 is highest)”,
range: “1…7”,
defaultValue: 4,
required: false,
displayDuringSetup: true
input “MotionReset”, “number”,
title: “PIR reset time”,
description: “Number of minutes to wait to report motion cleared after a motion event if there is no motion detected.”,
range: “1…255”,
defaultValue: 5,
required: false,
displayDuringSetup: true
}
}

def updated()
{
updateDataValue(“configured”, “false”)
state.debug = (“true” == debugOutput)
}

def parse(String description)
{
def result = null
if (description.startsWith(“Err 106”)) {
state.sec = 0
result = createEvent( name: “secureInclusion”, value: “failed”, isStateChange: true,
descriptionText: “This sensor failed to complete the network security key exchange. If you are unable to control it via SmartThings, you must remove it from your network and add it again.”)
} else if (description != “updated”) {
def cmd = zwave.parse(description, [0x31: 5, 0x71:3, 0x7A: 2, 0x81: 1, 0x84: 2, 0x86: 2])
if (cmd) {
result = zwaveEvent(cmd)
}
}
if (state.debug) log.debug "Parsed ‘${description}’ to ${result.inspect()}"
return result
}

def zwaveEvent(physicalgraph.zwave.commands.wakeupv2.WakeUpNotification cmd)
{
def result = [createEvent(descriptionText: “${device.displayName} woke up”, isStateChange: false)]
if (!isConfigured()) {
// we’re still in the process of configuring a newly joined device
if (state.debug) log.debug(“late configure”)
result += response(configure())
} else {
result += response(checkBattery())
}
result
}

def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) {
def encapsulatedCommand = cmd.encapsulatedCommand([0x31: 5, 0x71: 3, 0x7A: 2, 0x81: 1, 0x84: 2])
state.sec = 1
// if (state.debug) log.debug "encapsulated: ${encapsulatedCommand}"
if (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) {
if (state.debug) log.debug "—SECURITY COMMANDS SUPPORTED REPORT V1— ${device.displayName} sent commandClassControl: ${cmd.commandClassControl}, commandClassSupport: ${cmd.commandClassSupport}, reportsToFollow: ${cmd.reportsToFollow}"
response(configure())
}

def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.DeviceSpecificReport cmd) {
if (state.debug) log.debug “—MANUFACTURER SPECIFIC REPORT V2— ${device.displayName} sent deviceIdDataFormat: ${cmd.deviceIdDataFormat}, deviceIdDataLengthIndicator: ${cmd.deviceIdDataLengthIndicator}, deviceIdType: ${cmd.deviceIdType}, payload: ${cmd.payload}”
}

def zwaveEvent(physicalgraph.zwave.commands.versionv1.VersionCommandClassReport cmd) {
if (state.debug) log.debug “—COMMAND CLASS VERSION REPORT V1— ${device.displayName} has command class version: ${cmd.commandClassVersion} - payload: ${cmd.payload}”
}

def zwaveEvent(physicalgraph.zwave.commands.versionv1.VersionReport cmd) {
def fw = "${cmd.applicationVersion}.${cmd.applicationSubVersion}"
updateDataValue(“fw”, fw)
if (state.debug) log.debug “—VERSION REPORT V1— ${device.displayName} is running firmware version: $fw, Z-Wave version: ${cmd.zWaveProtocolVersion}.${cmd.zWaveProtocolSubVersion}”
}

def zwaveEvent(physicalgraph.zwave.commands.configurationv1.ConfigurationReport cmd) {
if (state.debug) log.debug “—CONFIGURATION REPORT V1— ${device.displayName} parameter ${cmd.parameterNumber} with a byte size of ${cmd.size} is set to ${cmd.configurationValue}”
}

def zwaveEvent(physicalgraph.zwave.commands.configurationv2.ConfigurationReport cmd) {
if (state.debug) log.debug “—CONFIGURATION REPORT V2— ${device.displayName} parameter ${cmd.parameterNumber} with a byte size of ${cmd.size} is set to ${cmd.configurationValue}”
}

def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) {
def map = [ name: “battery”, unit: “%” ]
if (cmd.batteryLevel == 0xFF) {
map.value = 1
map.descriptionText = "${device.displayName} battery is low"
map.isStateChange = true
createEvent(map)
} else {
map.value = cmd.batteryLevel
createEvent(map)
}
state.lastbatt = now()
createEvent(map)
}

def zwaveEvent(physicalgraph.zwave.commands.sensormultilevelv5.SensorMultilevelReport cmd) {
if (state.debug) log.debug "—SENSOR MULTILEVEL v5 REPORT— ${device.displayName} sent sensorType: ${cmd.sensorType} value: ${cmd.sensorValue} scale: ${cmd.scale} scaledSensorValue: ${cmd.scaledSensorValue}"
def map = [:]
switch (cmd.sensorType) {
case 1:
map.name = "temperature"
def cmdScale = cmd.scale == 1 ? “F” : "C"
map.value = convertTemperatureIfNeeded(cmd.scaledSensorValue, cmdScale, cmd.precision)
map.unit = getTemperatureScale()
break;
case 3:
map.name = "illuminance"
map.value = cmd.scaledSensorValue
map.unit = "%"
break;
case 5:
map.name = "humidity"
map.value = cmd.scaledSensorValue
map.unit = "%"
break;
default:
map.descriptionText = cmd.toString()
}
createEvent(map)
}

def motionEvent(value) {
def map = [name: “motion”]
if (value != 0) {
map.value = "active"
map.descriptionText = “$device.displayName detected motion”
} else {
map.value = "inactive"
map.descriptionText = “$device.displayName motion has stopped”
}
createEvent(map)
}

def zwaveEvent(physicalgraph.zwave.commands.sensorbinaryv2.SensorBinaryReport cmd) {
if (state.debug) log.debug "—SENSOR BINARY REPORT V2— ${device.displayName} sent value: ${cmd.sensorValue}"
motionEvent(cmd.sensorValue)
}

def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicSet cmd) {
if (state.debug) log.debug "—BASIC SET REPORT V1— ${device.displayName} sent value: ${cmd.value}"
motionEvent(cmd.value)
}

def zwaveEvent(physicalgraph.zwave.commands.notificationv3.NotificationReport cmd) {
if (state.debug) log.debug “—NOTIFICATION REPORT V3— ${device.displayName} sent eventParametersLength: ${cmd.eventParametersLength} eventParameter: ${cmd.eventParameter} notificationType: ${cmd.notificationType} event: ${cmd.event}”
def result = []
if (cmd.notificationType == 7) {
if (cmd.event == 0x00 && cmd.eventParameter == 0x08) {
result << motionEvent(0)
}
else if (cmd.event == 0x03) {
result << createEvent(name: “acceleration”, value: “active”, descriptionText: “$device.displayName cover is open.”)
}
else if (cmd.event == 0X00 || cmd.eventParameter == 0x03) {
result << createEvent(name: “acceleration”, value: “inactive”, descriptionText: “$device.displayName cover has been closed.”)
}
else if (cmd.event == 0x08) {
result << motionEvent(255)
}
}
else {
result << createEvent(descriptionText: cmd.toString(), isStateChange: false)
}
result
}

def zwaveEvent(physicalgraph.zwave.Command cmd) {
createEvent(descriptionText: cmd.toString(), isStateChange: false)
}

private checkBattery() {
def request = [
zwave.batteryV1.batteryGet(),
zwave.wakeUpV1.wakeUpNoMoreInformation()
]
commands(request)
}

def configure() {
// This sensor joins as a secure device if you double-click the button to include it
//if (device.device.rawDescription =~ /98/ && !state.sec) {
// if (state.debug) log.debug “4-in-1 sensor not sending configure until secure”
// return []
//}
if (state.debug) log.debug “–Sending configuration commands to zooZ 4-in-1 sensor–”
//if (state.debug) log.debug "Prefernces settings: PIRsensitivity: $PIRsensitivity, Temp offset: $tempoffset, Humidity offset: $humidityoffset, Luminance offset: $luminanceoffset"
def LEDbehav = 3
if (LEDbehavior == “LED Off”) {
LEDbehav=1
}
else if (LEDbehavior == “Breathing”) {
LEDbehav=2
}
else {
LEDbehav=3
}
def PIRsens = 4
if (PIRsensitivity) {
PIRsens=PIRsensitivity
}
else {
PIRsens = 4
}
def MotionRst = 3
if (MotionReset) {
MotionRst=MotionReset
}
else {
MotionRst = 3
}
def tempoff = 1
if (tempoffset) {
tempoff=tempoffset
}
else {
tempoff = 1
}
def humidityoff = 10
if (humidityoffset) {
humidityoff=humidityoffset
}
else {
humidityoff = 10
}
def luminanceoff = 10
if (luminanceoffset) {
luminanceoff=luminanceoffset
}
else {
luminanceoff = 10
}
if (state.debug) log.debug "settings: ${settings.inspect()}, state: ${state.inspect()}"
setConfigured()
def request = [
// set wakeup interval to 20 mins
zwave.wakeUpV1.wakeUpIntervalSet(seconds:3600, nodeid:zwaveHubNodeId),

	// Get Version information
    zwave.versionV1.versionGet(),
    zwave.firmwareUpdateMdV2.firmwareMdGet(),

    // configure temp scale to celcius or fahrenheight and set offset
	zwave.configurationV1.configurationSet(parameterNumber: 0x01, size: 1, scaledConfigurationValue: 1),
	zwave.configurationV1.configurationGet(parameterNumber: 0x01),
	zwave.configurationV1.configurationSet(parameterNumber: 0x02, size: 1, scaledConfigurationValue: tempoff),		
	zwave.configurationV1.configurationGet(parameterNumber: 0x02),

    // configure humidity offset
	zwave.configurationV1.configurationSet(parameterNumber: 0x03, size: 1, scaledConfigurationValue: humidityoff),
	zwave.configurationV1.configurationGet(parameterNumber: 0x03),

    // configure luminance offset
	zwave.configurationV1.configurationSet(parameterNumber: 0x04, size: 1, scaledConfigurationValue: luminanceoff),
	zwave.configurationV1.configurationGet(parameterNumber: 0x04),

	// send no-motion report x minutes after motion stops
	zwave.configurationV1.configurationSet(parameterNumber: 0x05, size: 1, scaledConfigurationValue: MotionRst),
	zwave.configurationV1.configurationGet(parameterNumber: 0x05),

	// set motion sensor sensitivity
    zwave.configurationV1.configurationSet(parameterNumber: 0x06, size: 1, scaledConfigurationValue: PIRsens),
	zwave.configurationV1.configurationGet(parameterNumber: 0x06),

    // set LED behavior
    zwave.configurationV1.configurationSet(parameterNumber: 0x07, size: 1, scaledConfigurationValue: LEDbehav),
    zwave.configurationV1.configurationGet(parameterNumber: 0x07),

	// get updated battery and sensor data
    zwave.batteryV1.batteryGet(),
	zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType:1, scale:1),
    zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType:3, scale:0),
    zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType:5, scale:0),

	// Can use the zwaveHubNodeId variable to add the hub to the device's associations:
	zwave.associationV1.associationSet(groupingIdentifier:2, nodeId:zwaveHubNodeId)
]
commands(request) + ["delay 20000", zwave.wakeUpV1.wakeUpNoMoreInformation().format()]

}

private setConfigured() {
updateDataValue(“configured”, “true”)
return []
}

private isConfigured() {
getDataValue(“configured”) == “true”
}

private command(physicalgraph.zwave.Command cmd) {
if (state.sec) {
zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format()
} else {
cmd.format()
}
}

private commands(commands, delay=1000) {
delayBetween(commands.collect{ command(it) }, delay)
}[/code]

I just tried using your edited grovestreams smartapp, and noticed that the handleilluminanceEvent has a mismatched capital… up above, it is listed as handleIlluminanceEvent with a capital I on illuminance

This smartapp works well for illuminance and other smart devices such as My Ecobee and MyAutomatic devices:

Regards.

1 Like

I have some Monoprice motion sensors with temp sensors that I added to the grove streams smart app but they haven’t shown up in on the website. I just noticed I have the following notification.

The feed from ‘52.203.225.134’ requires items in your organization that do not exist

Missing Required Items:

Component Id: Garage Temp/Motion
Missing Item type: stream
Missing Item Id: temperature

Some feeders will initially assume items exist and if they do not exist will include meta-data in the next upload so that items are automatically created. You will have to take corrective action if this message keeps repeating.

I received just the one notification for each monoprice sensor but I"m wondering if that is why the temp stream for those devices isn’t showing up.

Hi, hopefully this is a good place to post this question…

I’ve been using Grovestreams for ~9mo’s or so, only for temperature capture. Now I find I want to add power events (just got my AEON HEM v1 installed), and find that I must change my setup to use a different version of the smartApp/DH (currently using the first “simple” version from excellent the “getting started” page.

My question is whether there’s a way to make this upgrade without losing my existing historical temp data in my grovestream account? Can I add the new smartApp (w/energy/power capabilities) and keep the existing dataset for awhile?

If I can’t keep the old stuff that would be OK, but thought I’d ask the experts here on ways to “add” these new streams without losing the existing captured data.

thanks!

I use Grovestreams (GS) but I am not an expert.

You can copy one stream data to another NEW stream for archiving - so you won’t lose the data when you are manipulating the original stream. You perform these actions by logging into your user account at GS.

If you really want to protect it then download it in text/CSV.

A new smart-app will probably NOT direct GS to delete any historical data at GS. None of the GS smart-apps that I have seen and used, will delete - they just send new data to GS. I expect that changing a stream name, will cause the new stream name and its data to be recorded at GS, but the old stream name data will remain at GS .

Just to confirm - changing to a new GS smartApp worked fine for me, i.e. old streams in GS itself were not affected and it just added the new component/stream as I had wanted.

I think I went through the guide ok but I get no components showing, I am in the UK if that causes any problems.
Any idea what I can check to get this working?

well just typical, there are components now, hours after I set it all up :slight_smile:

yvesracine,

Thank you for posting this. I have been modifying the existing code to collect all of this data and doing it rouge. I’m glad I did as it forced me to learn about what’s going on behind the scenes. I ran into a wall when trying to figure out how to pass the enum variables. So I broke down and searched this post for ecobee support… appreciate the work :+1:

Nick

Thanks for putting this together!

Hi @Nsiegfried,

Please note that the groveStream’s ecobee support is done with My Ecobee device which is the most comprehensive ecobee integration with SmartThings.

Regards.

I have everything setup using your code at the bottom of the tutorial. I seem to be using a lot of data. I have only bee using it about a week and im very close to the 5MB monthly allowance. Any guidance on how to slow this down ?

Dear all

I have reached my maximum 5 mb of data in Grovestream. I have a lot of sensors that report different types of data. One sensor (power plug) reports data every 5-10 seconds.

I have read the entire thread but have not been able to find any solution to reduce my data usage - maybe someine in here could help me?

My grovestreams setup is as follows:

/**
 * SmartThings example Code for GroveStreams
 * A full "how to" guide for this example can be found at
 *   https://www.grovestreams.com/developers/getting_started_smartthings.html
 *
 * Copyright 2015 Jason Steele
 *
 * 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.
 *
 */
 
definition(
                name: "GroveStreams",
                namespace: "JasonBSteele",
                author: "Jason Steele",
                description: "Log to GroveStreams",
                category: "My Apps",
                iconUrl: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience.png",
                iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience@2x.png",
                iconX3Url: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience@2x.png")
 
preferences {
 
        section("Log devices...") {
                input "temperatures", "capability.temperatureMeasurement", title: "Temperatures", required:false, multiple: true
                input "illuminance", "capability.illuminanceMeasurement", title: "Illuminance", required:false, multiple: true
                input "ultravioletIndex", "capability.ultravioletIndex", title: "ultravioletindex", required:false, multiple: true
                input "humidities", "capability.relativeHumidityMeasurement", title: "Humidities", required: false, multiple: true
                input "contacts", "capability.contactSensor", title: "Doors open/close", required: false, multiple: true
                input "accelerations", "capability.accelerationSensor", title: "Accelerations", 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 "waterSensors", "capability.waterSensor", title: "Water sensors", required: false, multiple: true
                input "batteries", "capability.battery", title: "Batteries", required:false, multiple: true
                input "powers", "capability.powerMeter", title: "Power Meters", required:false, multiple: true
                input "energies", "capability.energyMeter", title: "Energy Meters", required:false, multiple: true
        }
 
        section ("GroveStreams Feed PUT API key...") {
                input "apiKey", "text", title: "API key"
        }
}
 
def installed() {
        initialize()
}
 
def updated() {
        unsubscribe()
        initialize()
}
 
def initialize() {
 
        subscribe(temperatures, "temperature", handleTemperatureEvent)
        subscribe(illuminance, "illuminance", handleIlluminanceEvent)
        subscribe(ultravioletIndex, "ultravioletIndex", handleultravioletIndexEvent)
		subscribe(waterSensors, "water", handleWaterEvent)
        subscribe(humidities, "humidity", handleHumidityEvent)
        subscribe(contacts, "contact", handleContactEvent)
        subscribe(accelerations, "acceleration", handleAccelerationEvent)
        subscribe(motions, "motion", handleMotionEvent)
        subscribe(presence, "presence", handlePresenceEvent)
        subscribe(switches, "switch", handleSwitchEvent)
        subscribe(batteries, "battery", handleBatteryEvent)
        subscribe(powers, "power", handlePowerEvent)
        subscribe(energies, "energy", handleEnergyEvent)
}
 
def handleTemperatureEvent(evt) {
        sendValue(evt) { it.toString() }
}
 
def handleIlluminanceEvent(evt) {
		sendValue(evt) { it.toString() }
}

def handleultravioletIndexEvent(evt) {
		sendValue(evt) { it.toString() }
}

def handleWaterEvent(evt) {
        sendValue(evt) { it == "wet" ? "true" : "false" }
}
 
def handleHumidityEvent(evt) {
        sendValue(evt) { it.toString() }
}
 
def handleContactEvent(evt) {
        sendValue(evt) { it == "open" ? "true" : "false" }
}
 
def handleAccelerationEvent(evt) {
        sendValue(evt) { it == "active" ? "true" : "false" }
}
 
def handleMotionEvent(evt) {
        sendValue(evt) { it == "active" ? "true" : "false" }
}
 
def handlePresenceEvent(evt) {
        sendValue(evt) { it == "present" ? "true" : "false" }
}
 
def handleSwitchEvent(evt) {
        sendValue(evt) { it == "on" ? "true" : "false" }
}
 
def handleBatteryEvent(evt) {
        sendValue(evt) { it.toString() }
}
 
def handlePowerEvent(evt) {
        sendValue(evt) { it.toString() }
}
 
def handleEnergyEvent(evt) {
        sendValue(evt) { it.toString() }
}
 
private sendValue(evt, Closure convert) {
        def compId = URLEncoder.encode(evt.displayName.trim())
        def streamId = evt.name
        def value = convert(evt.value)
       
        log.debug "Logging to GroveStreams ${compId}, ${streamId} = ${value}"
 
        def url = "https://grovestreams.com/api/feed?api_key=${apiKey}&compId=${compId}&${streamId}=${value}"
 
        //Make the actual device the origin of the message to avoid exceeding 12 calls within 2 minutes rule:
        //http://forum.grovestreams.com/topic/155/10-second-feed-put-limit-algorithm-change/
        def header = ["X-Forwarded-For": evt.deviceId]
 
        def putParams = [
                uri: url,
                header: header,
                body: []]
 
        httpPut(putParams) { response ->
                if (response.status != 200 ) {
                        log.debug "GroveStreams logging failed, status = ${response.status}"
                }
 
        }
 
}

you would have to switch to a device handler that doesn’t report so often. The Centralite plug is crazy-noisy at default. Maybe there is a custom handler for it.

I found it easier to use a different physical device with better defaults, or use custom DH with customizable report rates, e.g. Zooz Zen15.

1 Like