本帖最后由 gz234748157 于 2024-4-10 12:31 编辑
平常有各种各样的原因,有些实体会变成不可用状态,还需要通过手动重载集成条目去恢复。重载集成条目的调用如下:
{
domain: "homeassistant",
service: "reload_config_entry",
data: {
entry_id: Entry ID
}
}
但我不想手动去重载,也不想硬编码几个实体ID和Entry ID去做自动化,那太不智能了,所以试着去做一个自动重载的功能。
这里同步一下我所理解的HA实体概念:
我们正常添加设备,是会先通过集成(Platform)去创建一个条目(Entry),创建好条目就会添加设备(Device),而设备因为有各种各样的功能和传感器,就会生成N个实体(Entity)。
所以整个关系就是:HA->Platform->Entry->Device->Entity。
知道这个关系就要开始研究怎么做了,整个逻辑的思路很简单:当发现有实体的状态为不可用,自动去通过它所在的Entry ID重载。
实体状态查询很简单,官方API文档就给到/api/states这个接口去查询所有的实体状态。
当然,还能通过Subscribe的方式去订阅实体的状态。
而Entry ID,就是平常在HA地址栏里看到的这一串
对于Entry ID的查询,已知Entry、Device、Entity的注册信息都在.storage/的文件里,但我翻了一遍官网的API文档,发现并没有公开任何接口查询方法,那就只能抓包研究了。
通过抓包网页版HA的WebSocket包发现,当发送{"type:config/entity_registry/list"}指令时,会返回所有实体的详细注册信息,其中就包括它所在的Entry ID。看数据结构,应该就是从.storage/core.entity_registry调出的数据。
{
"id": 32,
"type": "result",
"success": true,
"result": [{
"area_id": null,
"config_entry_id": "0703xxxxxxxxxxxxxx",
"device_id": "f9efxxxxxxxxxxx",
"disabled_by": null,
"entity_category": null,
"entity_id": "fan.211106xxxxxx_fan",
"has_entity_name": false,
"hidden_by": null,
"icon": null,
"id": "dddf00dcxxxxxxxxx",
"labels": [],
"name": null,
"options": {
"conversation": {
"should_expose": true
}
},
"original_name": "电风扇",
"platform": "midea_ac_lan",
"translation_key": null,
"unique_id": "midea_ac_lan.211106xxxxxx_fan"
}]
}
两个接口各自都有对方没有的关键信息:状态、Entry ID,但他们有个共同点:都有实体ID。
那现在要做的逻辑就很明了:先找到不可用的实体,找出他们的实体ID,再通过实体ID去找到他的Entry ID,然后批量调用homeassistant.reload_config_entry去重载。
整个重载逻辑流程大致就是这样:
为了灵活配置,避免因为各种各样的特殊情况,我加入了一些例外配置,避免本不需要重载Entry的情况下被错误拉去重载了。
附上JSON配置:
[{"id":"325906dc479f1c16","type":"subflow","name":"重载Entry","info":"","category":"","in":[{"x":60,"y":40,"wires":[{"id":"636bbc6753eb840d"}]}],"out":[{"x":500,"y":40,"wires":[{"id":"3b68d20b81452b82","port":0}]}],"env":[],"meta":{},"color":"#DDAA99"},{"id":"636bbc6753eb840d","type":"function","z":"325906dc479f1c16","name":"重载Entry","func":"var entry=msg.payload;\nmsg.payload = {\n domain: "homeassistant",\n service: "reload_config_entry",\n data: {\n entry_id: entry\n }\n};\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":180,"y":40,"wires":[["3b68d20b81452b82"]]},{"id":"3b68d20b81452b82","type":"api-call-service","z":"325906dc479f1c16","name":"","server":"3b9976cf.8cca9a","version":5,"debugenabled":false,"domain":"","service":"","areaId":[],"deviceId":[],"entityId":[],"data":"","dataType":"jsonata","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":350,"y":40,"wires":[[]]},{"id":"9d45952ba1a6611d","type":"inject","z":"6277ce2382ca0ea3","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"600","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":140,"y":2120,"wires":[["b7bec502fc9c5fe3"]]},{"id":"b7bec502fc9c5fe3","type":"ha-api","z":"6277ce2382ca0ea3","name":"获取实体状态","server":"3b9976cf.8cca9a","version":1,"debugenabled":false,"protocol":"http","method":"get","path":"http://localhost:8123/api/states","data":"","dataType":"jsonata","responseType":"json","outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"results"}],"x":300,"y":2120,"wires":[["a0de84691f6a3e26","1ae6c5e7fe6f3e4b"]]},{"id":"a0de84691f6a3e26","type":"function","z":"6277ce2382ca0ea3","name":"整理需要重载的实体id","func":"//配置需要重载的特定集成\nmsg.config_platform = ["xiaomi_gateway3", "aqara_gateway"];\n//配置不需要走重载逻辑的例外实体\nmsg.exclude_entity_ids = ["这里填写你想要配置的例外entity_id"];\n//配置需要重载的状态\nconst need_reload_states = ["unavailable"];\n\n\nlet unavailableEntities = []; // 创建一个空数组来存储不可用的实体信息\nmsg.payload.forEach(function (entity) {\n if (need_reload_states.includes(entity.state) && !msg.exclude_entity_ids.includes(entity.entity_id)) {\n // 当实体的状态为需要重载的状态,并且不是例外的实体时,记录实体ID和状态\n unavailableEntities.push({\n entity_id: entity.entity_id,\n state: entity.state\n });\n }\n});\n\n//给向下传递筛选出来的数据\nmsg.unavailableEntities = unavailableEntities;\nmsg.payload = unavailableEntities.length;\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":520,"y":2120,"wires":[["e2970ea50b21a96e","7cf864be78774232"]]},{"id":"1ae6c5e7fe6f3e4b","type":"debug","z":"6277ce2382ca0ea3","name":"debug 36","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":450,"y":2060,"wires":[]},{"id":"e2970ea50b21a96e","type":"switch","z":"6277ce2382ca0ea3","name":"判断是否有需要重载的实体id","property":"payload","propertyType":"msg","rules":[{"t":"gt","v":"0","vt":"num"}],"checkall":"true","repair":false,"outputs":1,"x":780,"y":2120,"wires":[["aad207e889a11289"]]},{"id":"aad207e889a11289","type":"ha-api","z":"6277ce2382ca0ea3","name":"查询实体注册表","server":"3b9976cf.8cca9a","version":1,"debugenabled":false,"protocol":"websocket","method":"get","path":"","data":"{"type":"config/entity_registry/list"}","dataType":"json","responseType":"json","outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"results"}],"x":370,"y":2200,"wires":[["8abb1dd78f9a27fb"]]},{"id":"8abb1dd78f9a27fb","type":"function","z":"6277ce2382ca0ea3","name":"查找符合的entry id","func":"var unavailableEntities = msg.unavailableEntities;\n\n// 创建一个空对象来存储config_entry_id\nvar configEntryIds = [];\n\nmsg.payload.forEach(function (entity) {\n // 遍历unavailableEntities数组查找匹配的entity_id\n unavailableEntities.forEach(function (unavailableEntity) {\n //判断platform是否配置内\n if (entity.entity_id === unavailableEntity.entity_id\n && msg.config_platform.includes(entity.platform)\n && !configEntryIds.includes(entity.config_entry_id)) {\n // 如果找到了匹配的entity_id,记录entity的config_entry_id\n configEntryIds.push(entity.config_entry_id);\n }\n });\n});\n\nmsg.configEntryIds = configEntryIds;\n\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":570,"y":2200,"wires":[["67728f63105adfc5","a8c4e444956e7692"]]},{"id":"a6e24ef09fb5322c","type":"debug","z":"6277ce2382ca0ea3","name":"debug 37","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1340,"y":2280,"wires":[]},{"id":"67728f63105adfc5","type":"function","z":"6277ce2382ca0ea3","name":"遍历每个Entry id","func":"var current_reload_entry_id = ""\nif (msg.configEntryIds.length > 0) {\n current_reload_entry_id = msg.configEntryIds[0];\n msg.configEntryIds.shift(); // 移除第一个元素\n msg.reload_entry_id = current_reload_entry_id;\n} else {\n msg.reload_entry_id = "";\n}\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":370,"y":2280,"wires":[["56dfac2db63f5595"]]},{"id":"358657d2eab7a41f","type":"subflow:325906dc479f1c16","z":"6277ce2382ca0ea3","name":"","x":1160,"y":2280,"wires":[["67728f63105adfc5","a6e24ef09fb5322c"]]},{"id":"56dfac2db63f5595","type":"switch","z":"6277ce2382ca0ea3","name":"判断是否还有需要重载的Entry id","property":"reload_entry_id","propertyType":"msg","rules":[{"t":"nempty"}],"checkall":"true","repair":false,"outputs":1,"x":650,"y":2280,"wires":[["32d5508ca350a8f7"]]},{"id":"32d5508ca350a8f7","type":"function","z":"6277ce2382ca0ea3","name":"把entry_id赋值给payload","func":"msg.payload = msg.reload_entry_id;\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":950,"y":2280,"wires":[["358657d2eab7a41f","3f6f16216f9b679d"]]},{"id":"7cf864be78774232","type":"debug","z":"6277ce2382ca0ea3","name":"debug 39","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"unavailableEntities","targetType":"msg","statusVal":"","statusType":"auto","x":700,"y":2060,"wires":[]},{"id":"a8c4e444956e7692","type":"debug","z":"6277ce2382ca0ea3","name":"debug 40","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":760,"y":2200,"wires":[]},{"id":"3f6f16216f9b679d","type":"debug","z":"6277ce2382ca0ea3","name":"debug 41","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":1110,"y":2240,"wires":[]},{"id":"3b9976cf.8cca9a","type":"server","name":"Home Assistant","addon":false,"rejectUnauthorizedCerts":true,"ha_boolean":"","connectionDelay":false,"cacheJson":false,"heartbeat":false,"heartbeatInterval":"","statusSeparator":"","enableGlobalContextStore":false}]
flows (1).json.zip
(2.91 KB, 下载次数: 17)
|