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.38k stars 614 forks source link

miio_cloud_records for mmgg.feeder.petfeeder #352

Open Wh1terat opened 2 years ago

Wh1terat commented 2 years ago

Looking for some clarity over miio_cloud_records.

I've got a device that pulls data from https://api.io.mi.com/app/user/get_user_device_data (My beloved petfeeder 😆 )

Request:

{
    "accessKey": "xxx",
    "did": "xxx",
    "group": "raw",
    "key": "feedStats",
    "limit": 1000,
    "time_end": 1643673599,
    "time_start": 1640995200,
    "type": "event",
    "uid": "xxx"
}

Response:

{
    "code": 0,
    "message": "ok",
    "result": [
        {
            "did": "xxx",
            "key": "feedStats",
            "time": 1641198610,
            "type": "event",
            "uid": "xxx",
            "value": "[8,4]"
        },
        {
            "did": "xxx",
            "key": "feedStats",
            "time": 1641112211,
            "type": "event",
            "uid": "xxx",
            "value": "[8,4]"
        },
        {
            "did": "xxx",
            "key": "feedStats",
            "time": 1641025812,
            "type": "event",
            "uid": "xxx",
            "value": "[8,4]"
        }
    ]
}

So the plugin sends start+end time of day, week, month then iterates the response and adds up the first entry in "value".

var value = JSON.parse(item.value)[0];

(Wonder what the 2nd was meant for...meh)

How best to implement this within the current component? (easy of course in Python, but I don't think we want to have a load of per device hacks)

Wh1terat commented 2 years ago

Here's the plugin - it'll be easier for you to see than me posting snippets.

signed_10055_1000144_136_ANDROID_bundle_85c04f48e853b096ac0f10ced3ae9bae.zip

or

signed_10062_1000144_143_IOS_bundle_27f0377f59be7947a0599a6b5479b2fd.zip

al-one commented 2 years ago

This react plugin of mmgg.feeder.petfeeder doesn't use the second value, and I don't know what it means.

How best to implement this within the current component?

# customize.yaml
sensor.mmgg_petfeeder_entity_id:
  miio_cloud_records: event.feedStats:500
  miio_event_feedStats_template: |
    {%- set dat = namespace(today=0,month=0) %}
    {%- set tim = now() %}
    {%- set hour = tim - timedelta(minutes=tim.minute,seconds=tim.second) %}
    {%- set today = (hour - timedelta(hours=tim.hour)) | as_timestamp | int(0) %}
    {%- set mouth = (today - timedelta(days=tim.day-1)) | as_timestamp | int(0) %}
    {%- for d in (result or []) %}
    {%-   set t = d.time | default(0) | int(0) %}
    {%-   if t >= mouth %}"
    {%-     set v = (d.value | default('[]') | string | from_json) or [] %}
    {%-     set n = v[0] | default(0) %}
    {%-     if t >= today %}
    {%-       set dat.today = dat.today + n %}
    {%-     endif %}
    {%-     set dat.month = dat.month + n %}
    {%-   endif %}
    {%- endfor %}
    {{ {
      'feed_today': dat.today | round(3),
      'feed_month': dat.month | round(3),
    } }}
Wh1terat commented 2 years ago

Excellent stuff 🐱 Thank you 👏

Modified a little:

miio_event_feedStats_template: |
  {%- set dat = namespace(today=0,week=0,month=0) %}
  {%- set tim = now() %}
  {%- set hour = tim.replace(minute=0, second=0) %}
  {%- set today = hour.replace(hour=0) %}
  {%- set week = (today - timedelta(days=7)) | as_timestamp | int(0) %}
  {%- set month = (today - timedelta(days=tim.day-1)) | as_timestamp | int(0) %}
  {%- set today = today | as_timestamp | int(0) %}
  {%- for d in (result or []) %}
  {%-   set t = d.time | default(0) | int(0) %}
  {%-   if t >= month %}"
  {%-     set v = (d.value | default('[]') | string | from_json) or [] %}
  {%-     set n = v[0] | default(0) %}
  {%-     if t >= week %}
  {%-       set dat.week = dat.week + n %}
  {%-       if t >= today %}
  {%-         set dat.today = dat.today + n %}
  {%-       endif %}
  {%-     endif %}
  {%-     set dat.month = dat.month + n %}
  {%-   endif %}
  {%- endfor %}
  {{ {
    'feed_today': dat.today | int(0),
    'feed_week': dat.week | int(0),
    'feed_month': dat.month | int(0),
  } }}
event.feedStats: |-
  """""
  {'feed_today': 7, 'feed_week': 31, 'feed_month': 31}

Couple more Qs if you don't mind 😄 (The more I understand, the less I will need to bug you in future!)

Is there a way to disable miot on mixed miot/miio devices like this? It does not respond to miot at all: feeding.measure.error: '-704030013 Property is not readable' and this is also the state_property for the device so always shows "unknown" 😢 (I've tried exclude_miot_services)

Is there a way to break out miio properties as their own entities without manual templating? (like is possible with miot devices - binary_sensor_properties, etc)

Is there a method for setting user data? (for example to have a script which dispenses foods and then updates feedStats)

Slightly off topic, but for another device (pet fountain):

binary_sensor.mmgg_s1_5f470_no_water_flag:
  device_class: problem
  reverse_state: true # Doesn't work?

It's a weird property, 1= has water, 0 = no water hence wanting to reverse it. reverse_state doesn't seem to do anything.

al-one commented 2 years ago

Is there a way to disable miot on mixed miot/miio devices like this?

exclude_miot_services cannot be used to exclude primary service. Maybe you can try this way:

# configuration.yaml
xiaomi_miot:
  exclude_state_attributes:
    - feeding.measure.error

Is there a way to break out miio properties as their own entities without manual templating? (like is possible with miot devices - binary_sensor_properties, etc)

# customize.yaml
sensor.mmgg_petfeeder_entity_id:
  sensor_attributes: feed_today,miio.prop1,miio.prop2
  binary_sensor_attributes: miio.prop3,miio.prop4
  miio_event_feedStats_template: |
    # ...
    {{ {
      'feed_today': dat.today | int(0),
      'feed_week': dat.week | int(0),
      'feed_month': dat.month | int(0),
      '_entity_attrs': true,
    } }}

Extent to entity attributes via _entity_attrs: true


reverse_state doesn't seem to do anything.

This is my mistake. It can only act on parent entities at present. I think I should support it on sub entities.

Wh1terat commented 2 years ago

exclude_state_attributes stops it polling at least 👍

Great, thanks for info on _attributes - works well!

Not having any luck with entity_attrs though 😢 (I can't see any difference with/without) Looking at zimi_powerstrip_v2_power_cost I've tried:

sensor.mmgg_petfeeder_bf89_pet_feeder:
  sensor_attributes: event.feedStats:fed_today,event.feedStats:fed_week,event.feedStats:fed_month
  miio_cloud_records: event.feedStats:500
  miio_event_feedStats_template: |
    # ...
    {{ {
      'fed_today': dat.today | int(0),
      'fed_week': dat.week | int(0),
      'fed_month': dat.month | int(0)
    } }}

But the dict isn't broken out (i.e fed_x as attr of the root entity) and nor is it transposed to a yaml dict:

event.feedStats: |-
  """""
  {'fed_today': 7, 'fed_week': 31, 'fed_month': 31}

(renamed to fed_ as feed_today conflicted since it's valid miio prop but doesn't actually return anything...) Instead it seems to be treated as a string, resulting in:

Screenshot 2022-01-04 at 13 16 54

and thanks for confirming I'm not crazy about reverse_state 😆

Wh1terat commented 2 years ago

It's an issue parsing miio_event_feedStats_template through customize. Adding directly to device_customizes.py and templates.py works fine:

    'mmgg.feeder.petfeeder': {
        'sensor_attributes': 'clean_days,dryer_days,event.feedStats:fed_today,event.feedStats:fed_week,'
                             'event.feedStats:fed_month',
        'binary_sensor_attributes': 'feed_plan,wifi_led,key_lock,outlet_status,door_result',
        'miio_cloud_records': 'event.feedStats:500',
        'miio_event_feedStats_template': 'mmgg_feeder_petfeeder_feedstats',
        'miio_commands': {
            'getprops': [
                'food_status', 'feed_plan', 'door_result', 'feed_today', 'clean_days', 'outlet_status',
                'dryer_days', 'weight_level', 'wifi_led', 'key_lock', 'country_code',
            ],
        },
        'miot_local_mapping': {
            'feeding.measure': {'siid': 2, 'piid': 1},
        },
    },
    'mmgg_feeder_petfeeder_feedstats': "{%- set dat = namespace(today=0,week=0,month=0) %}"
                                        "{%- set tim = now() %}"
                                        "{%- set hour = tim.replace(minute=0, second=0) %}"
                                        "{%- set today = hour.replace(hour=0) %}"
                                        "{%- set week = (today - timedelta(days=7)) | as_timestamp | int(0) %}"
                                        "{%- set month = (today - timedelta(days=tim.day-1)) | as_timestamp | int(0) %}"
                                        "{%- set today = today | as_timestamp | int(0) %}"
                                        "{%- for d in (result or []) %}"
                                        "{%-   set t = d.time | default(0) | int(0) %}"
                                        "{%-   if t >= month %}"
                                        "{%-     set v = (d.value | default('[]') | string | from_json) or [] %}"
                                        "{%-     set n = v[0] | default(0) %}"
                                        "{%-     if t >= week %}"
                                        "{%-       set dat.week = dat.week + n %}"
                                        "{%-       if t >= today %}"
                                        "{%-         set dat.today = dat.today + n %}"
                                        "{%-       endif %}"
                                        "{%-     endif %}"
                                        "{%-     set dat.month = dat.month + n %}"
                                        "{%-   endif %}"
                                        "{%- endfor %}"
                                        "{{ {"
                                        "'fed_today': dat.today | int(0),"
                                        "'fed_week': dat.week | int(0),"
                                        "'fed_month': dat.month | int(0),"
                                        "} }}",
event.feedStats:
  fed_today: 7
  fed_week: 31
  fed_month: 31

and with entity_attrs

fed_today: 7
fed_week: 31
fed_month: 31

Although with entity_attrs it does not then populate the sub entities for some reason

1trackprojects1 commented 2 years ago

Hi, @Wh1terat really sorry to bother you on this issue thread, but i would really like to get in touch with you do you mind providing me with possibly a Discord or Telegram username or an email where i can message you?

Wh1terat commented 2 years ago

@1trackprojects1 I wish I had never published that incapsula gist... As I've said to others of your ilk, No. I will not help you with you spam bots.

image

al-one commented 2 years ago

exclude_state_attributes does not stop polling, just does not display the property.

al-one commented 2 years ago

reverse_state for sub binary_sesnor has added support in https://github.com/al-one/hass-xiaomi-miot/commit/844f85afb81b6362aa0ccc6706fad3a96d8cff7c

licheng5625 commented 2 years ago

Hi guys, you are awsome!! You guys have aleardy figured out the requests ..... (I wasted my time just repeating you have done....)

Current the state of sensor.mmgg_petfeeder_XX_pet_feeder is 'unkonw'.

I am thinking the state could be the food vaule of today with total_increasing attribute. The update interval could be half hour. It keep the same behavir as the app (showing how many food fed for today)

@al-one @Wh1terat How do you think ?

Wh1terat commented 2 years ago

Thanks @al-one

It's a good point with regard to the root sensor, @al-one is there anyway to override which attribute is used for state? This goes back to my comment on is there a way to disable miot for a mixed miio/miot device (since the spec is almost 100% broken for this device).

total_increasing doesn't make sense for a daily stats:

total_increasing, a monotonically increasing total, e.g. an amount of consumed gas, water or energy. When supported, the accumulated growth of the sensor's value since it was first added is updated hourly.

This is how I've got the feeder displayed currently:

Screenshot 2022-01-06 at 15 25 21

config:

input_number:
  mmgg_petfeeder_bf89_feed_amount:
    name: "Pet Feeder Amount"
    min: 1
    max: 30
    step: 1
    unit_of_measurement: portion(s)
    mode: slider

template:
  sensor:
    - name: mmgg_petfeeder_bf89_food_level_1
      unique_id: "mmgg_petfeeder_bf89_food_level_1"
      icon: mdi:bowl
      state: |
        {% set sta = states('sensor.mmgg_petfeeder_bf89_food_status') | default | int(-1) -%}
        {% set lst = ['normal','low','empty'] -%}
        {{ lst[sta] | default('unknown') }}

switch:
  - platform: template
    switches:
      mmgg_petfeeder_bf89_wifi_led_1:
        friendly_name: "Pet Feeder Wifi Status led"
        unique_id: "mmgg_petfeeder_bf89_wifi_led_1"
        value_template: "{{ is_state('binary_sensor.mmgg_petfeeder_bf89_wifi_led', 'on') }}"
        icon_template: >
          {% if is_state('binary_sensor.mmgg_petfeeder_bf89_wifi_led', 'on')  %}
            mdi:led-on
          {% else %}
            mdi:led-off
          {% endif %}
        turn_on:
          service: script.mmgg_feeder_set_wifi_led
          data:
            entity_id: sensor.mmgg_petfeeder_bf89_pet_feeder
            state: true
        turn_off:
          service: script.mmgg_feeder_set_wifi_led
          data:
            entity_id: sensor.mmgg_petfeeder_bf89_pet_feeder
            state: false
      mmgg_petfeeder_bf89_feed_plan_1:
        friendly_name: "Pet Feeder Automatic Feeding"
        unique_id: "mmgg_petfeeder_bf89_feed_plan_1"
        icon_template: mdi:refresh-auto
        value_template: "{{ is_state('binary_sensor.mmgg_petfeeder_bf89_feed_plan','on') }}"
        turn_on:
          service: script.mmgg_feeder_set_auto_feed
          data:
            entity_id: sensor.mmgg_petfeeder_bf89_pet_feeder
            state: true
        turn_off:
          service: script.mmgg_feeder_set_auto_feed
          data:
            entity_id: sensor.mmgg_petfeeder_bf89_pet_feeder
            state: false
lock:
  - platform: template
    name: mmgg_petfeeder_bf89_key_lock_1
    unique_id: "mmgg_petfeeder_bf89_key_lock_1"
    value_template: "{{ is_state('binary_sensor.mmgg_petfeeder_bf89_key_lock', 'off') }}"
    lock:
      service: script.mmgg_feeder_set_key_lock
      data:
        entity_id: sensor.mmgg_petfeeder_bf89_pet_feeder
        state: true
    unlock:
      service: script.mmgg_feeder_set_key_lock
      data:
        entity_id: sensor.mmgg_petfeeder_bf89_pet_feeder
        state: false

scripts:

mmgg_feeder_dispense:
  mode: queued
  alias: '[PetFeeder] - Dispense Food'
  description: Dispenses food from the feeder
  icon: mdi:bowl-mix
  fields:
    entity_id:
      description: ID of the PetFeeder
      required: true
      example: sensor.mmgg_petfeeder_bf89_pet_feeder
      selector:
        entity:
          integration: xiaomi_miot
          domain: sensor
    units:
      name: units
      description: Number of units to dispense
      required: false
      default: 1
      example: '1'
      selector:
        number:
          min: 1
          max: 30
          step: 1
          unit_of_measurement: units(s)
          mode: slider
    units_id:
      name: units_id
      description: ID for input_number holding portion value
      example: input_number.mmgg_petfeeder_bf89_feed_amount
      required: false
      selector:
        entity:
          domain: input_number
  sequence:
  - service: xiaomi_miot.send_command
    data_template:
      entity_id: '{{ entity_id }}'
      method: outfood
      params:
      - '{{ expand(units_id)[0].state | int(0) }}'
  max: 10
mmgg_feeder_reset_dryer:
  mode: single
  alias: '[PetFeeder] - Reset Desicant Age'
  description: Resets the descicant age, use when replaced
  icon: mdi:calendar-clock
  fields:
    entity_id:
      description: ID of the PetFeeder
      required: true
      example: sensor.mmgg_petfeeder_bf89_pet_feeder
      selector:
        entity:
          integration: xiaomi_miot
          domain: sensor
  sequence:
  - service: xiaomi_miot.send_command
    data_template:
      entity_id: '{{ entity_id }}'
      method: resetdryer
      params: []
mmgg_feeder_set_key_lock:
  mode: single
  alias: '[PetFeeder] - Lock Dispense Food Button'
  description: Lock Dispense Food Button
  icon: mdi:gesture-tap-button
  fields:
    entity_id:
      description: ID of the PetFeeder
      required: true
      example: sensor.mmgg_petfeeder_bf89_pet_feeder
      selector:
        entity:
          integration: xiaomi_miot
          domain: sensor
    state:
      description: Status
      required: true
      default: false
      example: 'false'
      selector:
        boolean:
  sequence:
  - service: xiaomi_miot.send_command
    data_template:
      entity_id: '{{ entity_id }}'
      method: keylock
      params:
      - '{{ not state | int }}'
mmgg_feeder_set_wifi_led:
  mode: single
  alias: '[PetFeeder] - Set WiFi indicator state '
  description: Turn on/off WiFi status led state
  icon: mdi:led-on
  fields:
    entity_id:
      description: ID of the PetFeeder
      required: true
      example: sensor.mmgg_petfeeder_bf89_pet_feeder
      selector:
        entity:
          integration: xiaomi_miot
          domain: sensor
    state:
      description: Status
      required: true
      default: false
      example: 'false'
      selector:
        boolean:
  sequence:
  - service: xiaomi_miot.send_command
    data_template:
      entity_id: '{{ entity_id }}'
      method: wifiledon
      params:
      - '{{ state | int }}'
mmgg_feeder_set_auto_feed:
  mode: single
  alias: '[PetFeeder] - Set automatic feeding state '
  description: Turn on/off automatic feeding
  icon: mdi:clock
  fields:
    entity_id:
      description: ID of the PetFeeder
      required: true
      example: sensor.mmgg_petfeeder_bf89_pet_feeder
      selector:
        entity:
          integration: xiaomi_miot
          domain: sensor
    state:
      description: Status
      required: true
      default: true
      example: 'true'
      selector:
        boolean:
  sequence:
  - service: xiaomi_miot.send_command
    data_template:
      entity_id: '{{ entity_id }}'
      method: stopfeed
      params:
      - '{{ not state | int }}'
licheng5625 commented 2 years ago

total_increasing doesn't make sense for a daily stats:

total_increasing, a monotonically increasing total, e.g. an amount of consumed gas, water or energy. When supported, the accumulated growth of the sensor's value since it was first added is updated hourly.

In my point of view, total_increasing is perfect fit to daily food amount. it is a monotonically increasing total.

Wh1terat commented 2 years ago

As a total of dispensed food ever yes it would suit, not daily/weekly/monthly.

al-one commented 2 years ago

This goes back to my comment on is there a way to disable miot for a mixed miio/miot device (since the spec is almost 100% broken for this device).

@Wh1terat https://github.com/al-one/hass-xiaomi-miot/issues/220#issuecomment-1005419419 (https://github.com/al-one/hass-xiaomi-miot/commit/a4a991cf1ca9769bebba5bc72bc700b0f293b245#commitcomment-62930948) is the best solution to this problem. This allows you to use mmgg.feeder.spec specifications on the device and read the device status directly locally.

Wh1terat commented 2 years ago

Oh I missed that comment in the noise, my apologies. Now that is a cool idea. I really like this approach.

I will definitely look into it 😺

Will the extend "feature" overwrite pre-existing iid from original spec with miio mapping? or better just to create new iid and ignore previous broken one?

Just read some more, absolutely love it. Honestly, I love your methodology, coding style and code quality. 🤩

al-one commented 2 years ago

The original spec will be overwritten. Thank you. I think you know me very well. 🤝

1trackprojects1 commented 2 years ago

@1trackprojects1 I wish I had never published that incapsula gist... As I've said to others of your ilk, No. I will not help you with you spam bots.

image

I just want to learn how to reverse javascript, don't want to build any spam bots lol. I don't mind paying you if you can teach me a couple things.

Wh1terat commented 2 years ago

@1trackprojects1 Your repos suggest otherwise. If you really want to learn then I suggest you read about JS abstract syntax tree. The gists I published are more than enough to get you started. Now stop hijacking this issue with your irrelevant noise.

Wh1terat commented 2 years ago

@al-one Hey 👋

Sorry it's taken me a few weeks to look at this, been a bit hectic!

Having good success 😸

Couple of questions though.

  1. Actions. How to implement? For switches I just use setter and template, all is good there. But for a button without a property? (i.e to call a service without a value) I tried this but no luck.
        'miio_specs': { 
            ...
            'prop.200.301': {'prop': None, 'setter': 'resetdryer'}
        },
                'actions': [
                    {
                        'iid': 301, 
                        'type': 'urn:miot-spec-v2:action:reset_desiccant', 
                        'description': 'Reset Desiccant',
                        'in': [],
                        'out': []
                    }, 
                ],
  1. Using pre-existing miot types I tried using preexisting types (e.g urn:miot-spec-v2:property:desiccant-left-time:0000010C - both with and without ":0000010C") but they were never populated. Is this meant to work? or should everything be custom defined?

  2. Descriptions Is it right to put descriptions here? I guess it's the only way, but otherwise entity names aren't so great.

  3. Friendly name For the root sensor I'm using food_level as the sensor state:

        'extend_miot_specs': [ 
            { 
                'iid': 2, 
                'properties': [ 
                    { 
                        'iid': 1, 
                        'type': 'urn:miot-spec-v2:property:food_level', 
                        'description': 'Food Level',
                        'format': 'uint8', 
                        'access': ['read'], 
                        'value-list': [ 
                            {'value': 0, 'description': 'Normal'}, 
                            {'value': 1, 'description': 'Low'}, 
                            {'value': 2, 'description': 'Empty'}, 
                        ], 
                    }, 
                ],
            },

Friendly name becomes:

friendly_name: Pet feeder Pet Feeder Food Level

So it's taking device name + siid description + property description Which isn't inherently wrong, in fact it makes sense - but in this situation it seems too long and looking at other service names, I can imagine others with this problem. Thoughts?

al-one commented 2 years ago
  1. Actions. How to implement?

Add support action for miio2miot in https://github.com/al-one/hass-xiaomi-miot/commit/9edc529934e3c2449fed78903c5071c2a935c0c7. But I don't have time to test it.

  1. Using pre-existing miot types

Maybe in a future version.

  1. Friendly name

Maybe in a future version the device name and service description will be deduplicated. Like this: https://github.com/al-one/hass-xiaomi-miot/blob/186b4a08b5860556ee312d8d834809210ee3cf80/custom_components/xiaomi_miot/core/miot_spec.py#L489-L502

Wh1terat commented 2 years ago

Great! Thank you, I will update and try later :smiley:

No problem using custom miot types, however I wonder if it's worth storing extend_miot_specs externally? This is just 1 device and already it is 80 lines without all actions being implemented yet :cry:

Wh1terat commented 2 years ago
    'mmgg.feeder.petfeeder': { 
        ...
        'extend_miot_specs': [ 
            ...
            {
                'iid': 200,
                'type': 'urn:miot-spec-v2:service:extend',
                'properties': [
                    ...
                ],
                'actions': [
                    {
                        'iid': 301, 
                        'type': 'urn:miot-spec-v2:action:reset_desiccant', 
                        'description': 'Reset Desiccant',
                        'in': [],
                        'out': []
                    },
                ], 
            }, 
        ], 
    },
    'mmgg.feeder.petfeeder': { 
        'without_props': True,
        'miio_commands': [
            ...
        ],
        'miio_specs': { 
            ...
            'action.200.301': {'setter': 'resetdryer', 'set_template':'mmgg_feeder_petfeeder_reset_desiccant'}
        }
    },
    'mmgg_feeder_petfeeder_reset_desiccant': "{%- set day = (now() + timedelta(days=30)).strftime('%Y-%m-%d') %}"
                                             "{{ [day] }}",
miot_action_error: '-704040002 Service does not exist'
miot_action_result:
  did: '<removed>'
  miid: 0
  siid: 200
  aiid: 301
  code: -704040002
  exe_time: 0
  withLatency: 0

If i incorrectly rename it to prop:

            'prop.200.301': {'setter': 'resetdryer', 'set_template':'mmgg_feeder_petfeeder_reset_desiccant'}

Then it does at least try to call it through miio2miot but ofcourse does not exist.

2022-01-20 23:38:26 WARNING (SyncWorker_6) [custom_components.xiaomi_miot.core.miio2miot] Call miio method via miot action failed: ['x.x.x.x, 'action.200.301', None, {}]
2022-01-20 23:38:26 WARNING (SyncWorker_6) [custom_components.xiaomi_miot.sensor] Pet feeder Pet Feeder Food Level: Call miot action {'did': '<removed>', 'siid': 200, 'aiid': 301, 'in': []} failed: cannot convert dictionary update sequence element #0 to a sequence, result: [None]
al-one commented 2 years ago

however I wonder if it's worth storing extend_miot_specs externally?

That's what I was thinking too, maybe migrate them to a yaml file.


Call action for miio2miot was fixed in https://github.com/al-one/hass-xiaomi-miot/commit/3daaaeb67d45bbf95a99c22772922b6426f85ca8.

Wh1terat commented 2 years ago

That commit fixed it :smiley_cat:

2022-01-21 13:23:18 INFO (SyncWorker_8) [custom_components.xiaomi_miot.core.miio2miot] Call miio method via miot action: ['x.x.x.x', 'action.200.301', 'resetdryer', ['2022-02-20']]

Although it still throws an error (even though it works) - seems unhappy with the response from miio2miot ?

2022-01-21 13:23:19 WARNING (SyncWorker_8) [custom_components.xiaomi_miot.sensor] Pet feeder Pet Feeder Food Level: Call miot action {'did': '<removed>', 'siid': 200, 'aiid': 301, 'in': []} failed: dictionary update sequence element #0 has length 4; 2 is required, result: [{'code': 0, 'siid': 200, 'aiid': 301, 'result': ['ok']}]

With regard to external specs.... I know HA is very pro yaml, but given native miot spec is json already it feels like leaving it as json might be best option ?

Wh1terat commented 2 years ago

Few more questions :)

In miot spec, action arguments are piids for that service - how to do the same? (i.e to pass the value of a miio prop as an argument to an action)

Next q: pet-food-out (aka dispense) takes an argument of feeding-measure. Unfortunately having disassembled the firmware I can see that "setoutweight" (which should set this value) is not properly implemented, the prop value is set only after dispense has been called.

So whatever I set it to becomes a race to dispense food (and in turn it updates feeding-measure) before the next polling updates feeding-measure back to last value. I need some kind of dummy setter, or perhaps a completely local dummy prop only used for this.

Any ideas?

al-one commented 2 years ago

In miot spec, action arguments are piids for that service - how to do the same? (i.e to pass the value of a miio prop as an argument to an action)

You can get miio props values from set_template. https://github.com/al-one/hass-xiaomi-miot/blob/495c43b5e61d1e9117a903e6a6cd485628d4e760/custom_components/xiaomi_miot/core/miio2miot.py#L211-L214


For pet-food-out with feeding-measure, at present, this component does not implement it very well. The best way is to execute the service in the card.

Wh1terat commented 2 years ago

I tried with prop name directly but it threw an exception that it did not exist. Edit: duh I'm blind. it's a dictionary. Ignore me on this point.

Oh for sure this device spec does not work well 😝 but I think we're very close to making it better. (Really does surprise me how little validation Xiaomi do for customer products...)

For feeding-measure, the way I did it before was to create a number input helper (slider) and passed this argument to pet-food-out. I'd like to do the same "out of the box" without need for this. But I need a way to create a dummy prop used to hold this value and a way to update without sending any miio/miot commands. All this because the setter for weight_level miio prop is not properly implemented in mcu firmware. 🤦

al-one commented 2 years ago

Hi, extend_miot_specs has been migrated to a single file core/miot_specs_extend.json.

al-one commented 2 years ago

@Wh1terat Can you create a PR for this device ?

Wh1terat commented 2 years ago

@al-one I'd like to but it still feels a little incomplete. I don't want to add a device that then requires manual addition of templated entities to work.

For feeding-measure, the way I did it before was to create a number input helper (slider) and passed this argument to pet-food-out. I'd like to do the same "out of the box" without need for this. But I need a way to create a dummy prop used to hold this value and a way to update without sending any miio/miot commands. All this because the setter for weight_level miio prop is not properly implemented in mcu firmware. facepalm

I'm happy to leave out schedule management as it'll be difficult to implement cleanly as well as being difficult to implement in HA itself without custom lovelace. (Although I did add to Miio - https://github.com/Wh1terat/python-miio/blob/petfeeder-dev/miio/integrations/petfeeder/device.py)

al-one commented 2 years ago

Do you have any suggestions if implemented using RestoreEntity and NumberEntity ?

Wh1terat commented 2 years ago

NumberEntity with RestoreEntity using weight_level prop would be great.

How would you suggest this be implemented ?

Currently the below works but of course without any write control over the prop.

        'miio_specs': { 
            'action.2.1': {
                'setter': 'outfood',
                'set_template': '{% set fval = props.get("weight_level")|default(1)|int(0) %}'
                                '{{ [fval] }}',
            },
ahaghshenas commented 1 year ago

@Wh1terat

Would you mind sharing your lovelace card settings?

148406644-37951706-7811-4e3b-8c09-04102dd7cdc8
licheng5625 commented 1 year ago
type: vertical-stack
cards:
  - type: glance
    entities:
      - entity: sensor.mmgg_petfeeder_fa4e_event_feedstats_fed_today
        name: today
        icon: mdi:food-drumstick
      - entity: sensor.mmgg_petfeeder_fa4e_event_feedstats_fed_week
        name: week
        icon: mdi:food-drumstick
      - entity: sensor.mmgg_petfeeder_fa4e_event_feedstats_fed_month
        name: month
        icon: mdi:food-drumstick
  - type: horizontal-stack
    cards:
      - type: entity
        entity: input_number.feed_food
        name: feed number
        unit: units
        icon: mdi:paw
      - type: button
        tap_action:
          action: call-service
          service: script.mmgg_feeder_dispense
          service_data:
            entity_id: sensor.mmgg_petfeeder_fa4e_pet_feeder
            units_id: input_number.feed_food
        icon: mdi:cat
        name: feed my cat
        show_state: false
  - type: glance
    entities:
      - entity: light.mmgg_petfeeder_bf89_wifi_led
        name: Led
      - entity: lock.mmgg_petfeeder_fa4e_key_lock
        name: Dispense Button
      - entity: sensor.mmgg_petfeeder_fa4e_food_level
        name: Food level
      - entity: sensor.mmgg_petfeeder_fa4e_clean_days
        name: Clean Days left
        icon: mdi:silverware-clean
      - entity: sensor.mmgg_petfeeder_fa4e_dryer_days
        name: Desiccant Days left
        icon: mdi:cookie-plus
wjablonski90 commented 10 months ago

Looking for some clarity over miio_cloud_records.

I've got a device that pulls data from https://api.io.mi.com/app/user/get_user_device_data (My beloved petfeeder 😆 )

Request:

{
    **"accessKey": "xxx"**,
    **"did": "xxx"**,
    "group": "raw",
    "key": "feedStats",
    "limit": 1000,
    "time_end": 1643673599,
    "time_start": 1640995200,
    "type": "event",
    **"uid": "xxx"**
}

Hi. I have the 'mmgg.feeder.f1' device and I'd like to create the same integration in Home Assistant as you have. I mean, I want to read information from the Xiaomi cloud about the number of food portions dispensed. My pet feeder has an attribute called 'outfood_num,' but it's always set to 5 (as far as I know, it's a known issue). I noticed that you're fetching data from the cloud. In the mobile app (Xiaomi Home), there is an option to view how many portions have been dispensed today, yesterday, in the last 7 days, etc., so I assume there must be a way to access this data. Going back to the quoted statement, I have no idea where to get the 'accessKey' for this request, could you provide some guidance? Properties