『瀚思彼岸』» 智能家居技术论坛

 找回密码
 立即注册
查看: 512|回复: 8

[技术探讨] 通过Python把HAOS中的所有设备及相关属性导出【已解决】

[复制链接]

5

主题

75

帖子

722

积分

高级会员

Rank: 4

积分
722
金钱
647
HASS币
0
发表于 2024-12-3 11:04:14 | 显示全部楼层 |阅读模式
本帖最后由 limo 于 2024-12-6 10:54 编辑

有没有什么办法可以把HAOS中的所有设备实体标识符、所在区域、名字等相关属性一次性导出来?

已解决【20241206】
回复

使用道具 举报

5

主题

75

帖子

722

积分

高级会员

Rank: 4

积分
722
金钱
647
HASS币
0
 楼主| 发表于 2024-12-3 16:22:13 | 显示全部楼层
本帖最后由 limo 于 2024-12-3 16:34 编辑

————————
回复

使用道具 举报

14

主题

1524

帖子

4849

积分

论坛元老

Rank: 8Rank: 8

积分
4849
金钱
3325
HASS币
0
发表于 2024-12-3 17:45:45 | 显示全部楼层
写个虫子,从他的api里挨个读出来。
回复

使用道具 举报

5

主题

75

帖子

722

积分

高级会员

Rank: 4

积分
722
金钱
647
HASS币
0
 楼主| 发表于 2024-12-4 11:00:23 | 显示全部楼层
隔壁的王叔叔 发表于 2024-12-3 17:45
写个虫子,从他的api里挨个读出来。

用 notify.send_message 服务拉出来了 image.png
回复

使用道具 举报

5

主题

75

帖子

722

积分

高级会员

Rank: 4

积分
722
金钱
647
HASS币
0
 楼主| 发表于 2024-12-4 18:52:22 | 显示全部楼层
隔壁的王叔叔 发表于 2024-12-3 17:45
写个虫子,从他的api里挨个读出来。

尴尬了,数据一多超出限制了,还是写虫子吧。。。
回复

使用道具 举报

14

主题

1524

帖子

4849

积分

论坛元老

Rank: 8Rank: 8

积分
4849
金钱
3325
HASS币
0
发表于 2024-12-4 22:53:25 | 显示全部楼层
limo 发表于 2024-12-4 18:52
尴尬了,数据一多超出限制了,还是写虫子吧。。。

点赞,我只会说,不会写
回复

使用道具 举报

0

主题

21

帖子

544

积分

高级会员

Rank: 4

积分
544
金钱
523
HASS币
0
发表于 2024-12-4 23:20:09 | 显示全部楼层
开发者工具-->模板
{%- for device in states | map(attribute='entity_id') | list -%}
{{ device }}
  名称: {{ states[device].name }}
  状态: {{ states[device].state }}
  所属区域: {{ states[device].attributes.area_id if 'area_id' in states[device].attributes else '未指定' }}
  设备类型: {{ states[device].attributes.device_class if 'device_class' in states[device].attributes else '未知类型' }}
  友好名称: {{ states[device].attributes.friendly_name }}
{%- endfor %}


如果设备太多會出現
Template output exceeded maximum size of 262144 characters

那就分別提取修改如:
{%- for device in states.camera | map(attribute='entity_id') | list -%}

可以在右侧实时输出结果

如果要导出为 JSON 格式
{
  "devices": [
    {%- for device in states -%}
    {
      "entity_id": "{{ device.entity_id }}",
      "name": "{{ device.name }}",
      "state": "{{ device.state }}",
      "area": "{{ device.attributes.area_id if 'area_id' in device.attributes else '未指定' }}",
      "device_class": "{{ device.attributes.device_class if 'device_class' in device.attributes else '未知类型' }}",
      "friendly_name": "{{ device.attributes.friendly_name }}"
    }{%- if not loop.last -%},{%- endif -%}
    {%- endfor -%}
  ]
}

结果可复制并保存为 .json 或 .txt
回复

使用道具 举报

5

主题

75

帖子

722

积分

高级会员

Rank: 4

积分
722
金钱
647
HASS币
0
 楼主| 发表于 2024-12-5 09:39:09 | 显示全部楼层
lulipang 发表于 2024-12-4 23:20
开发者工具-->模板

感谢大佬分享,我今天试一下;
我有个疑问,论坛的代码复制有什么技巧么?
我从Notion复制下,结果乱套了
回复

使用道具 举报

5

主题

75

帖子

722

积分

高级会员

Rank: 4

积分
722
金钱
647
HASS币
0
 楼主| 发表于 2024-12-6 10:51:42 | 显示全部楼层
隔壁的王叔叔 发表于 2024-12-4 22:53
点赞,我只会说,不会写

放个虫子;加了手动输入 link 和 key 的交互;可导出CSV文件方便查看;
import requests
import json
import csv
from datetime import datetime

template = """
{
  "devices": [
    {%- for entity_id in states | map(attribute='entity_id') | list -%}
    {
      "device": "{{ state_attr(entity_id, 'friendly_name') if state_attr(entity_id, 'friendly_name') else states[entity_id].name }}",
      "domain": "{{ entity_id.split('.')[0] }}",
      "entity_id": "{{ entity_id }}",
      "area": "{{ area_name(entity_id) if area_name(entity_id) else '未指定' }}"
    }{%- if not loop.last -%},{%- endif -%}
    {%- endfor -%}
  ]
}
"""

def get_ha_url():
    while True:
        url = input("请输入Home Assistant的URL (例如: http://192.168.31.223:8123): ").strip()
        # 验证URL格式
        if url.startswith(('http://', 'https://')):
            # 移除URL末尾的斜杠
            return url.rstrip('/')
        else:
            print("错误: URL必须以 'http://' 或 'https://' 开头")

def get_token():
    while True:
        token = input("请输入Long-Lived Access Token: ").strip()
        if token:
            return token
        else:
            print("错误: Token不能为空")

def get_device_info(ha_url, token):
    headers = {
        "Authorization": f"Bearer {token}",
        "Content-Type": "application/json",
    }
    
    try:
        response = requests.post(
            f"{ha_url}/api/template",
            headers=headers,
            json={"template": template}
        )
        response.raise_for_status()
        result = json.loads(response.text)
        return result['devices']
    except requests.exceptions.ConnectionError:
        print("连接错误: 无法连接到Home Assistant,请检查URL是否正确")
    except requests.exceptions.HTTPError as e:
        if e.response.status_code == 401:
            print("认证错误: Token无效或已过期")
        else:
            print(f"HTTP错误: {e}")
    except Exception as e:
        print(f"错误: {e}")
    return None

def save_to_csv(devices, filename):
    fieldnames = ['Device', 'Domain', 'Entity ID', 'Area']
    
    try:
        with open(filename, 'w', newline='', encoding='utf-8') as csvfile:
            writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
            writer.writeheader()
            
            for device in devices:
                writer.writerow({
                    'Device': device['device'],
                    'Domain': device['domain'],
                    'Entity ID': device['entity_id'],
                    'Area': device['area']
                })
        print(f"CSV文件已保存: {filename}")
    except Exception as e:
        print(f"保存CSV文件时出错: {e}")

def main():
    # 获取Home Assistant URL和Token
    ha_url = get_ha_url()
    token = get_token()
    
    # 获取设备信息
    devices = get_device_info(ha_url, token)
    
    if devices:
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
        filename = f"ha_devices_{timestamp}.csv"
        
        # 调整列宽
        device_width = 50
        domain_width = 30
        entity_id_width = 50
        area_width = 30
        
        # 计算总宽度用于分隔线
        total_width = device_width + domain_width + entity_id_width + area_width
        
        print("\n设备信息:")
        print("-" * total_width)
        print(f"{'Device':<{device_width}}{'Domain':<{domain_width}}{'Entity ID':<{entity_id_width}}{'Area':<{area_width}}")
        print("-" * total_width)
        
        for device in devices:
            # 截断过长的字符串以防止错位
            device_name = device['device'][:device_width-3] + '...' if len(device['device']) > device_width else device['device']
            domain = device['domain'][:domain_width-3] + '...' if len(device['domain']) > domain_width else device['domain']
            entity_id = device['entity_id'][:entity_id_width-3] + '...' if len(device['entity_id']) > entity_id_width else device['entity_id']
            area = device['area'][:area_width-3] + '...' if len(device['area']) > area_width else device['area']
            
            print(f"{device_name:<{device_width}}{domain:<{domain_width}}{entity_id:<{entity_id_width}}{area:<{area_width}}")
        
        print("-" * total_width)
        save_to_csv(devices, filename)

if __name__ == "__main__":
    main() 
SCR-20241206-jvzw.png


ha_device_export.zip (2.21 KB, 下载次数: 1)

评分

参与人数 1金钱 +12 收起 理由
隔壁的王叔叔 + 12 墙都不扶,就服楼主!

查看全部评分

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|Hassbian

GMT+8, 2025-3-7 09:09 , Processed in 0.058664 second(s), 36 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表