implemented ruuvi_ble and ruuvitag with RAWv1 and RAWv2 protocol (#810)

* implemented ruuvi_ble and ruuvitag with RAWv1 protocol

fixes esphome/feature-requests#313

* lint

* updated data calculations

* cpp lint

* use string directly in message

Co-Authored-By: Otto Winter <otto@otto-winter.com>

* add RAWv2 protocol support

* fix ICON_SIGNAL

* typo

* calculation correction and cleaning

* c++ lint

* added acceleration and fixed typo

* removed remote_receiver to reduce firmware size

remote_receiver also in test1.yaml
This commit is contained in:
Alexander Leisentritt 2019-11-07 22:10:09 +01:00 committed by Otto Winter
parent 003326f2eb
commit 3e8fd48dc0
10 changed files with 429 additions and 7 deletions

View File

@ -6,7 +6,7 @@ from esphome.const import CONF_ID, ESP_PLATFORM_ESP32, CONF_INTERVAL, \
from esphome.core import coroutine
ESP_PLATFORMS = [ESP_PLATFORM_ESP32]
AUTO_LOAD = ['xiaomi_ble']
AUTO_LOAD = ['xiaomi_ble', 'ruuvi_ble']
CONF_ESP32_BLE_ID = 'esp32_ble_id'
CONF_SCAN_PARAMETERS = 'scan_parameters'

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']
ruuvi_ble_ns = cg.esphome_ns.namespace('ruuvi_ble')
RuuviListener = ruuvi_ble_ns.class_('RuuviListener', esp32_ble_tracker.ESPBTDeviceListener)
CONFIG_SCHEMA = cv.Schema({
cv.GenerateID(): cv.declare_id(RuuviListener),
}).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,147 @@
#include "ruuvi_ble.h"
#include "esphome/core/log.h"
#ifdef ARDUINO_ARCH_ESP32
namespace esphome {
namespace ruuvi_ble {
static const char *TAG = "ruuvi_ble";
bool parse_ruuvi_data_byte(uint8_t data_type, uint8_t data_length, const uint8_t *data, RuuviParseResult &result) {
switch (data_type) {
case 0x03: { // RAWv1
if (data_length != 16)
return false;
const uint8_t temp_sign = (data[1] >> 7) & 1;
const float temp_val = (data[1] & 0x7F) + (data[2] / 100.0f);
const float temperature = temp_sign == 0 ? temp_val : -1 * temp_val;
const float humidity = data[0] * 0.5f;
const float pressure = (uint16_t(data[3] << 8) + uint16_t(data[4]) + 50000.0f) / 100.0f;
const float acceleration_x = (int16_t(data[5] << 8) + int16_t(data[6])) / 1000.0f;
const float acceleration_y = (int16_t(data[7] << 8) + int16_t(data[8])) / 1000.0f;
const float acceleration_z = (int16_t(data[9] << 8) + int16_t(data[10])) / 1000.0f;
const float battery_voltage = (uint16_t(data[11] << 8) + uint16_t(data[12])) / 1000.0f;
result.humidity = humidity;
result.temperature = temperature;
result.pressure = pressure;
result.acceleration_x = acceleration_x;
result.acceleration_y = acceleration_y;
result.acceleration_z = acceleration_z;
result.acceleration =
sqrt(acceleration_x * acceleration_x + acceleration_y * acceleration_y + acceleration_z * acceleration_z);
result.battery_voltage = battery_voltage;
return true;
}
case 0x05: { // RAWv2
if (data_length != 26)
return false;
const float temperature = (int16_t(data[0] << 8) + int16_t(data[1])) * 0.005f;
const float humidity = (uint16_t(data[2] << 8) | uint16_t(data[3])) / 400.0f;
const float pressure = ((uint16_t(data[4] << 8) | uint16_t(data[5])) + 50000.0f) / 100.0f;
const float acceleration_x = (int16_t(data[6] << 8) + int16_t(data[7])) / 1000.0f;
const float acceleration_y = (int16_t(data[8] << 8) + int16_t(data[9])) / 1000.0f;
const float acceleration_z = (int16_t(data[10] << 8) + int16_t(data[11])) / 1000.0f;
const uint8_t power_info = (data[12] << 8) | data[13];
const float battery_voltage = ((power_info >> 5) + 1600.0f) / 1000.0f;
const float tx_power = ((power_info & 0x1F) * 2.0f) - 40.0f;
const float movement_counter = float(data[14]);
const float measurement_sequence_number = float(uint16_t(data[15] << 8) | uint16_t(data[16]));
result.temperature = data[0] == 0x7F && data[1] == 0xFF ? NAN : temperature;
result.humidity = data[2] == 0xFF && data[3] == 0xFF ? NAN : humidity;
result.pressure = data[4] == 0xFF && data[5] == 0xFF ? NAN : pressure;
result.acceleration_x = data[6] == 0xFF && data[7] == 0xFF ? NAN : acceleration_x;
result.acceleration_y = data[8] == 0xFF && data[9] == 0xFF ? NAN : acceleration_y;
result.acceleration_z = data[10] == 0xFF && data[11] == 0xFF ? NAN : acceleration_z;
result.acceleration = result.acceleration_x == NAN || result.acceleration_y == NAN || result.acceleration_z == NAN
? NAN
: sqrt(acceleration_x * acceleration_x + acceleration_y * acceleration_y +
acceleration_z * acceleration_z);
result.battery_voltage = (power_info >> 5) == 0x7FF ? NAN : battery_voltage;
result.tx_power = (power_info & 0x1F) == 0x1F ? NAN : tx_power;
result.movement_counter = movement_counter;
result.measurement_sequence_number = measurement_sequence_number;
return true;
}
default:
return false;
}
}
optional<RuuviParseResult> parse_ruuvi(const esp32_ble_tracker::ESPBTDevice &device) {
const auto *raw = reinterpret_cast<const uint8_t *>(device.get_manufacturer_data().data());
bool is_ruuvi = raw[0] == 0x99 && raw[1] == 0x04;
if (!is_ruuvi) {
return {};
}
const uint8_t data_length = device.get_manufacturer_data().size();
const uint8_t format = raw[2];
const uint8_t *data = &raw[3];
RuuviParseResult result;
bool success = parse_ruuvi_data_byte(format, data_length, data, result);
if (!success)
return {};
return result;
}
bool RuuviListener::parse_device(const esp32_ble_tracker::ESPBTDevice &device) {
auto res = parse_ruuvi(device);
if (!res.has_value())
return false;
ESP_LOGD(TAG, "Got RuuviTag (%s):", device.address_str().c_str());
if (res->humidity.has_value()) {
ESP_LOGD(TAG, " Humidity: %.2f%%", *res->humidity);
}
if (res->temperature.has_value()) {
ESP_LOGD(TAG, " Temperature: %.2f°C", *res->temperature);
}
if (res->pressure.has_value()) {
ESP_LOGD(TAG, " Pressure: %.2fhPa", *res->pressure);
}
if (res->acceleration.has_value()) {
ESP_LOGD(TAG, " Acceleration: %.3fG", *res->acceleration);
}
if (res->acceleration_x.has_value()) {
ESP_LOGD(TAG, " Acceleration X: %.3fG", *res->acceleration_x);
}
if (res->acceleration_y.has_value()) {
ESP_LOGD(TAG, " Acceleration Y: %.3fG", *res->acceleration_y);
}
if (res->acceleration_z.has_value()) {
ESP_LOGD(TAG, " Acceleration Z: %.3fG", *res->acceleration_z);
}
if (res->battery_voltage.has_value()) {
ESP_LOGD(TAG, " Battery Voltage: %.3fV", *res->battery_voltage);
}
if (res->tx_power.has_value()) {
ESP_LOGD(TAG, " TX Power: %.0fdBm", *res->tx_power);
}
if (res->movement_counter.has_value()) {
ESP_LOGD(TAG, " Movement Counter: %.0f", *res->movement_counter);
}
if (res->measurement_sequence_number.has_value()) {
ESP_LOGD(TAG, " Measurement Sequence Number: %.0f", *res->measurement_sequence_number);
}
return true;
}
} // namespace ruuvi_ble
} // namespace esphome
#endif

View File

@ -0,0 +1,37 @@
#pragma once
#include "esphome/core/component.h"
#include "esphome/components/esp32_ble_tracker/esp32_ble_tracker.h"
#ifdef ARDUINO_ARCH_ESP32
namespace esphome {
namespace ruuvi_ble {
struct RuuviParseResult {
optional<float> humidity;
optional<float> temperature;
optional<float> pressure;
optional<float> acceleration;
optional<float> acceleration_x;
optional<float> acceleration_y;
optional<float> acceleration_z;
optional<float> battery_voltage;
optional<float> tx_power;
optional<float> movement_counter;
optional<float> measurement_sequence_number;
};
bool parse_ruuvi_data_byte(uint8_t data_type, const uint8_t *data, uint8_t data_length, RuuviParseResult &result);
optional<RuuviParseResult> parse_ruuvi(const esp32_ble_tracker::ESPBTDevice &device);
class RuuviListener : public esp32_ble_tracker::ESPBTDeviceListener {
public:
bool parse_device(const esp32_ble_tracker::ESPBTDevice &device) override;
};
} // namespace ruuvi_ble
} // namespace esphome
#endif

View File

View File

@ -0,0 +1,29 @@
#include "ruuvitag.h"
#include "esphome/core/log.h"
#ifdef ARDUINO_ARCH_ESP32
namespace esphome {
namespace ruuvitag {
static const char *TAG = "ruuvitag";
void RuuviTag::dump_config() {
ESP_LOGCONFIG(TAG, "RuuviTag");
LOG_SENSOR(" ", "Humidity", this->humidity_);
LOG_SENSOR(" ", "Temperature", this->temperature_);
LOG_SENSOR(" ", "Pressure", this->pressure_);
LOG_SENSOR(" ", "Acceleration", this->acceleration_);
LOG_SENSOR(" ", "Acceleration X", this->acceleration_x_);
LOG_SENSOR(" ", "Acceleration Y", this->acceleration_y_);
LOG_SENSOR(" ", "Acceleration Z", this->acceleration_z_);
LOG_SENSOR(" ", "Battery Voltage", this->battery_voltage_);
LOG_SENSOR(" ", "TX Power", this->tx_power_);
LOG_SENSOR(" ", "Movement Counter", this->movement_counter_);
LOG_SENSOR(" ", "Measurement Sequence Number", this->measurement_sequence_number_);
}
} // namespace ruuvitag
} // namespace esphome
#endif

View File

@ -0,0 +1,84 @@
#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/ruuvi_ble/ruuvi_ble.h"
#ifdef ARDUINO_ARCH_ESP32
namespace esphome {
namespace ruuvitag {
class RuuviTag : 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 {
if (device.address_uint64() != this->address_)
return false;
auto res = ruuvi_ble::parse_ruuvi(device);
if (!res.has_value())
return false;
if (res->humidity.has_value() && this->humidity_ != nullptr)
this->humidity_->publish_state(*res->humidity);
if (res->temperature.has_value() && this->temperature_ != nullptr)
this->temperature_->publish_state(*res->temperature);
if (res->pressure.has_value() && this->pressure_ != nullptr)
this->pressure_->publish_state(*res->pressure);
if (res->acceleration.has_value() && this->acceleration_ != nullptr)
this->acceleration_->publish_state(*res->acceleration);
if (res->acceleration_x.has_value() && this->acceleration_x_ != nullptr)
this->acceleration_x_->publish_state(*res->acceleration_x);
if (res->acceleration_y.has_value() && this->acceleration_y_ != nullptr)
this->acceleration_y_->publish_state(*res->acceleration_y);
if (res->acceleration_z.has_value() && this->acceleration_z_ != nullptr)
this->acceleration_z_->publish_state(*res->acceleration_z);
if (res->battery_voltage.has_value() && this->battery_voltage_ != nullptr)
this->battery_voltage_->publish_state(*res->battery_voltage);
if (res->tx_power.has_value() && this->tx_power_ != nullptr)
this->tx_power_->publish_state(*res->tx_power);
if (res->movement_counter.has_value() && this->movement_counter_ != nullptr)
this->movement_counter_->publish_state(*res->movement_counter);
if (res->measurement_sequence_number.has_value() && this->measurement_sequence_number_ != nullptr)
this->measurement_sequence_number_->publish_state(*res->measurement_sequence_number);
return true;
}
void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
void set_humidity(sensor::Sensor *humidity) { humidity_ = humidity; }
void set_temperature(sensor::Sensor *temperature) { temperature_ = temperature; }
void set_pressure(sensor::Sensor *pressure) { pressure_ = pressure; }
void set_acceleration(sensor::Sensor *acceleration) { acceleration_ = acceleration; }
void set_acceleration_x(sensor::Sensor *acceleration_x) { acceleration_x_ = acceleration_x; }
void set_acceleration_y(sensor::Sensor *acceleration_y) { acceleration_y_ = acceleration_y; }
void set_acceleration_z(sensor::Sensor *acceleration_z) { acceleration_z_ = acceleration_z; }
void set_battery_voltage(sensor::Sensor *battery_voltage) { battery_voltage_ = battery_voltage; }
void set_tx_power(sensor::Sensor *tx_power) { tx_power_ = tx_power; }
void set_movement_counter(sensor::Sensor *movement_counter) { movement_counter_ = movement_counter; }
void set_measurement_sequence_number(sensor::Sensor *measurement_sequence_number) {
measurement_sequence_number_ = measurement_sequence_number;
}
protected:
uint64_t address_;
sensor::Sensor *temperature_{nullptr};
sensor::Sensor *humidity_{nullptr};
sensor::Sensor *pressure_{nullptr};
sensor::Sensor *acceleration_{nullptr};
sensor::Sensor *acceleration_x_{nullptr};
sensor::Sensor *acceleration_y_{nullptr};
sensor::Sensor *acceleration_z_{nullptr};
sensor::Sensor *battery_voltage_{nullptr};
sensor::Sensor *tx_power_{nullptr};
sensor::Sensor *movement_counter_{nullptr};
sensor::Sensor *measurement_sequence_number_{nullptr};
};
} // namespace ruuvitag
} // namespace esphome
#endif

View File

@ -0,0 +1,76 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import sensor, esp32_ble_tracker
from esphome.const import CONF_HUMIDITY, CONF_MAC_ADDRESS, CONF_TEMPERATURE, \
CONF_PRESSURE, CONF_ACCELERATION, CONF_ACCELERATION_X, CONF_ACCELERATION_Y, \
CONF_ACCELERATION_Z, CONF_BATTERY_VOLTAGE, CONF_TX_POWER, \
CONF_MEASUREMENT_SEQUENCE_NUMBER, CONF_MOVEMENT_COUNTER, UNIT_CELSIUS, \
ICON_THERMOMETER, UNIT_PERCENT, UNIT_VOLT, UNIT_HECTOPASCAL, UNIT_G, \
UNIT_DECIBEL_MILLIWATT, UNIT_EMPTY, ICON_WATER_PERCENT, ICON_BATTERY, \
ICON_GAUGE, ICON_ACCELERATION, ICON_ACCELERATION_X, ICON_ACCELERATION_Y, \
ICON_ACCELERATION_Z, ICON_SIGNAL, CONF_ID
DEPENDENCIES = ['esp32_ble_tracker']
AUTO_LOAD = ['ruuvi_ble']
ruuvitag_ns = cg.esphome_ns.namespace('ruuvitag')
RuuviTag = ruuvitag_ns.class_(
'RuuviTag', esp32_ble_tracker.ESPBTDeviceListener, cg.Component)
CONFIG_SCHEMA = cv.Schema({
cv.GenerateID(): cv.declare_id(RuuviTag),
cv.Required(CONF_MAC_ADDRESS): cv.mac_address,
cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema(UNIT_CELSIUS, ICON_THERMOMETER, 2),
cv.Optional(CONF_HUMIDITY): sensor.sensor_schema(UNIT_PERCENT, ICON_WATER_PERCENT, 2),
cv.Optional(CONF_PRESSURE): sensor.sensor_schema(UNIT_HECTOPASCAL, ICON_GAUGE, 2),
cv.Optional(CONF_ACCELERATION): sensor.sensor_schema(UNIT_G, ICON_ACCELERATION, 3),
cv.Optional(CONF_ACCELERATION_X): sensor.sensor_schema(UNIT_G, ICON_ACCELERATION_X, 3),
cv.Optional(CONF_ACCELERATION_Y): sensor.sensor_schema(UNIT_G, ICON_ACCELERATION_Y, 3),
cv.Optional(CONF_ACCELERATION_Z): sensor.sensor_schema(UNIT_G, ICON_ACCELERATION_Z, 3),
cv.Optional(CONF_BATTERY_VOLTAGE): sensor.sensor_schema(UNIT_VOLT, ICON_BATTERY, 3),
cv.Optional(CONF_TX_POWER): sensor.sensor_schema(UNIT_DECIBEL_MILLIWATT, ICON_SIGNAL, 0),
cv.Optional(CONF_MOVEMENT_COUNTER): sensor.sensor_schema(UNIT_EMPTY, ICON_GAUGE, 0),
cv.Optional(CONF_MEASUREMENT_SEQUENCE_NUMBER): sensor.sensor_schema(UNIT_EMPTY, ICON_GAUGE, 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_TEMPERATURE in config:
sens = yield sensor.new_sensor(config[CONF_TEMPERATURE])
cg.add(var.set_temperature(sens))
if CONF_HUMIDITY in config:
sens = yield sensor.new_sensor(config[CONF_HUMIDITY])
cg.add(var.set_humidity(sens))
if CONF_PRESSURE in config:
sens = yield sensor.new_sensor(config[CONF_PRESSURE])
cg.add(var.set_pressure(sens))
if CONF_ACCELERATION in config:
sens = yield sensor.new_sensor(config[CONF_ACCELERATION])
cg.add(var.set_acceleration(sens))
if CONF_ACCELERATION_X in config:
sens = yield sensor.new_sensor(config[CONF_ACCELERATION_X])
cg.add(var.set_acceleration_x(sens))
if CONF_ACCELERATION_Y in config:
sens = yield sensor.new_sensor(config[CONF_ACCELERATION_Y])
cg.add(var.set_acceleration_y(sens))
if CONF_ACCELERATION_Z in config:
sens = yield sensor.new_sensor(config[CONF_ACCELERATION_Z])
cg.add(var.set_acceleration_z(sens))
if CONF_BATTERY_VOLTAGE in config:
sens = yield sensor.new_sensor(config[CONF_BATTERY_VOLTAGE])
cg.add(var.set_battery_voltage(sens))
if CONF_TX_POWER in config:
sens = yield sensor.new_sensor(config[CONF_TX_POWER])
cg.add(var.set_tx_power(sens))
if CONF_MOVEMENT_COUNTER in config:
sens = yield sensor.new_sensor(config[CONF_MOVEMENT_COUNTER])
cg.add(var.set_movement_counter(sens))
if CONF_MEASUREMENT_SEQUENCE_NUMBER in config:
sens = yield sensor.new_sensor(config[CONF_MEASUREMENT_SEQUENCE_NUMBER])
cg.add(var.set_measurement_sequence_number(sens))

View File

@ -29,6 +29,9 @@ HEADER_FILE_EXTENSIONS = {'.h', '.hpp', '.tcc'}
CONF_ABOVE = 'above'
CONF_ACCELERATION = 'acceleration'
CONF_ACCELERATION_X = 'acceleration_x'
CONF_ACCELERATION_Y = 'acceleration_y'
CONF_ACCELERATION_Z = 'acceleration_z'
CONF_ACCURACY = 'accuracy'
CONF_ACCURACY_DECIMALS = 'accuracy_decimals'
CONF_ACTION_ID = 'action_id'
@ -47,6 +50,7 @@ CONF_AVAILABILITY = 'availability'
CONF_AWAY = 'away'
CONF_AWAY_CONFIG = 'away_config'
CONF_BATTERY_LEVEL = 'battery_level'
CONF_BATTERY_VOLTAGE = 'battery_voltage'
CONF_BAUD_RATE = 'baud_rate'
CONF_BELOW = 'below'
CONF_BINARY = 'binary'
@ -239,6 +243,7 @@ CONF_MAX_TEMPERATURE = 'max_temperature'
CONF_MAX_VALUE = 'max_value'
CONF_MAX_VOLTAGE = 'max_voltage'
CONF_MEASUREMENT_DURATION = 'measurement_duration'
CONF_MEASUREMENT_SEQUENCE_NUMBER = 'measurement_sequence_number'
CONF_MEDIUM = 'medium'
CONF_METHOD = 'method'
CONF_MIN_LENGTH = 'min_length'
@ -254,6 +259,7 @@ CONF_MODEL = 'model'
CONF_MOISTURE = 'moisture'
CONF_MONTHS = 'months'
CONF_MOSI_PIN = 'mosi_pin'
CONF_MOVEMENT_COUNTER = 'movement_counter'
CONF_MQTT = 'mqtt'
CONF_MQTT_ID = 'mqtt_id'
CONF_MULTIPLEXER = 'multiplexer'
@ -449,6 +455,7 @@ CONF_TURN_OFF_ACTION = 'turn_off_action'
CONF_TURN_ON_ACTION = 'turn_on_action'
CONF_TX_BUFFER_SIZE = 'tx_buffer_size'
CONF_TX_PIN = 'tx_pin'
CONF_TX_POWER = 'tx_power'
CONF_TYPE = 'type'
CONF_TYPE_ID = 'type_id'
CONF_UART_ID = 'uart_id'
@ -483,6 +490,10 @@ CONF_WIND_SPEED = 'wind_speed'
CONF_WINDOW_SIZE = 'window_size'
CONF_ZERO = 'zero'
ICON_ACCELERATION = 'mdi:axis-arrow'
ICON_ACCELERATION_X = 'mdi:axis-x-arrow'
ICON_ACCELERATION_Y = 'mdi:axis-y-arrow'
ICON_ACCELERATION_Z = 'mdi:axis-z-arrow'
ICON_ARROW_EXPAND_VERTICAL = 'mdi:arrow-expand-vertical'
ICON_BATTERY = 'mdi:battery'
ICON_BRIEFCASE_DOWNLOAD = 'mdi:briefcase-download'
@ -508,7 +519,7 @@ ICON_ROTATE_RIGHT = 'mdi:rotate-right'
ICON_SCALE = 'mdi:scale'
ICON_SCREEN_ROTATION = 'mdi:screen-rotation'
ICON_SIGN_DIRECTION = 'mdi:sign-direction'
ICON_SIGNAL = 'mdi: signal-distance-variant'
ICON_SIGNAL = 'mdi:signal-distance-variant'
ICON_SIGNAL_DISTANCE_VARIANT = 'mdi:signal'
ICON_THERMOMETER = 'mdi:thermometer'
ICON_TIMER = 'mdi:timer'
@ -522,9 +533,11 @@ ICON_WIFI = 'mdi:wifi'
UNIT_AMPERE = 'A'
UNIT_CELSIUS = u'°C'
UNIT_DECIBEL = 'dB'
UNIT_DECIBEL_MILLIWATT = 'dBm'
UNIT_DEGREE_PER_SECOND = u'°/s'
UNIT_DEGREES = u'°'
UNIT_EMPTY = ''
UNIT_G = 'G'
UNIT_HECTOPASCAL = 'hPa'
UNIT_HZ = 'hz'
UNIT_KELVIN = 'K'

View File

@ -95,7 +95,7 @@ sensor:
temperature:
name: "Xiaomi LYWSD02 Temperature"
humidity:
name: "Xiaomi LYWSD02 Humidity"
name: "Xiaomi LYWSD02 Humidity"
- platform: xiaomi_cgg1
mac_address: 7A:80:8E:19:36:BA
temperature:
@ -160,6 +160,28 @@ sensor:
name: "Lightning Energy"
distance:
name: "Distance Storm"
- platform: ruuvitag
mac_address: FF:56:D3:2F:7D:E8
humidity:
name: "RuuviTag Humidity"
temperature:
name: "RuuviTag Temperature"
pressure:
name: "RuuviTag Pressure"
acceleration_x:
name: "RuuviTag Acceleration X"
acceleration_y:
name: "RuuviTag Acceleration Y"
acceleration_z:
name: "RuuviTag Acceleration Z"
battery_voltage:
name: "RuuviTag Battery Voltage"
tx_power:
name: "RuuviTag TX Power"
movement_counter:
name: "RuuviTag Movement Counter"
measurement_sequence_number:
name: "RuuviTag Measurement Sequence Number"
time:
- platform: homeassistant
@ -210,10 +232,6 @@ binary_sensor:
- platform: as3935
name: "Storm Alert"
remote_receiver:
pin: GPIO32
dump: []
esp32_ble_tracker:
#esp32_ble_beacon: