ronv42
March 29, 2026, 11:47am
1
I just installed the THIRDREALITY Smart Presence Sensor R3 to my C-8 Hub. After the install there wasn't a default driver for the device. Looking at this Thread at the beginning there was no driver and a community driver was posted. I used that driver and it seems to work good. Haven't put it though the paces yet but looked promising.
I noticed Third Reality has a new multi-sensor (air quality, lux, 60ghz mmWave plus RGB light & repeater). Seems like a solid deal for only $50. Starts shipping next week.
@mike.maxwell do you anticipate having a driver for this anytime soon?
https://a.co/d/07mYipZp
But as you read though the thread they said that the THRIDREALITY Night Light R3 was the official Hubitat driver. I changed to that and started to receive errors in my logs and lost control of the device, couldn't turn the light on or off etc. Also if this is the Official driver why wasn't it installed with the device when first paired?
Can someone from Hubitat confirm/deny that this device has a official driver? I checked the supported device list and this device still isn't listed so it leaves me wondering.
Thanks in advance.
I think the "official" R3 PRESENCE SENSOR driver is only in the Beta builds.
Public build 2.4.4.155 should have it. Tagging @mike.maxwell for the driver error. From the log, it looks like the correct one for this device and it appears you tried a Configure. If you were on this build when you paired it, can you provide the fingerprint ("Get Info" from the "Device" driver)?
1 Like
it should be not called aqi.. this is not standard aqi but tvoc (total volatile organic compounds)
1 Like
I originally used "TVOC" but the official driver uses "AQI" so I conformed my usage to Third Reality's usage.
ronv42
April 2, 2026, 10:37am
6
I wrote a small "dump" driver for the values being sent by the sensors. Confirmed that every payload for air quality is zero payload 0x042E:
THIRDREALITY replied to my support ticket stating that I need to wait for the "official" driver. Just sent them this log.
/**
* THIRDREALITY Smart Presence Sensor R3 — Raw Frame Dumper
*
* Purpose: Dump all raw Zigbee frames received from the device to the Hubitat
* log with zero interpretation or filtering. Intended for vendor
* diagnostics and firmware issue documentation.
*
* Author: RonV42
* Version: v1.0
* Date: 2026-04-01
*
* Usage: Install this driver, pair or swap to it on the device, then
* copy/paste the log output and send to THIRDREALITY support.
* Every frame the device sends will appear in the log exactly
* as received.
*/
metadata {
definition(
name: "THIRDREALITY Smart Presence Sensor R3 - Raw Dump",
namespace: "RonV42",
author: "RonV42"
) {
capability "Sensor"
capability "Initialize"
fingerprint profileId: "0104",
endpointId: "01",
inClusters: "0000,0003,0004,0005,0006,0008,0300,0400,0406,042E",
outClusters: "0019",
manufacturer: "Third Reality, Inc",
model: "3RPL01084Z",
deviceJoinName: "THIRDREALITY Smart Presence Sensor R3"
}
preferences {
input name: "logLevel",
type: "enum",
title: "Log Level",
options: ["INFO", "DEBUG"],
defaultValue: "DEBUG",
description: "INFO logs cluster+value summary. DEBUG logs full raw frame."
}
}
// ── Lifecycle ──────────────────────────────────────────────────────────────
def installed() {
log.info "RAW DUMP DRIVER installed — every Zigbee frame will be logged"
initialize()
}
def updated() {
log.info "RAW DUMP DRIVER updated — log level: ${logLevel}"
initialize()
}
def initialize() {
log.info "RAW DUMP DRIVER initialized — waiting for frames..."
}
// ── Parser — dump everything ───────────────────────────────────────────────
def parse(String description) {
// Always log the raw description string regardless of level
if (logLevel == "DEBUG") {
log.debug "RAW FRAME: ${description}"
}
// Attempt to parse into a descMap for a human-readable summary
try {
def descMap = zigbee.parseDescriptionAsMap(description)
if (descMap) {
def cluster = descMap.cluster ?: descMap.clusterId ?: "unknown"
def attrId = descMap.attrId ?: "N/A"
def encoding = descMap.encoding ?: "N/A"
def value = descMap.value ?: "N/A"
def command = descMap.command ?: "N/A"
def clusterName = clusterLabel(cluster)
log.info "CLUSTER: ${cluster} (${clusterName}) | attrId: ${attrId} | encoding: ${encoding} | command: ${command} | value: ${value}"
// Special handling for 0x042E — the TVOC cluster under investigation
if (cluster == "042E" || cluster == "1070") {
log.warn "TVOC CLUSTER 0x042E FRAME — attrId: ${attrId} | encoding: ${encoding} | raw value hex: ${value}"
if (encoding == "39" && value?.length() == 8) {
// Attempt IEEE-754 float decode both endiannesses
try {
long uintBE = Long.parseLong(value, 16)
float floatBE = Float.intBitsToFloat((int) uintBE)
String swapped = value[6..7] + value[4..5] + value[2..3] + value[0..1]
long uintLE = Long.parseLong(swapped, 16)
float floatLE = Float.intBitsToFloat((int) uintLE)
log.warn "TVOC DECODE — hex: ${value} | floatBE: ${floatBE} | floatLE: ${floatLE} | uint: ${uintBE}"
} catch (e) {
log.warn "TVOC DECODE failed: ${e.message}"
}
}
}
// Log catchall frames with full payload
if (description?.startsWith("catchall")) {
def payload = descMap.data ?: descMap.payload ?: "N/A"
log.info "CATCHALL — cluster: ${cluster} (${clusterName}) | command: ${command} | payload: ${payload}"
if (cluster == "042E" || cluster == "1070") {
log.warn "TVOC CATCHALL 0x042E — cluster: ${cluster} | command: ${command} | payload: ${payload}"
}
}
} else {
log.info "UNPARSEABLE FRAME: ${description}"
}
} catch (Exception e) {
log.error "PARSE EXCEPTION: ${e.message} | raw: ${description}"
}
return []
}
// ── Cluster label helper ───────────────────────────────────────────────────
private String clusterLabel(String cluster) {
switch (cluster?.toUpperCase()) {
case "0000": return "Basic"
case "0003": return "Identify"
case "0004": return "Groups"
case "0005": return "Scenes"
case "0006": return "On/Off"
case "0008": return "Level Control"
case "0019": return "OTA Upgrade"
case "001F": return "Power Configuration"
case "0036": return "Power Profile"
case "0300": return "Color Control"
case "0400": return "Illuminance Measurement"
case "0406": return "Occupancy Sensing"
case "042E": return "TVOC Measurement"
case "1070": return "TVOC Measurement (clusterInt)"
case "8021": return "Bind Response"
default: return "Unknown"
}
}
2 Likes
same on mine weird it works for awhile them simply craps out
ronv42
April 3, 2026, 7:19pm
8
Yes I have have had it "wake up" report a couple of times and the zero's again. Either it's a firmware bug or they have a real hardware issue on this device. I just returned my device to Amazon. I get the feeling the first batch may not be fully baked.