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

Looks good - go ahead and test it out. If you haven’t already done so, you probably want to tweak the name in the metadata to be something slightly different so you can tell your device handler from the stock one. Then hit save, then publish, then change the device to use your DH (it’ll be at the very bottom of the list).

Marked it “V2” so was easy to spot, updated devices and now we wait and see, everyone has been super helpful! Thank you!

So it appears this did not work the way we thought. Under the recent tab for the sensor it does not list the new expected intervals of values and neither is my data logger seeing them. Any ideas if there are other ways to verify that the new script is working and/or doing what we intend it to do?

open live logging in the ide and leave it open for a while to see if the sensor is actually sending events

See attached for IDE log as well as recent activity tab on the sensor. taken at same time.

Sorry - I gave you the wrong parameter. Use map.isStateChange instead.

just “map.isStateChange” or does it still need the “=true parameter” behind it as well?

map.isStateChange=true

Here’s the documentation on the parse function, which talks about this a bit: https://docs.smartthings.com/en/latest/device-type-developers-guide/parse.html

Looks like we are mostly there! The temperatue’s are now reporting and posting every 5 minutes however the humidity is hit or miss. Might I have put the command in a wrong place or could there be a run error somewhere? Attached the current code on the bottom.

Lastly, any chance I can change the 5 minute window to a much larger setting? Every 8 hours would be ideal for these particular units.

Also thank you for the link, I am learning as I go so eventually wont ask as many questions hopefully! :slight_smile:

// 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
}
}

The humidity one is in the right place. Are you seeing a log in the IDE indicating it received a humidity report that isn’t showing in the recent activity list? That would be an indication that the isStateChange isn’t working.

From the logs you posted, it looks like the device is only reporting humidity to your hub once an hour, currently around 7 minutes after the hour. That matches what @Automated_House said as well. If each hourly report is posting, then your code is fine.

Some devices like this can be sent a configuration command to change how often they report. I don’t have one of these (or anything similar that speaks zigbee), so I’m not sure how to do that with this device. It looks like there’s some information at https://docs.smartthings.com/en/latest/ref-docs/zigbee-ref.html under the zigbee.configureReporting command, but I’ve never played with it.

I think you are right, I am going to let the logging sit for a bit longer so we can see over an hour’s worth of data but you seem to be correct.

reading the zigbee guide now and will let you know if i figure out how to adjust the time interval.

you have been a great help! and also a great resource, have a ton to read now!

update this part of the configure code to change the time intervals. 30,3600 is the min and max for humidity. 30,300 is for temperature.

zigbee.configureReporting(0xFC45, 0x0000, DataType.UINT16, 30, 3600, 100, [“mfgCode”: 0x104E]) + // New firmware
zigbee.configureReporting(0xFC45, 0x0000, DataType.UINT16, 30, 3600, 100, [“mfgCode”: 0xC2DF]) + // Original firmware
zigbee.batteryConfig() +
zigbee.temperatureConfig(30, 300)

1 Like

as in update the “3600” max value to “28800”? I got that number from 60 seconds per minute x 60 minutes per hour x 8 as desired mark.

gathered as much from the zigbee link provided earlier and was going to try that myself.

yup. i don’t know if there is a maximum you can enter or not, but try it and watch your live logs

playing devils advocate here before I change that value, why is the temperature reporting every 5 minutes versus humidity every 60 minutes when seemingly both intervals are set for that 60 minute mark?

Logs attached and full current code in case that helps

/**
 *  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, 3600, 100, ["mfgCode": 0x104E]) +   // New firmware
		        zigbee.configureReporting(0xFC45, 0x0000, DataType.UINT16, 30, 3600, 100, ["mfgCode": 0xC2DF]) +   // Original firmware
		        zigbee.batteryConfig() +
		        zigbee.temperatureConfig(30, 300)
	}
}

Could you edit that to put ``` above and below your entire section of code? It’ll make it much easier for us to read

1 Like

I think the zigbee.configureReporting line is controlling humidity reporting (3600), while zigbee.temperatureConfig is doing temperature reporting (300).

Gotya, I am going to set it for 7200 first and see if it does what we want and then adjust to the larger number. It is just on the bottom that I would have to adjust the numbers right?

} else {
		return refresh() +
		        zigbee.configureReporting(0xFC45, 0x0000, DataType.UINT16, 30, 3600, 100, ["mfgCode": 0x104E]) +   // New firmware
		        zigbee.configureReporting(0xFC45, 0x0000, DataType.UINT16, 30, 3600, 100, ["mfgCode": 0xC2DF]) +   // Original firmware
		        zigbee.batteryConfig() +
		        zigbee.temperatureConfig(30, 300)
	}

Yes (unless the Centralite is actually a rebranded Heiman).

Also, I don’t see anywhere that actually calls the configure function, so that’s probably going to be an issue. What happens when you hit the refresh button in the app? Do you actually get a temp/humidity update from the device?