Request for Support for Matter compatible AiDot WELOV P200 Smart Air Purifier

Wildfires are becoming more and more frequent in the Western U.S., Canada, and many other parts of the world. Air purifiers are becoming a necessity to maintain a smoke free, healthy environment in homes when the air outside is full of smoke.

I'd like to see the Hubitat add support for the AiDot WELOV P200 Smart Air Purifier. The P200 is the first Matter compatible air purifier. Support for air purifiers was included in v1.2 of the Matter protocol spec. It is my understanding that Apple Home, along with some of the other big players in the world of Matter, will be adding support for v1.2 of Matter in the near future.

I haven't found air purifiers with good smart home integration. So, support for the P200 would be a big step forward in allowing the operation of an air purifier to be optimized in a smart home. For example, just being able to turn an air purifier off when the home isn't occupied can save the homeowner a great deal of money on filters for the purifier; which can be quite expensive.

Automatically changing the operating mode of a purifier in a bedroom from Auto mode to sleep mode at night is another nice use case that adds convenience to using an air purifier..

Thanks

3 Likes

I wanted to follow-up on my post from July. Apple has just released iOS 18 and included is support for Matter v1.2 in Apple Home. This now includes support for air purifiers, air quality sensors, and a host of other new devices categories.

I have validated that the AiDot WELOV P200 Smart Air Purifier is supported in Apple Home including control of power on/off and control of the fan speed According to AiDot, control of other functionality of the P200 Pro will be added in the future.

I have also validated that support for the P200 Pro is now included in HA. This includes control of power on/off, fan speed, and sensor readings from the P200's air quality sensor.

Any hope for support from Hubitat?

1 Like

Do you know what the matter clusters are for the device? If you add it to Hubitat it should provide a list of the clusters detected. Once that is done then it could likely a driver could be created. I created a driver for a Matter Fan device not long ago.

Add the device to hubitat and then scroll down to the bottom. Take a snapshot of the data section so the inclusters are show like this.

The inclusters show what functions the device supports. That example is a light device. Your air purfiier should have a different setup of clusters unique to air purifier devices.

Here you go:

  • endpointId: 01
  • hardwareVersion: 1.0.0
  • inClusters: 0003,0202,0071,005B,001D
  • manufacturer: Leedarson
  • model: Air Purifier
  • outClusters:
  • serialNumber:
  • softwareVersion: 1.00.00

Thanks!

I recognize a few of those clusters and looked up the others. The 0202 cluster is for fan control. 0003 and 001D is for information lookup. 0071 is for air quality info and for aome reason i can't find the other right now.

If you load my Govee H7105 fan driver it may enable some control. Some experimenting would be needed to figure out the Air quality sensor part.

What i dont see is a switch control for on/off, but that could be expected to be controlled with the Fan cluster with a value of zero being off. If you want to try my driver and let me know how it goes i can tweak it for your device with some input about how it goes.

Thanks so much @mavrrick58. After posting this I found out that a project I committed to a few months ago is going to start. That is going to take up my time for about 4 - 6 weeks.

Please go ahead and send me your driver code. If the project takes less of my time than I think, then I'll work on this as I find the time. In the worst case, I'll just start on it as soon as my project is done.

Hopefully this is agreeable to you.

Thanks

You can get it from my git hub repo.

https://raw.githubusercontent.com/Mavrrick/Hubitat-by-Mavrrick/refs/heads/main/Govee/Matter/GoveeH7105Matter

Thanks! I'll give it a try as time allows and let you know how it goes.

OK so upon now that i can review the document on my main computer i can expand on what i saw earlier.

Clust list
0x0003 = Identify
0x0202 = Fan Control
0x0071 = Hepa Filter Monitoring
0x005B = Air Quality
0x001D = ??? (but i don't believe important)

Here is a tweaked version of my Fan driver. I have added some additional values for it to subscribe to. That should set it up to retrieve the filter state and AQI, That said i don't have them updating the state values just yet. It is just recieving it and then logging the values. The values between what the standard Hubitat device capabilities and the documented Matter device return values don't seem to match up. I would like to see the exact data before coding a way to handle it.

/*
	Air Purifier Driver

	Copyright 2023 Hubitat Inc.  All Rights Reserved

	2023-11-02 2.3.7 maxwell
		-initial pub

*/

import groovy.transform.Field

@Field static final String   DEVICE_TYPE = 'MATTER_PURIFIER'

@Field Map getFanLevel = [
    "off": 0
    ,"speed 1": 8
	,"speed 2": 16
	,"speed 3": 24
    ,"speed 4": 32
	,"speed 5": 40
	,"speed 6": 48    
    ,"speed 7": 56
    ,"speed 8": 64
	,"speed 9": 72
	,"speed 10": 81
    ,"speed 11": 90
	,"speed 12": 100    
]

import groovy.transform.Field
import hubitat.helper.HexUtils

metadata {
    definition (name: "Air Purifier Driver(Matter)", namespace: "Mavrrick", author: "Mavrrick") {
        capability "Actuator"
        capability "Switch"
        capability "Configuration"
        capability "FanControl"
        capability "Initialize"
        capability "Refresh"
        capability "AirQuality"
        capability "FilterStatus"
        
//        command 'getInfo'
        command "setSpeed", [[name: "Fan speed*",type:"ENUM", description:"Fan speed to set", constraints: getFanLevel.collect {k,v -> k}]]
        
        fingerprint endpointId:"01", inClusters:"0003,0202,0071,005B,001D", outClusters:"", model:"Air Purifier", manufacturer:"Leedarson", controllerType:"MAT"

    }
    preferences {
//        input(name:"cycleInterval", type:"number", title:"Number of seconds between cycles", defaultValue:30)
        input(name:"logEnable", type:"bool", title:"Enable debug logging", defaultValue:false)
        input(name:"txtEnable", type:"bool", title:"Enable descriptionText logging", defaultValue:true)
    }
}

//parsers
void parse(String description) {
    Map descMap = matter.parseDescriptionAsMap(description)
    if (logEnable) log.debug "descMap:${descMap}"
    switch (descMap.cluster) {        
        case "0006" :
            if (descMap.attrId == "0000") { //switch
                sendSwitchEvent(descMap.value)
            }
            break
        case "0000" :
            if (descMap.attrId == "4000") { //software build
                updateDataValue("softwareBuild",descMap.value ?: "unknown")
            }
            break
        case "005B" :
/*            if (descMap.attrId == "4000") { //Air Quality
                updateDataValue("Air Quality",descMap.value ?: "unknown")
            } */
            logWarn "parse: skipped Air Quality, attribute:${descMap.attrId}, value:${descMap.value}"
            break
        case "0071" :
/*            if (descMap.attrId == "4000") { //Filter State
                updateDataValue("Filter State",descMap.value ?: "unknown")
            } */
            logWarn "parse: skipped Filter State, attribute:${descMap.attrId}, value:${descMap.value}"
            break
        case "0202" :
            if (descMap.attrId == "0000") { //fan speed
                if (logEnable) log.debug "parse(): Fan Event - Fan Speed ${descMap.value}"
            } else if (descMap.attrId == "0001") { //fan speed mode
                if (logEnable) log.debug "parse(): Fan Event - Fan speed mode ${descMap.value}"
            } else if (descMap.attrId == "0002") { //fan speed Percent Setting
                sendSpeedEvent(descMap.value) 
                if (logEnable) log.debug "parse(): Fan Event - Fan Speed  Percent ${descMap.value}"
            } else  if (descMap.attrId == "0003") { //fan speed Percent current
                if (logEnable) log.debug "parse(): Fan Event - Fan Speed Percent Curent ${descMap.value}"
            } else if (descMap.attrId == "0004") { //fan speed max (Don't expect to actually ever return in parse
                if (logEnable) log.debug "parse(): Fan Event - Fan Speed Max speed ${descMap.value}"
            } else if (descMap.attrId == "0005") { //fan speed setting
                if (logEnable) log.debug "parse(): Fan Event - Fan Speed setting ${descMap.value}"
            } else if (descMap.attrId == "0006") { //fan speed setting current
                if (logEnable) log.debug "parse(): Fan Event - Fan Speed current ${descMap.value}"
            } else if (descMap.attrId == "000A") { //WindSetting current
                if (logEnable) log.debug "parse(): Fan Event - Wind Speed setting ${descMap.value}"
            } else  if (descMap.attrId == "000B") { //Airflow Direction
                if (logEnable) log.debug "parse(): Fan Event - Airflow Direction setting ${descMap.value}"
            } else {
                logWarn "parse: skipped fan, attribute:${descMap.attrId}, value:${descMap.value}"
            }
//            gatherAttributesValuesInfo(descMap, FanClusterAttributes)
            break
        default :
            if (logEnable) {
                log.debug "skipped:${descMap}"
            }
    }
}

//events
private void sendSpeedEvent(String rawValue) {      
    Integer intValue = hexStrToUnsignedInt(rawValue) 
    
    switch(intValue) {
        case 0 :
            value = "off";
        break;
        case 8:
            value = "speed 1";
        break;
        case 16:
            value = "speed 2";
        break;
        case 24:
            value = "speed3 (low)";
        break;
        case 32:
            value = "speed 4";
        break;
        case 40:
            value = "speed 5";
        break;
        case 48:
            value = "speed 6 (medium)";
        break;
        case 56:
            value = "speed 7";
        break;
        case 64:
            value = "speed 8";
        break; 
        case 72:
            value = "speed 9";
        break;
        case 81:
            value = "speed 10";
        break;  
        case 90:
            value = "speed 11";
        break;
        case 100:
            value = "speed12 (high)";
        break; 
    }
    
//    if (device.currentValue("switch") == value) return
    String descriptionText = "${device.displayName} was set to speed ${value}"
    if (txtEnable) log.info descriptionText
    sendEvent(name:"speed", value:value, descriptionText:descriptionText)
}

private void sendSwitchEvent(String rawValue) {
    String value = rawValue == "01" ? "on" : "off"
    if (device.currentValue("switch") == value) return
    String descriptionText = "${device.displayName} was turned ${value}"
    if (txtEnable) log.info descriptionText
    sendEvent(name:"switch", value:value, descriptionText:descriptionText)
}

//capability commands
void on() {
    unschedule()
    if (logEnable) log.debug "on()"
    sendToDevice(matter.on())
}

void off() {
    unschedule()
    if (logEnable) log.debug "off()"
    sendToDevice(matter.off())
}

void setSpeed(fanspeed) {
    unschedule()
    if (logEnable) log.debug "Setting Fan Speed to ${fanspeed}"
    switch(fanspeed) {
        case "off":
        case "speed 0":
            value = 0;
        break;
        case "speed 1":
            value = 8;
        break;
        case "speed 2":
            value = 16;
        break;
        case "speed 3":
        case "low":
            value = 24;
        break;
        case "speed 4":
            value = 32;
        break;
        case "speed 5":
            value = 40;
        break;
        case "speed 6":
        case "medium":
            value = 48;
        break;
        case "speed 7":
            value = 56;
        break;
        case "speed 8":
            value = 64;
        break; 
        case "speed 9":
            value = 72;
        break;
        case "speed 10":
            value = 81;
        break;  
        case "speed 11":
            value = 90;
        break;
        case "speed 12":
        case "high":
            value = 100;
        break; 
    }
    if (value > 101) {
        if (logEnable) {log.debug ("setSpeed(): Unknown value}")};
        on()
    } else {
        speedValue = intToHexStr(value)  
        if (logEnable) log.debug "Setting Fan Speed percent ${fanspeed}  % ${value} value to ${speedValue}"
        List<Map<String, String>> attributeWriteRequests = []
        attributeWriteRequests.add(matter.attributeWriteRequest(device.endpointId, 0x0202, 0x0002, 0x04, speedValue ))
        String cmd = matter.writeAttributes(attributeWriteRequests)            
        sendToDevice(cmd)
    }
}

void cycleSpeed() {
    cycleChange()
}

void cycleChange() {
    Integer randomSpeed = Math.abs(new Random().nextInt() % 12) + 1
    String newSpeed = "speed "+randomSpeed
    setSpeed(newSpeed)
    runIn(cycleInterval, cycleChange)
    
}


void configure() {
    log.warn "configure..."
    sendToDevice(subscribeCmd())
    unschedule()
}

//lifecycle commands
void updated(){
    log.info "updated..."
    log.warn "debug logging is: ${logEnable == true}"
    log.warn "description logging is: ${txtEnable == true}"
    if (logEnable) runIn(1800,logsOff)
}

void initialize() {
    log.info "initialize..."
//    initializeVars(fullInit = true)
    sendToDevice(subscribeCmd())
}

void refresh() {
    if (logEnable) log.debug "refresh()"
    sendToDevice(refreshCmd())
}

String refreshCmd() {
    List<Map<String, String>> attributePaths = []
    
        attributePaths.add(matter.attributePath(device.endpointId, 0x0006, 0x0000))         // on/off
        attributePaths.add(matter.attributePath(device.endpointId, 0x0202, 0x0000))         // FanMode
        attributePaths.add(matter.attributePath(device.endpointId, 0x0202, 0x0002))         // PercentSetting
        attributePaths.add(matter.attributePath(device.endpointId, 0x0202, 0x0003))         // PercentCurrent
        attributePaths.add(matter.attributePath(device.endpointId, 0x0202, 0x000A))         // WindSetting
        attributePaths.add(matter.attributePath(device.endpointId, 0x0202, 0x000B))         // AirflowDirectionEnum
        attributePaths.add(matter.attributePath(device.endpointId, 0x0003, 0x0000))         
        attributePaths.add(matter.attributePath(device.endpointId, 0x0003, 0x0001))         // Power Configuration Cluster : Status
        attributePaths.add(matter.attributePath(device.endpointId, 0x005B, 0x0000)) 
        attributePaths.add(matter.attributePath(device.endpointId, 0x0071, 0x0000))
        attributePaths.add(matter.attributePath(device.endpointId, 0x0071, 0x0002))
    
    String cmd = matter.readAttributes(attributePaths)
    return cmd
}

String subscribeCmd() {
    List<Map<String, String>> attributePaths = []
    String cmd = ''
    
        attributePaths.add(matter.attributePath(0x01, 0x0006, 0x00))
        attributePaths.add(matter.attributePath(0x01, 0x0202, 0x00))
        attributePaths.add(matter.attributePath(0x01, 0x0202, 0x02))
        attributePaths.add(matter.attributePath(0x01, 0x0202, 0x03))
        attributePaths.add(matter.attributePath(0x01, 0x0202, 0x0A))
        attributePaths.add(matter.attributePath(0x01, 0x0202, 0x0B))
        attributePaths.add(matter.attributePath(0x01, 0x005B, 0x00))
        attributePaths.add(matter.attributePath(0x01, 0x0071, 0x00))
        attributePaths.add(matter.attributePath(0x01, 0x0071, 0x04))
        cmd = matter.subscribe(0, 0xFFFF, attributePaths)

    return cmd
}

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

Integer hex254ToInt100(String value) {
    return Math.round(hexStrToUnsignedInt(value) / 2.54)
}

String int100ToHex254(value) {
    return intToHexStr(Math.round(value * 2.54))
}


void sendToDevice(List<String> cmds, Integer delay = 300) {
    sendHubCommand(new hubitat.device.HubMultiAction(commands(cmds, delay), hubitat.device.Protocol.MATTER))
}

void sendToDevice(String cmd, Integer delay = 300) {
    sendHubCommand(new hubitat.device.HubAction(cmd, hubitat.device.Protocol.MATTER))
}

List<String> commands(List<String> cmds, Integer delay = 300) {
    return delayBetween(cmds.collect { it }, delay)
}
    
    

I would like to test if on/off work as well. If not can you confirm that the Set Speed command will turn it off when set there. They function slightly differently and technically the cluster for on/off isn't present. I will adjust the code based on the outcome of that test.

1 Like

Thanks so much. I'll let you know how it goes as soon as I have a chance to try it.

Hi, I spent a few minutes getting the driver loaded and tested. Overall it works pretty well for fan speed control. The power on/off doesn't do anything. However, setting power and fan speed through the setSpeed function works well for both setting power to off and turning the unit on and setting the speed.
Here is what I found for the different setSpeed values

Column 1 Column 2 Column 3
setSpeed Value Purifier Result Current State speed feedback
off Power Off off
1 Fan Low speed 1
2 Fan Low speed 2
3 Fan Low speed3 (low)
4 Fan Low speed 4
5 Fan Medium speed 5
6 Fan Medium speed 6 (medium)
7 Fan Medium speed 7
8 Fan Medium speed 8
9 Fan High speed 9
10 Fan High speed 10
11 Fan High speed 11
12 Fan High speed12 (high)

Let me know if there is more that I can do. Thanks

Ok so that is great to hear. The reason you have 12 values for speed is because the Govee Fan driver used to base this off of had 12 fan speeds. So that said i have two questions.

  1. Does the air purifier seem to actually run at different speeds for each of those values?
  2. If it does would you prefer to keep that higher number of speeds?

If the fan dosn't run at different fan speeds or you would prefer to match what the other app does, then I would like to get the values it actually produces. Can you turn on debug logging for the device, Open up live logging on the hub, and then change the value from your app or whatever else you use to control it. that should trigger updates from the device back to hubitat and the live logging should show the raw value.

I will update the on/off commands to submit the set Speed command. The basically generate the same thing as off, or submit the last value used speed. I will need to think about that as it will likely need to be stored somewhere.

I believe in your first post you mentioned setting it to a sleep mode. Can you try setting that through your other app and capture that in the live logging as well. I suspect that is just a very low fan speed, but i am a little suprised that didn't show up with the 12 options the driver already has.

Also with debug turned on can you click on the refresh button. That should also capture a value for the Air Quality, and the fitler status so i can see how that look.

Here is a updated driver with the On/off commands update to call the set speed command. I also added to the parse method to write whatever value is received for the filter and airquality values to the appropriate attribute.

/*
	Air Purifier Driver

	Copyright 2023 Hubitat Inc.  All Rights Reserved

	2023-11-02 2.3.7 maxwell
		-initial pub

*/

import groovy.transform.Field

@Field static final String   DEVICE_TYPE = 'MATTER_PURIFIER'

@Field Map getFanLevel = [
    "off": 0
    ,"speed 1": 8
	,"speed 2": 16
	,"speed 3": 24
    ,"speed 4": 32
	,"speed 5": 40
	,"speed 6": 48    
    ,"speed 7": 56
    ,"speed 8": 64
	,"speed 9": 72
	,"speed 10": 81
    ,"speed 11": 90
	,"speed 12": 100    
]

import groovy.transform.Field
import hubitat.helper.HexUtils

metadata {
    definition (name: "Air Purifier Driver(Matter)", namespace: "Mavrrick", author: "Mavrrick") {
        capability "Actuator"
        capability "Switch"
        capability "Configuration"
        capability "FanControl"
        capability "Initialize"
        capability "Refresh"
        capability "AirQuality"
        capability "FilterStatus"
        
//        command 'getInfo'
        command "setSpeed", [[name: "Fan speed*",type:"ENUM", description:"Fan speed to set", constraints: getFanLevel.collect {k,v -> k}]]
        
        fingerprint endpointId:"01", inClusters:"0003,0202,0071,005B,001D", outClusters:"", model:"Air Purifier", manufacturer:"Leedarson", controllerType:"MAT"

    }
    preferences {
//        input(name:"cycleInterval", type:"number", title:"Number of seconds between cycles", defaultValue:30)
        input(name:"logEnable", type:"bool", title:"Enable debug logging", defaultValue:false)
        input(name:"txtEnable", type:"bool", title:"Enable descriptionText logging", defaultValue:true)
    }
}

//parsers
void parse(String description) {
    Map descMap = matter.parseDescriptionAsMap(description)
    if (logEnable) log.debug "descMap:${descMap}"
    switch (descMap.cluster) {        
        case "0006" :
            if (descMap.attrId == "0000") { //switch
                sendSwitchEvent(descMap.value)
            }
            break
        case "0000" :
            if (descMap.attrId == "4000") { //software build
                updateDataValue("softwareBuild",descMap.value ?: "unknown")
            }
            break
        case "005B" :
/*            if (descMap.attrId == "4000") { //Air Quality
                updateDataValue("Air Quality",descMap.value ?: "unknown")
            } */
            sendEvent(name:"airQualityIndex ", value:value, descriptionText:descriptionText)
            if (logEnable) log.debug  "parse: skipped Air Quality, attribute:${descMap.attrId}, value:${descMap.value}"
            break
        case "0071" :
/*            if (descMap.attrId == "4000") { //Filter State
                updateDataValue("Filter State",descMap.value ?: "unknown")
            } */
            sendEvent(name:"filterStatus ", value:value, descriptionText:descriptionText) 
            if (logEnable) log.debug  "parse: skipped Filter State, attribute:${descMap.attrId}, value:${descMap.value}"
            break
        case "0202" :
            if (descMap.attrId == "0000") { //fan speed
                if (logEnable) log.debug "parse(): Fan Event - Fan Speed ${descMap.value}"
            } else if (descMap.attrId == "0001") { //fan speed mode
                if (logEnable) log.debug "parse(): Fan Event - Fan speed mode ${descMap.value}"
            } else if (descMap.attrId == "0002") { //fan speed Percent Setting
                sendSpeedEvent(descMap.value) 
                if (logEnable) log.debug "parse(): Fan Event - Fan Speed  Percent ${descMap.value}"
            } else  if (descMap.attrId == "0003") { //fan speed Percent current
                if (logEnable) log.debug "parse(): Fan Event - Fan Speed Percent Curent ${descMap.value}"
            } else if (descMap.attrId == "0004") { //fan speed max (Don't expect to actually ever return in parse
                if (logEnable) log.debug "parse(): Fan Event - Fan Speed Max speed ${descMap.value}"
            } else if (descMap.attrId == "0005") { //fan speed setting
                if (logEnable) log.debug "parse(): Fan Event - Fan Speed setting ${descMap.value}"
            } else if (descMap.attrId == "0006") { //fan speed setting current
                if (logEnable) log.debug "parse(): Fan Event - Fan Speed current ${descMap.value}"
            } else if (descMap.attrId == "000A") { //WindSetting current
                if (logEnable) log.debug "parse(): Fan Event - Wind Speed setting ${descMap.value}"
            } else  if (descMap.attrId == "000B") { //Airflow Direction
                if (logEnable) log.debug "parse(): Fan Event - Airflow Direction setting ${descMap.value}"
            } else {
                if (logEnable) log.debug  "parse: skipped fan, attribute:${descMap.attrId}, value:${descMap.value}"
            }
//            gatherAttributesValuesInfo(descMap, FanClusterAttributes)
            break
        default :
            if (logEnable) {
                log.debug "skipped:${descMap}"
            }
    }
}

//events
private void sendSpeedEvent(String rawValue) {      
    Integer intValue = hexStrToUnsignedInt(rawValue) 
    
    switch(intValue) {
        case 0 :
            value = "off";
        break;
        case 8:
            value = "speed 1";
        break;
        case 16:
            value = "speed 2";
        break;
        case 24:
            value = "speed3 (low)";
        break;
        case 32:
            value = "speed 4";
        break;
        case 40:
            value = "speed 5";
        break;
        case 48:
            value = "speed 6 (medium)";
        break;
        case 56:
            value = "speed 7";
        break;
        case 64:
            value = "speed 8";
        break; 
        case 72:
            value = "speed 9";
        break;
        case 81:
            value = "speed 10";
        break;  
        case 90:
            value = "speed 11";
        break;
        case 100:
            value = "speed12 (high)";
        break; 
    }
    
//    if (device.currentValue("switch") == value) return
    String descriptionText = "${device.displayName} was set to speed ${value}"
    if (txtEnable) log.info descriptionText
    sendEvent(name:"speed", value:value, descriptionText:descriptionText)
}

private void sendSwitchEvent(String rawValue) {
    String value = rawValue == "01" ? "on" : "off"
    if (device.currentValue("switch") == value) return
    String descriptionText = "${device.displayName} was turned ${value}"
    if (txtEnable) log.info descriptionText
    sendEvent(name:"switch", value:value, descriptionText:descriptionText)
}

//capability commands
void on() {
    unschedule()
    if (logEnable) log.debug "on()"
    sendToDevice(matter.on())
    fanspeed = "medium"
    setSpeed(fanspeed)    
   
}

void off() {
    unschedule()
    if (logEnable) log.debug "off()"
//    sendToDevice(matter.off())
    fanspeed = "off"
    setSpeed(fanspeed)
}

void setSpeed(fanspeed) {
    unschedule()
    if (logEnable) log.debug "Setting Fan Speed to ${fanspeed}"
    switch(fanspeed) {
        case "off":
        case "speed 0":
            value = 0;
        break;
        case "speed 1":
            value = 8;
        break;
        case "speed 2":
            value = 16;
        break;
        case "speed 3":
        case "low":
            value = 24;
        break;
        case "speed 4":
            value = 32;
        break;
        case "speed 5":
            value = 40;
        break;
        case "speed 6":
        case "medium":
            value = 48;
        break;
        case "speed 7":
            value = 56;
        break;
        case "speed 8":
            value = 64;
        break; 
        case "speed 9":
            value = 72;
        break;
        case "speed 10":
            value = 81;
        break;  
        case "speed 11":
            value = 90;
        break;
        case "speed 12":
        case "high":
            value = 100;
        break; 
    }
    if (value > 101) {
        if (logEnable) {log.debug ("setSpeed(): Unknown value}")};
        on()
    } else {
        speedValue = intToHexStr(value)  
        if (logEnable) log.debug "Setting Fan Speed percent ${fanspeed}  % ${value} value to ${speedValue}"
        List<Map<String, String>> attributeWriteRequests = []
        attributeWriteRequests.add(matter.attributeWriteRequest(device.endpointId, 0x0202, 0x0002, 0x04, speedValue ))
        String cmd = matter.writeAttributes(attributeWriteRequests)            
        sendToDevice(cmd)
    }
}

void cycleSpeed() {
    cycleChange()
}

void cycleChange() {
    Integer randomSpeed = Math.abs(new Random().nextInt() % 12) + 1
    String newSpeed = "speed "+randomSpeed
    setSpeed(newSpeed)
    runIn(cycleInterval, cycleChange)
    
}


void configure() {
    log.warn "configure..."
    sendToDevice(subscribeCmd())
    unschedule()
}

//lifecycle commands
void updated(){
    log.info "updated..."
    log.warn "debug logging is: ${logEnable == true}"
    log.warn "description logging is: ${txtEnable == true}"
    if (logEnable) runIn(1800,logsOff)
}

void initialize() {
    log.info "initialize..."
//    initializeVars(fullInit = true)
    sendToDevice(subscribeCmd())
}

void refresh() {
    if (logEnable) log.debug "refresh()"
    sendToDevice(refreshCmd())
}

String refreshCmd() {
    List<Map<String, String>> attributePaths = []
    
        attributePaths.add(matter.attributePath(device.endpointId, 0x0006, 0x0000))         // on/off
        attributePaths.add(matter.attributePath(device.endpointId, 0x0202, 0x0000))         // FanMode
        attributePaths.add(matter.attributePath(device.endpointId, 0x0202, 0x0002))         // PercentSetting
        attributePaths.add(matter.attributePath(device.endpointId, 0x0202, 0x0003))         // PercentCurrent
        attributePaths.add(matter.attributePath(device.endpointId, 0x0202, 0x000A))         // WindSetting
        attributePaths.add(matter.attributePath(device.endpointId, 0x0202, 0x000B))         // AirflowDirectionEnum
        attributePaths.add(matter.attributePath(device.endpointId, 0x0003, 0x0000))         
        attributePaths.add(matter.attributePath(device.endpointId, 0x0003, 0x0001))         // Power Configuration Cluster : Status
        attributePaths.add(matter.attributePath(device.endpointId, 0x005B, 0x0000)) 
        attributePaths.add(matter.attributePath(device.endpointId, 0x0071, 0x0000))
        attributePaths.add(matter.attributePath(device.endpointId, 0x0071, 0x0002))
    
    String cmd = matter.readAttributes(attributePaths)
    return cmd
}

String subscribeCmd() {
    List<Map<String, String>> attributePaths = []
    String cmd = ''
    
        attributePaths.add(matter.attributePath(0x01, 0x0006, 0x00))
        attributePaths.add(matter.attributePath(0x01, 0x0202, 0x00))
        attributePaths.add(matter.attributePath(0x01, 0x0202, 0x02))
        attributePaths.add(matter.attributePath(0x01, 0x0202, 0x03))
        attributePaths.add(matter.attributePath(0x01, 0x0202, 0x0A))
        attributePaths.add(matter.attributePath(0x01, 0x0202, 0x0B))
        attributePaths.add(matter.attributePath(0x01, 0x005B, 0x00))
        attributePaths.add(matter.attributePath(0x01, 0x0071, 0x00))
        attributePaths.add(matter.attributePath(0x01, 0x0071, 0x04))
        cmd = matter.subscribe(0, 0xFFFF, attributePaths)

    return cmd
}

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

Integer hex254ToInt100(String value) {
    return Math.round(hexStrToUnsignedInt(value) / 2.54)
}

String int100ToHex254(value) {
    return intToHexStr(Math.round(value * 2.54))
}


void sendToDevice(List<String> cmds, Integer delay = 300) {
    sendHubCommand(new hubitat.device.HubMultiAction(commands(cmds, delay), hubitat.device.Protocol.MATTER))
}

void sendToDevice(String cmd, Integer delay = 300) {
    sendHubCommand(new hubitat.device.HubAction(cmd, hubitat.device.Protocol.MATTER))
}

List<String> commands(List<String> cmds, Integer delay = 300) {
    return delayBetween(cmds.collect { it }, delay)
}
    
    

Thanks for your help. The purifier (WELOV P200 Pro) only has 3 speeds. Column 2 in the chart shows what fan speed the purifier went to for the different speeds (1-12) that I commanded it to go to. It would seem that the only setSpeed values that should be supported are off, 3, 6, and 12 as these produced feedback that truly corresponded to the command sent. I've loaded the updated code and will try to collect some more data for you through logging.
Thanks again

Here is the log
dev:6452024-09-20 02:02:27.711 PMwarndescription logging is: true

dev:6452024-09-20 02:02:27.710 PMwarndebug logging is: true

dev:6452024-09-20 02:02:27.709 PMinfoupdated...

dev:6452024-09-20 01:57:20.708 PMdebugparse(): Fan Event - Fan Speed Percent Curent 00

dev:6452024-09-20 01:57:20.707 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0003, value:00, clusterInt:514, attrInt:3]

dev:6452024-09-20 01:57:20.634 PMdebugparse(): Fan Event - Fan Speed Percent Curent 00

dev:6452024-09-20 01:57:20.632 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0003, value:00, clusterInt:514, attrInt:3]

dev:6452024-09-20 01:57:20.614 PMdebugparse(): Fan Event - Fan Speed Percent Curent 00

dev:6452024-09-20 01:57:20.612 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0003, value:00, clusterInt:514, attrInt:3]

dev:6452024-09-20 01:57:20.602 PMdebugparse(): Fan Event - Fan Speed Percent 00

dev:6452024-09-20 01:57:20.598 PMinfoAiDot P200 Pro Air Purifier - Matter was set to speed off

dev:6452024-09-20 01:57:20.596 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0002, value:00, clusterInt:514, attrInt:2]

dev:6452024-09-20 01:57:20.587 PMdebugparse(): Fan Event - Fan Speed 00

dev:6452024-09-20 01:57:20.586 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0000, value:00, clusterInt:514, attrInt:0]

dev:6452024-09-20 01:57:20.565 PMdebugparse(): Fan Event - Fan Speed Percent Curent 00

dev:6452024-09-20 01:57:20.563 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0003, value:00, clusterInt:514, attrInt:3]

dev:6452024-09-20 01:57:20.552 PMdebugparse(): Fan Event - Fan Speed Percent 00

dev:6452024-09-20 01:57:20.548 PMinfoAiDot P200 Pro Air Purifier - Matter was set to speed off

dev:6452024-09-20 01:57:20.545 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0002, value:00, clusterInt:514, attrInt:2]

dev:6452024-09-20 01:57:20.535 PMdebugparse(): Fan Event - Fan Speed 00

dev:6452024-09-20 01:57:20.533 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0000, value:00, clusterInt:514, attrInt:0]

dev:6452024-09-20 01:57:20.487 PMdebugparse(): Fan Event - Fan Speed Percent 00

dev:6452024-09-20 01:57:20.483 PMinfoAiDot P200 Pro Air Purifier - Matter was set to speed off

dev:6452024-09-20 01:57:20.480 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0002, value:00, clusterInt:514, attrInt:2]

dev:6452024-09-20 01:57:20.472 PMdebugparse(): Fan Event - Fan Speed 00

dev:6452024-09-20 01:57:20.470 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0000, value:00, clusterInt:514, attrInt:0]

dev:6452024-09-20 01:57:20.440 PMdebugparse(): Fan Event - Fan Speed Percent 00

dev:6452024-09-20 01:57:20.437 PMinfoAiDot P200 Pro Air Purifier - Matter was set to speed off

dev:6452024-09-20 01:57:20.435 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0002, value:00, clusterInt:514, attrInt:2]

dev:6452024-09-20 01:57:20.426 PMdebugparse(): Fan Event - Fan Speed 00

dev:6452024-09-20 01:57:20.424 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0000, value:00, clusterInt:514, attrInt:0]

dev:6452024-09-20 01:57:17.249 PMdebugparse(): Fan Event - Fan Speed Percent Curent 64

dev:6452024-09-20 01:57:17.248 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0003, value:64, clusterInt:514, attrInt:3]

dev:6452024-09-20 01:57:17.206 PMdebugparse(): Fan Event - Fan Speed Percent Curent 64

dev:6452024-09-20 01:57:17.205 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0003, value:64, clusterInt:514, attrInt:3]

dev:6452024-09-20 01:57:17.191 PMdebugparse(): Fan Event - Fan Speed Percent Curent 64

dev:6452024-09-20 01:57:17.190 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0003, value:64, clusterInt:514, attrInt:3]

dev:6452024-09-20 01:57:17.183 PMdebugparse(): Fan Event - Fan Speed Percent 64

dev:6452024-09-20 01:57:17.181 PMinfoAiDot P200 Pro Air Purifier - Matter was set to speed speed12 (high)

dev:6452024-09-20 01:57:17.179 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0002, value:64, clusterInt:514, attrInt:2]

dev:6452024-09-20 01:57:17.172 PMdebugparse(): Fan Event - Fan Speed 03

dev:6452024-09-20 01:57:17.171 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0000, value:03, clusterInt:514, attrInt:0]

dev:6452024-09-20 01:57:17.149 PMdebugparse(): Fan Event - Fan Speed Percent Curent 64

dev:6452024-09-20 01:57:17.147 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0003, value:64, clusterInt:514, attrInt:3]

dev:6452024-09-20 01:57:17.141 PMdebugparse(): Fan Event - Fan Speed Percent 64

dev:6452024-09-20 01:57:17.115 PMinfoAiDot P200 Pro Air Purifier - Matter was set to speed speed12 (high)

dev:6452024-09-20 01:57:17.113 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0002, value:64, clusterInt:514, attrInt:2]

dev:6452024-09-20 01:57:17.107 PMdebugparse(): Fan Event - Fan Speed 03

dev:6452024-09-20 01:57:17.105 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0000, value:03, clusterInt:514, attrInt:0]

dev:6452024-09-20 01:57:17.089 PMdebugparse(): Fan Event - Fan Speed Percent 64

dev:6452024-09-20 01:57:17.087 PMinfoAiDot P200 Pro Air Purifier - Matter was set to speed speed12 (high)

dev:6452024-09-20 01:57:17.085 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0002, value:64, clusterInt:514, attrInt:2]

dev:6452024-09-20 01:57:17.079 PMdebugparse(): Fan Event - Fan Speed 03

dev:6452024-09-20 01:57:17.077 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0000, value:03, clusterInt:514, attrInt:0]

dev:6452024-09-20 01:57:17.062 PMdebugparse(): Fan Event - Fan Speed Percent 64

dev:6452024-09-20 01:57:17.059 PMinfoAiDot P200 Pro Air Purifier - Matter was set to speed speed12 (high)

dev:6452024-09-20 01:57:17.057 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0002, value:64, clusterInt:514, attrInt:2]

dev:6452024-09-20 01:57:17.051 PMdebugparse(): Fan Event - Fan Speed 03

dev:6452024-09-20 01:57:17.050 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0000, value:03, clusterInt:514, attrInt:0]

dev:6452024-09-20 01:57:14.505 PMdebugparse(): Fan Event - Fan Speed Percent Curent 42

dev:6452024-09-20 01:57:14.503 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0003, value:42, clusterInt:514, attrInt:3]

dev:6452024-09-20 01:57:14.497 PMdebugparse(): Fan Event - Fan Speed Percent 42

dev:6452024-09-20 01:57:14.494 PMinfoAiDot P200 Pro Air Purifier - Matter was set to speed null

dev:6452024-09-20 01:57:14.491 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0002, value:42, clusterInt:514, attrInt:2]

dev:6452024-09-20 01:57:14.485 PMdebugparse(): Fan Event - Fan Speed 02

dev:6452024-09-20 01:57:14.484 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0000, value:02, clusterInt:514, attrInt:0]

dev:6452024-09-20 01:57:14.468 PMdebugparse(): Fan Event - Fan Speed Percent Curent 42

dev:6452024-09-20 01:57:14.467 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0003, value:42, clusterInt:514, attrInt:3]

dev:6452024-09-20 01:57:14.460 PMdebugparse(): Fan Event - Fan Speed Percent 42

dev:6452024-09-20 01:57:14.457 PMinfoAiDot P200 Pro Air Purifier - Matter was set to speed null

dev:6452024-09-20 01:57:14.455 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0002, value:42, clusterInt:514, attrInt:2]

dev:6452024-09-20 01:57:14.448 PMdebugparse(): Fan Event - Fan Speed 02

dev:6452024-09-20 01:57:14.447 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0000, value:02, clusterInt:514, attrInt:0]

dev:6452024-09-20 01:57:13.829 PMdebugparse(): Fan Event - Fan Speed Percent Curent 42

dev:6452024-09-20 01:57:13.827 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0003, value:42, clusterInt:514, attrInt:3]

dev:6452024-09-20 01:57:13.820 PMdebugparse(): Fan Event - Fan Speed Percent 42

dev:6452024-09-20 01:57:13.817 PMinfoAiDot P200 Pro Air Purifier - Matter was set to speed null

dev:6452024-09-20 01:57:13.815 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0002, value:42, clusterInt:514, attrInt:2]

dev:6452024-09-20 01:57:13.808 PMdebugparse(): Fan Event - Fan Speed 02

dev:6452024-09-20 01:57:13.807 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0000, value:02, clusterInt:514, attrInt:0]

dev:6452024-09-20 01:57:13.790 PMdebugparse(): Fan Event - Fan Speed Percent Curent 42

dev:6452024-09-20 01:57:13.788 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0003, value:42, clusterInt:514, attrInt:3]

dev:6452024-09-20 01:57:13.781 PMdebugparse(): Fan Event - Fan Speed Percent 42

dev:6452024-09-20 01:57:13.778 PMinfoAiDot P200 Pro Air Purifier - Matter was set to speed null

dev:6452024-09-20 01:57:13.776 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0002, value:42, clusterInt:514, attrInt:2]

dev:6452024-09-20 01:57:13.769 PMdebugparse(): Fan Event - Fan Speed 02

dev:6452024-09-20 01:57:13.768 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0000, value:02, clusterInt:514, attrInt:0]

dev:6452024-09-20 01:57:09.169 PMdebugparse(): Fan Event - Fan Speed Percent Curent 21

dev:6452024-09-20 01:57:09.168 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0003, value:21, clusterInt:514, attrInt:3]

dev:6452024-09-20 01:57:09.153 PMdebugparse(): Fan Event - Fan Speed Percent Curent 21

dev:6452024-09-20 01:57:09.151 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0003, value:21, clusterInt:514, attrInt:3]

dev:6452024-09-20 01:57:09.105 PMdebugparse(): Fan Event - Fan Speed Percent Curent 21

dev:6452024-09-20 01:57:09.103 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0003, value:21, clusterInt:514, attrInt:3]

dev:6452024-09-20 01:57:09.096 PMdebugparse(): Fan Event - Fan Speed Percent 21

dev:6452024-09-20 01:57:09.093 PMinfoAiDot P200 Pro Air Purifier - Matter was set to speed null

dev:6452024-09-20 01:57:09.091 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0002, value:21, clusterInt:514, attrInt:2]

dev:6452024-09-20 01:57:09.084 PMdebugparse(): Fan Event - Fan Speed 01

dev:6452024-09-20 01:57:09.082 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0000, value:01, clusterInt:514, attrInt:0]

dev:6452024-09-20 01:57:09.064 PMdebugparse(): Fan Event - Fan Speed Percent Curent 21

dev:6452024-09-20 01:57:09.062 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0003, value:21, clusterInt:514, attrInt:3]

dev:6452024-09-20 01:57:09.055 PMdebugparse(): Fan Event - Fan Speed Percent 21

dev:6452024-09-20 01:57:09.052 PMinfoAiDot P200 Pro Air Purifier - Matter was set to speed null

dev:6452024-09-20 01:57:09.050 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0002, value:21, clusterInt:514, attrInt:2]

dev:6452024-09-20 01:57:09.043 PMdebugparse(): Fan Event - Fan Speed 01

dev:6452024-09-20 01:57:09.042 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0000, value:01, clusterInt:514, attrInt:0]

dev:6452024-09-20 01:57:08.981 PMdebugparse(): Fan Event - Fan Speed Percent 21

dev:6452024-09-20 01:57:08.978 PMinfoAiDot P200 Pro Air Purifier - Matter was set to speed null

dev:6452024-09-20 01:57:08.976 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0002, value:21, clusterInt:514, attrInt:2]

dev:6452024-09-20 01:57:08.969 PMdebugparse(): Fan Event - Fan Speed 01

dev:6452024-09-20 01:57:08.968 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0000, value:01, clusterInt:514, attrInt:0]

dev:6452024-09-20 01:57:08.952 PMdebugparse(): Fan Event - Fan Speed Percent 21

dev:6452024-09-20 01:57:08.949 PMinfoAiDot P200 Pro Air Purifier - Matter was set to speed null

dev:6452024-09-20 01:57:08.947 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0002, value:21, clusterInt:514, attrInt:2]

dev:6452024-09-20 01:57:08.940 PMdebugparse(): Fan Event - Fan Speed 01

dev:6452024-09-20 01:57:08.939 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0000, value:01, clusterInt:514, attrInt:0]

dev:6452024-09-20 01:57:07.456 PMdebugparse(): Fan Event - Fan Speed Percent Curent 64

dev:6452024-09-20 01:57:07.454 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0003, value:64, clusterInt:514, attrInt:3]

dev:6452024-09-20 01:57:07.447 PMdebugparse(): Fan Event - Fan Speed Percent 64

dev:6452024-09-20 01:57:07.444 PMinfoAiDot P200 Pro Air Purifier - Matter was set to speed speed12 (high)

dev:6452024-09-20 01:57:07.442 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0002, value:64, clusterInt:514, attrInt:2]

dev:6452024-09-20 01:57:07.436 PMdebugparse(): Fan Event - Fan Speed 03

dev:6452024-09-20 01:57:07.434 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0000, value:03, clusterInt:514, attrInt:0]

dev:6452024-09-20 01:57:07.418 PMdebugparse(): Fan Event - Fan Speed Percent Curent 64

dev:6452024-09-20 01:57:07.416 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0003, value:64, clusterInt:514, attrInt:3]

dev:6452024-09-20 01:57:07.409 PMdebugparse(): Fan Event - Fan Speed Percent 64

dev:6452024-09-20 01:57:07.407 PMinfoAiDot P200 Pro Air Purifier - Matter was set to speed speed12 (high)

dev:6452024-09-20 01:57:07.405 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0002, value:64, clusterInt:514, attrInt:2]

dev:6452024-09-20 01:57:07.398 PMdebugparse(): Fan Event - Fan Speed 03

dev:6452024-09-20 01:57:07.396 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0000, value:03, clusterInt:514, attrInt:0]

dev:6452024-09-20 01:57:07.365 PMdebugparse(): Fan Event - Fan Speed Percent Curent 64

dev:6452024-09-20 01:57:07.363 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0003, value:64, clusterInt:514, attrInt:3]

dev:6452024-09-20 01:57:07.355 PMdebugparse(): Fan Event - Fan Speed Percent 64

dev:6452024-09-20 01:57:07.353 PMinfoAiDot P200 Pro Air Purifier - Matter was set to speed speed12 (high)

dev:6452024-09-20 01:57:07.351 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0002, value:64, clusterInt:514, attrInt:2]

dev:6452024-09-20 01:57:07.343 PMdebugparse(): Fan Event - Fan Speed 03

dev:6452024-09-20 01:57:07.342 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0000, value:03, clusterInt:514, attrInt:0]

dev:6452024-09-20 01:57:07.324 PMdebugparse(): Fan Event - Fan Speed Percent Curent 64

dev:6452024-09-20 01:57:07.323 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0003, value:64, clusterInt:514, attrInt:3]

dev:6452024-09-20 01:57:07.316 PMdebugparse(): Fan Event - Fan Speed Percent 64

dev:6452024-09-20 01:57:07.313 PMinfoAiDot P200 Pro Air Purifier - Matter was set to speed speed12 (high)

dev:6452024-09-20 01:57:07.311 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0002, value:64, clusterInt:514, attrInt:2]

dev:6452024-09-20 01:57:07.304 PMdebugparse(): Fan Event - Fan Speed 03

dev:6452024-09-20 01:57:07.303 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0000, value:03, clusterInt:514, attrInt:0]

dev:6452024-09-20 01:57:02.936 PMdebugparse(): Fan Event - Fan Speed Percent Curent 05

dev:6452024-09-20 01:57:02.935 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0003, value:05, clusterInt:514, attrInt:3]

dev:6452024-09-20 01:57:02.927 PMdebugparse(): Fan Event - Fan Speed Percent 05

dev:6452024-09-20 01:57:02.923 PMinfoAiDot P200 Pro Air Purifier - Matter was set to speed null

dev:6452024-09-20 01:57:02.920 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0002, value:05, clusterInt:514, attrInt:2]

dev:6452024-09-20 01:57:02.914 PMdebugparse(): Fan Event - Fan Speed 05

dev:6452024-09-20 01:57:02.912 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0000, value:05, clusterInt:514, attrInt:0]

dev:6452024-09-20 01:57:02.896 PMdebugparse(): Fan Event - Fan Speed Percent Curent 05

dev:6452024-09-20 01:57:02.894 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0003, value:05, clusterInt:514, attrInt:3]

dev:6452024-09-20 01:57:02.887 PMdebugparse(): Fan Event - Fan Speed Percent 05

dev:6452024-09-20 01:57:02.884 PMinfoAiDot P200 Pro Air Purifier - Matter was set to speed null

dev:6452024-09-20 01:57:02.881 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0002, value:05, clusterInt:514, attrInt:2]

dev:6452024-09-20 01:57:02.875 PMdebugparse(): Fan Event - Fan Speed 05

dev:6452024-09-20 01:57:02.873 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0000, value:05, clusterInt:514, attrInt:0]

dev:6452024-09-20 01:57:02.816 PMdebugparse(): Fan Event - Fan Speed Percent Curent 05

dev:6452024-09-20 01:57:02.814 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0003, value:05, clusterInt:514, attrInt:3]

dev:6452024-09-20 01:57:02.807 PMdebugparse(): Fan Event - Fan Speed Percent 05

dev:6452024-09-20 01:57:02.804 PMinfoAiDot P200 Pro Air Purifier - Matter was set to speed null

dev:6452024-09-20 01:57:02.801 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0002, value:05, clusterInt:514, attrInt:2]

dev:6452024-09-20 01:57:02.795 PMdebugparse(): Fan Event - Fan Speed 05

dev:6452024-09-20 01:57:02.793 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0000, value:05, clusterInt:514, attrInt:0]

dev:6452024-09-20 01:57:02.778 PMdebugparse(): Fan Event - Fan Speed Percent Curent 05

dev:6452024-09-20 01:57:02.776 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0003, value:05, clusterInt:514, attrInt:3]

dev:6452024-09-20 01:57:02.766 PMdebugparse(): Fan Event - Fan Speed Percent 05

dev:6452024-09-20 01:57:02.762 PMinfoAiDot P200 Pro Air Purifier - Matter was set to speed null

dev:6452024-09-20 01:57:02.759 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0002, value:05, clusterInt:514, attrInt:2]

dev:6452024-09-20 01:57:02.753 PMdebugparse(): Fan Event - Fan Speed 05

dev:6452024-09-20 01:57:02.751 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0000, value:05, clusterInt:514, attrInt:0]

dev:6452024-09-20 01:56:07.638 PMwarndescription logging is: true

dev:6452024-09-20 01:56:07.637 PMwarndebug logging is: true

dev:6452024-09-20 01:56:07.635 PMinfoupdated...

dev:6452024-09-20 11:10:00.111 AMinfoinitialize...

dev:6452024-09-20 11:04:35.991 AMinfoinitialize...

dev:6452024-09-20 11:03:55.195 AMerrorgroovy.lang.MissingMethodException: No signature of method: user_driver_Mavrrick_Air_Purifier_Driver_Matter__1086.logWarn() is applicable for argument types: (org.codehaus.groovy.runtime.GStringImpl) values: [parse: skipped Air Quality, attribute:0000, value:01]
Possible solutions: logsOff() on line 77 (method parse)

dev:6452024-09-20 11:03:55.150 AMerrorgroovy.lang.MissingMethodException: No signature of method: user_driver_Mavrrick_Air_Purifier_Driver_Matter__1086.logWarn() is applicable for argument types: (org.codehaus.groovy.runtime.GStringImpl) values: [parse: skipped Filter State, attribute:0000, value:60]
Possible solutions: logsOff() on line 83 (method parse)

dev:6452024-09-20 11:03:54.424 AMinfoinitialize...

dev:6452024-09-20 11:02:02.313 AMerrorgroovy.lang.MissingMethodException: No signature of method: user_driver_Mavrrick_Air_Purifier_Driver_Matter__1086.logWarn() is applicable for argument types: (org.codehaus.groovy.runtime.GStringImpl) values: [parse: skipped Air Quality, attribute:0000, value:01]
Possible solutions: logsOff() on line 77 (method parse)

dev:6452024-09-20 11:02:02.275 AMerrorgroovy.lang.MissingMethodException: No signature of method: user_driver_Mavrrick_Air_Purifier_Driver_Matter__1086.logWarn() is applicable for argument types: (org.codehaus.groovy.runtime.GStringImpl) values: [parse: skipped Filter State, attribute:0000, value:60]
Possible solutions: logsOff() on line 83 (method parse)

dev:6452024-09-20 11:02:01.612 AMinfoinitialize...

dev:6452024-09-20 11:01:21.456 AMerrorgroovy.lang.MissingMethodException: No signature of method: user_driver_Mavrrick_Air_Purifier_Driver_Matter__1086.logWarn() is applicable for argument types: (org.codehaus.groovy.runtime.GStringImpl) values: [parse: skipped Air Quality, attribute:0000, value:01]
Possible solutions: logsOff() on line 77 (method parse)

dev:6452024-09-20 11:01:21.411 AMerrorgroovy.lang.MissingMethodException: No signature of method: user_driver_Mavrrick_Air_Purifier_Driver_Matter__1086.logWarn() is applicable for argument types: (org.codehaus.groovy.runtime.GStringImpl) values: [parse: skipped Filter State, attribute:0000, value:60]
Possible solutions: logsOff() on line 83 (method parse)

dev:6452024-09-20 11:01:20.689 AMinfoinitialize...

dev:6452024-09-20 11:00:46.544 AMerrorgroovy.lang.MissingMethodException: No signature of method: user_driver_Mavrrick_Air_Purifier_Driver_Matter__1086.logWarn() is applicable for argument types: (org.codehaus.groovy.runtime.GStringImpl) values: [parse: skipped Air Quality, attribute:0000, value:01]
Possible solutions: logsOff() on line 77 (method parse)

dev:6452024-09-20 11:00:46.446 AMerrorgroovy.lang.MissingMethodException: No signature of method: user_driver_Mavrrick_Air_Purifier_Driver_Matter__1086.logWarn() is applicable for argument types: (org.codehaus.groovy.runtime.GStringImpl) values: [parse: skipped Filter State, attribute:0000, value:60]
Possible solutions: logsOff() on line 83 (method parse)

dev:6452024-09-20 11:00:45.614 AMinfoinitialize...

Let me provide one more piece of info. Sleep mode is a special mode that affects not only the fan speed but other aspects of the purifier. It specifically sets the fan speed to a VERY slow speed that makes the purifier virtually silent. Outside of turning on sleep mode you can't set the fan speed to this very slow speed. Sleep mode also turns off all lights on the purifier including the air quality indicator light and the control panel backlight. All this is designed for using the purifier in a bedroom when the fan or lights on the purifier could impact people's ability to sleep.

One thing I noticed when changing fan speed using the purifier's app was that the current state speed feedback on the device page showed feedback of off and speed 12 (high). However, if I switch the fan speed to low or medium using the app the feedback was null.
Hope all this helps and thanks
Jay

Here is a updated driver. I removed extra fan speeds so you only have the ones you mentioned. It sounds like the options for Sleep mode are not available through MATTER.

It looks like i fixed some issues with the the parser for the Air Filter and the Air Quality since your driver.

The process to update the attribute to wasn't matching the value passed when you updated from the app. I added some logging to catch it better so i can capture that and fix it on the next driver update. Try the below driver with all the logging and let me know what the results are.

/*
	Air Purifier Driver

	Copyright 2023 Hubitat Inc.  All Rights Reserved

	2023-11-02 2.3.7 maxwell
		-initial pub

*/

import groovy.transform.Field

@Field static final String   DEVICE_TYPE = 'MATTER_PURIFIER'

@Field Map getFanLevel = [
    "off": 0
    ,"low": 33
	,"medium": 66
	,"high": 100   
]

import groovy.transform.Field
import hubitat.helper.HexUtils

metadata {
    definition (name: "Air Purifier Driver(Matter)", namespace: "Mavrrick", author: "Mavrrick") {
        capability "Actuator"
        capability "Switch"
        capability "Configuration"
        capability "FanControl"
        capability "Initialize"
        capability "Refresh"
        capability "AirQuality"
        capability "FilterStatus"
        
//        command 'getInfo'
        command "setSpeed", [[name: "Fan speed*",type:"ENUM", description:"Fan speed to set", constraints: getFanLevel.collect {k,v -> k}]]
        
        fingerprint endpointId:"01", inClusters:"0003,0202,0071,005B,001D", outClusters:"", model:"Air Purifier", manufacturer:"Leedarson", controllerType:"MAT"

    }
    preferences {
//        input(name:"cycleInterval", type:"number", title:"Number of seconds between cycles", defaultValue:30)
        input(name:"logEnable", type:"bool", title:"Enable debug logging", defaultValue:false)
        input(name:"txtEnable", type:"bool", title:"Enable descriptionText logging", defaultValue:true)
    }
}

//parsers
void parse(String description) {
    Map descMap = matter.parseDescriptionAsMap(description)
    if (logEnable) log.debug "descMap:${descMap}"
    switch (descMap.cluster) {        
        case "0006" :
            if (descMap.attrId == "0000") { //switch
                sendSwitchEvent(descMap.value)
            }
            break
        case "0000" :
            if (descMap.attrId == "4000") { //software build
                updateDataValue("softwareBuild",descMap.value ?: "unknown")
            }
            break
        case "005B" :
/*            if (descMap.attrId == "4000") { //Air Quality
                updateDataValue("Air Quality",descMap.value ?: "unknown")
            } */
            sendEvent(name:"airQualityIndex ", value:value, descriptionText:descriptionText)
            if (logEnable) log.debug  "parse: skipped Air Quality, attribute:${descMap.attrId}, value:${descMap.value}"
            break
        case "0071" :
/*            if (descMap.attrId == "4000") { //Filter State
                updateDataValue("Filter State",descMap.value ?: "unknown")
            } */
            sendEvent(name:"filterStatus ", value:value, descriptionText:descriptionText) 
            if (logEnable) log.debug  "parse: skipped Filter State, attribute:${descMap.attrId}, value:${descMap.value}"
            break
        case "0202" :
            if (descMap.attrId == "0000") { //fan speed
                if (logEnable) log.debug "parse(): Fan Event - Fan Speed ${descMap.value}"
            } else if (descMap.attrId == "0001") { //fan speed mode
                if (logEnable) log.debug "parse(): Fan Event - Fan speed mode ${descMap.value}"
            } else if (descMap.attrId == "0002") { //fan speed Percent Setting
                sendSpeedEvent(descMap.value) 
                if (logEnable) log.debug "parse(): Fan Event - Fan Speed  Percent ${descMap.value}"
            } else  if (descMap.attrId == "0003") { //fan speed Percent current
                if (logEnable) log.debug "parse(): Fan Event - Fan Speed Percent Curent ${descMap.value}"
            } else if (descMap.attrId == "0004") { //fan speed max (Don't expect to actually ever return in parse
                if (logEnable) log.debug "parse(): Fan Event - Fan Speed Max speed ${descMap.value}"
            } else if (descMap.attrId == "0005") { //fan speed setting
                if (logEnable) log.debug "parse(): Fan Event - Fan Speed setting ${descMap.value}"
            } else if (descMap.attrId == "0006") { //fan speed setting current
                if (logEnable) log.debug "parse(): Fan Event - Fan Speed current ${descMap.value}"
            } else if (descMap.attrId == "000A") { //WindSetting current
                if (logEnable) log.debug "parse(): Fan Event - Wind Speed setting ${descMap.value}"
            } else  if (descMap.attrId == "000B") { //Airflow Direction
                if (logEnable) log.debug "parse(): Fan Event - Airflow Direction setting ${descMap.value}"
            } else {
                if (logEnable) log.debug  "parse: skipped fan, attribute:${descMap.attrId}, value:${descMap.value}"
            }
//            gatherAttributesValuesInfo(descMap, FanClusterAttributes)
            break
        default :
            if (logEnable) {
                log.debug "skipped:${descMap}"
            }
    }
}

//events
private void sendSpeedEvent(String rawValue) {      
    Integer intValue = hexStrToUnsignedInt(rawValue) 
    
    switch(intValue) {
        case 0 :
            value = "off";
        break;
        case 33:
            value = "low";
        break;
        case 66:
            value = "medium";
        break;
        case 100:
            value = "high";
        break; 
    }
    
//    if (device.currentValue("switch") == value) return
    String descriptionText = "${device.displayName} was set to speed ${value} RawValue: ${intValue}"
    if (txtEnable) log.info descriptionText
    sendEvent(name:"speed", value:value, descriptionText:descriptionText)
}

private void sendSwitchEvent(String rawValue) {
    String value = rawValue == "01" ? "on" : "off"
    if (device.currentValue("switch") == value) return
    String descriptionText = "${device.displayName} was turned ${value}"
    if (txtEnable) log.info descriptionText
    sendEvent(name:"switch", value:value, descriptionText:descriptionText)
}

//capability commands
void on() {
    unschedule()
    if (logEnable) log.debug "on()"
    sendToDevice(matter.on())
    fanspeed = "medium"
    setSpeed(fanspeed)    
   
}

void off() {
    unschedule()
    if (logEnable) log.debug "off()"
//    sendToDevice(matter.off())
    fanspeed = "off"
    setSpeed(fanspeed)
}

void setSpeed(fanspeed) {
    unschedule()
    if (logEnable) log.debug "Setting Fan Speed to ${fanspeed}"
    switch(fanspeed) {
        case "off":
            value = 0;
        break;
        case "low":
            value = 33;
        break;
        case "medium":
            value = 66;
        break;
        case "high":
            value = 100;
        break; 
    }
    if (value > 101) {
        if (logEnable) {log.debug ("setSpeed(): Unknown value}")};
        on()
    } else {
        speedValue = intToHexStr(value)  
        if (logEnable) log.debug "Setting Fan Speed percent ${fanspeed}  % ${value} value to ${speedValue}"
        List<Map<String, String>> attributeWriteRequests = []
        attributeWriteRequests.add(matter.attributeWriteRequest(device.endpointId, 0x0202, 0x0002, 0x04, speedValue ))
        String cmd = matter.writeAttributes(attributeWriteRequests)            
        sendToDevice(cmd)
    }
}

void cycleSpeed() {
    cycleChange()
}

void cycleChange() {
    Integer randomSpeed = Math.abs(new Random().nextInt() % 12) + 1
    String newSpeed = "speed "+randomSpeed
    setSpeed(newSpeed)
    runIn(cycleInterval, cycleChange)
    
}


void configure() {
    log.warn "configure..."
    sendToDevice(subscribeCmd())
    unschedule()
}

//lifecycle commands
void updated(){
    log.info "updated..."
    log.warn "debug logging is: ${logEnable == true}"
    log.warn "description logging is: ${txtEnable == true}"
    if (logEnable) runIn(1800,logsOff)
}

void initialize() {
    log.info "initialize..."
//    initializeVars(fullInit = true)
    sendToDevice(subscribeCmd())
}

void refresh() {
    if (logEnable) log.debug "refresh()"
    sendToDevice(refreshCmd())
}

String refreshCmd() {
    List<Map<String, String>> attributePaths = []
    
        attributePaths.add(matter.attributePath(device.endpointId, 0x0006, 0x0000))         // on/off
        attributePaths.add(matter.attributePath(device.endpointId, 0x0202, 0x0000))         // FanMode
        attributePaths.add(matter.attributePath(device.endpointId, 0x0202, 0x0002))         // PercentSetting
        attributePaths.add(matter.attributePath(device.endpointId, 0x0202, 0x0003))         // PercentCurrent
        attributePaths.add(matter.attributePath(device.endpointId, 0x0202, 0x000A))         // WindSetting
        attributePaths.add(matter.attributePath(device.endpointId, 0x0202, 0x000B))         // AirflowDirectionEnum
        attributePaths.add(matter.attributePath(device.endpointId, 0x0003, 0x0000))         
        attributePaths.add(matter.attributePath(device.endpointId, 0x0003, 0x0001))         // Power Configuration Cluster : Status
        attributePaths.add(matter.attributePath(device.endpointId, 0x005B, 0x0000)) 
        attributePaths.add(matter.attributePath(device.endpointId, 0x0071, 0x0000))
        attributePaths.add(matter.attributePath(device.endpointId, 0x0071, 0x0002))
    
    String cmd = matter.readAttributes(attributePaths)
    return cmd
}

String subscribeCmd() {
    List<Map<String, String>> attributePaths = []
    String cmd = ''
    
        attributePaths.add(matter.attributePath(0x01, 0x0006, 0x00))
        attributePaths.add(matter.attributePath(0x01, 0x0202, 0x00))
        attributePaths.add(matter.attributePath(0x01, 0x0202, 0x02))
        attributePaths.add(matter.attributePath(0x01, 0x0202, 0x03))
        attributePaths.add(matter.attributePath(0x01, 0x0202, 0x0A))
        attributePaths.add(matter.attributePath(0x01, 0x0202, 0x0B))
        attributePaths.add(matter.attributePath(0x01, 0x005B, 0x00))
        attributePaths.add(matter.attributePath(0x01, 0x0071, 0x00))
        attributePaths.add(matter.attributePath(0x01, 0x0071, 0x04))
        cmd = matter.subscribe(0, 0xFFFF, attributePaths)

    return cmd
}

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

Integer hex254ToInt100(String value) {
    return Math.round(hexStrToUnsignedInt(value) / 2.54)
}

String int100ToHex254(value) {
    return intToHexStr(Math.round(value * 2.54))
}


void sendToDevice(List<String> cmds, Integer delay = 300) {
    sendHubCommand(new hubitat.device.HubMultiAction(commands(cmds, delay), hubitat.device.Protocol.MATTER))
}

void sendToDevice(String cmd, Integer delay = 300) {
    sendHubCommand(new hubitat.device.HubAction(cmd, hubitat.device.Protocol.MATTER))
}

List<String> commands(List<String> cmds, Integer delay = 300) {
    return delayBetween(cmds.collect { it }, delay)
}
    
    

Thanks so much. I've loaded the latest driver code and it is working very well. Setting the fan speed works perfectly including feedback. Also, On/Off is working. On turns the purifier on and sets the fan speed to medium. Off simply turns it off in the same way that setting the fan speed to off works.

Any ideas, from what you are seeing, with being able to retrieve a reading from the air quality sensor? This is supported by HA. I believe that on/off, fan speed, and sensor readings are the only functionality the manufacturer currently supports through Matter. However, I believe that list will expand at some point in the future.

Just so you could see it, I captured another live log

dev:6452024-09-20 04:57:53.706 PMdebugparse(): Fan Event - Fan Speed Percent Curent 05

dev:6452024-09-20 04:57:53.704 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0003, value:05, clusterInt:514, attrInt:3]

dev:6452024-09-20 04:57:53.698 PMdebugparse(): Fan Event - Fan Speed Percent 05

dev:6452024-09-20 04:57:53.695 PMinfoAiDot P200 Pro Air Purifier - Matter was set to speed null RawValue: 5

dev:6452024-09-20 04:57:53.692 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0002, value:05, clusterInt:514, attrInt:2]

dev:6452024-09-20 04:57:53.663 PMdebugparse(): Fan Event - Fan Speed Percent Curent 05

dev:6452024-09-20 04:57:53.661 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0003, value:05, clusterInt:514, attrInt:3]

dev:6452024-09-20 04:57:53.655 PMdebugparse(): Fan Event - Fan Speed Percent 05

dev:6452024-09-20 04:57:53.652 PMinfoAiDot P200 Pro Air Purifier - Matter was set to speed null RawValue: 5

dev:6452024-09-20 04:57:53.649 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0002, value:05, clusterInt:514, attrInt:2]

dev:6452024-09-20 04:57:53.635 PMdebugparse(): Fan Event - Fan Speed Percent Curent 05

dev:6452024-09-20 04:57:53.633 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0003, value:05, clusterInt:514, attrInt:3]

dev:6452024-09-20 04:57:53.626 PMdebugparse(): Fan Event - Fan Speed Percent 05

dev:6452024-09-20 04:57:53.623 PMinfoAiDot P200 Pro Air Purifier - Matter was set to speed null RawValue: 5

dev:6452024-09-20 04:57:53.620 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0002, value:05, clusterInt:514, attrInt:2]

dev:6452024-09-20 04:57:53.397 PMdebugparse(): Fan Event - Fan Speed Percent Curent 05

dev:6452024-09-20 04:57:53.345 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0003, value:05, clusterInt:514, attrInt:3]

dev:6452024-09-20 04:57:53.338 PMdebugparse(): Fan Event - Fan Speed Percent 05

dev:6452024-09-20 04:57:53.335 PMinfoAiDot P200 Pro Air Purifier - Matter was set to speed null RawValue: 5

dev:6452024-09-20 04:57:53.333 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0002, value:05, clusterInt:514, attrInt:2]

dev:6452024-09-20 04:57:53.327 PMdebugparse(): Fan Event - Fan Speed 05

dev:6452024-09-20 04:57:53.325 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0000, value:05, clusterInt:514, attrInt:0]

dev:6452024-09-20 04:57:53.266 PMdebugparse(): Fan Event - Fan Speed 05

dev:6452024-09-20 04:57:53.263 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0000, value:05, clusterInt:514, attrInt:0]

dev:6452024-09-20 04:57:53.251 PMdebugparse(): Fan Event - Fan Speed 05

dev:6452024-09-20 04:57:53.249 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0000, value:05, clusterInt:514, attrInt:0]

dev:6452024-09-20 04:57:53.236 PMdebugparse(): Fan Event - Fan Speed 05

dev:6452024-09-20 04:57:53.233 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0000, value:05, clusterInt:514, attrInt:0]

dev:6452024-09-20 04:55:07.151 PMdebugparse(): Fan Event - Fan Speed Percent Curent 21

dev:6452024-09-20 04:55:07.149 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0003, value:21, clusterInt:514, attrInt:3]

dev:6452024-09-20 04:55:07.143 PMdebugparse(): Fan Event - Fan Speed Percent 21

dev:6452024-09-20 04:55:07.140 PMinfoAiDot P200 Pro Air Purifier - Matter was set to speed low RawValue: 33

dev:6452024-09-20 04:55:07.138 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0002, value:21, clusterInt:514, attrInt:2]

dev:6452024-09-20 04:55:07.133 PMdebugparse(): Fan Event - Fan Speed 01

dev:6452024-09-20 04:55:07.130 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0000, value:01, clusterInt:514, attrInt:0]

dev:6452024-09-20 04:55:07.105 PMdebugparse(): Fan Event - Fan Speed Percent Curent 21

dev:6452024-09-20 04:55:07.102 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0003, value:21, clusterInt:514, attrInt:3]

dev:6452024-09-20 04:55:07.096 PMdebugparse(): Fan Event - Fan Speed Percent 21

dev:6452024-09-20 04:55:07.094 PMinfoAiDot P200 Pro Air Purifier - Matter was set to speed low RawValue: 33

dev:6452024-09-20 04:55:07.091 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0002, value:21, clusterInt:514, attrInt:2]

dev:6452024-09-20 04:55:07.086 PMdebugparse(): Fan Event - Fan Speed 01

dev:6452024-09-20 04:55:07.084 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0000, value:01, clusterInt:514, attrInt:0]

dev:6452024-09-20 04:55:07.070 PMdebugparse(): Fan Event - Fan Speed Percent Curent 21

dev:6452024-09-20 04:55:07.067 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0003, value:21, clusterInt:514, attrInt:3]

dev:6452024-09-20 04:55:07.061 PMdebugparse(): Fan Event - Fan Speed Percent 21

dev:6452024-09-20 04:55:07.059 PMinfoAiDot P200 Pro Air Purifier - Matter was set to speed low RawValue: 33

dev:6452024-09-20 04:55:07.056 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0002, value:21, clusterInt:514, attrInt:2]

dev:6452024-09-20 04:55:07.051 PMdebugparse(): Fan Event - Fan Speed 01

dev:6452024-09-20 04:55:07.048 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0000, value:01, clusterInt:514, attrInt:0]

dev:6452024-09-20 04:55:07.032 PMdebugparse(): Fan Event - Fan Speed Percent Curent 21

dev:6452024-09-20 04:55:07.029 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0003, value:21, clusterInt:514, attrInt:3]

dev:6452024-09-20 04:55:07.023 PMdebugparse(): Fan Event - Fan Speed Percent 21

dev:6452024-09-20 04:55:07.021 PMinfoAiDot P200 Pro Air Purifier - Matter was set to speed low RawValue: 33

dev:6452024-09-20 04:55:07.018 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0002, value:21, clusterInt:514, attrInt:2]

dev:6452024-09-20 04:55:07.013 PMdebugparse(): Fan Event - Fan Speed 01

dev:6452024-09-20 04:55:07.011 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0000, value:01, clusterInt:514, attrInt:0]

dev:6452024-09-20 04:54:35.950 PMdebugparse(): Fan Event - Fan Speed Percent Curent 42

dev:6452024-09-20 04:54:35.947 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0003, value:42, clusterInt:514, attrInt:3]

dev:6452024-09-20 04:54:35.942 PMdebugparse(): Fan Event - Fan Speed Percent 42

dev:6452024-09-20 04:54:35.939 PMinfoAiDot P200 Pro Air Purifier - Matter was set to speed medium RawValue: 66

dev:6452024-09-20 04:54:35.936 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0002, value:42, clusterInt:514, attrInt:2]

dev:6452024-09-20 04:54:35.930 PMdebugparse(): Fan Event - Fan Speed 02

dev:6452024-09-20 04:54:35.928 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0000, value:02, clusterInt:514, attrInt:0]

dev:6452024-09-20 04:54:35.899 PMdebugparse(): Fan Event - Fan Speed Percent Curent 42

dev:6452024-09-20 04:54:35.897 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0003, value:42, clusterInt:514, attrInt:3]

dev:6452024-09-20 04:54:35.891 PMdebugparse(): Fan Event - Fan Speed Percent 42

dev:6452024-09-20 04:54:35.888 PMinfoAiDot P200 Pro Air Purifier - Matter was set to speed medium RawValue: 66

dev:6452024-09-20 04:54:35.886 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0002, value:42, clusterInt:514, attrInt:2]

dev:6452024-09-20 04:54:35.880 PMdebugparse(): Fan Event - Fan Speed 02

dev:6452024-09-20 04:54:35.877 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0000, value:02, clusterInt:514, attrInt:0]

dev:6452024-09-20 04:54:35.863 PMdebugparse(): Fan Event - Fan Speed Percent Curent 42

dev:6452024-09-20 04:54:35.860 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0003, value:42, clusterInt:514, attrInt:3]

dev:6452024-09-20 04:54:35.855 PMdebugparse(): Fan Event - Fan Speed Percent 42

dev:6452024-09-20 04:54:35.852 PMinfoAiDot P200 Pro Air Purifier - Matter was set to speed medium RawValue: 66

dev:6452024-09-20 04:54:35.850 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0002, value:42, clusterInt:514, attrInt:2]

dev:6452024-09-20 04:54:35.844 PMdebugparse(): Fan Event - Fan Speed 02

dev:6452024-09-20 04:54:35.842 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0000, value:02, clusterInt:514, attrInt:0]

dev:6452024-09-20 04:54:35.832 PMdebugparse(): Fan Event - Fan Speed Percent Curent 42

dev:6452024-09-20 04:54:35.821 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0003, value:42, clusterInt:514, attrInt:3]

dev:6452024-09-20 04:54:35.814 PMdebugparse(): Fan Event - Fan Speed Percent 42

dev:6452024-09-20 04:54:35.811 PMinfoAiDot P200 Pro Air Purifier - Matter was set to speed medium RawValue: 66

dev:6452024-09-20 04:54:35.809 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0002, value:42, clusterInt:514, attrInt:2]

dev:6452024-09-20 04:54:35.803 PMdebugparse(): Fan Event - Fan Speed 02

dev:6452024-09-20 04:54:35.801 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0000, value:02, clusterInt:514, attrInt:0]

FYI - at this point in the log

2024-09-20 04:57:53.652 PMinfoAiDot P200 Pro Air Purifier - Matter was set to speed null RawValue: 5

I used the app to turn the purifier to auto mode using the app.

Thanks again for all your help

1 Like

Based on the clusters the device presented to Hibitat it will potentially send Air Quality and Filter status. I already setup the matter subscriptions to request those updates. I just need to make sure i can interpret them to something meaningful in hubitat. To get sample data just get the live logging ready, click clear to remove all the old data, and then click on refresh. The info for those attributes shuould be retrieved so we can see what it has now. The you could state what it shows in the app and hopefully i can create something good in hubitat from it.

The big problem for Air Quality is that it looks like Matter doesnt do AQI, but just a flat good, bad, worse, horrible kind of thing with a numericle value. It will probably be really simple once i confirm it.

I am thinking filter status is just a scale of 1-100. Just not sure if that is what is left, or what is consumed. We have made allot of progress today.

Here is the log data I've collected.

dev:6452024-09-20 06:24:58.860 PMdebugparse(): Fan Event - Fan Speed Percent Curent 21

dev:6452024-09-20 06:24:58.857 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0003, value:21, clusterInt:514, attrInt:3]

dev:6452024-09-20 06:24:58.851 PMdebugparse(): Fan Event - Fan Speed Percent 21

dev:6452024-09-20 06:24:58.849 PMinfoAiDot P200 Pro Air Purifier - Matter was set to speed low RawValue: 33

dev:6452024-09-20 06:24:58.847 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0002, value:21, clusterInt:514, attrInt:2]

dev:6452024-09-20 06:24:58.842 PMdebugparse(): Fan Event - Fan Speed 01

dev:6452024-09-20 06:24:58.839 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0000, value:01, clusterInt:514, attrInt:0]

dev:6452024-09-20 06:24:58.825 PMdebugparse(): Fan Event - Fan Speed Percent Curent 21

dev:6452024-09-20 06:24:58.823 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0003, value:21, clusterInt:514, attrInt:3]

dev:6452024-09-20 06:24:58.817 PMdebugparse(): Fan Event - Fan Speed Percent 21

dev:6452024-09-20 06:24:58.814 PMinfoAiDot P200 Pro Air Purifier - Matter was set to speed low RawValue: 33

dev:6452024-09-20 06:24:58.812 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0002, value:21, clusterInt:514, attrInt:2]

dev:6452024-09-20 06:24:58.807 PMdebugparse(): Fan Event - Fan Speed 01

dev:6452024-09-20 06:24:58.805 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0000, value:01, clusterInt:514, attrInt:0]

dev:6452024-09-20 06:24:58.790 PMdebugparse(): Fan Event - Fan Speed Percent Curent 21

dev:6452024-09-20 06:24:58.788 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0003, value:21, clusterInt:514, attrInt:3]

dev:6452024-09-20 06:24:58.782 PMdebugparse(): Fan Event - Fan Speed Percent 21

dev:6452024-09-20 06:24:58.779 PMinfoAiDot P200 Pro Air Purifier - Matter was set to speed low RawValue: 33

dev:6452024-09-20 06:24:58.777 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0002, value:21, clusterInt:514, attrInt:2]

dev:6452024-09-20 06:24:58.771 PMdebugparse(): Fan Event - Fan Speed 01

dev:6452024-09-20 06:24:58.769 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0000, value:01, clusterInt:514, attrInt:0]

dev:6452024-09-20 06:24:58.754 PMdebugparse(): Fan Event - Fan Speed Percent Curent 21

dev:6452024-09-20 06:24:58.752 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0003, value:21, clusterInt:514, attrInt:3]

dev:6452024-09-20 06:24:58.745 PMdebugparse(): Fan Event - Fan Speed Percent 21

dev:6452024-09-20 06:24:58.742 PMinfoAiDot P200 Pro Air Purifier - Matter was set to speed low RawValue: 33

dev:6452024-09-20 06:24:58.740 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0002, value:21, clusterInt:514, attrInt:2]

dev:6452024-09-20 06:24:58.735 PMdebugparse(): Fan Event - Fan Speed 01

dev:6452024-09-20 06:24:58.732 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0000, value:01, clusterInt:514, attrInt:0]

dev:6452024-09-20 06:24:56.971 PMdebugparse(): Fan Event - Fan Speed Percent Curent 00

dev:6452024-09-20 06:24:56.969 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0003, value:00, clusterInt:514, attrInt:3]

dev:6452024-09-20 06:24:56.963 PMdebugparse(): Fan Event - Fan Speed Percent 00

dev:6452024-09-20 06:24:56.960 PMinfoAiDot P200 Pro Air Purifier - Matter was set to speed off RawValue: 0

dev:6452024-09-20 06:24:56.958 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0002, value:00, clusterInt:514, attrInt:2]

dev:6452024-09-20 06:24:56.922 PMdebugparse(): Fan Event - Fan Speed 00

dev:6452024-09-20 06:24:56.920 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0000, value:00, clusterInt:514, attrInt:0]

dev:6452024-09-20 06:24:56.905 PMdebugparse(): Fan Event - Fan Speed Percent Curent 00

dev:6452024-09-20 06:24:56.903 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0003, value:00, clusterInt:514, attrInt:3]

dev:6452024-09-20 06:24:56.897 PMdebugparse(): Fan Event - Fan Speed Percent 00

dev:6452024-09-20 06:24:56.894 PMinfoAiDot P200 Pro Air Purifier - Matter was set to speed off RawValue: 0

dev:6452024-09-20 06:24:56.892 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0002, value:00, clusterInt:514, attrInt:2]

dev:6452024-09-20 06:24:56.887 PMdebugparse(): Fan Event - Fan Speed 00

dev:6452024-09-20 06:24:56.884 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0000, value:00, clusterInt:514, attrInt:0]

dev:6452024-09-20 06:24:56.746 PMdebugparse(): Fan Event - Fan Speed Percent Curent 00

dev:6452024-09-20 06:24:56.744 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0003, value:00, clusterInt:514, attrInt:3]

dev:6452024-09-20 06:24:56.738 PMdebugparse(): Fan Event - Fan Speed Percent 00

dev:6452024-09-20 06:24:56.736 PMinfoAiDot P200 Pro Air Purifier - Matter was set to speed off RawValue: 0

dev:6452024-09-20 06:24:56.733 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0002, value:00, clusterInt:514, attrInt:2]

dev:6452024-09-20 06:24:56.728 PMdebugparse(): Fan Event - Fan Speed 00

dev:6452024-09-20 06:24:56.725 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0000, value:00, clusterInt:514, attrInt:0]

dev:6452024-09-20 06:24:56.709 PMdebugparse(): Fan Event - Fan Speed Percent Curent 00

dev:6452024-09-20 06:24:56.707 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0003, value:00, clusterInt:514, attrInt:3]

dev:6452024-09-20 06:24:56.701 PMdebugparse(): Fan Event - Fan Speed Percent 00

dev:6452024-09-20 06:24:56.699 PMinfoAiDot P200 Pro Air Purifier - Matter was set to speed off RawValue: 0

dev:6452024-09-20 06:24:56.696 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0002, value:00, clusterInt:514, attrInt:2]

dev:6452024-09-20 06:24:56.691 PMdebugparse(): Fan Event - Fan Speed 00

dev:6452024-09-20 06:24:56.688 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0000, value:00, clusterInt:514, attrInt:0]

dev:6452024-09-20 06:24:48.853 PMdebugparse(): Fan Event - Fan Speed Percent Curent 21

dev:6452024-09-20 06:24:48.850 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0003, value:21, clusterInt:514, attrInt:3]

dev:6452024-09-20 06:24:48.843 PMdebugparse(): Fan Event - Fan Speed Percent 21

dev:6452024-09-20 06:24:48.841 PMinfoAiDot P200 Pro Air Purifier - Matter was set to speed low RawValue: 33

dev:6452024-09-20 06:24:48.839 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0002, value:21, clusterInt:514, attrInt:2]

dev:6452024-09-20 06:24:48.833 PMdebugparse(): Fan Event - Fan Speed 01

dev:6452024-09-20 06:24:48.831 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0000, value:01, clusterInt:514, attrInt:0]

dev:6452024-09-20 06:24:48.816 PMdebugparse(): Fan Event - Fan Speed Percent Curent 21

dev:6452024-09-20 06:24:48.814 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0003, value:21, clusterInt:514, attrInt:3]

dev:6452024-09-20 06:24:48.808 PMdebugparse(): Fan Event - Fan Speed Percent 21

dev:6452024-09-20 06:24:48.806 PMinfoAiDot P200 Pro Air Purifier - Matter was set to speed low RawValue: 33

dev:6452024-09-20 06:24:48.804 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0002, value:21, clusterInt:514, attrInt:2]

dev:6452024-09-20 06:24:48.799 PMdebugparse(): Fan Event - Fan Speed 01

dev:6452024-09-20 06:24:48.796 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0000, value:01, clusterInt:514, attrInt:0]

dev:6452024-09-20 06:24:48.781 PMdebugparse(): Fan Event - Fan Speed Percent Curent 21

dev:6452024-09-20 06:24:48.779 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0003, value:21, clusterInt:514, attrInt:3]

dev:6452024-09-20 06:24:48.773 PMdebugparse(): Fan Event - Fan Speed Percent 21

dev:6452024-09-20 06:24:48.771 PMinfoAiDot P200 Pro Air Purifier - Matter was set to speed low RawValue: 33

dev:6452024-09-20 06:24:48.768 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0002, value:21, clusterInt:514, attrInt:2]

dev:6452024-09-20 06:24:48.763 PMdebugparse(): Fan Event - Fan Speed 01

dev:6452024-09-20 06:24:48.761 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0000, value:01, clusterInt:514, attrInt:0]

dev:6452024-09-20 06:24:48.744 PMdebugparse(): Fan Event - Fan Speed Percent Curent 21

dev:6452024-09-20 06:24:48.739 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0003, value:21, clusterInt:514, attrInt:3]

dev:6452024-09-20 06:24:48.734 PMdebugparse(): Fan Event - Fan Speed Percent 21

dev:6452024-09-20 06:24:48.731 PMinfoAiDot P200 Pro Air Purifier - Matter was set to speed low RawValue: 33

dev:6452024-09-20 06:24:48.729 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0002, value:21, clusterInt:514, attrInt:2]

dev:6452024-09-20 06:24:48.724 PMdebugparse(): Fan Event - Fan Speed 01

dev:6452024-09-20 06:24:48.721 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0000, value:01, clusterInt:514, attrInt:0]

dev:6452024-09-20 06:24:44.514 PMdebugparse(): Fan Event - Fan Speed Percent Curent 00

dev:6452024-09-20 06:24:44.511 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0003, value:00, clusterInt:514, attrInt:3]

dev:6452024-09-20 06:24:44.506 PMdebugparse(): Fan Event - Fan Speed Percent 00

dev:6452024-09-20 06:24:44.503 PMinfoAiDot P200 Pro Air Purifier - Matter was set to speed off RawValue: 0

dev:6452024-09-20 06:24:44.501 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0002, value:00, clusterInt:514, attrInt:2]

dev:6452024-09-20 06:24:44.383 PMdebugparse(): Fan Event - Fan Speed Percent Curent 00

dev:6452024-09-20 06:24:44.381 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0003, value:00, clusterInt:514, attrInt:3]

dev:6452024-09-20 06:24:44.375 PMdebugparse(): Fan Event - Fan Speed Percent 00

dev:6452024-09-20 06:24:44.373 PMinfoAiDot P200 Pro Air Purifier - Matter was set to speed off RawValue: 0

dev:6452024-09-20 06:24:44.370 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0002, value:00, clusterInt:514, attrInt:2]

dev:6452024-09-20 06:24:44.049 PMdebugparse(): Fan Event - Fan Speed Percent Curent 00

dev:6452024-09-20 06:24:44.047 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0003, value:00, clusterInt:514, attrInt:3]

dev:6452024-09-20 06:24:44.041 PMdebugparse(): Fan Event - Fan Speed Percent 00

dev:6452024-09-20 06:24:44.039 PMinfoAiDot P200 Pro Air Purifier - Matter was set to speed off RawValue: 0

dev:6452024-09-20 06:24:44.036 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0002, value:00, clusterInt:514, attrInt:2]

dev:6452024-09-20 06:24:44.031 PMdebugparse(): Fan Event - Fan Speed 00

dev:6452024-09-20 06:24:44.029 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0000, value:00, clusterInt:514, attrInt:0]

dev:6452024-09-20 06:24:44.000 PMdebugparse(): Fan Event - Fan Speed Percent Curent 00

dev:6452024-09-20 06:24:43.998 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0003, value:00, clusterInt:514, attrInt:3]

dev:6452024-09-20 06:24:43.992 PMdebugparse(): Fan Event - Fan Speed Percent 00

dev:6452024-09-20 06:24:43.990 PMinfoAiDot P200 Pro Air Purifier - Matter was set to speed off RawValue: 0

dev:6452024-09-20 06:24:43.987 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0002, value:00, clusterInt:514, attrInt:2]

dev:6452024-09-20 06:24:43.981 PMdebugparse(): Fan Event - Fan Speed 00

dev:6452024-09-20 06:24:43.979 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0000, value:00, clusterInt:514, attrInt:0]

dev:6452024-09-20 06:24:43.964 PMdebugparse(): Fan Event - Fan Speed 00

dev:6452024-09-20 06:24:43.962 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0000, value:00, clusterInt:514, attrInt:0]

dev:6452024-09-20 06:24:43.588 PMdebugparse(): Fan Event - Fan Speed 00

dev:6452024-09-20 06:24:43.585 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0000, value:00, clusterInt:514, attrInt:0]

dev:6452024-09-20 06:23:27.413 PMdebugparse(): Fan Event - Fan Speed Percent Curent 21

dev:6452024-09-20 06:23:27.410 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0003, value:21, clusterInt:514, attrInt:3]

dev:6452024-09-20 06:23:27.404 PMdebugparse(): Fan Event - Fan Speed Percent 21

dev:6452024-09-20 06:23:27.402 PMinfoAiDot P200 Pro Air Purifier - Matter was set to speed low RawValue: 33

dev:6452024-09-20 06:23:27.400 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0002, value:21, clusterInt:514, attrInt:2]

dev:6452024-09-20 06:23:27.395 PMdebugparse(): Fan Event - Fan Speed 01

dev:6452024-09-20 06:23:27.392 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0000, value:01, clusterInt:514, attrInt:0]

dev:6452024-09-20 06:23:27.378 PMdebugparse(): Fan Event - Fan Speed Percent Curent 21

dev:6452024-09-20 06:23:27.375 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0003, value:21, clusterInt:514, attrInt:3]

dev:6452024-09-20 06:23:27.370 PMdebugparse(): Fan Event - Fan Speed Percent 21

dev:6452024-09-20 06:23:27.367 PMinfoAiDot P200 Pro Air Purifier - Matter was set to speed low RawValue: 33

dev:6452024-09-20 06:23:27.365 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0002, value:21, clusterInt:514, attrInt:2]

dev:6452024-09-20 06:23:27.359 PMdebugparse(): Fan Event - Fan Speed 01

dev:6452024-09-20 06:23:27.357 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0000, value:01, clusterInt:514, attrInt:0]

dev:6452024-09-20 06:23:26.425 PMdebugparse(): Fan Event - Fan Speed Percent Curent 21

dev:6452024-09-20 06:23:26.422 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0003, value:21, clusterInt:514, attrInt:3]

dev:6452024-09-20 06:23:26.416 PMdebugparse(): Fan Event - Fan Speed Percent 21

dev:6452024-09-20 06:23:26.414 PMinfoAiDot P200 Pro Air Purifier - Matter was set to speed low RawValue: 33

dev:6452024-09-20 06:23:26.412 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0002, value:21, clusterInt:514, attrInt:2]

dev:6452024-09-20 06:23:26.407 PMdebugparse(): Fan Event - Fan Speed 01

dev:6452024-09-20 06:23:26.404 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0000, value:01, clusterInt:514, attrInt:0]

dev:6452024-09-20 06:23:26.389 PMdebugparse(): Fan Event - Fan Speed Percent Curent 21

dev:6452024-09-20 06:23:26.385 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0003, value:21, clusterInt:514, attrInt:3]

dev:6452024-09-20 06:23:26.379 PMdebugparse(): Fan Event - Fan Speed Percent 21

dev:6452024-09-20 06:23:26.377 PMinfoAiDot P200 Pro Air Purifier - Matter was set to speed low RawValue: 33

dev:6452024-09-20 06:23:26.374 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0002, value:21, clusterInt:514, attrInt:2]

dev:6452024-09-20 06:23:26.369 PMdebugparse(): Fan Event - Fan Speed 01

dev:6452024-09-20 06:23:26.366 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0000, value:01, clusterInt:514, attrInt:0]

dev:6452024-09-20 06:22:14.515 PMdebugparse(): Fan Event - Fan Speed Percent Curent 64

dev:6452024-09-20 06:22:14.513 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0003, value:64, clusterInt:514, attrInt:3]

dev:6452024-09-20 06:22:14.507 PMdebugparse(): Fan Event - Fan Speed Percent 64

dev:6452024-09-20 06:22:14.504 PMinfoAiDot P200 Pro Air Purifier - Matter was set to speed high RawValue: 100

dev:6452024-09-20 06:22:14.502 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0002, value:64, clusterInt:514, attrInt:2]

dev:6452024-09-20 06:22:14.435 PMdebugparse(): Fan Event - Fan Speed Percent Curent 64

dev:6452024-09-20 06:22:14.432 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0003, value:64, clusterInt:514, attrInt:3]

dev:6452024-09-20 06:22:14.427 PMdebugparse(): Fan Event - Fan Speed Percent 64

dev:6452024-09-20 06:22:14.424 PMinfoAiDot P200 Pro Air Purifier - Matter was set to speed high RawValue: 100

dev:6452024-09-20 06:22:14.422 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0002, value:64, clusterInt:514, attrInt:2]

dev:6452024-09-20 06:22:14.391 PMdebugparse(): Fan Event - Fan Speed Percent Curent 64

dev:6452024-09-20 06:22:14.389 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0003, value:64, clusterInt:514, attrInt:3]

dev:6452024-09-20 06:22:14.383 PMdebugparse(): Fan Event - Fan Speed Percent 64

dev:6452024-09-20 06:22:14.381 PMinfoAiDot P200 Pro Air Purifier - Matter was set to speed high RawValue: 100

dev:6452024-09-20 06:22:14.378 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0002, value:64, clusterInt:514, attrInt:2]

dev:6452024-09-20 06:22:14.373 PMdebugparse(): Fan Event - Fan Speed 03

dev:6452024-09-20 06:22:14.371 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0000, value:03, clusterInt:514, attrInt:0]

dev:6452024-09-20 06:22:14.356 PMdebugparse(): Fan Event - Fan Speed Percent Curent 64

dev:6452024-09-20 06:22:14.353 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0003, value:64, clusterInt:514, attrInt:3]

dev:6452024-09-20 06:22:14.347 PMdebugparse(): Fan Event - Fan Speed Percent 64

dev:6452024-09-20 06:22:14.345 PMinfoAiDot P200 Pro Air Purifier - Matter was set to speed high RawValue: 100

dev:6452024-09-20 06:22:14.342 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0002, value:64, clusterInt:514, attrInt:2]

dev:6452024-09-20 06:22:14.337 PMdebugparse(): Fan Event - Fan Speed 03

dev:6452024-09-20 06:22:14.335 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0000, value:03, clusterInt:514, attrInt:0]

dev:6452024-09-20 06:22:14.314 PMdebugparse(): Fan Event - Fan Speed 03

dev:6452024-09-20 06:22:14.312 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0000, value:03, clusterInt:514, attrInt:0]

dev:6452024-09-20 06:22:14.299 PMdebugparse(): Fan Event - Fan Speed 03

dev:6452024-09-20 06:22:14.296 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0000, value:03, clusterInt:514, attrInt:0]

dev:6452024-09-20 06:22:13.061 PMdebugparse(): Fan Event - Fan Speed Percent Curent 42

dev:6452024-09-20 06:22:13.059 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0003, value:42, clusterInt:514, attrInt:3]

dev:6452024-09-20 06:22:13.036 PMdebugparse(): Fan Event - Fan Speed Percent Curent 42

dev:6452024-09-20 06:22:13.034 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0003, value:42, clusterInt:514, attrInt:3]

dev:6452024-09-20 06:22:12.649 PMdebugparse(): Fan Event - Fan Speed Percent Curent 42

dev:6452024-09-20 06:22:12.647 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0003, value:42, clusterInt:514, attrInt:3]

dev:6452024-09-20 06:22:12.641 PMdebugparse(): Fan Event - Fan Speed Percent 42

dev:6452024-09-20 06:22:12.639 PMinfoAiDot P200 Pro Air Purifier - Matter was set to speed medium RawValue: 66

dev:6452024-09-20 06:22:12.636 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0002, value:42, clusterInt:514, attrInt:2]

dev:6452024-09-20 06:22:12.631 PMdebugparse(): Fan Event - Fan Speed 02

dev:6452024-09-20 06:22:12.629 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0000, value:02, clusterInt:514, attrInt:0]

dev:6452024-09-20 06:22:12.387 PMdebugparse(): Fan Event - Fan Speed Percent Curent 42

dev:6452024-09-20 06:22:12.385 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0003, value:42, clusterInt:514, attrInt:3]

dev:6452024-09-20 06:22:12.379 PMdebugparse(): Fan Event - Fan Speed Percent 42

dev:6452024-09-20 06:22:12.377 PMinfoAiDot P200 Pro Air Purifier - Matter was set to speed medium RawValue: 66

dev:6452024-09-20 06:22:12.374 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0002, value:42, clusterInt:514, attrInt:2]

dev:6452024-09-20 06:22:12.369 PMdebugparse(): Fan Event - Fan Speed 02

dev:6452024-09-20 06:22:12.367 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0000, value:02, clusterInt:514, attrInt:0]

dev:6452024-09-20 06:22:12.251 PMdebugparse(): Fan Event - Fan Speed Percent 42

dev:6452024-09-20 06:22:12.249 PMinfoAiDot P200 Pro Air Purifier - Matter was set to speed medium RawValue: 66

dev:6452024-09-20 06:22:12.246 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0002, value:42, clusterInt:514, attrInt:2]

dev:6452024-09-20 06:22:12.241 PMdebugparse(): Fan Event - Fan Speed 02

dev:6452024-09-20 06:22:12.239 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0000, value:02, clusterInt:514, attrInt:0]

dev:6452024-09-20 06:22:12.220 PMdebugparse(): Fan Event - Fan Speed Percent 42

dev:6452024-09-20 06:22:12.217 PMinfoAiDot P200 Pro Air Purifier - Matter was set to speed medium RawValue: 66

dev:6452024-09-20 06:22:12.214 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0002, value:42, clusterInt:514, attrInt:2]

dev:6452024-09-20 06:22:12.209 PMdebugparse(): Fan Event - Fan Speed 02

dev:6452024-09-20 06:22:12.206 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0000, value:02, clusterInt:514, attrInt:0]

dev:6452024-09-20 06:21:27.436 PMdebugparse(): Fan Event - Fan Speed Percent Curent 21

dev:6452024-09-20 06:21:27.433 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0003, value:21, clusterInt:514, attrInt:3]

dev:6452024-09-20 06:21:27.427 PMdebugparse(): Fan Event - Fan Speed Percent 21

dev:6452024-09-20 06:21:27.424 PMinfoAiDot P200 Pro Air Purifier - Matter was set to speed low RawValue: 33

dev:6452024-09-20 06:21:27.422 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0002, value:21, clusterInt:514, attrInt:2]

dev:6452024-09-20 06:21:27.416 PMdebugparse(): Fan Event - Fan Speed 01

dev:6452024-09-20 06:21:27.414 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0000, value:01, clusterInt:514, attrInt:0]

dev:6452024-09-20 06:21:27.398 PMdebugparse(): Fan Event - Fan Speed Percent Curent 21

dev:6452024-09-20 06:21:27.395 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0003, value:21, clusterInt:514, attrInt:3]

dev:6452024-09-20 06:21:27.389 PMdebugparse(): Fan Event - Fan Speed Percent 21

dev:6452024-09-20 06:21:27.386 PMinfoAiDot P200 Pro Air Purifier - Matter was set to speed low RawValue: 33

dev:6452024-09-20 06:21:27.384 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0002, value:21, clusterInt:514, attrInt:2]

dev:6452024-09-20 06:21:27.378 PMdebugparse(): Fan Event - Fan Speed 01

dev:6452024-09-20 06:21:27.376 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0000, value:01, clusterInt:514, attrInt:0]

dev:6452024-09-20 06:21:27.212 PMdebugparse(): Fan Event - Fan Speed Percent Curent 21

dev:6452024-09-20 06:21:27.210 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0003, value:21, clusterInt:514, attrInt:3]

dev:6452024-09-20 06:21:27.200 PMdebugparse(): Fan Event - Fan Speed Percent 21

dev:6452024-09-20 06:21:27.197 PMinfoAiDot P200 Pro Air Purifier - Matter was set to speed low RawValue: 33

dev:6452024-09-20 06:21:27.195 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0002, value:21, clusterInt:514, attrInt:2]

dev:6452024-09-20 06:21:27.190 PMdebugparse(): Fan Event - Fan Speed 01

dev:6452024-09-20 06:21:27.187 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0000, value:01, clusterInt:514, attrInt:0]

dev:6452024-09-20 06:21:27.172 PMdebugparse(): Fan Event - Fan Speed Percent Curent 21

dev:6452024-09-20 06:21:27.169 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0003, value:21, clusterInt:514, attrInt:3]

dev:6452024-09-20 06:21:27.164 PMdebugparse(): Fan Event - Fan Speed Percent 21

dev:6452024-09-20 06:21:27.162 PMinfoAiDot P200 Pro Air Purifier - Matter was set to speed low RawValue: 33

dev:6452024-09-20 06:21:27.159 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0002, value:21, clusterInt:514, attrInt:2]

dev:6452024-09-20 06:21:27.153 PMdebugparse(): Fan Event - Fan Speed 01

dev:6452024-09-20 06:21:27.151 PMdebugdescMap:[endpoint:01, cluster:0202, attrId:0000, value:01, clusterInt:514, attrInt:0]

I looked at HA and all they show for air quality is the a generic description. Mine is showing "good" right now.

You are correct. I forgot to mention filter status. It is the percentage of life left in the filter. So, 100% is a brand new filter and 0% is end of life.

You are right. You've made a great amount of progress with the driver. Very impressive. Hopefully, I've been decent at getting you the info you've needed.

Thanks again for all this

Here is a new driver. I was able to look back and found some info on the filter and the Air Quality values. Hopefully this will give you a final driver..

I removed two standard capabilities since they won't line up with what MATTER is putting out and created custom attributes for filterLife and airQuality.

I added a routine take the provided filter life value and simply populate the new attribute with it so you should start to see a value of 96% in there as i believe that is the % left you have based on the values.

I then created a route that will take the value provided for the Air quality monitor and translate the value to Unknown, Good, Fair, Moderate, Poor, Very Poor, or Extreamly Poor. Then it will post that to the new attribute Air Quality. That is based on the Matter documentation.

Lastly i have a routine that will capture the last time it got a update for the filter and it will just log it if enabled. I will probably need to convert the timestap which i haven't put time into completing yet.

Once you update the driver you may want to click on configure and wait a min or two to ensure the driver fully subscribes to the device attributes. Then click on refresh and i think it will populate the airquality and filterlife attributes.

Last thing to think about is what happens when you just press the "On" button. Right now that is going to medium speed. I am starting to think i need to create a configuration value that allows you to set what speed the on option goes to.

/*
	Air Purifier Driver

	Copyright 2023 Hubitat Inc.  All Rights Reserved

	2023-11-02 2.3.7 maxwell
		-initial pub

*/

import groovy.transform.Field

@Field static final String   DEVICE_TYPE = 'MATTER_PURIFIER'

@Field Map getFanLevel = [
    "off": 0
    ,"low": 33
	,"medium": 66
	,"high": 100   
]

import groovy.transform.Field
import hubitat.helper.HexUtils

metadata {
    definition (name: "Air Purifier Driver(Matter)", namespace: "Mavrrick", author: "Mavrrick") {
        capability "Actuator"
        capability "Switch"
        capability "Configuration"
        capability "FanControl"
        capability "Initialize"
        capability "Refresh"
//        capability "AirQuality"
//        capability "FilterStatus"
        attribute "filterLife", "integer"
        attribute "airQuality", "string"
        
        command "setSpeed", [[name: "Fan speed*",type:"ENUM", description:"Fan speed to set", constraints: getFanLevel.collect {k,v -> k}]]
        
        fingerprint endpointId:"01", inClusters:"0003,0202,0071,005B,001D", outClusters:"", model:"Air Purifier", manufacturer:"Leedarson", controllerType:"MAT"

    }
    preferences {
        input(name:"cycleInterval", type:"number", title:"Number of seconds between cycles", defaultValue:30)
        input(name:"logEnable", type:"bool", title:"Enable debug logging", defaultValue:false)
        input(name:"txtEnable", type:"bool", title:"Enable descriptionText logging", defaultValue:true)
    }
}

//parsers
void parse(String description) {
    Map descMap = matter.parseDescriptionAsMap(description)
    if (logEnable) log.debug "descMap:${descMap}"
    switch (descMap.cluster) {        
        case "0006" :
            if (descMap.attrId == "0000") { //switch
                sendSwitchEvent(descMap.value)
            }
            break
        case "0000" :
            if (descMap.attrId == "4000") { //software build
                updateDataValue("softwareBuild",descMap.value ?: "unknown")
            }
            break
        case "005B" :
//            sendEvent(name:"airQualityIndex ", value:value, descriptionText:descriptionText)
            if (logEnable) log.debug  "parse: Air Quality, attribute:${descMap.attrId}, value:${descMap.value}"
            sendAirQualityEvent(descMap.value)
            break
        case "0071" :
            if (descMap.attrId == "0000") { //Filter State
//                sendEvent(name:"filterStatus ", value:value, descriptionText:descriptionText) 
                if (logEnable) log.debug  "parse: ilter State, attribute:${descMap.attrId}, value:${descMap.value}"
                sendFilterEvent(descMap.value)
            } else if (descMap.attrId == "0004") { //Last Change time
                if (logEnable) log.debug  "parse: Filter last change time, attribute:${descMap.attrId}, value:${descMap.value}"
            }
            break
        case "0202" :
            if (descMap.attrId == "0000") { //fan speed
                if (logEnable) log.debug "parse(): Fan Event - Fan Speed ${descMap.value}"
            } else if (descMap.attrId == "0001") { //fan speed mode
                if (logEnable) log.debug "parse(): Fan Event - Fan speed mode ${descMap.value}"
            } else if (descMap.attrId == "0002") { //fan speed Percent Setting
                sendSpeedEvent(descMap.value) 
                if (logEnable) log.debug "parse(): Fan Event - Fan Speed  Percent ${descMap.value}"
            } else  if (descMap.attrId == "0003") { //fan speed Percent current
                if (logEnable) log.debug "parse(): Fan Event - Fan Speed Percent Curent ${descMap.value}"
            } else if (descMap.attrId == "0004") { //fan speed max (Don't expect to actually ever return in parse
                if (logEnable) log.debug "parse(): Fan Event - Fan Speed Max speed ${descMap.value}"
            } else if (descMap.attrId == "0005") { //fan speed setting
                if (logEnable) log.debug "parse(): Fan Event - Fan Speed setting ${descMap.value}"
            } else if (descMap.attrId == "0006") { //fan speed setting current
                if (logEnable) log.debug "parse(): Fan Event - Fan Speed current ${descMap.value}"
            } else if (descMap.attrId == "000A") { //WindSetting current
                if (logEnable) log.debug "parse(): Fan Event - Wind Speed setting ${descMap.value}"
            } else  if (descMap.attrId == "000B") { //Airflow Direction
                if (logEnable) log.debug "parse(): Fan Event - Airflow Direction setting ${descMap.value}"
            } else {
                if (logEnable) log.debug  "parse: skipped fan, attribute:${descMap.attrId}, value:${descMap.value}"
            }
//            gatherAttributesValuesInfo(descMap, FanClusterAttributes)
            break
        default :
            if (logEnable) {
                log.debug "skipped:${descMap}"
            }
    }
}

//events
private void sendSpeedEvent(String rawValue) {      
    Integer intValue = hexStrToUnsignedInt(rawValue)
    
    switch(intValue) {
        case 0 :
            value = "off";
        break;
        case 33:
            value = "low";
        break;
        case 66:
            value = "medium";
        break;
        case 100:
            value = "high";
        break; 
    }
    
    String descriptionText = "${device.displayName} was set to speed ${value} RawValue: ${intValue}"
    if (txtEnable) log.info descriptionText
    sendEvent(name:"speed", value:value, descriptionText:descriptionText)
 
}

private void sendFilterEvent(String rawValue) {      
    Integer intValue = hexStrToUnsignedInt(rawValue) 

    String descriptionText = "${device.displayName} Filter % Life left ${intValue} RawValue: ${rawValue}"    
    if (txtEnable) log.info descriptionText
   sendEvent(name:"filterLife", value:intValue, descriptionText:descriptionText)
}

private void sendAirQualityEvent(String rawValue) {      
    Integer intValue = hexStrToUnsignedInt(rawValue) 
    
    switch(intValue) {
        case 0 :
            value = "Unknown";
        break;
        case 1 :
            value = "Good";
        break;
        case 2:
            value = "Fair";
        break;
        case 3 :
            value = "Moderate";
        break;
        case 4 :
            value = "Poor";
        break;
        case 5 :
            value = "VeryPoor";
        break;
        case 6 :
            value = "ExtremelyPoor";
        break;
    }

    String descriptionText = "${device.displayName} Air Quality Value left ${value} RawValue: ${intValue}"    
    if (txtEnable) log.info descriptionText
   sendEvent(name:"airQuality", value:value, descriptionText:descriptionText)
}    

private void sendSwitchEvent(String rawValue) {
    String value = rawValue == "01" ? "on" : "off"
    if (device.currentValue("switch") == value) return
    String descriptionText = "${device.displayName} was turned ${value}"
    if (txtEnable) log.info descriptionText
    sendEvent(name:"switch", value:value, descriptionText:descriptionText)
}

//capability commands
void on() {
    unschedule()
    if (logEnable) log.debug "on()"
    sendToDevice(matter.on())
    fanspeed = "medium"
    setSpeed(fanspeed)    
   
}

void off() {
    unschedule()
    if (logEnable) log.debug "off()"
//    sendToDevice(matter.off())
    fanspeed = "off"
    setSpeed(fanspeed)
}

void setSpeed(fanspeed) {
    unschedule()
    if (logEnable) log.debug "Setting Fan Speed to ${fanspeed}"
    switch(fanspeed) {
        case "off":
            value = 0;
        break;
        case "low":
            value = 33;
        break;
        case "medium":
            value = 66;
        break;
        case "high":
            value = 100;
        break; 
    }
    if (value > 101) {
        if (logEnable) {log.debug ("setSpeed(): Unknown value}")};
        on()
    } else {
        speedValue = intToHexStr(value)  
        if (logEnable) log.debug "Setting Fan Speed percent ${fanspeed}  % ${value} value to ${speedValue}"
        List<Map<String, String>> attributeWriteRequests = []
        attributeWriteRequests.add(matter.attributeWriteRequest(device.endpointId, 0x0202, 0x0002, 0x04, speedValue ))
        String cmd = matter.writeAttributes(attributeWriteRequests)            
        sendToDevice(cmd)
    }
}

void cycleSpeed() {
    cycleChange()
}

void cycleChange() {
    Integer randomSpeed = Math.abs(new Random().nextInt() % 12) + 1
    String newSpeed = "speed "+randomSpeed
    setSpeed(newSpeed)
    runIn(cycleInterval, cycleChange)
    
}


void configure() {
    log.warn "configure..."
    sendToDevice(subscribeCmd())
    unschedule()
}

//lifecycle commands
void updated(){
    log.info "updated..."
    log.warn "debug logging is: ${logEnable == true}"
    log.warn "description logging is: ${txtEnable == true}"
    if (logEnable) runIn(1800,logsOff)
}

void initialize() {
    log.info "initialize..."
//    initializeVars(fullInit = true)
    sendToDevice(subscribeCmd())
}

void refresh() {
    if (logEnable) log.debug "refresh()"
    sendToDevice(refreshCmd())
}

String refreshCmd() {
    List<Map<String, String>> attributePaths = []
    
        attributePaths.add(matter.attributePath(device.endpointId, 0x0006, 0x0000))         // on/off
        attributePaths.add(matter.attributePath(device.endpointId, 0x0202, 0x0000))         // FanMode
        attributePaths.add(matter.attributePath(device.endpointId, 0x0202, 0x0002))         // PercentSetting
        attributePaths.add(matter.attributePath(device.endpointId, 0x0202, 0x0003))         // PercentCurrent
        attributePaths.add(matter.attributePath(device.endpointId, 0x0202, 0x000A))         // WindSetting
        attributePaths.add(matter.attributePath(device.endpointId, 0x0202, 0x000B))         // AirflowDirectionEnum
        attributePaths.add(matter.attributePath(device.endpointId, 0x0003, 0x0000))         
        attributePaths.add(matter.attributePath(device.endpointId, 0x0003, 0x0001))         // Power Configuration Cluster : Status
        attributePaths.add(matter.attributePath(device.endpointId, 0x005B, 0x0000)) 
        attributePaths.add(matter.attributePath(device.endpointId, 0x0071, 0x0000))
    
    String cmd = matter.readAttributes(attributePaths)
    return cmd
}

String subscribeCmd() {
    List<Map<String, String>> attributePaths = []
    String cmd = ''
    
        attributePaths.add(matter.attributePath(0x01, 0x0006, 0x00))
        attributePaths.add(matter.attributePath(0x01, 0x0202, 0x00))
        attributePaths.add(matter.attributePath(0x01, 0x0202, 0x02))
        attributePaths.add(matter.attributePath(0x01, 0x0202, 0x03))
        attributePaths.add(matter.attributePath(0x01, 0x0202, 0x0A))
        attributePaths.add(matter.attributePath(0x01, 0x0202, 0x0B))
        attributePaths.add(matter.attributePath(0x01, 0x005B, 0x00))
        attributePaths.add(matter.attributePath(0x01, 0x0071, 0x00))
        attributePaths.add(matter.attributePath(0x01, 0x0071, 0x04))
        cmd = matter.subscribe(0, 0xFFFF, attributePaths)

    return cmd
}

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

Integer hex254ToInt100(String value) {
    return Math.round(hexStrToUnsignedInt(value) / 2.54)
}

String int100ToHex254(value) {
    return intToHexStr(Math.round(value * 2.54))
}


void sendToDevice(List<String> cmds, Integer delay = 300) {
    sendHubCommand(new hubitat.device.HubMultiAction(commands(cmds, delay), hubitat.device.Protocol.MATTER))
}

void sendToDevice(String cmd, Integer delay = 300) {
    sendHubCommand(new hubitat.device.HubAction(cmd, hubitat.device.Protocol.MATTER))
}

List<String> commands(List<String> cmds, Integer delay = 300) {
    return delayBetween(cmds.collect { it }, delay)
}