al-one / hass-xiaomi-miot

Automatic integrate all Xiaomi devices to HomeAssistant via miot-spec, support Wi-Fi, BLE, ZigBee devices. 小米米家智能家居设备接入Hass集成
https://miot-spec.com
Apache License 2.0
4.45k stars 625 forks source link

Xiaomi Air Purifier 4 Compact (xiaomi.airp.cpa4) - No fan speed control #1674

Open VolunPotest opened 4 months ago

VolunPotest commented 4 months ago

Device model / 设备型号

xiaomi.airp.cpa4

Component version / 插件版本

0.7.18

HA core version / HA版本

2024.3.3

Integrated mode / 集成方式

Automatic (自动模式)

The problem / 问题详情

Hi!

I can't control the fan speed on the device. Is it possible to add support for that?

Entity attributes / 实体属性

N?A

Home Assistant Logs / 系统日志

No response

Samay97 commented 4 months ago

Same for me too. Would be nice to have this feature. Support for changing modes would also be very nice.

bugale commented 3 months ago

It is possible to set the fan speed manually using a service call, e.g.:

service: xiaomi_miot.set_miot_property
data:
  entity_id: fan.xiaomi_cpa4_7865_air_purifier
  siid: 9
  piid: 11
  value: 4

This sets the manual level to 4.

To find the properties, you can install latest python-miio on some computer: pip install git+https://github.com/rytilahti/python-miio.git Then find your device IP and token (e.g. using miiocli cloud), and running:

> miiocli genericmiot --ip <ip> --token <token> settings
Running command settings
Switch Status (air-purifier:on)
        Type: <class 'bool'>
        Attribute: air_purifier_on
        Access: rw-
        Extras: {'urn': <URN urn:miot-spec-v2:property:on:00000006:xiaomi-cpa4:1 parent:namespace='miot-spec-v2' type='service' name='air-purifier' internal_id='00007811' model='xiaomi-cpa4' version=1 unexpected=None>, 'siid': 2, 'piid': 1, 'miot_property': MiotProperty(urn=<URN urn:miot-spec-v2:property:on:00000006:xiaomi-cpa4:1 parent:namespace='miot-spec-v2' type='service' name='air-purifier' internal_id='00007811' model='xiaomi-cpa4' version=1 unexpected=None>, description='Switch Status', service=MiotService(siid=2, urn=<URN urn:miot-spec-v2:service:air-purifier:00007811:xiaomi-cpa4:1 parent:None>, description='Air Purifier'), piid=1, format=<class 'bool'>, access=[<MiotAccess.Read: 'read'>, <MiotAccess.Write: 'write'>, <MiotAccess.Notify: 'notify'>], unit=None, range=None, choices=None, gatt_access=None, value=None)}
        Setter: functools.partial(<bound method MiotDevice.set_property_by of <GenericMiot: 192.168.1.116 (token: f6e2cba59591dc9d5b7aed1f7fad417d)>>, 2, 1, name='air-purifier:on')
        Constraint: PropertyConstraint.Unset

Mode (air-purifier:mode)
        Type: <class 'int'>
        Attribute: air_purifier_mode
        Access: rw-
        Extras: {'urn': <URN urn:miot-spec-v2:property:mode:00000008:xiaomi-cpa4:1 parent:namespace='miot-spec-v2' type='service' name='air-purifier' internal_id='00007811' model='xiaomi-cpa4' version=1 unexpected=None>, 'siid': 2, 'piid': 4, 'miot_property': MiotProperty(urn=<URN urn:miot-spec-v2:property:mode:00000008:xiaomi-cpa4:1 parent:namespace='miot-spec-v2' type='service' name='air-purifier' internal_id='00007811' model='xiaomi-cpa4' version=1 unexpected=None>, description='Mode', service=MiotService(siid=2, urn=<URN urn:miot-spec-v2:service:air-purifier:00007811:xiaomi-cpa4:1 parent:None>, description='Air Purifier'), piid=4, format=<class 'int'>, access=[<MiotAccess.Read: 'read'>, <MiotAccess.Write: 'write'>, <MiotAccess.Notify: 'notify'>], unit=None, range=None, choices=[MiotEnumValue(description='Auto', value=0), MiotEnumValue(description='Sleep', value=1), MiotEnumValue(description='Favorite', value=2)], gatt_access=[], value=None)}
        Setter: functools.partial(<bound method MiotDevice.set_property_by of <GenericMiot: 192.168.1.116 (token: f6e2cba59591dc9d5b7aed1f7fad417d)>>, 2, 4, name='air-purifier:mode')
        Constraint: PropertyConstraint.Choice
        Choices: <enum 'Mode'>

Alarm (alarm:alarm)
        Type: <class 'bool'>
        Attribute: alarm_alarm
        Access: rw-
        Extras: {'urn': <URN urn:miot-spec-v2:property:alarm:00000012:xiaomi-cpa4:1 parent:namespace='miot-spec-v2' type='service' name='alarm' internal_id='00007804' model='xiaomi-cpa4' version=1 unexpected=None>, 'siid': 6, 'piid': 1, 'miot_property': MiotProperty(urn=<URN urn:miot-spec-v2:property:alarm:00000012:xiaomi-cpa4:1 parent:namespace='miot-spec-v2' type='service' name='alarm' internal_id='00007804' model='xiaomi-cpa4' version=1 unexpected=None>, description='Alarm', service=MiotService(siid=6, urn=<URN urn:miot-spec-v2:service:alarm:00007804:xiaomi-cpa4:1 parent:None>, description='Alarm'), piid=1, format=<class 'bool'>, access=[<MiotAccess.Read: 'read'>, <MiotAccess.Write: 'write'>, <MiotAccess.Notify: 'notify'>], unit=None, range=None, choices=None, gatt_access=None, value=None)}
        Setter: functools.partial(<bound method MiotDevice.set_property_by of <GenericMiot: 192.168.1.116 (token: f6e2cba59591dc9d5b7aed1f7fad417d)>>, 6, 1, name='alarm:alarm')
        Constraint: PropertyConstraint.Unset

Physical Control Locked (physical-controls-locked:physical-controls-locked)
        Type: <class 'bool'>
        Attribute: physical_controls_locked_physical_controls_locked
        Access: rw-
        Extras: {'urn': <URN urn:miot-spec-v2:property:physical-controls-locked:0000001D:xiaomi-cpa4:1 parent:namespace='miot-spec-v2' type='service' name='physical-controls-locked' internal_id='00007807' model='xiaomi-cpa4' version=1 unexpected=None>, 'siid': 8, 'piid': 1, 'miot_property': MiotProperty(urn=<URN urn:miot-spec-v2:property:physical-controls-locked:0000001D:xiaomi-cpa4:1 parent:namespace='miot-spec-v2' type='service' name='physical-controls-locked' internal_id='00007807' model='xiaomi-cpa4' version=1 unexpected=None>, description='Physical Control Locked', service=MiotService(siid=8, urn=<URN urn:miot-spec-v2:service:physical-controls-locked:00007807:xiaomi-cpa4:1 parent:None>, description='Physical Control Locked'), piid=1, format=<class 'bool'>, access=[<MiotAccess.Read: 'read'>, <MiotAccess.Write: 'write'>, <MiotAccess.Notify: 'notify'>], unit=None, range=None, choices=None, gatt_access=None, value=None)}
        Setter: functools.partial(<bound method MiotDevice.set_property_by of <GenericMiot: 192.168.1.116 (token: f6e2cba59591dc9d5b7aed1f7fad417d)>>, 8, 1, name='physical-controls-locked:physical-controls-locked')
        Constraint: PropertyConstraint.Unset

Brightness (screen:brightness)
        Type: <class 'int'>
        Unit: percentage
        Attribute: screen_brightness
        Access: rw-
        Extras: {'urn': <URN urn:miot-spec-v2:property:brightness:0000000D:xiaomi-cpa4:1 parent:namespace='miot-spec-v2' type='service' name='screen' internal_id='00007806' model='xiaomi-cpa4' version=1 unexpected=None>, 'siid': 13, 'piid': 2, 'miot_property': MiotProperty(urn=<URN urn:miot-spec-v2:property:brightness:0000000D:xiaomi-cpa4:1 parent:namespace='miot-spec-v2' type='service' name='screen' internal_id='00007806' model='xiaomi-cpa4' version=1 unexpected=None>, description='Brightness', service=MiotService(siid=13, urn=<URN urn:miot-spec-v2:service:screen:00007806:xiaomi-cpa4:1 parent:None>, description='Screen'), piid=2, format=<class 'int'>, access=[<MiotAccess.Read: 'read'>, <MiotAccess.Write: 'write'>, <MiotAccess.Notify: 'notify'>], unit='percentage', range=None, choices=[MiotEnumValue(description='Close', value=0), MiotEnumValue(description='Bright', value=1), MiotEnumValue(description='Brightness', value=2)], gatt_access=[], value=None)}
        Setter: functools.partial(<bound method MiotDevice.set_property_by of <GenericMiot: 192.168.1.116 (token: f6e2cba59591dc9d5b7aed1f7fad417d)>>, 13, 2, name='screen:brightness')
        Constraint: PropertyConstraint.Choice
        Choices: <enum 'Brightness'>

country-code (custom-service:country-code)
        Type: <class 'int'>
        Attribute: custom_service_country_code
        Access: rw-
        Extras: {'urn': <URN urn:xiaomi-spec:property:country-code:0000000a:xiaomi-cpa4:1 parent:namespace='xiaomi-spec' type='service' name='custom-service' internal_id='00007801' model='xiaomi-cpa4' version=1 unexpected=None>, 'siid': 9, 'piid': 10, 'miot_property': MiotProperty(urn=<URN urn:xiaomi-spec:property:country-code:0000000a:xiaomi-cpa4:1 parent:namespace='xiaomi-spec' type='service' name='custom-service' internal_id='00007801' model='xiaomi-cpa4' version=1 unexpected=None>, description='country-code', service=MiotService(siid=9, urn=<URN urn:xiaomi-spec:service:custom-service:00007801:xiaomi-cpa4:1 parent:None>, description='custom-service'), piid=10, format=<class 'int'>, access=[<MiotAccess.Read: 'read'>, <MiotAccess.Notify: 'notify'>, <MiotAccess.Write: 'write'>], unit=None, range=None, choices=[MiotEnumValue(description='CN', value=17230), MiotEnumValue(description='EU', value=17749), MiotEnumValue(description='TH', value=21576)], gatt_access=[], value=None)}
        Setter: functools.partial(<bound method MiotDevice.set_property_by of <GenericMiot: 192.168.1.116 (token: f6e2cba59591dc9d5b7aed1f7fad417d)>>, 9, 10, name='custom-service:country-code')
        Constraint: PropertyConstraint.Choice
        Choices: <enum 'country-code'>

 (custom-service:favorite-level)
        Type: <class 'int'>
        Attribute: custom_service_favorite_level
        Access: rw-
        Extras: {'urn': <URN urn:xiaomi-spec:property:favorite-level:00000002:xiaomi-cpa4:1 parent:namespace='xiaomi-spec' type='service' name='custom-service' internal_id='00007801' model='xiaomi-cpa4' version=1 unexpected=None>, 'siid': 9, 'piid': 11, 'miot_property': MiotProperty(urn=<URN urn:xiaomi-spec:property:favorite-level:00000002:xiaomi-cpa4:1 parent:namespace='xiaomi-spec' type='service' name='custom-service' internal_id='00007801' model='xiaomi-cpa4' version=1 unexpected=None>, description='', service=MiotService(siid=9, urn=<URN urn:xiaomi-spec:service:custom-service:00007801:xiaomi-cpa4:1 parent:None>, description='custom-service'), piid=11, format=<class 'int'>, access=[<MiotAccess.Read: 'read'>, <MiotAccess.Notify: 'notify'>, <MiotAccess.Write: 'write'>], unit=None, range=[0, 14, 1], choices=None, gatt_access=None, value=None)}
        Setter: functools.partial(<bound method MiotDevice.set_property_by of <GenericMiot: 192.168.1.116 (token: f6e2cba59591dc9d5b7aed1f7fad417d)>>, 9, 11, name='custom-service:favorite-level')
        Constraint: PropertyConstraint.Range
        Range: 0 - 14 (step 1)

 (custom-service:filter-used-time-dbg)
        Type: <class 'int'>
        Unit: hours
        Attribute: custom_service_filter_used_time_dbg
        Access: -w-
        Extras: {'urn': <URN urn:xiaomi-spec:property:filter-used-time-dbg:00000003:xiaomi-cpa4:1 parent:namespace='xiaomi-spec' type='service' name='custom-service' internal_id='00007801' model='xiaomi-cpa4' version=1 unexpected=None>, 'siid': 9, 'piid': 12, 'miot_property': MiotProperty(urn=<URN urn:xiaomi-spec:property:filter-used-time-dbg:00000003:xiaomi-cpa4:1 parent:namespace='xiaomi-spec' type='service' name='custom-service' internal_id='00007801' model='xiaomi-cpa4' version=1 unexpected=None>, description='', service=MiotService(siid=9, urn=<URN urn:xiaomi-spec:service:custom-service:00007801:xiaomi-cpa4:1 parent:None>, description='custom-service'), piid=12, format=<class 'int'>, access=[<MiotAccess.Write: 'write'>], unit='hours', range=[0, 7000, 1], choices=None, gatt_access=None, value=None)}
        Setter: functools.partial(<bound method MiotDevice.set_property_by of <GenericMiot: 192.168.1.116 (token: f6e2cba59591dc9d5b7aed1f7fad417d)>>, 9, 12, name='custom-service:filter-used-time-dbg')
        Constraint: PropertyConstraint.Range
        Range: 0 - 7000 (step 1)

 (aqi:aqi-updata-heartbeat)
        Type: <class 'int'>
        Attribute: aqi_aqi_updata_heartbeat
        Access: rw-
        Extras: {'urn': <URN urn:xiaomi-spec:property:aqi-updata-heartbeat:00000004:xiaomi-cpa4:1 parent:namespace='xiaomi-spec' type='service' name='aqi' internal_id='00007803' model='xiaomi-cpa4' version=1 unexpected=None>, 'siid': 11, 'piid': 4, 'miot_property': MiotProperty(urn=<URN urn:xiaomi-spec:property:aqi-updata-heartbeat:00000004:xiaomi-cpa4:1 parent:namespace='xiaomi-spec' type='service' name='aqi' internal_id='00007803' model='xiaomi-cpa4' version=1 unexpected=None>, description='', service=MiotService(siid=11, urn=<URN urn:xiaomi-spec:service:aqi:00007803:xiaomi-cpa4:1 parent:None>, description='aqi'), piid=4, format=<class 'int'>, access=[<MiotAccess.Read: 'read'>, <MiotAccess.Notify: 'notify'>, <MiotAccess.Write: 'write'>], unit=None, range=[0, 65535, 1], choices=None, gatt_access=None, value=None)}
        Setter: functools.partial(<bound method MiotDevice.set_property_by of <GenericMiot: 192.168.1.116 (token: f6e2cba59591dc9d5b7aed1f7fad417d)>>, 11, 4, name='aqi:aqi-updata-heartbeat')
        Constraint: PropertyConstraint.Range
        Range: 0 - 65535 (step 1)
VolunPotest commented 3 months ago

I have an update on this!

Yes, @bugale, I was able to set the priority. Thank you! I also added a custom button to control the speed.

Here how I did this. DON't forget to change your entity_id!

  1. Add a custom script to HA

    alias: Set Fan Speed
    sequence:
    - service: xiaomi_miot.set_miot_property
    data:
      entity_id: fan.xiaomi_cpa4_7xxx_air_purifier
      siid: 9
      piid: 11
      value: >
            {% set percentage = states('input_number.fan_speed_percentage') | int(0) %}
            {% set speed = (percentage * 14 / 100) | round(0) %}
            {{ speed }}
    mode: single
    description: ""
    icon: mdi:fan
  2. Add A input_number to configuration.yaml file

input_number:
  fan_speed_percentage:
    name: Fan Speed Percentage
    min: 0
    max: 100
    step: 1
    unit_of_measurement: "%"
  1. Create a new automation!
    
    alias: Adjust Fan Speed
    trigger:
    - platform: state
    entity_id: input_number.fan_speed_percentage
    action:
    - service: script.set_fan_speed

4. Create a custom card

type: entities entities:

After that you should see something like this image