1
0
mirror of https://github.com/esphome/esphome.git synced 2025-11-01 15:41:52 +00:00

Compare commits

...

3 Commits

Author SHA1 Message Date
Jesse Hills
a85b7b3f84 Code tidy 2021-12-22 15:58:02 +13:00
Jesse Hills
a207ed08a9 Merge branch 'dev' into pr/ciB89/1424-1 2021-12-22 15:49:07 +13:00
Ian
90c3cb62b3 Add tracker for OralB toothbrushes
The OralB toothbrushes expose some of their information in their bluetooth advertisement data.

This data lets us see the state (idle, running), brush mode (daily clean, tongue, whitening, etc.), pressure and some other bits of data.

This component lets you expose that data with config as follows:

```
esp32_ble_tracker:

sensor:
  - platform: oralb_brush
    mac_address: 00:00:00:00:00:00
    state:
      name: "Toothbrush State"
```

Checkout https://github.com/zewelor/bt-mqtt-gateway/blob/master/workers/toothbrush_homeassistant.py and https://esphome.io/components/esp32_ble_tracker.html for more information.
2020-05-03 15:23:21 +01:00
7 changed files with 193 additions and 0 deletions

View File

@@ -0,0 +1,18 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import esp32_ble_tracker
from esphome.const import CONF_ID
DEPENDENCIES = ['esp32_ble_tracker']
oralb_ble_ns = cg.esphome_ns.namespace('oralb_ble')
OralbListener = oralb_ble_ns.class_('OralbListener', esp32_ble_tracker.ESPBTDeviceListener)
CONFIG_SCHEMA = cv.Schema({
cv.GenerateID(): cv.declare_id(OralbListener),
}).extend(esp32_ble_tracker.ESP_BLE_DEVICE_SCHEMA)
def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
yield esp32_ble_tracker.register_ble_device(var, config)

View File

@@ -0,0 +1,48 @@
#include "oralb_ble.h"
#include "esphome/core/log.h"
#ifdef USE_ESP32
namespace esphome {
namespace oralb_ble {
static const char *const TAG = "oralb_ble";
bool parse_oralb_data_byte(const esp32_ble_tracker::adv_data_t &adv_data, OralbParseResult &result) {
result.state = adv_data[3];
return true;
}
optional<OralbParseResult> parse_oralb(const esp32_ble_tracker::ESPBTDevice &device) {
bool success = false;
OralbParseResult result{};
for (auto &it : device.get_manufacturer_datas()) {
bool is_oralb = it.uuid.contains(0xDC, 0x00);
if (!is_oralb)
continue;
if (parse_oralb_data_byte(it.data, result))
success = true;
}
if (!success)
return {};
return result;
}
bool OralbListener::parse_device(const esp32_ble_tracker::ESPBTDevice &device) {
auto res = parse_oralb(device);
if (!res.has_value())
return false;
ESP_LOGD(TAG, "Got OralB (%s):", device.address_str().c_str());
if (res->state.has_value()) {
ESP_LOGD(TAG, " State: %d", *res->state);
}
return true;
}
} // namespace oralb_ble
} // namespace esphome
#endif // USE_ESP32

View File

@@ -0,0 +1,27 @@
#pragma once
#include "esphome/core/component.h"
#include "esphome/components/esp32_ble_tracker/esp32_ble_tracker.h"
#ifdef USE_ESP32
namespace esphome {
namespace oralb_ble {
struct OralbParseResult {
optional<uint8_t> state;
};
bool parse_oralb_data_byte(uint8_t data_type, const uint8_t *data, uint8_t data_length, OralbParseResult &result);
optional<OralbParseResult> parse_oralb(const esp32_ble_tracker::ESPBTDevice &device);
class OralbListener : public esp32_ble_tracker::ESPBTDeviceListener {
public:
bool parse_device(const esp32_ble_tracker::ESPBTDevice &device) override;
};
} // namespace oralb_ble
} // namespace esphome
#endif // USE_ESP32

View File

@@ -0,0 +1,33 @@
#include "oralb_brush.h"
#include "esphome/core/log.h"
#ifdef USE_ESP32
namespace esphome {
namespace oralb_brush {
static const char *const TAG = "oralb_brush";
void OralbBrush::dump_config() {
ESP_LOGCONFIG(TAG, "OralbBrush");
LOG_SENSOR(" ", "State", this->state_);
}
bool OralbBrush::parse_device(const esp32_ble_tracker::ESPBTDevice &device) {
if (device.address_uint64() != this->address_)
return false;
auto res = oralb_ble::parse_oralb(device);
if (!res.has_value())
return false;
if (res->state.has_value() && this->state_ != nullptr)
this->state_->publish_state(*res->state);
return true;
}
} // namespace oralb_brush
} // namespace esphome
#endif // USE_ESP32

View File

@@ -0,0 +1,31 @@
#pragma once
#include "esphome/core/component.h"
#include "esphome/components/sensor/sensor.h"
#include "esphome/components/esp32_ble_tracker/esp32_ble_tracker.h"
#include "esphome/components/oralb_ble/oralb_ble.h"
#ifdef USE_ESP32
namespace esphome {
namespace oralb_brush {
class OralbBrush : public Component, public esp32_ble_tracker::ESPBTDeviceListener {
public:
void set_address(uint64_t address) { address_ = address; }
bool parse_device(const esp32_ble_tracker::ESPBTDevice &device) override;
void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
void set_state(sensor::Sensor *state) { state_ = state; }
protected:
uint64_t address_;
sensor::Sensor *state_{nullptr};
};
} // namespace oralb_brush
} // namespace esphome
#endif // USE_ESP32

View File

@@ -0,0 +1,36 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import sensor, esp32_ble_tracker
from esphome.const import CONF_MAC_ADDRESS, CONF_ID, CONF_STATE
DEPENDENCIES = ["esp32_ble_tracker"]
AUTO_LOAD = ["oralb_ble"]
oralb_brush_ns = cg.esphome_ns.namespace("oralb_brush")
OralbBrush = oralb_brush_ns.class_(
"OralbBrush", esp32_ble_tracker.ESPBTDeviceListener, cg.Component
)
CONFIG_SCHEMA = (
cv.Schema(
{
cv.GenerateID(): cv.declare_id(OralbBrush),
cv.Required(CONF_MAC_ADDRESS): cv.mac_address,
cv.Optional(CONF_STATE): sensor.sensor_schema(accuracy_decimals=0),
}
)
.extend(esp32_ble_tracker.ESP_BLE_DEVICE_SCHEMA)
.extend(cv.COMPONENT_SCHEMA)
)
def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
yield cg.register_component(var, config)
yield esp32_ble_tracker.register_ble_device(var, config)
cg.add(var.set_address(config[CONF_MAC_ADDRESS].as_hex))
if CONF_STATE in config:
sens = yield sensor.new_sensor(config[CONF_STATE])
cg.add(var.set_state(sens))