|
本帖最后由 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 %}
==========================================================================================================================================================================
效果展示:
后续:以后想往上面添加蓝牙节点,可以继续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
|
|