Xiaomi Pet Feeder - Estimation niveau restant

Salut la communauté HACF !

Je voulais partager avec vous une solution que j’ai mise en place pour résoudre un petit problème avec mon Xiaomi Pet Feeder. Comme certains d’entre vous le savent peut-être, le distributeur de croquettes Xiaomi ne fournit d’informations que lorsqu’il est preque ou complètement vide, ce qui peut être un peu contraignant d’autant plus que le distributeur est opaque donc c’est la suprise…

En partant d’un principe très simple : Si je sais quel poids de croquette j’ai mis dedans, que je connais le poid de la portion et que je sais ce qui est distribué… Je suis capable de calculer à tout instant ce qu’il reste ?

J’ai donc décidé d’utiliser Node-RED en conjonction avec l’intégration Xiaomi Miot Auto pour surveiller le niveau de croquettes de mon distributeur. J’ai créé un flow qui calcule :

  • Le pourcentage de remplissage
  • Le nombre de jours d’autonomie restant

Ce qui me permet de savoir à tout moment où j’en suis (et si le chat ne vas pas mourrir de faim!)

Pré-requis :

  1. Home Assistant & Node-RED (bon ca c’est la base!)
  2. L’intégration Xiaomi Miot Auto configurée.
  3. Avoir une balance pour mesurer le poids de croquette

Le Flow :

Code du flow :

[{"id":"c65d3df16ae7148f","type":"tab","label":"Cat feeder","disabled":false,"info":"","env":[]},{"id":"0e104bbeb206452d","type":"group","z":"c65d3df16ae7148f","name":"Manual action","style":{"fill":"#ffffbf","label":true},"nodes":["cae917a32ee39a65","661fd62976703d7d","8b78dbbe37544d83"],"x":414,"y":279,"w":652,"h":122},{"id":"e353313c06e83627","type":"group","z":"c65d3df16ae7148f","name":"Refill action","style":{"fill":"#e3f3d3","label":true},"nodes":["aef7bbb1aa97ad5b","22b54ea151ecf725","6cb50c214796da5b","a18f6f15e6f74a6e"],"x":374,"y":179,"w":692,"h":82},{"id":"58d21fe60c4e917f","type":"group","z":"c65d3df16ae7148f","name":"Feeder distribution","style":{"fill":"#bfdbef","label":true,"color":"#3f3f3f"},"nodes":["6a63e920c071752b","95f8aa13fb63c339","eb99ccfc56cde376","f6a1480e37912733","9ae7de4a93e7d2ec"],"x":374,"y":19,"w":832,"h":142},{"id":"2e0555dab3725f9b","type":"group","z":"c65d3df16ae7148f","name":"Data calculation","style":{"fill":"#ffbfbf","label":true,"color":"#3f3f3f","label-position":"ne"},"nodes":["45dc2f7033200e9a","9a9c5fd649cfac42","4ba9b46b7b6b0d7c","20736b6fa93de977","14b35983c9824a18"],"x":1114,"y":199,"w":472,"h":182},{"id":"2d5343aa8a1f6172","type":"group","z":"c65d3df16ae7148f","name":"Refresh engine","style":{"fill":"#bfbfbf","label":true,"color":"#000000"},"nodes":["6c9661ca0af7edc2","3f70c72538d8e12b","e99cc3bff01c348c","f7a8f95370be24bd","eae11e364624a982","f85ebb3215faa7d3"],"x":34,"y":19,"w":252,"h":282},{"id":"d20a3d469230ec07","type":"group","z":"c65d3df16ae7148f","name":"Readjust action","style":{"fill":"#ffdf7f","label":true,"color":"#3f3f3f"},"nodes":["0b38c0af4aedb3fc","e33b92625677ed4b","65a1cb867fd7bc93","5ad96682d4afbdb1"],"x":194,"y":419,"w":872,"h":82},{"id":"6a63e920c071752b","type":"api-call-service","z":"c65d3df16ae7148f","g":"58d21fe60c4e917f","name":"XiaomiMiot GetFeedPlan","server":"46c552d5.09318c","version":5,"debugenabled":false,"domain":"xiaomi_miot","service":"call_action","areaId":[],"deviceId":[],"entityId":["sensor.mmgg_spec_a7e8_pet_feeder"],"data":"{\"siid\":5,\"aiid\":6,\"throw\":false,\"params\":0}","dataType":"json","mergeContext":"","mustacheAltTags":false,"outputProperties":[{"property":"data","propertyType":"msg","value":"","valueType":"data"}],"queue":"none","x":510,"y":60,"wires":[["95f8aa13fb63c339"]]},{"id":"95f8aa13fb63c339","type":"api-current-state","z":"c65d3df16ae7148f","g":"58d21fe60c4e917f","name":"Retrieve FeedPlan data","server":"46c552d5.09318c","version":3,"outputs":1,"halt_if":"","halt_if_type":"str","halt_if_compare":"is","entity_id":"sensor.mmgg_spec_a7e8_pet_feeder","state_type":"str","blockInputOverrides":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"data","propertyType":"msg","value":"","valueType":"entity"}],"for":"0","forType":"num","forUnits":"minutes","override_topic":false,"state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","x":790,"y":60,"wires":[["eb99ccfc56cde376","f6a1480e37912733"]]},{"id":"eb99ccfc56cde376","type":"function","z":"c65d3df16ae7148f","g":"58d21fe60c4e917f","name":"Parse data","func":"// Data initialisation\nif (flow.get('total_distributed_portion') === undefined) {\n    flow.set('total_distributed_portion', 0);\n}\nif (flow.get('daily_distributed_portion') === undefined) {\n    flow.set('daily_distributed_portion', 0);\n}\n\nvar dataString = msg.data.attributes.miot_action_result.out[0].value;\n\n// Split data\nvar dataArr = dataString.split(',').map(function(item) {\n    return parseInt(item.trim(), 10);\n});\n\n// Check data integrity\nif (dataArr.length % 5 !== 0) {\n    node.error(\"Données invalides\");\n    node.status({ fill: \"red\", shape: \"dot\", text: \"Invalid data\" });\n    return null;\n}\n\n// Calculate daily_distributed_portion\nvar dailyDistributedPortion = 0;\n\n// Iterate over table\nfor (var i = 0; i < dataArr.length; i += 5) {\n    var deliveredPortions = dataArr[i + 3];\n    dailyDistributedPortion += deliveredPortions;\n}\n\n// Set daily_distributed_portion\nflow.set('daily_distributed_portion', dailyDistributedPortion);\n\n// Get last proccessedData\nvar lastProcessedData = context.get('lastProcessedData') || {};\n\n// Iterate over table\nfor (var i = 0; i < dataArr.length; i += 5) {\n    var index = dataArr[i];\n    var status = dataArr[i + 4];\n\n    // Check if status has changed from 255->0\n    if (lastProcessedData[index] === 255 && status === 0) {\n        // Add new delivered portions\n        flow.set('total_distributed_portion', flow.get('total_distributed_portion') + dataArr[i + 3]);\n    }\n    lastProcessedData[index] = status;\n}\n\nnode.status({ fill: \"green\", shape: \"dot\", text: \"OK\" });\ncontext.set('lastProcessedData', lastProcessedData);\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1090,"y":120,"wires":[["45dc2f7033200e9a"]],"icon":"node-red/parser-json.svg"},{"id":"aef7bbb1aa97ad5b","type":"server-state-changed","z":"c65d3df16ae7148f","g":"e353313c06e83627","name":"Confirm refill","server":"46c552d5.09318c","version":5,"outputs":1,"exposeAsEntityConfig":"","entityId":"input_button.valider_remplissage","entityIdType":"exact","outputInitially":false,"stateType":"str","ifState":"","ifStateType":"str","ifStateOperator":"is","outputOnlyOnStateChange":true,"for":"0","forType":"num","forUnits":"minutes","ignorePrevStateNull":false,"ignorePrevStateUnknown":false,"ignorePrevStateUnavailable":false,"ignoreCurrentStateUnknown":true,"ignoreCurrentStateUnavailable":true,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"data","propertyType":"msg","value":"","valueType":"eventData"}],"x":470,"y":220,"wires":[["22b54ea151ecf725"]]},{"id":"22b54ea151ecf725","type":"api-current-state","z":"c65d3df16ae7148f","g":"e353313c06e83627","name":"Refiled weight","server":"46c552d5.09318c","version":3,"outputs":1,"halt_if":"","halt_if_type":"str","halt_if_compare":"is","entity_id":"input_text.total_distributeur","state_type":"num","blockInputOverrides":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"}],"for":"0","forType":"num","forUnits":"minutes","override_topic":false,"state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","x":660,"y":220,"wires":[["a18f6f15e6f74a6e"]]},{"id":"6cb50c214796da5b","type":"change","z":"c65d3df16ae7148f","g":"e353313c06e83627","name":"Set variables","rules":[{"t":"set","p":"weight_total","pt":"flow","to":"payload","tot":"msg"},{"t":"set","p":"weight_remaining","pt":"flow","to":"payload","tot":"msg"},{"t":"set","p":"weight_distributed","pt":"flow","to":"0","tot":"num"},{"t":"set","p":"remaining_percentage","pt":"flow","to":"100","tot":"num"},{"t":"set","p":"total_distributed_portion","pt":"flow","to":"0","tot":"num"}],"action":"","property":"","from":"","to":"","reg":false,"x":970,"y":220,"wires":[["45dc2f7033200e9a"]]},{"id":"cae917a32ee39a65","type":"server-state-changed","z":"c65d3df16ae7148f","g":"0e104bbeb206452d","name":"Manual Feed","server":"46c552d5.09318c","version":5,"outputs":1,"exposeAsEntityConfig":"","entityId":"button.mmgg_spec_a7e8_outfood","entityIdType":"exact","outputInitially":false,"stateType":"str","ifState":"","ifStateType":"str","ifStateOperator":"is","outputOnlyOnStateChange":true,"for":"0","forType":"num","forUnits":"minutes","ignorePrevStateNull":false,"ignorePrevStateUnknown":false,"ignorePrevStateUnavailable":false,"ignoreCurrentStateUnknown":true,"ignoreCurrentStateUnavailable":true,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"data","propertyType":"msg","value":"","valueType":"eventData"}],"x":510,"y":320,"wires":[["661fd62976703d7d"]]},{"id":"45dc2f7033200e9a","type":"function","z":"c65d3df16ae7148f","g":"2e0555dab3725f9b","name":"Calculate/Update","func":"// Get const datas from flow vars\nconst totalDistributedPortion = flow.get(\"total_distributed_portion\");\nconst dailyDistributedPortion = flow.get(\"daily_distributed_portion\");\nconst weightDistributed = flow.get(\"weight_distributed\");\nconst weightRemaining = flow.get(\"weight_remaining\");\nconst weightTotal = flow.get(\"weight_total\");\nconst weight_by_portion = flow.get(\"weight_by_portion\");\n\n// Calculate remaining percentage\nvar t_distributed = totalDistributedPortion * weight_by_portion;\nvar r_weight = weightTotal - t_distributed;\nvar r_percentage = Math.floor((r_weight / weightTotal) * 100);\n\n// Calculate remaining days\nvar r_days = Math.floor(r_weight / (dailyDistributedPortion * weight_by_portion));\n\n// Calculate empty date\nvar d_empty = new Date();\nd_empty.setDate(d_empty.getDate() + r_days);\n\n// Set flow var\nflow.set(\"weight_distributed\", t_distributed);\nflow.set(\"weight_remaining\", r_weight);\nflow.set(\"remaining_percentage\", r_percentage);\nflow.set(\"days_remaining\", r_days);\nflow.set(\"empty_date\", d_empty);\n\n// Output message\nmsg.weightDistributed = t_distributed;\nmsg.weightRemaining = r_weight;\nmsg.pourcentageRestant = r_percentage;\nmsg.daysRemaining = r_days;\nmsg.emptyDate = d_empty.toISOString();\nreturn msg;\n","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1250,"y":280,"wires":[["9a9c5fd649cfac42","20736b6fa93de977","14b35983c9824a18"]],"icon":"node-red/cog.svg"},{"id":"661fd62976703d7d","type":"function","z":"c65d3df16ae7148f","g":"0e104bbeb206452d","name":"Increment","func":"var currentPortion = flow.get(\"total_distributed_portion\") || 0;\nvar updatedPortion = currentPortion + 1;\nflow.set(\"total_distributed_portion\", updatedPortion);\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":980,"y":320,"wires":[["45dc2f7033200e9a"]]},{"id":"8b78dbbe37544d83","type":"inject","z":"c65d3df16ae7148f","g":"0e104bbeb206452d","name":"Manual Increment 1p","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":820,"y":360,"wires":[["661fd62976703d7d"]]},{"id":"9a9c5fd649cfac42","type":"ha-sensor","z":"c65d3df16ae7148f","g":"2e0555dab3725f9b","name":"Remaining %","entityConfig":"73f282adfaa8d67d","version":0,"state":"pourcentageRestant","stateType":"msg","attributes":[{"property":"weight_distributed","value":"weightDistributed","valueType":"msg"},{"property":"weight_remaining","value":"weightRemaining","valueType":"msg"},{"property":"weight_total","value":"weight_total","valueType":"flow"},{"property":"total_distributed_portion","value":"total_distributed_portion","valueType":"flow"}],"inputOverride":"allow","outputProperties":[],"x":1470,"y":280,"wires":[[]],"icon":"font-awesome/fa-info-circle"},{"id":"4ba9b46b7b6b0d7c","type":"inject","z":"c65d3df16ae7148f","g":"2e0555dab3725f9b","name":"Recalculate","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":1230,"y":340,"wires":[["45dc2f7033200e9a"]]},{"id":"9ae7de4a93e7d2ec","type":"inject","z":"c65d3df16ae7148f","g":"58d21fe60c4e917f","name":"Send init day data","props":[{"p":"data.attributes.miot_action_result.out[0].value","v":"0,5,30,4,255,1,9,0,3,255,2,13,0,2,255,3,17,0,3,255,4,21,0,2,255","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":870,"y":120,"wires":[["eb99ccfc56cde376"]]},{"id":"f6a1480e37912733","type":"debug","z":"c65d3df16ae7148f","g":"58d21fe60c4e917f","name":"FeedData debug","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1070,"y":60,"wires":[]},{"id":"6c9661ca0af7edc2","type":"inject","z":"c65d3df16ae7148f","g":"2d5343aa8a1f6172","name":"Refresh 05h30","props":[{"p":"payload"}],"repeat":"","crontab":"32 05 * * *","once":true,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":160,"y":100,"wires":[["6a63e920c071752b"]]},{"id":"3f70c72538d8e12b","type":"inject","z":"c65d3df16ae7148f","g":"2d5343aa8a1f6172","name":"Refresh 09h00","props":[{"p":"payload"}],"repeat":"","crontab":"02 09 * * *","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":160,"y":140,"wires":[["6a63e920c071752b"]]},{"id":"e99cc3bff01c348c","type":"inject","z":"c65d3df16ae7148f","g":"2d5343aa8a1f6172","name":"Init refresh","props":[{"p":"payload"}],"repeat":"","crontab":"10 00 * * *","once":true,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":190,"y":60,"wires":[["6a63e920c071752b"]]},{"id":"f7a8f95370be24bd","type":"inject","z":"c65d3df16ae7148f","g":"2d5343aa8a1f6172","name":"Refresh 13h00","props":[{"p":"payload"}],"repeat":"","crontab":"02 13 * * *","once":true,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":160,"y":180,"wires":[["6a63e920c071752b"]]},{"id":"eae11e364624a982","type":"inject","z":"c65d3df16ae7148f","g":"2d5343aa8a1f6172","name":"Refresh 17h00","props":[{"p":"payload"}],"repeat":"","crontab":"02 17 * * *","once":true,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":160,"y":220,"wires":[["6a63e920c071752b"]]},{"id":"f85ebb3215faa7d3","type":"inject","z":"c65d3df16ae7148f","g":"2d5343aa8a1f6172","name":"Refresh 21h00","props":[{"p":"payload"}],"repeat":"","crontab":"02 21 * * *","once":true,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":160,"y":260,"wires":[["6a63e920c071752b"]]},{"id":"20736b6fa93de977","type":"debug","z":"c65d3df16ae7148f","g":"2e0555dab3725f9b","name":"Data debug","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1450,"y":240,"wires":[]},{"id":"14b35983c9824a18","type":"ha-sensor","z":"c65d3df16ae7148f","g":"2e0555dab3725f9b","name":"Remaining Days","entityConfig":"77a945f1024390c0","version":0,"state":"daysRemaining","stateType":"msg","attributes":[{"property":"empty_date","value":"emptyDate","valueType":"msg"}],"inputOverride":"allow","outputProperties":[],"x":1480,"y":340,"wires":[[]],"icon":"font-awesome/fa-exclamation-circle"},{"id":"a18f6f15e6f74a6e","type":"change","z":"c65d3df16ae7148f","g":"e353313c06e83627","name":"Tare","rules":[{"t":"set","p":"payload","pt":"msg","to":"payload - 472","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":830,"y":220,"wires":[["6cb50c214796da5b"]]},{"id":"0b38c0af4aedb3fc","type":"server-state-changed","z":"c65d3df16ae7148f","g":"d20a3d469230ec07","name":"Adjust Food portion","server":"46c552d5.09318c","version":5,"outputs":1,"exposeAsEntityConfig":"","entityId":"input_button.reajuster_la_portion","entityIdType":"exact","outputInitially":false,"stateType":"str","ifState":"","ifStateType":"str","ifStateOperator":"is","outputOnlyOnStateChange":true,"for":"0","forType":"num","forUnits":"minutes","ignorePrevStateNull":false,"ignorePrevStateUnknown":false,"ignorePrevStateUnavailable":false,"ignoreCurrentStateUnknown":true,"ignoreCurrentStateUnavailable":true,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"data","propertyType":"msg","value":"","valueType":"eventData"}],"x":310,"y":460,"wires":[["e33b92625677ed4b"]]},{"id":"e33b92625677ed4b","type":"api-current-state","z":"c65d3df16ae7148f","g":"d20a3d469230ec07","name":"Mesured weight","server":"46c552d5.09318c","version":3,"outputs":1,"halt_if":"","halt_if_type":"str","halt_if_compare":"is","entity_id":"input_text.poids_mesure_reajustement_portions","state_type":"num","blockInputOverrides":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"}],"for":"0","forType":"num","forUnits":"minutes","override_topic":false,"state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","x":520,"y":460,"wires":[["65a1cb867fd7bc93"]]},{"id":"65a1cb867fd7bc93","type":"function","z":"c65d3df16ae7148f","g":"d20a3d469230ec07","name":"Adjust weight portion","func":"// Feeder tare (weight of feeder empty)\nconst feeder_tare = 472;\n// Input number Min/Max values\nconst min_wbp = 2;\nconst max_wbp = 6;\n// Get flow datas\nconst weightTotal = flow.get(\"weight_total\");\nconst totalDistributedPortion = flow.get(\"total_distributed_portion\");\nconst old_weight_by_portion = flow.get(\"weight_by_portion\") || 3.5;\n\n// Calculate weight by portion\nvar weight_remaining = msg.payload - feeder_tare;\nvar raw_w_by_portion = (weightTotal - weight_remaining) / totalDistributedPortion;\nvar new_weight_by_portion = (old_weight_by_portion + raw_w_by_portion) / 2;\nvar weight_by_portion = parseFloat(new_weight_by_portion.toFixed(1));\n\n// Check if value is OK ?\nif (weight_by_portion >= min_wbp && weight_by_portion <= max_wbp) {\n    flow.set(\"weight_remaining\", weight_remaining);\n    flow.set(\"weight_by_portion\", weight_by_portion);\n    node.status({ fill: \"green\", shape: \"dot\", text: \"New portion is = \" + weight_by_portion });\n    msg.weight_by_portion = weight_by_portion;\n    return msg;\n} else {\n    node.status({ fill: \"red\", shape: \"dot\", text: \"Error\" });\n}\n","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":740,"y":460,"wires":[["5ad96682d4afbdb1"]],"icon":"node-red-contrib-home-assistant-websocket/ha-poll-state.svg"},{"id":"5ad96682d4afbdb1","type":"api-call-service","z":"c65d3df16ae7148f","g":"d20a3d469230ec07","name":"Set Poids Portion","server":"46c552d5.09318c","version":5,"debugenabled":false,"domain":"input_number","service":"set_value","areaId":[],"deviceId":[],"entityId":["input_number.poids_portion"],"data":"{\"value\": weight_by_portion}","dataType":"jsonata","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":950,"y":460,"wires":[["45dc2f7033200e9a"]]},{"id":"46c552d5.09318c","type":"server","name":"Home Assistant","addon":true,"rejectUnauthorizedCerts":true,"ha_boolean":"","connectionDelay":false,"cacheJson":false,"heartbeat":false,"heartbeatInterval":"","areaSelector":"friendlyName","deviceSelector":"friendlyName","entitySelector":"friendlyName","statusSeparator":"","statusYear":"numeric","statusMonth":"numeric","statusDay":"numeric","statusHourCycle":"h23","statusTimeFormat":"h:m:s","enableGlobalContextStore":false},{"id":"73f282adfaa8d67d","type":"ha-entity-config","server":"46c552d5.09318c","deviceConfig":"","name":"remaining percentage cat feeder","version":"6","entityType":"sensor","haConfig":[{"property":"name","value":"remaining percentage cat feeder"},{"property":"icon","value":"mdi:gauge"},{"property":"entity_picture","value":""},{"property":"entity_category","value":""},{"property":"device_class","value":""},{"property":"unit_of_measurement","value":"%"},{"property":"state_class","value":""}],"resend":false,"debugEnabled":false},{"id":"77a945f1024390c0","type":"ha-entity-config","server":"46c552d5.09318c","deviceConfig":"","name":"remaining days cat feeder","version":"6","entityType":"sensor","haConfig":[{"property":"name","value":"remaining days cat feeder"},{"property":"icon","value":"mdi:calendar-arrow-right"},{"property":"entity_picture","value":""},{"property":"entity_category","value":""},{"property":"device_class","value":"duration"},{"property":"unit_of_measurement","value":"d"},{"property":"state_class","value":""}],"resend":false,"debugEnabled":false}]

Ce flow est constitué de plusieurs parties :

  • Feeder Distribution : Récupère les données depuis l’intégration Xiaomi Miot data
  • Refill action : Met à jour le poids de croquette ajouté lors de la réappro
  • Manual action : Pour prendre en compte dans le calcul, lors d’une distribution manuelle
  • Readjust action : Pour réajuster le poids de la portion (qui varie en fonction de la forme et la taille des croquette) par rapport à ce qui est mesuré.

Le panel de configuration :

Ce panel apparait uniquement si la trappe du Pet Feeder est ouverte, (grâce aux tuiles conditionnelles) me permet de renseigner les données de remplissage, et de réajustement si besoin ai.

Le resulat sur le dashboard :

Screenshot from 2023-12-28 18-27-12

N’hésitez pas à partager vos expériences ou à poser des questions si vous avez des problèmes. J’espère que cette solution sera utile à certains (les rares qui ont un Xiaomi Pet Feeder & ont Home Assistant)

Bonne automatisation à tous !

2 « J'aime »