Advice on Thermostat with remote humidity/temp sensors

Situation is: i have a heater and temperature sensor.
How do (can I ?) combine them to "thermostat" and control by Thermostat Controller ?

Install Thermostat Controller. Pick the real connected thermostat, then pick your connected temperature sensor as the remote sensor.

A virtual Thermostat with the same name as your real Thermostat will be created with “Controller” appended to its name. You change the switch in the app from Free to Controlled. Now your real connected thermostat will use the set points of the virtual thermostat.

1 Like

Have NO real thermostat. But heaters controlled by relay and temperature sensors.

1 Like
  1. Create a Virtual Thermostat on HE
  2. Setup a very simple Rule Machine rule that uses the condition of the virtual controller device's custom attribute thermostatOperatingState , then you can have it turn your heater ON when the Virtual Thermostat Controller value = "heating" and turn if OFF when the value = "idle".
  3. Name it in the device label.
  4. Add the Hubitat Virtual Thermostat to a new Thermostat Controller child app.
  5. Select your temperature sensor(s) as the remote temperature sensor(s).
  6. It will create a device named with your Virtual Thermostat's name, and the word "Controller" appended to it.
  7. Change the switch in the app from Free to Controlled. Now your virtual thermostat will use the set points of the thermostat controller and the remote sensors as input for the thermostat hysteresis.

Looks promising. Will check as soon as posisble and provide a feedback. Thank You very much.

I'm interested in your hack driver version because this thing (tuya sensor) reports only when it feels like it which has nothing to do with temperature nor humidity change.

Curiously, on a whim I reverted the driver for this to the generic zigbee one and it’s working perfectly fine. I’ll do some flip flopping and see if there’s actually a difference and will post my hack.

So with the standard Zigbee "generic motion/humidity sensor", I get the following readings, which appear to be roughly every 5 minutes. I'll switch the driver and report back for the other one (the publicly posted sample driver that I modified):

temperature 69.62 °F Humidity Sensor: Rog Bathroom temperature is 69.62°F DEVICE 2021-03-20 11:38:06.511 AM PDT
humidity 66.8 %RH Humidity Sensor: Rog Bathroom is 66.8%RH DEVICE 2021-03-20 11:22:59.998 AM PDT
humidity 73.2 %RH Humidity Sensor: Rog Bathroom is 73.2%RH DEVICE 2021-03-20 11:18:58.140 AM PDT
temperature 69.80 °F Humidity Sensor: Rog Bathroom temperature is 69.80°F DEVICE 2021-03-20 11:18:57.600 AM PDT
humidity 61.5 %RH Humidity Sensor: Rog Bathroom is 61.5%RH DEVICE 2021-03-20 11:17:57.666 AM PDT
humidity 51.6 %RH Humidity Sensor: Rog Bathroom is 51.6%RH DEVICE 2021-03-20 11:15:56.684 AM PDT
temperature 69.44 °F Humidity Sensor: Rog Bathroom temperature is 69.44°F DEVICE 2021-03-20 11:15:56.173 AM PDT
humidity 46.5 %RH Humidity Sensor: Rog Bathroom is 46.5%RH DEVICE 2021-03-20 10:13:27.636 AM PDT
temperature 69.99 °F Humidity Sensor: Rog Bathroom temperature is 69.99°F DEVICE 2021-03-20 10:13:27.127 AM PDT
humidity 42.4 %RH Humidity Sensor: Rog Bathroom is 42.4%RH DEVICE 2021-03-20 09:33:08.923 AM PDT
temperature 70.34 °F Humidity Sensor: Rog Bathroom temperature is 70.34°F DEVICE 2021-03-20 09:33:08.423 AM PDT
humidity 43 %RH Humidity Sensor: Rog Bathroom is 43%RH DEVICE 2021-03-20 09:25:05.158 AM PDT
temperature 69.09 °F Humidity Sensor: Rog Bathroom temperature is 69.09°F DEVICE 2021-03-20 09:25:04.646 AM PDT
temperature 70.34 °F Humidity Sensor: Rog Bathroom temperature is 70.34°F DEVICE 2021-03-20 08:01:25.964 AM PDT
humidity 43.5 %RH Humidity Sensor: Rog Bathroom is 43.5%RH DEVICE 2021-03-20 07:53:22.656 AM PDT
temperature 69.09 °F Humidity Sensor: Rog Bathroom temperature is 69.09°F DEVICE 2021-03-20 07:53:22.150 AM PDT
humidity 44.9 %RH Humidity Sensor: Rog Bathroom is 44.9%RH DEVICE 2021-03-20 07:46:19.358 AM PDT
temperature 67.82 °F Humidity Sensor: Rog Bathroom temperature is 67.82°F DEVICE 2021-03-20 07:46:18.858 AM PDT
humidity 46.3 %RH Humidity Sensor: Rog Bathroom is 46.3%RH DEVICE 2021-03-20 07:39:16.032 AM PDT
temperature 66.57 °F Humidity Sensor: Rog Bathroom temperature is 66.57°F DEVICE 2021-03-20 07:39:15.492 AM PDT
humidity 47.3 %RH Humidity Sensor: Rog Bathroom is 47.3%RH DEVICE 2021-03-20 07:00:57.999 AM PDT
temperature 65.30 °F Humidity Sensor: Rog Bathroom temperature is 65.30°F DEVICE 2021-03-20 07:00:57.501 AM PDT
humidity 45.2 %RH Humidity Sensor: Rog Bathroom is 45.2%RH DEVICE 2021-03-20 06:08:33.391 AM PDT
temperature 66.57 °F Humidity Sensor: Rog Bathroom temperature is 66.57°F DEVICE 2021-03-20 06:08:32.919 AM PDT

Here's the modified driver. It's been a while, but think the change had to do specifically with the humidity line.

/*
	Tuya Humidty and Temperature Sensor

*/

import groovy.transform.Field

@Field Map diagAttributes = [
    	"0000":["name":"ResetCount","val":0x0000],
    	"0104":["name":"TXRetrys","val":0x0104],
    	"0105":["name":"TXFails","val":0x0105],
    	"011A":["name":"PacketDrops","val":0x011A],
    	"0115":["name":"DecryptFailures","val":0x0115],
    	"011D":["name":"RSSI","val":0x011D],
    	"011E":["name":"Parent","val":0x011E],
    	"011F":["name":"Children","val":0x011F],
    	"0120":["name":"Neighbors","val":0x0120]
    ]

metadata {
    definition (name: "Tuya TS0201 Humidity and Temperature", namespace: "rnoia", author: "rnoia") {
	capability "Configuration"
	capability "Refresh"
	capability "Temperature Measurement"
	capability "RelativeHumidityMeasurement"
	capability "Sensor"

        fingerprint profileId: "0000", inClusters: " 0000,0001,0402,0405", manufacturer: "TuYa", model: "TS0201", deviceJoinName: "Hummidity and Temperature Sensor"
/*

driver based on: https://github.com/hubitat/HubitatPublic/blob/master/examples/drivers/environmentSensor.groovy
by iharyadi/maxwell

Data from Hub upon inclusion:
Manufactutrer: _TZ2000_a476raq2
    endpointId: 01
    application: 43
    softwareBuild:
    inClusters: 0000,0001,0402,0405
    outClusters: 0019
    model: TS0201
    manufacturer: _TZ2000_a476raq2
[raw:catchall: 0000 0013 00 00 0040 00 5930 00 00 0000 00 00 81305972DCE4FEFFBD1BEC80, profileId:0000, clusterId:0013, clusterInt:19, sourceEndpoint:00, destinationEndpoint:00, options:0040, messageType:00, dni:5930, isClusterSpecific:false, isManufacturerSpecific:false, manufacturerId:0000, command:00, direction:00, data:[81, 30, 59, 72, DC, E4, FE, FF, BD, 1B, EC, 80]]

*/
	}
        
    preferences {
        //standard logging options
        input name: "logEnable", type: "bool", title: "Enable debug logging", defaultValue: true
        input name: "txtEnable", type: "bool", title: "Enable descriptionText logging", defaultValue: true
        
        input "refTemp", "decimal", title: "Reference temperature", description: "Enter current reference temperature reading", range: "*..*"
        
        input "tempOffset", "decimal", title: "Degrees", description: "Adjust temperature by this many degrees in Celcius",range: "*..*"
        input "tempFilter", "decimal", title: "Coeficient", description: "Temperature filter between 0.0 and 1.0",range: "*..*"
		input "humOffset", "decimal", title: "Percent", description: "Adjust humidity by this many percent",range: "*..*"
    }
}

def logsOff(){
    log.warn "debug logging disabled..."
    device.updateSetting("logEnable",[value:"false",type:"bool"])
}

def parse(String description) {
	if (logEnable) log.debug "description is ${description}"
	if (description.startsWith("catchall")) return
	def descMap = zigbee.parseDescriptionAsMap(description)
	if (logEnable) log.debug "descMap:${descMap}"
	
	def cluster = descMap.cluster
	def hexValue = descMap.value
	def attrId = descMap.attrId
	
	switch (cluster){
		case "0402" :	//temp
			getTemperatureResult(hexValue)
			break
		case "0405" :	//humidity
			getHumidityResult(hexValue)
			break
		case "0B05" : //diag
        		if (logEnable) log.warn "attrId:${attrId}, hexValue:${hexValue}"
        		def value = hexStrToUnsignedInt(hexValue)
        		log.warn "diag- ${diagAttributes."${attrId}".name}:${value} "
			break
		default :
			//log.warn "skipped cluster: ${cluster}, descMap:${descMap}"
			break
	}
	return
}

//event methods
private getTemperatureResult(hex){
    def valueRaw = hexStrToSignedInt(hex)
    valueRaw = valueRaw / 100
    def value = convertTemperatureIfNeeded(valueRaw.toFloat(),"c",1)
   	state.sensorTemp = value
    if (state.tempOffset) {
        value =  (value.toFloat() + state.tempOffset.toFloat()).round(2)
    }
	 def name = "temperature"
    def unit = "°${location.temperatureScale}"
    def descriptionText = "${device.displayName} ${name} is ${value}${unit}"
    if (txtEnable) log.info "${descriptionText}"
    sendEvent(name: name,value: value,descriptionText: descriptionText,unit: unit)
}

private getHumidityResult(hex){
    def valueRaw = hexStrToUnsignedInt(hex)
    def value = valueRaw / 100
    def name = "humidity"
    def unit = "%"
    def descriptionText = "${device.displayName} ${name} is ${value}${unit}"
    if (txtEnable) log.info "${descriptionText}"
    sendEvent(name: name,value: value,descriptionText: descriptionText,unit: unit)
}


//capability and device methods
def off() {
    zigbee.off()
}

def on() {
    zigbee.on()
}

def refresh() {
    log.debug "Refresh"
    
	//readAttribute(cluster,attribute,mfg code,optional delay ms)
    def cmds = zigbee.readAttribute(0x0402,0x0000,[:],200) +		//temp
        zigbee.readAttribute(0x0405,0x0000,[:],200) + 			//humidity
      	diagAttributes.each{ it ->
            //log.debug "it:${it.value.val}"
		//	cmds +=  zigbee.readAttribute(0x0B05,it.value.val,[:],200) 
		}  
    return cmds
}

def configure() {
    log.debug "Configuring Reporting and Bindings."
    runIn(1800,logsOff)
    
    //temp offset init
    state.tempOffset = 0
    
    List cmds = zigbee.temperatureConfig(5,300)												//temp
    cmds = cmds + zigbee.configureReporting(0x0405, 0x0000, DataType.UINT16, 5, 300, 100)	//humidity
    cmds = cmds + zigbee.configureReporting(0x0403, 0x0000, DataType.UINT16, 5, 300, 2)		//pressure
    cmds = cmds + refresh()
    log.info "cmds:${cmds}"
    return cmds
}

def updated() {
    log.trace "Updated()"
    log.warn "debug logging is: ${logEnable == true}"
    log.warn "description logging is: ${txtEnable == true}"
    if (logEnable) runIn(1800,logsOff)    

   	def crntTemp = device?.currentValue("temperature")
    if (refTemp && crntTemp && state.sensorTemp) {
        def prevOffset = (state.tempOffset ?: 0).toFloat().round(2)
        def deviceTemp = state.sensorTemp.toFloat().round(2)
        def newOffset =  (refTemp.toFloat() - deviceTemp).round(2)
        def newTemp = (deviceTemp + newOffset).round(2)
        //send new event on offSet change
        if (newOffset.toString() != prevOffset.toString()){
            state.tempOffset = newOffset
            def map = [name: "temperature", value: "${newTemp}", descriptionText: "${device.displayName} temperature offset was set to ${newOffset}°${location.temperatureScale}"]
            if (txtEnable) log.info "${map.descriptionText}"
            sendEvent(map)
        }
        //clear refTemp so it doesn't get changed later...
        device.removeSetting("refTemp")
    }
	
}
1 Like

I just checked my logs again and for the entire duration of the day today whenever the temperature or humidity is constant (unchanged since last time) there does not appear to be an event. You can force it with the little button the device, however.

Thank you for help. I tried your version but unfortunately it does not change the erratic behavior of this device. It is true that pressing the button will update the readings but this is antithetical to an automation system point of view.

I wish there would be a setting to have the device update itself on a timely manner. The way it behaving now makes it totaly useless.

Thanks again for your effort. It is appreciated.

This,

I use temp probes (connected with nodemcu's/konnected), wired thermal actuators on the rads (again, nodemcu's/konnected/3V_relays), one zwave boiler switch and schedules through webcore. Works ace.

I've gone through my AC-powered environmental devices and they all behave the same, despite having power to report constantly/periodically:

  • Aeotec motion (mulisensor 6) sensor (which also does humidity) doesn't do constant humidity or any environmental sensing periodically - only upon change. Going through my logs, the AC reporting is 5-10 times a second (showing 100%). Lux, temperature and humidity only show up on a change.

  • My homeseer light sensor (which also does temperature), has a selectable polling temperature interval when ac-powered (not on battery). but the reporting behavior is the same - temperature only on change. I will admit this does seem a bit odd to me as well, especially since the polling is selectable.

However, I do think the Tuya device isn't as sensitive as it could be, I can see periods of no change, like when I take a shower, that it goes from 46% to 75%. But this device's battery has lasted over 9 months, so I'm willing to accept that.

This topic was automatically closed 365 days after the last reply. New replies are no longer allowed.