Is there a way to force a sensor to respond even if the value hasn’t changed?

configure can be called by going into edit mode for the device in the IDE and then saving.

1 Like

it does state Heiman so maybe it is! In the app the refresh button does initiate and show a update in its recent activity tab. Whats interesting is when I just tested this it posted each value twice. I dont remember it doing that previously.

Going to try edit mode first and then mess with code otherwise.

So configure works the same as updated?

Edit: I see you said in the IDE. I’ll have to play with that - sounds like it could be useful.

No configure option to be found in edit mode on device.

did find this though, so Heiman and Centralite are one and the same it would appear

No, that’s listing the devices the device handler will work with. It won’t hurt to edit all of the lines in configure, but you probably do want the ones in the else.

So far have not found a configuration window or button either off of the device or the device handler so might just edit the code itself

In IDE, click Devices, click the device you’re working on, click Edit, click Update. Do that with a logging window open and you should see a log saying it’s running config.

ok did all that but there was not a configure window or button or link that popped up, it was just a bunch of data coming across the log?

Was there a debug log line that says “Configuring Reporting and Bindings”?

Yes there was, one of the first ones to pop up

Then the configure function ran. If no errors popped up after that, then sit back and wait to see if it worked.

Set it for 7200, updated all 3x sensors to make sure they are all exposed to published code, will check back on them in a few hours. Now trying to get some actual work done at work :slight_smile: thanks!

1 Like

like this
sendEvent(name:“nextHeatingSetpoint”, value: degrees, unit: getTemperatureScale(), descriptionText: “Next heating setpoint is ${degrees}”, displayed: true, isStateChange:true)

when it recives a report isStateChange:true logs it even if it is the same

I’m going to let this sit for a bit to gather some data but I did notice some weird things over the course of last night.

  • At times the sensors would be offline in the smartthings app but come back online when hitting the refresh button.
  • every time you hit the refresh button it will refresh and post the values twice
  • The interval of 7200 (2 hours) doesnt seem to actually work because I got values reported more often then that.

Will post logs and screenshots when it has captured enough to give a complete picture

1 Like

They may just be getting marked by ST as offline because they’re checking in more infrequently now. If you don’t hit refresh when they’re showing offline, do they still report?

I’ve seen that doubling of reports with other devices. I’m not sure what’s going on - it could be the app thinking you hit the button twice.

When it reports more frequently than two hours, is it associated with a temp/humidity change? It could be that the device is reporting every time there’s a change, and then also every two hours.

Hard to tell if they are reporting when offline because I cant tell when they go offline. One of them is currently offline and its last posted report was 67 minutes ago.

The additional reports are not due to a change. This particular unit is in my humidor so its very stable in there.

As of right now we went from too little data to too much data hahaha! Trying to find the happy medium of it reporting a temperature and humidity reading every 6 hours and also stay online in the app. Still waiting on the log to populate a bit more

did you set the minimum or maximum to 7200?

for the time used to determine online/offline, check the checkInterval value for the device. May need to adjust it in the device handler.

This is what I am currently trying to make work. The time adjustments made are all the way to the bottom

/**
 *  SmartSense Temp/Humidity Sensor
 *
 *  Copyright 2014 SmartThings
 *
 *  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.
 *
 */
import physicalgraph.zigbee.zcl.DataType

metadata {
	definition(name: "SmartSense Temp/Humidity Sensor V2", namespace: "smartthings", author: "SmartThings", runLocally: false, minHubCoreVersion: '000.017.0012', executeCommandsLocally: false) {
		capability "Configuration"
		capability "Battery"
		capability "Refresh"
		capability "Temperature Measurement"
		capability "Relative Humidity Measurement"
		capability "Health Check"
		capability "Sensor"

		fingerprint profileId: "0104", inClusters: "0001,0003,0020,0402,0B05,FC45", outClusters: "0019,0003", manufacturer: "CentraLite", model: "3310-S", deviceJoinName: "SmartSense Temp & Humidity Sensor"
		fingerprint profileId: "0104", inClusters: "0001,0003,0020,0402,0B05,FC45", outClusters: "0019,0003", manufacturer: "CentraLite", model: "3310-G", deviceJoinName: "Temp & Humidity Sensor"
		fingerprint profileId: "0104", inClusters: "0001,0003,0020,0402,0B05,FC45", outClusters: "0019,0003", manufacturer: "CentraLite", model: "3310", deviceJoinName: "Temp & Humidity Sensor"
		fingerprint profileId: "0104", deviceId: "0302", inClusters: "0000,0001,0003,0402", manufacturer: "Heiman", model: "b467083cfc864f5e826459e5d8ea6079", deviceJoinName: "Orvibo Temperature & Humidity Sensor"
		fingerprint profileId: "0104", deviceId: "0302", inClusters: "0000,0001,0003,0402", manufacturer: "HEIMAN", model: "888a434f3cfc47f29ec4a3a03e9fc442", deviceJoinName: "Orvibo Temperature & Humidity Sensor"
	}

	simulator {
		status 'H 40': 'catchall: 0104 FC45 01 01 0140 00 D9B9 00 04 C2DF 0A 01 000021780F'
		status 'H 45': 'catchall: 0104 FC45 01 01 0140 00 D9B9 00 04 C2DF 0A 01 0000218911'
		status 'H 57': 'catchall: 0104 FC45 01 01 0140 00 4E55 00 04 C2DF 0A 01 0000211316'
		status 'H 53': 'catchall: 0104 FC45 01 01 0140 00 20CD 00 04 C2DF 0A 01 0000219814'
		status 'H 43': 'read attr - raw: BF7601FC450C00000021A410, dni: BF76, endpoint: 01, cluster: FC45, size: 0C, attrId: 0000, result: success, encoding: 21, value: 10a4'
	}

	preferences {
		input title: "Temperature Offset", description: "This feature allows you to correct any temperature variations by selecting an offset. Ex: If your sensor consistently reports a temp that's 5 degrees too warm, you'd enter \"-5\". If 3 degrees too cold, enter \"+3\".", displayDuringSetup: false, type: "paragraph", element: "paragraph"
		input "tempOffset", "number", title: "Degrees", description: "Adjust temperature by this many degrees", range: "*..*", displayDuringSetup: false
		input title: "Humidity Offset", description: "This feature allows you to correct any humidity variations by selecting an offset. Ex: If your sensor consistently reports a humidity that's 6% higher then a similiar calibrated sensor, you'd enter \"-6\".", displayDuringSetup: false, type: "paragraph", element: "paragraph"
		input "humidityOffset", "number", title: "Humidity Offset in Percent", description: "Adjust humidity by this percentage", range: "*..*", displayDuringSetup: false
	}

	tiles(scale: 2) {
		multiAttributeTile(name: "temperature", type: "generic", width: 6, height: 4, canChangeIcon: true) {
			tileAttribute("device.temperature", key: "PRIMARY_CONTROL") {
				attributeState "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("humidity", "device.humidity", inactiveLabel: false, width: 2, height: 2) {
			state "humidity", label: '${currentValue}% humidity', unit: ""
		}
		valueTile("battery", "device.battery", decoration: "flat", inactiveLabel: false, width: 2, height: 2) {
			state "battery", label: '${currentValue}% battery'
		}
		standardTile("refresh", "device.refresh", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
			state "default", action: "refresh.refresh", icon: "st.secondary.refresh"
		}

		main "temperature", "humidity"
		details(["temperature", "humidity", "battery", "refresh"])
	}
}

def parse(String description) {
	log.debug "description: $description"

	// getEvent will handle temperature and humidity
	Map map = zigbee.getEvent(description)
	if (!map) {
		Map descMap = zigbee.parseDescriptionAsMap(description)
		if (descMap.clusterInt == 0x0001 && descMap.commandInt != 0x07 && descMap?.value) {
			map = getBatteryResult(Integer.parseInt(descMap.value, 16))
		} else if (descMap?.clusterInt == zigbee.TEMPERATURE_MEASUREMENT_CLUSTER && descMap.commandInt == 0x07) {
			if (descMap.data[0] == "00") {
				log.debug "TEMP REPORTING CONFIG RESPONSE: $descMap"
				sendEvent(name: "checkInterval", value: 60 * 12, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
			} else {
				log.warn "TEMP REPORTING CONFIG FAILED- error code: ${descMap.data[0]}"
			}
		}
	} else if (map.name == "temperature") {
    map.isStateChange=true
		if (tempOffset) {
			map.value = (int) map.value + (int) tempOffset
		}
		map.descriptionText = temperatureScale == 'C' ? '{{ device.displayName }} was {{ value }}°C' : '{{ device.displayName }} was {{ value }}°F'
		map.translatable = true
	} else if (map.name == "humidity") {
    map.isStateChange=true
		if (humidityOffset) {
        			map.value = (int) map.value + (int) humidityOffset
		}
	}

	log.debug "Parse returned $map"
	return map ? createEvent(map) : [:]
}

private Map getBatteryResult(rawValue) {
	log.debug 'Battery'
	def linkText = getLinkText(device)

  def result = [:]

	def volts = rawValue / 10
	if (!(rawValue == 0 || rawValue == 255)) {
		def minVolts = 2.1
		def maxVolts = 3.0
		def pct = (volts - minVolts) / (maxVolts - minVolts)
		def roundedPct = Math.round(pct * 100)
		if (roundedPct <= 0)
			roundedPct = 1
		result.value = Math.min(100, roundedPct)
		result.descriptionText = "${linkText} battery was ${result.value}%"
		result.name = 'battery'

	}

	return result
}

/**
 * PING is used by Device-Watch in attempt to reach the Device
 * */
def ping() {
	return zigbee.readAttribute(0x0001, 0x0020) // Read the Battery Level
}

def refresh() {
	log.debug "refresh temperature, humidity, and battery"

	def manufacturer = device.getDataValue("manufacturer")

	if (manufacturer == "Heiman"|| manufacturer == "HEIMAN") {
		return zigbee.readAttribute(zigbee.POWER_CONFIGURATION_CLUSTER, 0x0021, [destEndpoint: 0x01])+
		        zigbee.readAttribute(0x0402, 0x0000, [destEndpoint: 0x01])+
		        zigbee.readAttribute(0x0405, 0x0000, [destEndpoint: 0x02])
	} else {
		return zigbee.readAttribute(0xFC45, 0x0000, ["mfgCode": 0x104E]) +   // New firmware
		        zigbee.readAttribute(0xFC45, 0x0000, ["mfgCode": 0xC2DF]) +   // Original firmware
		        zigbee.readAttribute(zigbee.TEMPERATURE_MEASUREMENT_CLUSTER, 0x0000) +
		        zigbee.readAttribute(zigbee.POWER_CONFIGURATION_CLUSTER, 0x0020)
	}
}

def configure() {
	// Device-Watch allows 2 check-in misses from device + ping (plus 1 min lag time)
	// enrolls with default periodic reporting until newer 5 min interval is confirmed
	sendEvent(name: "checkInterval", value: 2 * 60 * 60 + 1 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])

	log.debug "Configuring Reporting and Bindings."

	// temperature minReportTime 30 seconds, maxReportTime 5 min. Reporting interval if no activity
	// battery minReport 30 seconds, maxReportTime 6 hrs by default
	def manufacturer = device.getDataValue("manufacturer")
	if (manufacturer == "Heiman"|| manufacturer == "HEIMAN") {
		return refresh() +
		        zigbee.temperatureConfig(30, 300) +
		        zigbee.configureReporting(zigbee.POWER_CONFIGURATION_CLUSTER, 0x0021, DataType.UINT8, 30, 21600, 0x10) +
		        zigbee.configureReporting(0x0405, 0x0000, DataType.UINT16, 30, 3600, 100, [destEndpoint: 0x02])
	} else {
		return refresh() +
		        zigbee.configureReporting(0xFC45, 0x0000, DataType.UINT16, 30, 7200, 100, ["mfgCode": 0x104E]) +   // New firmware
		        zigbee.configureReporting(0xFC45, 0x0000, DataType.UINT16, 30, 7200, 100, ["mfgCode": 0xC2DF]) +   // Original firmware
		        zigbee.batteryConfig() +
		        zigbee.temperatureConfig(30, 7200)
	}
}

You updated the maximum. The minimum is still set to 30 seconds. You can see the checkInterval being several rows up in the configure() section if you want to also adjust it.

So the checkInterval is what would report the status back to the app? Does it need to correlate to the reporting time in any manner? It appears to be in a equation format as opposed to single number as interval?

Also any suggested minimum interval I should use?

Also attached are the logs and stuff I have up until now.