Merge branch 'dev' into optolink

This commit is contained in:
j0ta29 2023-03-31 09:27:17 +02:00 committed by GitHub
commit 99e01efdec
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
52 changed files with 477 additions and 121 deletions

View File

@ -0,0 +1,60 @@
---
name: Synchronise Device Classes from Home Assistant
on:
workflow_dispatch:
schedule:
- cron: '45 6 * * *'
permissions:
contents: write
pull-requests: write
jobs:
sync:
name: Sync Device Classes
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Checkout Home Assistant
uses: actions/checkout@v3
with:
repository: home-assistant/core
path: lib/home-assistant
- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: 3.11
- name: Install Home Assistant
run: |
python -m pip install --upgrade pip
pip install -e lib/home-assistant
- name: Sync
run: |
python ./script/sync-device_class.py
- name: Get PR template
id: pr-template-body
run: |
body=$(cat .github/PULL_REQUEST_TEMPLATE.md)
delimiter="$(openssl rand -hex 8)"
echo "body<<$delimiter" >> $GITHUB_OUTPUT
echo "$body" >> $GITHUB_OUTPUT
echo "$delimiter" >> $GITHUB_OUTPUT
- name: Commit changes
uses: peter-evans/create-pull-request@v4
with:
commit-message: "Synchronise Device Classes from Home Assistant"
committer: esphomebot <esphome@nabucasa.com>
author: esphomebot <esphome@nabucasa.com>
branch: sync/device-classes/
branch-suffix: timestamp
delete-branch: true
title: "Synchronise Device Classes from Home Assistant"
body: ${{ steps.pr-template-body.outputs.body }}

View File

@ -53,6 +53,8 @@ service APIConnection {
rpc bluetooth_gatt_write_descriptor(BluetoothGATTWriteDescriptorRequest) returns (void) {}
rpc bluetooth_gatt_notify(BluetoothGATTNotifyRequest) returns (void) {}
rpc subscribe_bluetooth_connections_free(SubscribeBluetoothConnectionsFreeRequest) returns (BluetoothConnectionsFreeResponse) {}
rpc unsubscribe_bluetooth_le_advertisements(UnsubscribeBluetoothLEAdvertisementsRequest) returns (void) {}
}
@ -1125,6 +1127,7 @@ message MediaPlayerCommandRequest {
message SubscribeBluetoothLEAdvertisementsRequest {
option (id) = 66;
option (source) = SOURCE_CLIENT;
option (ifdef) = "USE_BLUETOOTH_PROXY";
}
message BluetoothServiceData {
@ -1361,6 +1364,12 @@ message BluetoothDeviceUnpairingResponse {
int32 error = 3;
}
message UnsubscribeBluetoothLEAdvertisementsRequest {
option (id) = 87;
option (source) = SOURCE_CLIENT;
option (ifdef) = "USE_BLUETOOTH_PROXY";
}
message BluetoothDeviceClearCacheResponse {
option (id) = 88;
option (source) = SOURCE_SERVER;

View File

@ -97,6 +97,12 @@ class APIConnection : public APIServerConnection {
this->send_homeassistant_service_response(call);
}
#ifdef USE_BLUETOOTH_PROXY
void subscribe_bluetooth_le_advertisements(const SubscribeBluetoothLEAdvertisementsRequest &msg) override {
this->bluetooth_le_advertisement_subscription_ = true;
}
void unsubscribe_bluetooth_le_advertisements(const UnsubscribeBluetoothLEAdvertisementsRequest &msg) override {
this->bluetooth_le_advertisement_subscription_ = false;
}
bool send_bluetooth_le_advertisement(const BluetoothLEAdvertisementResponse &msg);
void bluetooth_device_request(const BluetoothDeviceRequest &msg) override;
@ -150,9 +156,7 @@ class APIConnection : public APIServerConnection {
return {};
}
void execute_service(const ExecuteServiceRequest &msg) override;
void subscribe_bluetooth_le_advertisements(const SubscribeBluetoothLEAdvertisementsRequest &msg) override {
this->bluetooth_le_advertisement_subscription_ = true;
}
bool is_authenticated() override { return this->connection_state_ == ConnectionState::AUTHENTICATED; }
bool is_connection_setup() override {
return this->connection_state_ == ConnectionState ::CONNECTED || this->is_authenticated();
@ -197,7 +201,9 @@ class APIConnection : public APIServerConnection {
uint32_t last_traffic_;
bool sent_ping_{false};
bool service_call_subscription_{false};
#ifdef USE_BLUETOOTH_PROXY
bool bluetooth_le_advertisement_subscription_{false};
#endif
bool next_close_ = false;
APIServer *parent_;
InitialStateIterator initial_state_iterator_;

View File

@ -6062,6 +6062,12 @@ void BluetoothDeviceUnpairingResponse::dump_to(std::string &out) const {
out.append("}");
}
#endif
void UnsubscribeBluetoothLEAdvertisementsRequest::encode(ProtoWriteBuffer buffer) const {}
#ifdef HAS_PROTO_MESSAGE_DUMP
void UnsubscribeBluetoothLEAdvertisementsRequest::dump_to(std::string &out) const {
out.append("UnsubscribeBluetoothLEAdvertisementsRequest {}");
}
#endif
bool BluetoothDeviceClearCacheResponse::decode_varint(uint32_t field_id, ProtoVarInt value) {
switch (field_id) {
case 1: {

View File

@ -1555,6 +1555,15 @@ class BluetoothDeviceUnpairingResponse : public ProtoMessage {
protected:
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
};
class UnsubscribeBluetoothLEAdvertisementsRequest : public ProtoMessage {
public:
void encode(ProtoWriteBuffer buffer) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
#endif
protected:
};
class BluetoothDeviceClearCacheResponse : public ProtoMessage {
public:
uint64_t address{0};

View File

@ -329,6 +329,8 @@ bool APIServerConnectionBase::send_media_player_state_response(const MediaPlayer
#ifdef USE_MEDIA_PLAYER
#endif
#ifdef USE_BLUETOOTH_PROXY
#endif
#ifdef USE_BLUETOOTH_PROXY
bool APIServerConnectionBase::send_bluetooth_le_advertisement_response(const BluetoothLEAdvertisementResponse &msg) {
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "send_bluetooth_le_advertisement_response: %s", msg.dump().c_str());
@ -442,6 +444,8 @@ bool APIServerConnectionBase::send_bluetooth_device_unpairing_response(const Blu
}
#endif
#ifdef USE_BLUETOOTH_PROXY
#endif
#ifdef USE_BLUETOOTH_PROXY
bool APIServerConnectionBase::send_bluetooth_device_clear_cache_response(const BluetoothDeviceClearCacheResponse &msg) {
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "send_bluetooth_device_clear_cache_response: %s", msg.dump().c_str());
@ -717,12 +721,14 @@ bool APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
break;
}
case 66: {
#ifdef USE_BLUETOOTH_PROXY
SubscribeBluetoothLEAdvertisementsRequest msg;
msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_subscribe_bluetooth_le_advertisements_request: %s", msg.dump().c_str());
#endif
this->on_subscribe_bluetooth_le_advertisements_request(msg);
#endif
break;
}
case 68: {
@ -810,6 +816,17 @@ bool APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
ESP_LOGVV(TAG, "on_subscribe_bluetooth_connections_free_request: %s", msg.dump().c_str());
#endif
this->on_subscribe_bluetooth_connections_free_request(msg);
#endif
break;
}
case 87: {
#ifdef USE_BLUETOOTH_PROXY
UnsubscribeBluetoothLEAdvertisementsRequest msg;
msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_unsubscribe_bluetooth_le_advertisements_request: %s", msg.dump().c_str());
#endif
this->on_unsubscribe_bluetooth_le_advertisements_request(msg);
#endif
break;
}
@ -1073,6 +1090,7 @@ void APIServerConnection::on_media_player_command_request(const MediaPlayerComma
this->media_player_command(msg);
}
#endif
#ifdef USE_BLUETOOTH_PROXY
void APIServerConnection::on_subscribe_bluetooth_le_advertisements_request(
const SubscribeBluetoothLEAdvertisementsRequest &msg) {
if (!this->is_connection_setup()) {
@ -1085,6 +1103,7 @@ void APIServerConnection::on_subscribe_bluetooth_le_advertisements_request(
}
this->subscribe_bluetooth_le_advertisements(msg);
}
#endif
#ifdef USE_BLUETOOTH_PROXY
void APIServerConnection::on_bluetooth_device_request(const BluetoothDeviceRequest &msg) {
if (!this->is_connection_setup()) {
@ -1193,6 +1212,20 @@ void APIServerConnection::on_subscribe_bluetooth_connections_free_request(
}
}
#endif
#ifdef USE_BLUETOOTH_PROXY
void APIServerConnection::on_unsubscribe_bluetooth_le_advertisements_request(
const UnsubscribeBluetoothLEAdvertisementsRequest &msg) {
if (!this->is_connection_setup()) {
this->on_no_setup_connection();
return;
}
if (!this->is_authenticated()) {
this->on_unauthenticated_access();
return;
}
this->unsubscribe_bluetooth_le_advertisements(msg);
}
#endif
} // namespace api
} // namespace esphome

View File

@ -154,8 +154,10 @@ class APIServerConnectionBase : public ProtoService {
#ifdef USE_MEDIA_PLAYER
virtual void on_media_player_command_request(const MediaPlayerCommandRequest &value){};
#endif
#ifdef USE_BLUETOOTH_PROXY
virtual void on_subscribe_bluetooth_le_advertisements_request(
const SubscribeBluetoothLEAdvertisementsRequest &value){};
#endif
#ifdef USE_BLUETOOTH_PROXY
bool send_bluetooth_le_advertisement_response(const BluetoothLEAdvertisementResponse &msg);
#endif
@ -216,6 +218,10 @@ class APIServerConnectionBase : public ProtoService {
#ifdef USE_BLUETOOTH_PROXY
bool send_bluetooth_device_unpairing_response(const BluetoothDeviceUnpairingResponse &msg);
#endif
#ifdef USE_BLUETOOTH_PROXY
virtual void on_unsubscribe_bluetooth_le_advertisements_request(
const UnsubscribeBluetoothLEAdvertisementsRequest &value){};
#endif
#ifdef USE_BLUETOOTH_PROXY
bool send_bluetooth_device_clear_cache_response(const BluetoothDeviceClearCacheResponse &msg);
#endif
@ -270,7 +276,9 @@ class APIServerConnection : public APIServerConnectionBase {
#ifdef USE_MEDIA_PLAYER
virtual void media_player_command(const MediaPlayerCommandRequest &msg) = 0;
#endif
#ifdef USE_BLUETOOTH_PROXY
virtual void subscribe_bluetooth_le_advertisements(const SubscribeBluetoothLEAdvertisementsRequest &msg) = 0;
#endif
#ifdef USE_BLUETOOTH_PROXY
virtual void bluetooth_device_request(const BluetoothDeviceRequest &msg) = 0;
#endif
@ -295,6 +303,9 @@ class APIServerConnection : public APIServerConnectionBase {
#ifdef USE_BLUETOOTH_PROXY
virtual BluetoothConnectionsFreeResponse subscribe_bluetooth_connections_free(
const SubscribeBluetoothConnectionsFreeRequest &msg) = 0;
#endif
#ifdef USE_BLUETOOTH_PROXY
virtual void unsubscribe_bluetooth_le_advertisements(const UnsubscribeBluetoothLEAdvertisementsRequest &msg) = 0;
#endif
protected:
void on_hello_request(const HelloRequest &msg) override;
@ -342,7 +353,9 @@ class APIServerConnection : public APIServerConnectionBase {
#ifdef USE_MEDIA_PLAYER
void on_media_player_command_request(const MediaPlayerCommandRequest &msg) override;
#endif
#ifdef USE_BLUETOOTH_PROXY
void on_subscribe_bluetooth_le_advertisements_request(const SubscribeBluetoothLEAdvertisementsRequest &msg) override;
#endif
#ifdef USE_BLUETOOTH_PROXY
void on_bluetooth_device_request(const BluetoothDeviceRequest &msg) override;
#endif
@ -367,6 +380,10 @@ class APIServerConnection : public APIServerConnectionBase {
#ifdef USE_BLUETOOTH_PROXY
void on_subscribe_bluetooth_connections_free_request(const SubscribeBluetoothConnectionsFreeRequest &msg) override;
#endif
#ifdef USE_BLUETOOTH_PROXY
void on_unsubscribe_bluetooth_le_advertisements_request(
const UnsubscribeBluetoothLEAdvertisementsRequest &msg) override;
#endif
};
} // namespace api

View File

@ -12,7 +12,6 @@ from esphome.const import (
CONF_CAPACITANCE,
)
AUTO_LOAD = ["sensor", "binary_sensor"]
MULTI_CONF = True
CONF_AS3935_ID = "as3935_id"

View File

@ -26,9 +26,13 @@ void AS3935Component::setup() {
void AS3935Component::dump_config() {
ESP_LOGCONFIG(TAG, "AS3935:");
LOG_PIN(" Interrupt Pin: ", this->irq_pin_);
#ifdef USE_BINARY_SENSOR
LOG_BINARY_SENSOR(" ", "Thunder alert", this->thunder_alert_binary_sensor_);
#endif
#ifdef USE_SENSOR
LOG_SENSOR(" ", "Distance", this->distance_sensor_);
LOG_SENSOR(" ", "Lightning energy", this->energy_sensor_);
#endif
}
float AS3935Component::get_setup_priority() const { return setup_priority::DATA; }
@ -44,16 +48,22 @@ void AS3935Component::loop() {
ESP_LOGI(TAG, "Disturber was detected - try increasing the spike rejection value!");
} else if (int_value == LIGHTNING_INT) {
ESP_LOGI(TAG, "Lightning has been detected!");
if (this->thunder_alert_binary_sensor_ != nullptr)
#ifdef USE_BINARY_SENSOR
if (this->thunder_alert_binary_sensor_ != nullptr) {
this->thunder_alert_binary_sensor_->publish_state(true);
this->set_timeout(10, [this]() { this->thunder_alert_binary_sensor_->publish_state(false); });
}
#endif
#ifdef USE_SENSOR
uint8_t distance = this->get_distance_to_storm_();
if (this->distance_sensor_ != nullptr)
this->distance_sensor_->publish_state(distance);
uint32_t energy = this->get_lightning_energy_();
if (this->energy_sensor_ != nullptr)
this->energy_sensor_->publish_state(energy);
#endif
}
this->thunder_alert_binary_sensor_->publish_state(false);
}
void AS3935Component::write_indoor(bool indoor) {

View File

@ -1,9 +1,14 @@
#pragma once
#include "esphome/core/component.h"
#include "esphome/core/defines.h"
#include "esphome/core/hal.h"
#ifdef USE_SENSOR
#include "esphome/components/sensor/sensor.h"
#endif
#ifdef USE_BINARY_SENSOR
#include "esphome/components/binary_sensor/binary_sensor.h"
#endif
namespace esphome {
namespace as3935 {
@ -52,6 +57,15 @@ enum AS3935Values {
};
class AS3935Component : public Component {
#ifdef USE_SENSOR
SUB_SENSOR(distance)
SUB_SENSOR(energy)
#endif
#ifdef USE_BINARY_SENSOR
SUB_BINARY_SENSOR(thunder_alert)
#endif
public:
void setup() override;
void dump_config() override;
@ -59,11 +73,7 @@ class AS3935Component : public Component {
void loop() override;
void set_irq_pin(GPIOPin *irq_pin) { irq_pin_ = irq_pin; }
void set_distance_sensor(sensor::Sensor *distance_sensor) { distance_sensor_ = distance_sensor; }
void set_energy_sensor(sensor::Sensor *energy_sensor) { energy_sensor_ = energy_sensor; }
void set_thunder_alert_binary_sensor(binary_sensor::BinarySensor *thunder_alert_binary_sensor) {
thunder_alert_binary_sensor_ = thunder_alert_binary_sensor;
}
void set_indoor(bool indoor) { indoor_ = indoor; }
void write_indoor(bool indoor);
void set_noise_level(uint8_t noise_level) { noise_level_ = noise_level; }
@ -92,9 +102,6 @@ class AS3935Component : public Component {
virtual void write_register(uint8_t reg, uint8_t mask, uint8_t bits, uint8_t start_position) = 0;
sensor::Sensor *distance_sensor_{nullptr};
sensor::Sensor *energy_sensor_{nullptr};
binary_sensor::BinarySensor *thunder_alert_binary_sensor_{nullptr};
GPIOPin *irq_pin_;
bool indoor_;

View File

@ -30,7 +30,7 @@ void BinarySensorMap::process_group_() {
if (bs.binary_sensor->state) {
num_active_sensors++;
total_current_value += bs.sensor_value;
mask |= 1 << i;
mask |= 1ULL << i;
}
}
// check if the sensor map was touched
@ -38,12 +38,11 @@ void BinarySensorMap::process_group_() {
// did the bit_mask change or is it a new sensor touch
if (this->last_mask_ != mask) {
float publish_value = total_current_value / num_active_sensors;
ESP_LOGD(TAG, "'%s' - Publishing %.2f", this->name_.c_str(), publish_value);
this->publish_state(publish_value);
}
} else if (this->last_mask_ != 0ULL) {
// is this a new sensor release
ESP_LOGD(TAG, "'%s' - No binary sensor active, publishing NAN", this->name_.c_str());
ESP_LOGV(TAG, "'%s' - No binary sensor active, publishing NAN", this->name_.c_str());
this->publish_state(NAN);
}
this->last_mask_ = mask;
@ -52,28 +51,22 @@ void BinarySensorMap::process_group_() {
void BinarySensorMap::process_sum_() {
float total_current_value = 0.0;
uint64_t mask = 0x00;
// check all binary_sensors for its state. when active add its value to total_current_value.
// create a bitmask for the binary_sensor status on all channels
// - check all binary_sensor states
// - if active, add its value to total_current_value
// - creates a bitmask for the binary_sensor status on all channels
for (size_t i = 0; i < this->channels_.size(); i++) {
auto bs = this->channels_[i];
if (bs.binary_sensor->state) {
total_current_value += bs.sensor_value;
mask |= 1 << i;
mask |= 1ULL << i;
}
}
// check if the sensor map was touched
if (mask != 0ULL) {
// did the bit_mask change or is it a new sensor touch
if (this->last_mask_ != mask) {
float publish_value = total_current_value;
ESP_LOGD(TAG, "'%s' - Publishing %.2f", this->name_.c_str(), publish_value);
this->publish_state(publish_value);
}
} else if (this->last_mask_ != 0ULL) {
// is this a new sensor release
ESP_LOGD(TAG, "'%s' - No binary sensor active, publishing 0", this->name_.c_str());
this->publish_state(0.0);
// update state only if the binary sensor states have changed or if no state has ever been sent on boot
if ((this->last_mask_ != mask) || (!this->has_state())) {
this->publish_state(total_current_value);
}
this->last_mask_ = mask;
}

View File

@ -39,7 +39,7 @@ CONFIG_SCHEMA = cv.typed_schema(
).extend(
{
cv.Required(CONF_CHANNELS): cv.All(
cv.ensure_list(entry), cv.Length(min=1)
cv.ensure_list(entry), cv.Length(min=1, max=64)
),
}
),
@ -50,7 +50,7 @@ CONFIG_SCHEMA = cv.typed_schema(
).extend(
{
cv.Required(CONF_CHANNELS): cv.All(
cv.ensure_list(entry), cv.Length(min=1)
cv.ensure_list(entry), cv.Length(min=1, max=64)
),
}
),

View File

@ -6,9 +6,6 @@ namespace button {
static const char *const TAG = "button";
Button::Button(const std::string &name) : EntityBase(name) {}
Button::Button() : Button("") {}
void Button::press() {
ESP_LOGD(TAG, "'%s' Pressed.", this->get_name().c_str());
this->press_action();

View File

@ -28,9 +28,6 @@ namespace button {
*/
class Button : public EntityBase {
public:
explicit Button();
explicit Button(const std::string &name);
/** Press this button. This is called by the front-end.
*
* For implementing buttons, please override press_action.

View File

@ -453,12 +453,7 @@ void Climate::set_visual_temperature_step_override(float target, float current)
this->visual_target_temperature_step_override_ = target;
this->visual_current_temperature_step_override_ = current;
}
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
Climate::Climate(const std::string &name) : EntityBase(name) {}
#pragma GCC diagnostic pop
Climate::Climate() : Climate("") {}
ClimateCall Climate::make_call() { return ClimateCall(this); }
ClimateCall ClimateDeviceRestoreState::to_call(Climate *climate) {

View File

@ -166,11 +166,6 @@ struct ClimateDeviceRestoreState {
*/
class Climate : public EntityBase {
public:
/// Construct a climate device with empty name (will be set later).
Climate();
/// Construct a climate device with a name.
Climate(const std::string &name);
/// The active mode of the climate device.
ClimateMode mode{CLIMATE_MODE_OFF};
/// The active state of the climate device.

View File

@ -31,7 +31,7 @@ const char *cover_operation_to_str(CoverOperation op) {
}
}
Cover::Cover(const std::string &name) : EntityBase(name), position{COVER_OPEN} {}
Cover::Cover() : position{COVER_OPEN} {}
CoverCall::CoverCall(Cover *parent) : parent_(parent) {}
CoverCall &CoverCall::set_command(const char *command) {
@ -204,7 +204,6 @@ optional<CoverRestoreState> Cover::restore_state_() {
return {};
return recovered;
}
Cover::Cover() : Cover("") {}
std::string Cover::get_device_class() {
if (this->device_class_override_.has_value())
return *this->device_class_override_;

View File

@ -111,7 +111,6 @@ const char *cover_operation_to_str(CoverOperation op);
class Cover : public EntityBase {
public:
explicit Cover();
explicit Cover(const std::string &name);
/// The current operation of the cover (idle, opening, closing).
CoverOperation current_operation{COVER_OPERATION_IDLE};

View File

@ -6,6 +6,7 @@
#include <esp_bt.h>
#include <esp_bt_main.h>
#include <esp_bt_device.h>
#include <esp_gap_ble_api.h>
#include <freertos/FreeRTOS.h>
#include <freertos/FreeRTOSConfig.h>
@ -211,7 +212,16 @@ void ESP32BLE::real_gattc_event_handler_(esp_gattc_cb_event_t event, esp_gatt_if
float ESP32BLE::get_setup_priority() const { return setup_priority::BLUETOOTH; }
void ESP32BLE::dump_config() { ESP_LOGCONFIG(TAG, "ESP32 BLE:"); }
void ESP32BLE::dump_config() {
const uint8_t *mac_address = esp_bt_dev_get_address();
if (mac_address) {
ESP_LOGCONFIG(TAG, "ESP32 BLE:");
ESP_LOGCONFIG(TAG, " MAC address: %02X:%02X:%02X:%02X:%02X:%02X", mac_address[0], mac_address[1], mac_address[2],
mac_address[3], mac_address[4], mac_address[5]);
} else {
ESP_LOGCONFIG(TAG, "ESP32 BLE: bluetooth stack is not enabled");
}
}
ESP32BLE *global_ble = nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)

View File

@ -202,7 +202,7 @@ void ESP32Camera::loop() {
float ESP32Camera::get_setup_priority() const { return setup_priority::DATA; }
/* ---------------- constructors ---------------- */
ESP32Camera::ESP32Camera(const std::string &name) : EntityBase(name) {
ESP32Camera::ESP32Camera() {
this->config_.pin_pwdn = -1;
this->config_.pin_reset = -1;
this->config_.pin_xclk = -1;
@ -215,7 +215,6 @@ ESP32Camera::ESP32Camera(const std::string &name) : EntityBase(name) {
global_esp32_camera = this;
}
ESP32Camera::ESP32Camera() : ESP32Camera("") {}
/* ---------------- setters ---------------- */
/* set pin assignment */

View File

@ -103,7 +103,6 @@ class CameraImageReader {
/* ---------------- ESP32Camera class ---------------- */
class ESP32Camera : public Component, public EntityBase {
public:
ESP32Camera(const std::string &name);
ESP32Camera();
/* setters */

View File

@ -12,14 +12,14 @@ static const char *const TAG = "ezo.sensor";
enum EzoCommandType : uint8_t {
EZO_READ = 0,
EZO_LED = 1,
EZO_DEVICE_INFORMATION = 2,
EZO_SLOPE = 3,
EZO_LED,
EZO_DEVICE_INFORMATION,
EZO_SLOPE,
EZO_CALIBRATION,
EZO_SLEEP = 4,
EZO_I2C = 5,
EZO_T = 6,
EZO_CUSTOM = 7
EZO_SLEEP,
EZO_I2C,
EZO_T,
EZO_CUSTOM
};
enum EzoCalibrationType : uint8_t { EZO_CAL_LOW = 0, EZO_CAL_MID = 1, EZO_CAL_HIGH = 2 };

View File

@ -80,9 +80,6 @@ void FanRestoreState::apply(Fan &fan) {
fan.publish_state();
}
Fan::Fan() : EntityBase("") {}
Fan::Fan(const std::string &name) : EntityBase(name) {}
FanCall Fan::turn_on() { return this->make_call().set_state(true); }
FanCall Fan::turn_off() { return this->make_call().set_state(false); }
FanCall Fan::toggle() { return this->make_call().set_state(!this->state); }

View File

@ -99,10 +99,6 @@ struct FanRestoreState {
class Fan : public EntityBase {
public:
Fan();
/// Construct the fan with name.
explicit Fan(const std::string &name);
/// The current on/off state of the fan.
bool state{false};
/// The current oscillation state of the fan.

View File

@ -15,7 +15,6 @@ enum ESPDEPRECATED("LegacyFanDirection members are deprecated, use FanDirection
class ESPDEPRECATED("FanState is deprecated, use Fan instead.", "2022.2") FanState : public Fan, public Component {
public:
FanState() = default;
explicit FanState(const std::string &name) : Fan(name) {}
/// Get the traits of this fan.
FanTraits get_traits() override { return this->traits_; }

View File

@ -8,7 +8,6 @@ namespace light {
static const char *const TAG = "light";
LightState::LightState(const std::string &name, LightOutput *output) : EntityBase(name), output_(output) {}
LightState::LightState(LightOutput *output) : output_(output) {}
LightTraits LightState::get_traits() { return this->output_->get_traits(); }

View File

@ -33,9 +33,6 @@ enum LightRestoreMode {
*/
class LightState : public EntityBase, public Component {
public:
/// Construct this LightState using the provided traits and name.
LightState(const std::string &name, LightOutput *output);
LightState(LightOutput *output);
LightTraits get_traits();

View File

@ -24,8 +24,7 @@ const char *lock_state_to_string(LockState state) {
}
}
Lock::Lock(const std::string &name) : EntityBase(name), state(LOCK_STATE_NONE) {}
Lock::Lock() : Lock("") {}
Lock::Lock() : state(LOCK_STATE_NONE) {}
LockCall Lock::make_call() { return LockCall(this); }
void Lock::lock() {

View File

@ -103,7 +103,6 @@ class LockCall {
class Lock : public EntityBase {
public:
explicit Lock();
explicit Lock(const std::string &name);
/** Make a lock device control call, this is used to control the lock device, see the LockCall description
* for more info.

View File

@ -31,6 +31,7 @@ from esphome.const import (
DEVICE_CLASS_DISTANCE,
DEVICE_CLASS_EMPTY,
DEVICE_CLASS_ENERGY,
DEVICE_CLASS_ENERGY_STORAGE,
DEVICE_CLASS_FREQUENCY,
DEVICE_CLASS_GAS,
DEVICE_CLASS_HUMIDITY,
@ -59,6 +60,7 @@ from esphome.const import (
DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS,
DEVICE_CLASS_VOLTAGE,
DEVICE_CLASS_VOLUME,
DEVICE_CLASS_VOLUME_STORAGE,
DEVICE_CLASS_WATER,
DEVICE_CLASS_WEIGHT,
DEVICE_CLASS_WIND_SPEED,
@ -81,6 +83,7 @@ DEVICE_CLASSES = [
DEVICE_CLASS_DISTANCE,
DEVICE_CLASS_EMPTY,
DEVICE_CLASS_ENERGY,
DEVICE_CLASS_ENERGY_STORAGE,
DEVICE_CLASS_FREQUENCY,
DEVICE_CLASS_GAS,
DEVICE_CLASS_HUMIDITY,
@ -109,6 +112,7 @@ DEVICE_CLASSES = [
DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS,
DEVICE_CLASS_VOLTAGE,
DEVICE_CLASS_VOLUME,
DEVICE_CLASS_VOLUME_STORAGE,
DEVICE_CLASS_WATER,
DEVICE_CLASS_WEIGHT,
DEVICE_CLASS_WIND_SPEED,

View File

@ -102,7 +102,7 @@ async def to_code(config):
conf[CONF_ADDRESSABLE_LIGHT_ID],
await cg.get_variable(conf[CONF_SINGLE_LIGHT_ID]),
)
light_state = cg.new_Pvariable(conf[CONF_LIGHT_ID], "", wrapper)
light_state = cg.new_Pvariable(conf[CONF_LIGHT_ID], wrapper)
await cg.register_component(light_state, conf)
segments.append(AddressableSegment(light_state, 0, 1, False))

View File

@ -43,6 +43,7 @@ from esphome.const import (
DEVICE_CLASS_DURATION,
DEVICE_CLASS_EMPTY,
DEVICE_CLASS_ENERGY,
DEVICE_CLASS_ENERGY_STORAGE,
DEVICE_CLASS_FREQUENCY,
DEVICE_CLASS_GAS,
DEVICE_CLASS_HUMIDITY,
@ -72,6 +73,7 @@ from esphome.const import (
DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS,
DEVICE_CLASS_VOLTAGE,
DEVICE_CLASS_VOLUME,
DEVICE_CLASS_VOLUME_STORAGE,
DEVICE_CLASS_WATER,
DEVICE_CLASS_WEIGHT,
DEVICE_CLASS_WIND_SPEED,
@ -97,6 +99,7 @@ DEVICE_CLASSES = [
DEVICE_CLASS_DURATION,
DEVICE_CLASS_EMPTY,
DEVICE_CLASS_ENERGY,
DEVICE_CLASS_ENERGY_STORAGE,
DEVICE_CLASS_FREQUENCY,
DEVICE_CLASS_GAS,
DEVICE_CLASS_HUMIDITY,
@ -126,6 +129,7 @@ DEVICE_CLASSES = [
DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS,
DEVICE_CLASS_VOLTAGE,
DEVICE_CLASS_VOLUME,
DEVICE_CLASS_VOLUME_STORAGE,
DEVICE_CLASS_WATER,
DEVICE_CLASS_WEIGHT,
DEVICE_CLASS_WIND_SPEED,

View File

@ -20,8 +20,7 @@ std::string state_class_to_string(StateClass state_class) {
}
}
Sensor::Sensor(const std::string &name) : EntityBase(name), state(NAN), raw_state(NAN) {}
Sensor::Sensor() : Sensor("") {}
Sensor::Sensor() : state(NAN), raw_state(NAN) {}
std::string Sensor::get_unit_of_measurement() {
if (this->unit_of_measurement_.has_value())

View File

@ -57,7 +57,6 @@ std::string state_class_to_string(StateClass state_class);
class Sensor : public EntityBase {
public:
explicit Sensor();
explicit Sensor(const std::string &name);
/// Get the unit of measurement, using the manual override if set.
std::string get_unit_of_measurement();
@ -162,7 +161,6 @@ class Sensor : public EntityBase {
CallbackManager<void(float)> raw_callback_; ///< Storage for raw state callbacks.
CallbackManager<void(float)> callback_; ///< Storage for filtered state callbacks.
bool has_state_{false};
Filter *filter_list_{nullptr}; ///< Store all active filters.
optional<std::string> unit_of_measurement_; ///< Unit of measurement override
@ -170,6 +168,7 @@ class Sensor : public EntityBase {
optional<std::string> device_class_; ///< Device class override
optional<StateClass> state_class_{STATE_CLASS_NONE}; ///< State class override
bool force_update_{false}; ///< Force update mode
bool has_state_{false};
};
} // namespace sensor

View File

@ -6,8 +6,7 @@ namespace switch_ {
static const char *const TAG = "switch";
Switch::Switch(const std::string &name) : EntityBase(name), state(false) {}
Switch::Switch() : Switch("") {}
Switch::Switch() : state(false) {}
void Switch::turn_on() {
ESP_LOGD(TAG, "'%s' Turning ON.", this->get_name().c_str());

View File

@ -32,7 +32,6 @@ enum SwitchRestoreMode {
class Switch : public EntityBase {
public:
explicit Switch();
explicit Switch(const std::string &name);
/** Publish a state to the front-end from the back-end.
*

View File

@ -6,9 +6,6 @@ namespace text_sensor {
static const char *const TAG = "text_sensor";
TextSensor::TextSensor() : TextSensor("") {}
TextSensor::TextSensor(const std::string &name) : EntityBase(name) {}
void TextSensor::publish_state(const std::string &state) {
this->raw_state = state;
this->raw_callback_.call(state);

View File

@ -30,9 +30,6 @@ namespace text_sensor {
class TextSensor : public EntityBase {
public:
explicit TextSensor();
explicit TextSensor(const std::string &name);
/// Getter-syntax for .state.
std::string get_state() const;
/// Getter-syntax for .raw_state

View File

@ -100,8 +100,8 @@ void ESP32ArduinoUARTComponent::setup() {
invert = true;
if (rx_pin_ != nullptr && rx_pin_->is_inverted())
invert = true;
this->hw_serial_->begin(this->baud_rate_, get_config(), rx, tx, invert);
this->hw_serial_->setRxBufferSize(this->rx_buffer_size_);
this->hw_serial_->begin(this->baud_rate_, get_config(), rx, tx, invert);
}
void ESP32ArduinoUARTComponent::dump_config() {

View File

@ -28,6 +28,9 @@ class ESP32ArduinoUARTComponent : public UARTComponent, public Component {
uint32_t get_config();
HardwareSerial *get_hw_serial() { return this->hw_serial_; }
uint8_t get_hw_serial_number() { return this->number_; }
protected:
void check_logger_conflict() override;

View File

@ -79,7 +79,12 @@ void IDFUARTComponent::setup() {
return;
}
err = uart_driver_install(this->uart_num_, this->rx_buffer_size_, 0, 0, nullptr, 0);
err = uart_driver_install(this->uart_num_, /* UART RX ring buffer size. */ this->rx_buffer_size_,
/* UART TX ring buffer size. If set to zero, driver will not use TX buffer, TX function will
block task until all data have been sent out.*/
0,
/* UART event queue size/depth. */ 20, &(this->uart_event_queue_),
/* Flags used to allocate the interrupt. */ 0);
if (err != ESP_OK) {
ESP_LOGW(TAG, "uart_driver_install failed: %s", esp_err_to_name(err));
this->mark_failed();

View File

@ -23,9 +23,13 @@ class IDFUARTComponent : public UARTComponent, public Component {
int available() override;
void flush() override;
uint8_t get_hw_serial_number() { return this->uart_num_; }
QueueHandle_t *get_uart_event_queue() { return &this->uart_event_queue_; }
protected:
void check_logger_conflict() override;
uart_port_t uart_num_;
QueueHandle_t uart_event_queue_;
uart_config_t get_config_();
SemaphoreHandle_t lock_;

View File

@ -30,6 +30,9 @@ class RP2040UartComponent : public UARTComponent, public Component {
uint16_t get_config();
bool is_hw_serial() { return this->hw_serial_; }
HardwareSerial *get_hw_serial() { return this->serial_; }
protected:
void check_logger_conflict() override {}
bool hw_serial_{false};

View File

@ -946,6 +946,7 @@ DEVICE_CLASS_DOOR = "door"
DEVICE_CLASS_DURATION = "duration"
DEVICE_CLASS_EMPTY = ""
DEVICE_CLASS_ENERGY = "energy"
DEVICE_CLASS_ENERGY_STORAGE = "energy_storage"
DEVICE_CLASS_FREQUENCY = "frequency"
DEVICE_CLASS_GARAGE = "garage"
DEVICE_CLASS_GARAGE_DOOR = "garage_door"
@ -1000,6 +1001,7 @@ DEVICE_CLASS_VIBRATION = "vibration"
DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS = "volatile_organic_compounds"
DEVICE_CLASS_VOLTAGE = "voltage"
DEVICE_CLASS_VOLUME = "volume"
DEVICE_CLASS_VOLUME_STORAGE = "volume_storage"
DEVICE_CLASS_WATER = "water"
DEVICE_CLASS_WEIGHT = "weight"
DEVICE_CLASS_WINDOW = "window"

View File

@ -6,19 +6,16 @@ namespace esphome {
static const char *const TAG = "entity_base";
EntityBase::EntityBase(std::string name) : name_(std::move(name)) { this->calc_object_id_(); }
// Entity Name
const std::string &EntityBase::get_name() const { return this->name_; }
void EntityBase::set_name(const std::string &name) {
if (name.empty()) {
this->name_ = App.get_friendly_name();
const StringRef &EntityBase::get_name() const { return this->name_; }
void EntityBase::set_name(const char *name) {
this->name_ = StringRef(name);
if (this->name_.empty()) {
this->name_ = StringRef(App.get_friendly_name());
this->has_own_name_ = false;
} else {
this->name_ = name;
this->has_own_name_ = true;
}
this->calc_object_id_();
}
// Entity Internal
@ -43,13 +40,37 @@ EntityCategory EntityBase::get_entity_category() const { return this->entity_cat
void EntityBase::set_entity_category(EntityCategory entity_category) { this->entity_category_ = entity_category; }
// Entity Object ID
const std::string &EntityBase::get_object_id() { return this->object_id_; }
std::string EntityBase::get_object_id() const {
// Check if `App.get_friendly_name()` is constant or dynamic.
if (!this->has_own_name_ && App.is_name_add_mac_suffix_enabled()) {
// `App.get_friendly_name()` is dynamic.
return str_sanitize(str_snake_case(App.get_friendly_name()));
} else {
// `App.get_friendly_name()` is constant.
if (this->object_id_c_str_ == nullptr) {
return "";
}
return this->object_id_c_str_;
}
}
void EntityBase::set_object_id(const char *object_id) {
this->object_id_c_str_ = object_id;
this->calc_object_id_();
}
// Calculate Object ID Hash from Entity Name
void EntityBase::calc_object_id_() {
this->object_id_ = str_sanitize(str_snake_case(this->name_));
// FNV-1 hash
this->object_id_hash_ = fnv1_hash(this->object_id_);
// Check if `App.get_friendly_name()` is constant or dynamic.
if (!this->has_own_name_ && App.is_name_add_mac_suffix_enabled()) {
// `App.get_friendly_name()` is dynamic.
const auto object_id = str_sanitize(str_snake_case(App.get_friendly_name()));
// FNV-1 hash
this->object_id_hash_ = fnv1_hash(object_id);
} else {
// `App.get_friendly_name()` is constant.
// FNV-1 hash
this->object_id_hash_ = fnv1_hash(this->object_id_c_str_);
}
}
uint32_t EntityBase::get_object_id_hash() { return this->object_id_hash_; }

View File

@ -2,6 +2,7 @@
#include <string>
#include <cstdint>
#include "string_ref.h"
namespace esphome {
@ -14,18 +15,16 @@ enum EntityCategory : uint8_t {
// The generic Entity base class that provides an interface common to all Entities.
class EntityBase {
public:
EntityBase() : EntityBase("") {}
explicit EntityBase(std::string name);
// Get/set the name of this Entity
const std::string &get_name() const;
void set_name(const std::string &name);
const StringRef &get_name() const;
void set_name(const char *name);
// Get whether this Entity has its own name or it should use the device friendly_name.
bool has_own_name() const { return this->has_own_name_; }
// Get the sanitized name of this Entity as an ID. Caching it internally.
const std::string &get_object_id();
// Get the sanitized name of this Entity as an ID.
std::string get_object_id() const;
void set_object_id(const char *object_id);
// Get the unique Object ID of this Entity
uint32_t get_object_id_hash();
@ -54,11 +53,11 @@ class EntityBase {
virtual uint32_t hash_base() { return 0L; }
void calc_object_id_();
std::string name_;
bool has_own_name_{false};
std::string object_id_;
StringRef name_;
const char *object_id_c_str_{nullptr};
const char *icon_c_str_{nullptr};
uint32_t object_id_hash_;
bool has_own_name_{false};
bool internal_{false};
bool disabled_by_default_{false};
EntityCategory entity_category_{ENTITY_CATEGORY_NONE};

View File

@ -0,0 +1,12 @@
#include "string_ref.h"
namespace esphome {
#ifdef USE_JSON
// NOLINTNEXTLINE(readability-identifier-naming)
void convertToJson(const StringRef &src, JsonVariant dst) { dst.set(src.c_str()); }
#endif // USE_JSON
} // namespace esphome

134
esphome/core/string_ref.h Normal file
View File

@ -0,0 +1,134 @@
#pragma once
#include <string>
#include <iterator>
#include <cstring>
#include "esphome/core/defines.h"
#ifdef USE_JSON
#include "esphome/components/json/json_util.h"
#endif // USE_JSON
namespace esphome {
/**
* StringRef is a reference to a string owned by something else. So it behaves like simple string, but it does not own
* pointer. When it is default constructed, it has empty string. You can freely copy or move around this struct, but
* never free its pointer. str() function can be used to export the content as std::string. StringRef is adopted from
* <https://github.com/nghttp2/nghttp2/blob/29cbf8b83ff78faf405d1086b16adc09a8772eca/src/template.h#L376>
*/
class StringRef {
public:
using traits_type = std::char_traits<char>;
using value_type = traits_type::char_type;
using allocator_type = std::allocator<char>;
using size_type = std::allocator_traits<allocator_type>::size_type;
using difference_type = std::allocator_traits<allocator_type>::difference_type;
using const_reference = const value_type &;
using const_pointer = const value_type *;
using const_iterator = const_pointer;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
constexpr StringRef() : base_(""), len_(0) {}
explicit StringRef(const std::string &s) : base_(s.c_str()), len_(s.size()) {}
explicit StringRef(const char *s) : base_(s), len_(strlen(s)) {}
constexpr StringRef(const char *s, size_t n) : base_(s), len_(n) {}
template<typename CharT>
constexpr StringRef(const CharT *s, size_t n) : base_(reinterpret_cast<const char *>(s)), len_(n) {}
template<typename InputIt>
StringRef(InputIt first, InputIt last)
: base_(reinterpret_cast<const char *>(&*first)), len_(std::distance(first, last)) {}
template<typename InputIt>
StringRef(InputIt *first, InputIt *last)
: base_(reinterpret_cast<const char *>(first)), len_(std::distance(first, last)) {}
template<typename CharT, size_t N> constexpr static StringRef from_lit(const CharT (&s)[N]) {
return StringRef{s, N - 1};
}
static StringRef from_maybe_nullptr(const char *s) {
if (s == nullptr) {
return StringRef();
}
return StringRef(s);
}
constexpr const_iterator begin() const { return base_; };
constexpr const_iterator cbegin() const { return base_; };
constexpr const_iterator end() const { return base_ + len_; };
constexpr const_iterator cend() const { return base_ + len_; };
const_reverse_iterator rbegin() const { return const_reverse_iterator{base_ + len_}; }
const_reverse_iterator crbegin() const { return const_reverse_iterator{base_ + len_}; }
const_reverse_iterator rend() const { return const_reverse_iterator{base_}; }
const_reverse_iterator crend() const { return const_reverse_iterator{base_}; }
constexpr const char *c_str() const { return base_; }
constexpr size_type size() const { return len_; }
constexpr bool empty() const { return len_ == 0; }
constexpr const_reference operator[](size_type pos) const { return *(base_ + pos); }
std::string str() const { return std::string(base_, len_); }
const uint8_t *byte() const { return reinterpret_cast<const uint8_t *>(base_); }
operator std::string() const { return str(); }
private:
const char *base_;
size_type len_;
};
inline bool operator==(const StringRef &lhs, const StringRef &rhs) {
return lhs.size() == rhs.size() && std::equal(std::begin(lhs), std::end(lhs), std::begin(rhs));
}
inline bool operator==(const StringRef &lhs, const std::string &rhs) {
return lhs.size() == rhs.size() && std::equal(std::begin(lhs), std::end(lhs), std::begin(rhs));
}
inline bool operator==(const std::string &lhs, const StringRef &rhs) { return rhs == lhs; }
inline bool operator==(const StringRef &lhs, const char *rhs) {
return lhs.size() == strlen(rhs) && std::equal(std::begin(lhs), std::end(lhs), rhs);
}
inline bool operator==(const char *lhs, const StringRef &rhs) { return rhs == lhs; }
inline bool operator!=(const StringRef &lhs, const StringRef &rhs) { return !(lhs == rhs); }
inline bool operator!=(const StringRef &lhs, const std::string &rhs) { return !(lhs == rhs); }
inline bool operator!=(const std::string &lhs, const StringRef &rhs) { return !(rhs == lhs); }
inline bool operator!=(const StringRef &lhs, const char *rhs) { return !(lhs == rhs); }
inline bool operator!=(const char *lhs, const StringRef &rhs) { return !(rhs == lhs); }
inline bool operator<(const StringRef &lhs, const StringRef &rhs) {
return std::lexicographical_compare(std::begin(lhs), std::end(lhs), std::begin(rhs), std::end(rhs));
}
inline std::string &operator+=(std::string &lhs, const StringRef &rhs) {
lhs.append(rhs.c_str(), rhs.size());
return lhs;
}
inline std::string operator+(const char *lhs, const StringRef &rhs) {
auto str = std::string(lhs);
str.append(rhs.c_str(), rhs.size());
return str;
}
inline std::string operator+(const StringRef &lhs, const char *rhs) {
auto str = lhs.str();
str.append(rhs);
return str;
}
#ifdef USE_JSON
// NOLINTNEXTLINE(readability-identifier-naming)
void convertToJson(const StringRef &src, JsonVariant dst);
#endif // USE_JSON
} // namespace esphome

View File

@ -20,6 +20,7 @@ from esphome.types import ConfigType, ConfigFragmentType
from esphome.cpp_generator import add, get_variable
from esphome.cpp_types import App
from esphome.util import Registry, RegistryEntry
from esphome.helpers import snake_case, sanitize
_LOGGER = logging.getLogger(__name__)
@ -101,6 +102,10 @@ async def register_parented(var, value):
async def setup_entity(var, config):
"""Set up generic properties of an Entity"""
add(var.set_name(config[CONF_NAME]))
if not config[CONF_NAME]:
add(var.set_object_id(sanitize(snake_case(CORE.friendly_name))))
else:
add(var.set_object_id(sanitize(snake_case(config[CONF_NAME]))))
add(var.set_disabled_by_default(config[CONF_DISABLED_BY_DEFAULT]))
if CONF_INTERNAL in config:
add(var.set_internal(config[CONF_INTERNAL]))

View File

@ -7,6 +7,7 @@ from pathlib import Path
from typing import Union
import tempfile
from urllib.parse import urlparse
import re
_LOGGER = logging.getLogger(__name__)
@ -334,3 +335,13 @@ def add_class_to_obj(value, cls):
if type(value) is type_: # pylint: disable=unidiomatic-typecheck
return add_class_to_obj(func(value), cls)
raise
def snake_case(value):
"""Same behaviour as `helpers.cpp` method `str_snake_case`."""
return value.replace(" ", "_").lower()
def sanitize(value):
"""Same behaviour as `helpers.cpp` method `str_sanitize`."""
return re.sub("[^-_0-9a-zA-Z]", r"", value)

View File

@ -25,9 +25,9 @@ DOMAINS = {
def sub(path, pattern, repl):
with open(path, "r") as handle:
with open(path) as handle:
content = handle.read()
content = re.sub(pattern, repl, content, flags=re.MULTILINE, count=1)
content = re.sub(pattern, repl, content, flags=re.MULTILINE)
with open(path, "w") as handle:
handle.write(content)
@ -48,7 +48,7 @@ def main():
out = ""
for cls in sorted(classes):
out += f'DEVICE_CLASS_{cls.upper()} = "{classes[cls]}"\n'
sub("esphome/const.py", '(DEVICE_CLASS_\w+ = "\w*"\r?\n)+', out)
sub("esphome/const.py", '(DEVICE_CLASS_\\w+ = "\\w*"\r?\n)+', out)
for domain in sorted(allowed):
# replace imports
@ -58,7 +58,7 @@ def main():
sub(
f"esphome/components/{domain}/__init__.py",
"( DEVICE_CLASS_\w+,\r?\n)+",
"( DEVICE_CLASS_\\w+,\r?\n)+",
out,
)

View File

@ -229,3 +229,37 @@ def test_file_compare(fixture_path, file1, file2, expected):
actual = helpers.file_compare(path1, path2)
assert actual == expected
@pytest.mark.parametrize(
"text, expected",
(
("foo", "foo"),
("foo bar", "foo_bar"),
("foo Bar", "foo_bar"),
("foo BAR", "foo_bar"),
("foo.bar", "foo.bar"),
("fooBAR", "foobar"),
("Foo-bar_EEK", "foo-bar_eek"),
(" foo", "__foo"),
),
)
def test_snake_case(text, expected):
actual = helpers.snake_case(text)
assert actual == expected
@pytest.mark.parametrize(
"text, expected",
(
("foo_bar", "foo_bar"),
('!"§$%&/()=?foo_bar', "foo_bar"),
('foo_!"§$%&/()=?bar', "foo_bar"),
('foo_bar!"§$%&/()=?', "foo_bar"),
),
)
def test_sanitize(text, expected):
actual = helpers.sanitize(text)
assert actual == expected