Skip to content

Commit

Permalink
Add exposure notifications (#1135)
Browse files Browse the repository at this point in the history
  • Loading branch information
OttoWinter committed Jul 14, 2020
1 parent 412351f commit 465cd3d
Show file tree
Hide file tree
Showing 4 changed files with 109 additions and 0 deletions.
3 changes: 3 additions & 0 deletions esphome/components/esp32_ble_tracker/esp32_ble_tracker.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ class ESPBTUUID {
bool contains(uint8_t data1, uint8_t data2) const;

bool operator==(const ESPBTUUID &uuid) const;
bool operator!=(const ESPBTUUID &uuid) const { return !(*this == uuid); }

esp_bt_uuid_t get_uuid();

Expand Down Expand Up @@ -74,6 +75,8 @@ class ESPBTDevice {

uint64_t address_uint64() const;

const uint8_t *address() const { return address_; }

esp_ble_addr_type_t get_address_type() const { return this->address_type_; }
int get_rssi() const { return rssi_; }
const std::string &get_name() const { return this->name_; }
Expand Down
28 changes: 28 additions & 0 deletions esphome/components/exposure_notifications/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import esphome.codegen as cg
from esphome import automation
import esphome.config_validation as cv
from esphome.components import esp32_ble_tracker
from esphome.const import CONF_TRIGGER_ID

DEPENDENCIES = ['esp32_ble_tracker']

exposure_notifications_ns = cg.esphome_ns.namespace('exposure_notifications')
ExposureNotification = exposure_notifications_ns.struct('ExposureNotification')
ExposureNotificationTrigger = exposure_notifications_ns.class_(
'ExposureNotificationTrigger', esp32_ble_tracker.ESPBTDeviceListener,
automation.Trigger.template(ExposureNotification))

CONF_ON_EXPOSURE_NOTIFICATION = 'on_exposure_notification'

CONFIG_SCHEMA = cv.Schema({
cv.Required(CONF_ON_EXPOSURE_NOTIFICATION): automation.validate_automation(cv.Schema({
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ExposureNotificationTrigger),
}).extend(esp32_ble_tracker.ESP_BLE_DEVICE_SCHEMA)),
})


def to_code(config):
for conf in config.get(CONF_ON_EXPOSURE_NOTIFICATION, []):
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID])
yield automation.build_automation(trigger, [(ExposureNotification, 'x')], conf)
yield esp32_ble_tracker.register_ble_device(trigger, conf)
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#include "exposure_notifications.h"
#include "esphome/core/log.h"
#include "esphome/core/helpers.h"

#ifdef ARDUINO_ARCH_ESP32

namespace esphome {
namespace exposure_notifications {

using namespace esp32_ble_tracker;

static const char *TAG = "exposure_notifications";

bool ExposureNotificationTrigger::parse_device(const ESPBTDevice &device) {
// See also https://blog.google/documents/70/Exposure_Notification_-_Bluetooth_Specification_v1.2.2.pdf
if (device.get_service_uuids().size() != 1)
return false;

// Exposure notifications have Service UUID FD 6F
ESPBTUUID uuid = device.get_service_uuids()[0];
// constant service identifier
const ESPBTUUID expected_uuid = ESPBTUUID::from_uint16(0xFD6F);
if (uuid != expected_uuid)
return false;
if (device.get_service_datas().size() != 1)
return false;

// The service data should be 20 bytes
// First 16 bytes are the rolling proximity identifier (RPI)
// Then 4 bytes of encrypted metadata follow which can be used to get the transmit power level.
ServiceData service_data = device.get_service_datas()[0];
if (service_data.uuid != expected_uuid)
return false;
auto data = service_data.data;
if (data.size() != 20)
return false;
ExposureNotification notification{};
memcpy(&notification.address[0], device.address(), 6);
memcpy(&notification.rolling_proximity_identifier[0], &data[0], 16);
memcpy(&notification.associated_encrypted_metadata[0], &data[16], 4);
notification.rssi = device.get_rssi();
this->trigger(notification);
return true;
}

} // namespace exposure_notifications
} // namespace esphome

#endif
29 changes: 29 additions & 0 deletions esphome/components/exposure_notifications/exposure_notifications.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#pragma once

#include "esphome/core/component.h"
#include "esphome/core/automation.h"
#include "esphome/components/esp32_ble_tracker/esp32_ble_tracker.h"
#include <array>

#ifdef ARDUINO_ARCH_ESP32

namespace esphome {
namespace exposure_notifications {

struct ExposureNotification {
std::array<uint8_t, 6> address;
int rssi;
std::array<uint8_t, 16> rolling_proximity_identifier;
std::array<uint8_t, 4> associated_encrypted_metadata;
};

class ExposureNotificationTrigger : public Trigger<ExposureNotification>,
public esp32_ble_tracker::ESPBTDeviceListener {
public:
bool parse_device(const esp32_ble_tracker::ESPBTDevice &device) override;
};

} // namespace exposure_notifications
} // namespace esphome

#endif

0 comments on commit 465cd3d

Please sign in to comment.