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

 找回密码
 立即注册
查看: 2495|回复: 9

[技术探讨] 用esp32定位ibeacon小记

[复制链接]

6

主题

217

帖子

1321

积分

金牌会员

Rank: 6Rank: 6

积分
1321
金钱
1104
HASS币
0
发表于 2022-8-28 03:29:44 | 显示全部楼层 |阅读模式
本帖最后由 leonarddo 于 2022-8-28 21:23 编辑

一直想有一个能在室内进行定位的方法,已经试过mesh wifi进行定位,但是路由器的定位范围毕竟太广,而且mesh节点有数量限制,且成本较高,有些想法可能无法达成。最近想尝试一下定位手机模拟的ibeacon,在论坛上没找到类似的,遂将过程记录下来。我对homeassistant熟悉度不高,且只会简单的esp32编写,如有疏漏还请指教,献丑了。注:本文的uuid等信息,在安卓手机安装ha官方app模拟ibeacon后测试无误。若使用其他设备,不保证完全可用,请自行修改适配。

需求:
之前使用过Passive BLE monitor来进行室内定位,使用它进行定位时,它会给出当前最近的Gateway ID。通过Gateway ID来判断当前的一个范围。我未来想通过多个Gateway来判断,故需要将尽可能多的节点的信息在homeassistant里展示出来。也希望esp32配置好以后,能直接在ha中直接进行配置设置,尽量不再用esphome进行刷写。

思路:
将esp32作为BLE Gateway,在ha上抓取数据进行分析,然后分别展示出来。

代码:
esp32作为gateway:
   esp32(片段,仅作参考,详见https://github.com/myhomeiot/esphome-components/tree/main/examples/ble_gateway 的esphome.yaml):
==========================================================================================================================================================================
substitutions:
  # Name the device and it's entities
  device: esp32-ble-tracker-test
  device_name: ble_tracker
external_components:
  - source: github://myhomeiot/esphome-components@main
# Example configuration entry
esp32_ble_tracker:
  scan_parameters:
    interval: 120ms
    window: 99ms

ble_gateway:
  id: $device_name

  on_ble_advertise:
    then:
      - homeassistant.service:
          service: ble_monitor.parse_data
          data:
            packet: !lambda return packet;
            gateway_id: $device_name
      - homeassistant.event:
          event: esphome.on_ble_advertise
          data:
            packet: !lambda return packet;
            gateway_id: $device_name

binary_sensor:
  - platform: homeassistant
    id: ble_gateway_discovery
    entity_id: binary_sensor.ble_gateway
    attribute: discovery
    on_state:
      then:
        lambda: id($device_name).set_discovery(x);

sensor:
  # WiFi signals strength sensor
  - platform: wifi_signal
    name: $device WiFi Signal Sensor
    update_interval: 60s

text_sensor:
  - platform: homeassistant
    id: ble_gateway_devices
    entity_id: binary_sensor.ble_gateway
    attribute: devices
    on_value:
      then:
        lambda: id($device_name).set_devices(x);
  # IP address of device. Not really needed for HA (as HA already knows it), but for showing on the display during startup. The startup screen will leave on if no instance connects to the API.
  - platform: wifi_info
    ip_address:
      name: $device_name IP address
      id: ip_address
  # ESPHome version used to compile the app
  - platform: version
    name: $device_name ESPHome Version

switch:
  - platform: template
    id: switch_ble_gateway_discovery
    name: BLE Gateway Discovery
    icon: mdi:bluetooth-connect
    lambda: |-
      id(switch_ble_gateway_discovery).turn_on();
      return id($device_name).get_discovery();
    turn_on_action: [lambda: id($device_name).set_discovery(true);]
    turn_off_action: [lambda: id($device_name).set_discovery(false);]
    disabled_by_default: false
    entity_category: config
==========================================================================================================================================================================

   configuration.yaml(仅供参考,详见https://github.com/myhomeiot/esphome-components/tree/main/examples/ble_gateway 的homeassistant.yaml)
==========================================================================================================================================================================
ble_monitor:
  bt_interface: !secret ble_monitor_bt_interface_builtin
  discovery: false
  restore_state: true
  decimals: 1
  period: 300
  devices:
    - name: Living Room Thermo
      mac: !secret living_room_thermo_mac
      encryption_key: !secret living_room_thermo_mi_bind_key
    - name: Living Room Flower Care
      mac: !secret living_room_flower_care_mac

input_boolean:
  settings_ble_gateway:
    name: BLE Gateway
    icon: mdi:bluetooth
  settings_ble_gateway_discovery:
    name: BLE Gateway Discovery
    icon: mdi:bluetooth-connect

input_text:
  settings_ble_gateway_add_device:
    name: BLE Gateway Add Device
    icon: mdi:bluetooth-connect
    initial: ''

template:
  - binary_sensor:
      - name: BLE Gateway
        icon: mdi:bluetooth
        state: "{{ is_state('input_boolean.settings_ble_gateway', 'on') }}"
        attributes:
          discovery: "{{ is_state('input_boolean.settings_ble_gateway_discovery', 'on') }}"
          devices: >-
            {% set devices = namespace(items = []) %}
            {% for s in states | selectattr('entity_id', 'search', '^(device_tracker|sensor).ble_') | map(attribute='entity_id') %}
              {% set devices.items = devices.items + [device_id(s)] %}
            {% endfor %}
            {% set ns = namespace(items = []) %}
            {% for s in devices.items | unique %}
              {% set ns.items = ns.items + [(device_attr(s, 'identifiers') | first)[1]] %}
            {% endfor %}
            {{ ns.items | unique | sort | join('') | replace(':', '') ~ (states('input_text.settings_ble_gateway_add_device') | replace(':', '') | trim) if is_state('binary_sensor.ble_gateway', 'on') }}
==========================================================================================================================================================================
   重启后,在实体注册表里找到BLE Gateway Discovery 和 BLE Gateway,如果是关闭状态打开即可。

在ha中建立实体展示数据:
由于暂时没想好如何处理数据,先简单的将数据全部展示出来,后续再做考虑。这里的代码写的很烂,由于没找到Jinja2中list的操作函数(类似append、push之类),只能重新字符串拼接后再split,非常的丑陋。以后查到可以修改。总感觉Jinja2好难用啊。。。
==========================================================================================================================================================================
template:
  - trigger:
      - platform: event
        event_type: esphome.on_ble_advertise
    sensor:
      # Keep track how many days have past since a date
      - name: "ble_demo"
        state: ''
        attributes:
            info: >
                {% set info = trigger.event.data.packet|list%}
                {% set area= namespace() %}
                {% set area.str= "" %}
                {% for li in info %}
                  {% if loop.index is divisibleby 2 -%}
                    {% set area.str= area.str+li+"," %}
                  {%- else -%}
                    {% set area.str= area.str+li %}
                  {%- endif %}
                {% endfor %}
                {% set list = area.str.split(',') %}
                {% set uuid = list[20:36]| join %}
                {% set mac = list[::-1][-13:-7]| join(":") %}
                {%set rssi = 0xFF - int(list[-2:-1]|join,0,16) + 1 %}
                {%set major = int(list[37]|join,0,16) %}
                {%set minor = int(list[39]|join,0,16) %}
                {%set measured_power = 0xFF - int(list[40]|join,0,16) +1 %}
                {% set my_test_json = {"uuid": uuid,"mac": mac,"rssi":
                  "-"+rssi|string,"major": major|string,"minor": minor|string,"Gateway_ID":
                  trigger.event.data.gateway_id,"measured_power": "-"+ measured_power|string,"time_stamp": now()|string }
                  %}
                {{ my_test_json }}
==========================================================================================================================================================================

加点条件就能根据uuid进行筛选
==========================================================================================================================================================================
template:
  - trigger:
      - platform: event
        event_type: esphome.on_ble_advertise
    sensor:
      # Keep track how many days have past since a date
      - name: "ble_demo"
        state: ''
        attributes:
            info: >
                {% set info = trigger.event.data.packet|list%}
                {% set area= namespace() %}
                {% set area.str= "" %}
                {% for li in info %}
                  {% if loop.index is divisibleby 2 -%}
                    {% set area.str= area.str+li+"," %}
                  {%- else -%}
                    {% set area.str= area.str+li %}
                  {%- endif %}
                {% endfor %}
                {% set list = area.str.split(',') %}
                {% set uuid = list[20:36]| join %}
                {% set mac = list[::-1][-13:-7]| join(":") %}
                {%set rssi = 0xFF - int(list[-2:-1]|join,0,16) + 1 %}
                {%set major = int(list[37]|join,0,16) %}
                {%set minor = int(list[39]|join,0,16) %}
                {%set measured_power = 0xFF - int(list[40]|join,0,16) +1 %}
                {% if uuid=="你的uuid" -%}
                  {% set my_test_json = {"uuid": uuid,"mac": mac,"rssi":
                    "-"+rssi|string,"major": major|string,"minor": minor|string,"Gateway_ID":
                    trigger.event.data.gateway_id,"measured_power": "-"+ measured_power|string,"time_stamp": now()|string }
                    %}
                  {{ my_test_json }}
                {%- else -%}
                  {{ states.sensor.ble_demo.attributes.info }}
                {%- endif %}
==========================================================================================================================================================================
效果展示:
]W~ZGHDZN4_2)P[7BCPCL6E.png

后续:以后想往上面添加蓝牙节点,可以继续info_2,info_3。没有写超时判断,后续添加。

优势:相比于Passive BLE monitor 1秒一次的更新,它的rssi刷新速度更快。


可能存在的问题:
esp32偶尔会卡死重启的情况,导致丢失一段时间的定位信息

一些想法:
由于逻辑上来说,无论是蓝牙标签对gateway,还是gateway对蓝牙标签,都是一对多的关系,暂时不知道如何处理比较好。现在的想法是以ibeacon为实体,下面有三到四条info,列出当前最近的几个gateway的id。还有个建立坐标系的想法,还得查点资料看看。


参考资料:
esp32做ble gateway:https://github.com/myhomeiot/esphome-components


回复

使用道具 举报

6

主题

217

帖子

1321

积分

金牌会员

Rank: 6Rank: 6

积分
1321
金钱
1104
HASS币
0
 楼主| 发表于 2022-8-28 03:50:36 | 显示全部楼层
怎么代码插入不了啊。。。只能用分割线区分一下了
回复

使用道具 举报

32

主题

119

帖子

749

积分

高级会员

Rank: 4

积分
749
金钱
630
HASS币
0
发表于 2022-8-28 04:04:10 | 显示全部楼层
为什么在APP找不到虚拟ibeacon的?
回复

使用道具 举报

6

主题

217

帖子

1321

积分

金牌会员

Rank: 6Rank: 6

积分
1321
金钱
1104
HASS币
0
 楼主| 发表于 2022-8-28 05:01:03 | 显示全部楼层
学习 发表于 2022-8-28 04:04
为什么在APP找不到虚拟ibeacon的?

安卓手机吗? 配置-手机app-管理传感器-蓝牙发射器
回复

使用道具 举报

32

主题

119

帖子

749

积分

高级会员

Rank: 4

积分
749
金钱
630
HASS币
0
发表于 2022-8-28 06:04:56 | 显示全部楼层
leonarddo 发表于 2022-8-28 05:01
安卓手机吗? 配置-手机app-管理传感器-蓝牙发射器

IPHONE 是不是要安卓手机才行?
回复

使用道具 举报

6

主题

217

帖子

1321

积分

金牌会员

Rank: 6Rank: 6

积分
1321
金钱
1104
HASS币
0
 楼主| 发表于 2022-8-28 06:22:39 来自手机 | 显示全部楼层
学习 发表于 2022-8-28 06:04
IPHONE 是不是要安卓手机才行?

我没有iphone,不是很了解
回复

使用道具 举报

27

主题

387

帖子

3257

积分

元老级技术达人

积分
3257
金钱
2850
HASS币
40

教程狂人

发表于 2022-8-28 09:06:42 | 显示全部楼层
学习 发表于 2022-8-28 06:04
IPHONE 是不是要安卓手机才行?

iphone的藍芽id是開機後隨機生成的
所以ble掃描對iphone來說沒有安卓好用
回复

使用道具 举报

1

主题

141

帖子

1328

积分

金牌会员

Rank: 6Rank: 6

积分
1328
金钱
1187
HASS币
0
发表于 2022-10-6 13:42:52 | 显示全部楼层
楼主, 最新的HA2022.10里面有新的蓝牙代理和对iBeacon Tracker的支持. 这个会不会, 对这个定位的方案有帮助?
https://www.home-assistant.io/integrations/ibeacon
https://esphome.github.io/bluetooth-proxies/
回复

使用道具 举报

0

主题

608

帖子

2520

积分

金牌会员

Rank: 6Rank: 6

积分
2520
金钱
1912
HASS币
0
发表于 2022-10-6 19:45:08 | 显示全部楼层
厉害了,顶一顶大佬
回复

使用道具 举报

6

主题

217

帖子

1321

积分

金牌会员

Rank: 6Rank: 6

积分
1321
金钱
1104
HASS币
0
 楼主| 发表于 2022-10-7 21:39:51 | 显示全部楼层
W@LTER 发表于 2022-10-6 13:42
楼主, 最新的HA2022.10里面有新的蓝牙代理和对iBeacon Tracker的支持. 这个会不会, 对这个定位的方案有帮助 ...

下次放假有空研究研究
回复

使用道具 举报

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

本版积分规则

Archiver|手机版|小黑屋|Hassbian

GMT+8, 2024-11-29 00:43 , Processed in 0.256161 second(s), 36 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

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