mirror of
				https://github.com/esphome/esphome.git
				synced 2025-11-03 16:41:50 +00:00 
			
		
		
		
	Compare commits
	
		
			201 Commits
		
	
	
		
			ina226-ext
			...
			2023.10.4
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					1e0daefa16 | ||
| 
						 | 
					6d991a1fc8 | ||
| 
						 | 
					a1845e1e72 | ||
| 
						 | 
					f96a839bcf | ||
| 
						 | 
					1282a15b14 | ||
| 
						 | 
					35039b45e4 | ||
| 
						 | 
					390766eb67 | ||
| 
						 | 
					899d280ac7 | ||
| 
						 | 
					96dc7f0259 | ||
| 
						 | 
					0104bf3fc8 | ||
| 
						 | 
					9b1e1bf56c | ||
| 
						 | 
					33e0f16b3b | ||
| 
						 | 
					0807d60c6a | ||
| 
						 | 
					f018fde369 | ||
| 
						 | 
					c47f8fc02c | ||
| 
						 | 
					76ab923780 | ||
| 
						 | 
					11dba3147d | ||
| 
						 | 
					8c2d9101d5 | ||
| 
						 | 
					61b8004536 | ||
| 
						 | 
					db02c4ea21 | ||
| 
						 | 
					f077a5962d | ||
| 
						 | 
					fa4ba43eb9 | ||
| 
						 | 
					9579423b24 | ||
| 
						 | 
					02449f24c9 | ||
| 
						 | 
					b973238323 | ||
| 
						 | 
					582b8383d2 | ||
| 
						 | 
					e1c9418aee | ||
| 
						 | 
					2aa787f5f0 | ||
| 
						 | 
					2189a40a39 | ||
| 
						 | 
					51688d4078 | ||
| 
						 | 
					cc4c0e3e0b | ||
| 
						 | 
					1a44c6487e | ||
| 
						 | 
					5e7ce610a0 | ||
| 
						 | 
					1f02096edb | ||
| 
						 | 
					fd7d3c4332 | ||
| 
						 | 
					61cf566560 | ||
| 
						 | 
					97d624114d | ||
| 
						 | 
					52e8a2e9e4 | ||
| 
						 | 
					261c271d60 | ||
| 
						 | 
					cb6e314336 | ||
| 
						 | 
					90315b3c40 | ||
| 
						 | 
					5d7c3d1622 | ||
| 
						 | 
					8c1ad1e9a6 | ||
| 
						 | 
					969f6dbe13 | ||
| 
						 | 
					6cce6d4c36 | ||
| 
						 | 
					d27e5e9c97 | ||
| 
						 | 
					af3b22f8b7 | ||
| 
						 | 
					cbc1b29f3e | ||
| 
						 | 
					54363f1246 | ||
| 
						 | 
					d500531c04 | ||
| 
						 | 
					0d800958aa | ||
| 
						 | 
					471533d041 | ||
| 
						 | 
					7dfc4c74da | ||
| 
						 | 
					f709350b04 | ||
| 
						 | 
					85c5928baa | ||
| 
						 | 
					f5dfbaff4b | ||
| 
						 | 
					689c2f11a3 | ||
| 
						 | 
					f73fd97525 | ||
| 
						 | 
					40523e6823 | ||
| 
						 | 
					5e1472185c | ||
| 
						 | 
					af005a6554 | ||
| 
						 | 
					efd31be21c | ||
| 
						 | 
					e9bda2810f | ||
| 
						 | 
					ec4777b8d0 | ||
| 
						 | 
					9b75121337 | ||
| 
						 | 
					d262548d2e | ||
| 
						 | 
					b5b654e054 | ||
| 
						 | 
					dae8ab563c | ||
| 
						 | 
					5751e9ec59 | ||
| 
						 | 
					cc1b7a7a56 | ||
| 
						 | 
					29249cdc1b | ||
| 
						 | 
					e5bae8187f | ||
| 
						 | 
					69adebfefa | ||
| 
						 | 
					7dabbb65d0 | ||
| 
						 | 
					b30bab8c1b | ||
| 
						 | 
					0a1ed58454 | ||
| 
						 | 
					5f5ee9c920 | ||
| 
						 | 
					0aeebdd289 | ||
| 
						 | 
					33e2aa341e | ||
| 
						 | 
					a42788812e | ||
| 
						 | 
					b07a038bc8 | ||
| 
						 | 
					55e36ab982 | ||
| 
						 | 
					90835ab917 | ||
| 
						 | 
					5b46088ae4 | ||
| 
						 | 
					d7e267eca5 | ||
| 
						 | 
					807c47a076 | ||
| 
						 | 
					7ebe6a5894 | ||
| 
						 | 
					41c829fa32 | ||
| 
						 | 
					8f1ce8c7f7 | ||
| 
						 | 
					e55636ed52 | ||
| 
						 | 
					e886262055 | ||
| 
						 | 
					2fa7f8c511 | ||
| 
						 | 
					4622ef770d | ||
| 
						 | 
					d76f18b4f2 | ||
| 
						 | 
					ec20778d83 | ||
| 
						 | 
					b3ca71c6fb | ||
| 
						 | 
					2d53dd05d8 | ||
| 
						 | 
					68a2c45edf | ||
| 
						 | 
					d2616cd6c6 | ||
| 
						 | 
					01ec414873 | ||
| 
						 | 
					150c9b5fa3 | ||
| 
						 | 
					55df88d7ae | ||
| 
						 | 
					619787e6d2 | ||
| 
						 | 
					3f8bad3ed1 | ||
| 
						 | 
					c146712b16 | ||
| 
						 | 
					2cabe59c22 | ||
| 
						 | 
					a67b92a04c | ||
| 
						 | 
					9fb8e9edef | ||
| 
						 | 
					d2bccbe8ac | ||
| 
						 | 
					e44a60e814 | ||
| 
						 | 
					02a71cb6a7 | ||
| 
						 | 
					e600784ebf | ||
| 
						 | 
					5e19a3b892 | ||
| 
						 | 
					8bf112669f | ||
| 
						 | 
					4278664208 | ||
| 
						 | 
					0789657fd5 | ||
| 
						 | 
					b566c78f00 | ||
| 
						 | 
					a35122231c | ||
| 
						 | 
					7e4ee32b54 | ||
| 
						 | 
					7df80eadcf | ||
| 
						 | 
					2aaba1d2b8 | ||
| 
						 | 
					7c129a4018 | ||
| 
						 | 
					cb66ce069e | ||
| 
						 | 
					a27e72362a | ||
| 
						 | 
					f44e5d3142 | ||
| 
						 | 
					532163738e | ||
| 
						 | 
					63fa922547 | ||
| 
						 | 
					48e4cb5ae2 | ||
| 
						 | 
					ff8a73c2d1 | ||
| 
						 | 
					afd26c6f1a | ||
| 
						 | 
					67b06a88b2 | ||
| 
						 | 
					265e019381 | ||
| 
						 | 
					560e36a65c | ||
| 
						 | 
					b05a3fbb55 | ||
| 
						 | 
					3a899e28dc | ||
| 
						 | 
					f26238e824 | ||
| 
						 | 
					3717e34bba | ||
| 
						 | 
					be6f95d43e | ||
| 
						 | 
					99a765dc06 | ||
| 
						 | 
					351e7ea16b | ||
| 
						 | 
					2fa79a2e2f | ||
| 
						 | 
					44a917929d | ||
| 
						 | 
					21ebc7f95b | ||
| 
						 | 
					72e72d7d4b | ||
| 
						 | 
					02ed2c0ebe | ||
| 
						 | 
					0f506ea8eb | ||
| 
						 | 
					b914d6e305 | ||
| 
						 | 
					956e19be7d | ||
| 
						 | 
					b3d5a4dfdb | ||
| 
						 | 
					c63cdae84f | ||
| 
						 | 
					dec044ad8b | ||
| 
						 | 
					2a12ec09fb | ||
| 
						 | 
					91e920c498 | ||
| 
						 | 
					9b19c45735 | ||
| 
						 | 
					3843d21dbf | ||
| 
						 | 
					73db164fb1 | ||
| 
						 | 
					ab32dd7420 | ||
| 
						 | 
					2a7aa2fc0d | ||
| 
						 | 
					f5e98eb86f | ||
| 
						 | 
					362a19c2e1 | ||
| 
						 | 
					f4a4956dd4 | ||
| 
						 | 
					746488cabf | ||
| 
						 | 
					4449248c6f | ||
| 
						 | 
					036e14ab7f | ||
| 
						 | 
					f840eee1b7 | ||
| 
						 | 
					553132443f | ||
| 
						 | 
					d20242f589 | ||
| 
						 | 
					68affce274 | ||
| 
						 | 
					c4b9065749 | ||
| 
						 | 
					d57a5d1793 | ||
| 
						 | 
					74e062fdb3 | ||
| 
						 | 
					6bdc0c92fe | ||
| 
						 | 
					d7945de001 | ||
| 
						 | 
					3ba2a29e54 | ||
| 
						 | 
					76b438f79c | ||
| 
						 | 
					bc14f06a07 | ||
| 
						 | 
					feee075122 | ||
| 
						 | 
					a77cf1beec | ||
| 
						 | 
					d7bfdd0efc | ||
| 
						 | 
					62aee36f82 | ||
| 
						 | 
					0709367587 | ||
| 
						 | 
					98277f6ceb | ||
| 
						 | 
					8dd509ba53 | ||
| 
						 | 
					8df455f55b | ||
| 
						 | 
					36782f13bf | ||
| 
						 | 
					e823067a6b | ||
| 
						 | 
					c3ef12d580 | ||
| 
						 | 
					321155eb40 | ||
| 
						 | 
					d34c074b92 | ||
| 
						 | 
					abc8e903c1 | ||
| 
						 | 
					832ba38f1b | ||
| 
						 | 
					70de2f5278 | ||
| 
						 | 
					604d4eec79 | ||
| 
						 | 
					b806eb6a61 | ||
| 
						 | 
					39948db59a | ||
| 
						 | 
					fbfb4e2a73 | ||
| 
						 | 
					595ac84779 | ||
| 
						 | 
					746f72a279 | ||
| 
						 | 
					dec6f04499 | ||
| 
						 | 
					a90d266017 | ||
| 
						 | 
					df9fcf9850 | 
@@ -225,7 +225,7 @@ esphome/components/pn532_spi/* @OttoWinter @jesserockz
 | 
			
		||||
esphome/components/power_supply/* @esphome/core
 | 
			
		||||
esphome/components/preferences/* @esphome/core
 | 
			
		||||
esphome/components/psram/* @esphome/core
 | 
			
		||||
esphome/components/pulse_meter/* @cstaahl @stevebaxter
 | 
			
		||||
esphome/components/pulse_meter/* @TrentHouliston @cstaahl @stevebaxter
 | 
			
		||||
esphome/components/pvvx_mithermometer/* @pasiz
 | 
			
		||||
esphome/components/qmp6988/* @andrewpc
 | 
			
		||||
esphome/components/qr_code/* @wjtje
 | 
			
		||||
 
 | 
			
		||||
@@ -1459,6 +1459,8 @@ enum VoiceAssistantEvent {
 | 
			
		||||
  VOICE_ASSISTANT_WAKE_WORD_END = 10;
 | 
			
		||||
  VOICE_ASSISTANT_STT_VAD_START = 11;
 | 
			
		||||
  VOICE_ASSISTANT_STT_VAD_END = 12;
 | 
			
		||||
  VOICE_ASSISTANT_TTS_STREAM_START = 98;
 | 
			
		||||
  VOICE_ASSISTANT_TTS_STREAM_END = 99;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message VoiceAssistantEventData {
 | 
			
		||||
 
 | 
			
		||||
@@ -452,6 +452,10 @@ template<> const char *proto_enum_to_string<enums::VoiceAssistantEvent>(enums::V
 | 
			
		||||
      return "VOICE_ASSISTANT_STT_VAD_START";
 | 
			
		||||
    case enums::VOICE_ASSISTANT_STT_VAD_END:
 | 
			
		||||
      return "VOICE_ASSISTANT_STT_VAD_END";
 | 
			
		||||
    case enums::VOICE_ASSISTANT_TTS_STREAM_START:
 | 
			
		||||
      return "VOICE_ASSISTANT_TTS_STREAM_START";
 | 
			
		||||
    case enums::VOICE_ASSISTANT_TTS_STREAM_END:
 | 
			
		||||
      return "VOICE_ASSISTANT_TTS_STREAM_END";
 | 
			
		||||
    default:
 | 
			
		||||
      return "UNKNOWN";
 | 
			
		||||
  }
 | 
			
		||||
 
 | 
			
		||||
@@ -184,6 +184,8 @@ enum VoiceAssistantEvent : uint32_t {
 | 
			
		||||
  VOICE_ASSISTANT_WAKE_WORD_END = 10,
 | 
			
		||||
  VOICE_ASSISTANT_STT_VAD_START = 11,
 | 
			
		||||
  VOICE_ASSISTANT_STT_VAD_END = 12,
 | 
			
		||||
  VOICE_ASSISTANT_TTS_STREAM_START = 98,
 | 
			
		||||
  VOICE_ASSISTANT_TTS_STREAM_END = 99,
 | 
			
		||||
};
 | 
			
		||||
enum AlarmControlPanelState : uint32_t {
 | 
			
		||||
  ALARM_STATE_DISARMED = 0,
 | 
			
		||||
 
 | 
			
		||||
@@ -37,10 +37,14 @@ void BP1658CJ::loop() {
 | 
			
		||||
  uint8_t data[12];
 | 
			
		||||
  if (this->pwm_amounts_[0] == 0 && this->pwm_amounts_[1] == 0 && this->pwm_amounts_[2] == 0 &&
 | 
			
		||||
      this->pwm_amounts_[3] == 0 && this->pwm_amounts_[4] == 0) {
 | 
			
		||||
    // Off / Sleep
 | 
			
		||||
    data[0] = BP1658CJ_MODEL_ID + BP1658CJ_ADDR_STANDBY;
 | 
			
		||||
    for (int i = 1; i < 12; i++)
 | 
			
		||||
      data[i] = 0;
 | 
			
		||||
 | 
			
		||||
    // First turn all channels off
 | 
			
		||||
    data[0] = BP1658CJ_MODEL_ID + BP1658CJ_ADDR_START_5CH;
 | 
			
		||||
    this->write_buffer_(data, 12);
 | 
			
		||||
    // Then sleep
 | 
			
		||||
    data[0] = BP1658CJ_MODEL_ID + BP1658CJ_ADDR_STANDBY;
 | 
			
		||||
    this->write_buffer_(data, 12);
 | 
			
		||||
  } else if (this->pwm_amounts_[0] == 0 && this->pwm_amounts_[1] == 0 && this->pwm_amounts_[2] == 0 &&
 | 
			
		||||
             (this->pwm_amounts_[3] > 0 || this->pwm_amounts_[4] > 0)) {
 | 
			
		||||
 
 | 
			
		||||
@@ -17,12 +17,16 @@ static const uint8_t BP5758D_ADDR_START_2CH = 0b00100000;
 | 
			
		||||
static const uint8_t BP5758D_ADDR_START_5CH = 0b00110000;
 | 
			
		||||
static const uint8_t BP5758D_ALL_DATA_CHANNEL_ENABLEMENT = 0b00011111;
 | 
			
		||||
 | 
			
		||||
static const uint8_t BP5758D_DELAY = 2;
 | 
			
		||||
 | 
			
		||||
void BP5758D::setup() {
 | 
			
		||||
  ESP_LOGCONFIG(TAG, "Setting up BP5758D Output Component...");
 | 
			
		||||
  this->data_pin_->setup();
 | 
			
		||||
  this->data_pin_->digital_write(false);
 | 
			
		||||
  delayMicroseconds(BP5758D_DELAY);
 | 
			
		||||
  this->clock_pin_->setup();
 | 
			
		||||
  this->clock_pin_->digital_write(false);
 | 
			
		||||
  delayMicroseconds(BP5758D_DELAY);
 | 
			
		||||
  this->channel_current_.resize(5, 0);
 | 
			
		||||
  this->pwm_amounts_.resize(5, 0);
 | 
			
		||||
}
 | 
			
		||||
@@ -39,11 +43,11 @@ void BP5758D::loop() {
 | 
			
		||||
  uint8_t data[17];
 | 
			
		||||
  if (this->pwm_amounts_[0] == 0 && this->pwm_amounts_[1] == 0 && this->pwm_amounts_[2] == 0 &&
 | 
			
		||||
      this->pwm_amounts_[3] == 0 && this->pwm_amounts_[4] == 0) {
 | 
			
		||||
    for (int i = 1; i < 16; i++)
 | 
			
		||||
    for (int i = 1; i < 17; i++)
 | 
			
		||||
      data[i] = 0;
 | 
			
		||||
 | 
			
		||||
    // First turn all channels off
 | 
			
		||||
    data[0] = BP5758D_MODEL_ID + BP5758D_ADDR_START_3CH;
 | 
			
		||||
    data[0] = BP5758D_MODEL_ID + BP5758D_ADDR_START_5CH;
 | 
			
		||||
    this->write_buffer_(data, 17);
 | 
			
		||||
    // Then sleep
 | 
			
		||||
    data[0] = BP5758D_MODEL_ID + BP5758D_ADDR_STANDBY;
 | 
			
		||||
@@ -123,28 +127,42 @@ void BP5758D::set_channel_value_(uint8_t channel, uint16_t value) {
 | 
			
		||||
void BP5758D::set_channel_current_(uint8_t channel, uint8_t current) { this->channel_current_[channel] = current; }
 | 
			
		||||
 | 
			
		||||
void BP5758D::write_bit_(bool value) {
 | 
			
		||||
  this->clock_pin_->digital_write(false);
 | 
			
		||||
  this->data_pin_->digital_write(value);
 | 
			
		||||
  delayMicroseconds(BP5758D_DELAY);
 | 
			
		||||
  this->clock_pin_->digital_write(true);
 | 
			
		||||
  delayMicroseconds(BP5758D_DELAY);
 | 
			
		||||
  this->clock_pin_->digital_write(false);
 | 
			
		||||
  delayMicroseconds(BP5758D_DELAY);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void BP5758D::write_byte_(uint8_t data) {
 | 
			
		||||
  for (uint8_t mask = 0x80; mask; mask >>= 1) {
 | 
			
		||||
    this->write_bit_(data & mask);
 | 
			
		||||
  }
 | 
			
		||||
  this->clock_pin_->digital_write(false);
 | 
			
		||||
  this->data_pin_->digital_write(true);
 | 
			
		||||
 | 
			
		||||
  // ack bit
 | 
			
		||||
  this->data_pin_->pin_mode(gpio::FLAG_INPUT);
 | 
			
		||||
  this->clock_pin_->digital_write(true);
 | 
			
		||||
  delayMicroseconds(BP5758D_DELAY);
 | 
			
		||||
  this->clock_pin_->digital_write(false);
 | 
			
		||||
  delayMicroseconds(BP5758D_DELAY);
 | 
			
		||||
  this->data_pin_->pin_mode(gpio::FLAG_OUTPUT);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void BP5758D::write_buffer_(uint8_t *buffer, uint8_t size) {
 | 
			
		||||
  this->data_pin_->digital_write(false);
 | 
			
		||||
  delayMicroseconds(BP5758D_DELAY);
 | 
			
		||||
  this->clock_pin_->digital_write(false);
 | 
			
		||||
  delayMicroseconds(BP5758D_DELAY);
 | 
			
		||||
 | 
			
		||||
  for (uint32_t i = 0; i < size; i++) {
 | 
			
		||||
    this->write_byte_(buffer[i]);
 | 
			
		||||
  }
 | 
			
		||||
  this->clock_pin_->digital_write(false);
 | 
			
		||||
 | 
			
		||||
  this->clock_pin_->digital_write(true);
 | 
			
		||||
  delayMicroseconds(BP5758D_DELAY);
 | 
			
		||||
  this->data_pin_->digital_write(true);
 | 
			
		||||
  delayMicroseconds(BP5758D_DELAY);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}  // namespace bp5758d
 | 
			
		||||
 
 | 
			
		||||
@@ -17,11 +17,12 @@ CONF_ON_FRAME = "on_frame"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def validate_id(config):
 | 
			
		||||
    can_id = config[CONF_CAN_ID]
 | 
			
		||||
    id_ext = config[CONF_USE_EXTENDED_ID]
 | 
			
		||||
    if not id_ext:
 | 
			
		||||
        if can_id > 0x7FF:
 | 
			
		||||
            raise cv.Invalid("Standard IDs must be 11 Bit (0x000-0x7ff / 0-2047)")
 | 
			
		||||
    if CONF_CAN_ID in config:
 | 
			
		||||
        can_id = config[CONF_CAN_ID]
 | 
			
		||||
        id_ext = config[CONF_USE_EXTENDED_ID]
 | 
			
		||||
        if not id_ext:
 | 
			
		||||
            if can_id > 0x7FF:
 | 
			
		||||
                raise cv.Invalid("Standard IDs must be 11 Bit (0x000-0x7ff / 0-2047)")
 | 
			
		||||
    return config
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -151,22 +152,18 @@ async def canbus_action_to_code(config, action_id, template_arg, args):
 | 
			
		||||
    if can_id := config.get(CONF_CAN_ID):
 | 
			
		||||
        can_id = await cg.templatable(can_id, args, cg.uint32)
 | 
			
		||||
        cg.add(var.set_can_id(can_id))
 | 
			
		||||
    use_extended_id = await cg.templatable(
 | 
			
		||||
        config[CONF_USE_EXTENDED_ID], args, cg.uint32
 | 
			
		||||
    )
 | 
			
		||||
    cg.add(var.set_use_extended_id(use_extended_id))
 | 
			
		||||
        cg.add(var.set_use_extended_id(config[CONF_USE_EXTENDED_ID]))
 | 
			
		||||
 | 
			
		||||
    remote_transmission_request = await cg.templatable(
 | 
			
		||||
        config[CONF_REMOTE_TRANSMISSION_REQUEST], args, bool
 | 
			
		||||
    cg.add(
 | 
			
		||||
        var.set_remote_transmission_request(config[CONF_REMOTE_TRANSMISSION_REQUEST])
 | 
			
		||||
    )
 | 
			
		||||
    cg.add(var.set_remote_transmission_request(remote_transmission_request))
 | 
			
		||||
 | 
			
		||||
    data = config[CONF_DATA]
 | 
			
		||||
    if isinstance(data, bytes):
 | 
			
		||||
        data = [int(x) for x in data]
 | 
			
		||||
    if cg.is_template(data):
 | 
			
		||||
        templ = await cg.templatable(data, args, cg.std_vector.template(cg.uint8))
 | 
			
		||||
        cg.add(var.set_data_template(templ))
 | 
			
		||||
    else:
 | 
			
		||||
        if isinstance(data, bytes):
 | 
			
		||||
            data = [int(x) for x in data]
 | 
			
		||||
        cg.add(var.set_data_static(data))
 | 
			
		||||
    return var
 | 
			
		||||
 
 | 
			
		||||
@@ -213,6 +213,8 @@ ClimateCall &ClimateCall::set_preset(const std::string &preset) {
 | 
			
		||||
    this->set_preset(CLIMATE_PRESET_SLEEP);
 | 
			
		||||
  } else if (str_equals_case_insensitive(preset, "ACTIVITY")) {
 | 
			
		||||
    this->set_preset(CLIMATE_PRESET_ACTIVITY);
 | 
			
		||||
  } else if (str_equals_case_insensitive(preset, "NONE")) {
 | 
			
		||||
    this->set_preset(CLIMATE_PRESET_NONE);
 | 
			
		||||
  } else {
 | 
			
		||||
    if (this->parent_->get_traits().supports_custom_preset(preset)) {
 | 
			
		||||
      this->custom_preset_ = preset;
 | 
			
		||||
 
 | 
			
		||||
@@ -104,7 +104,8 @@ void CurrentBasedCover::loop() {
 | 
			
		||||
      ESP_LOGD(TAG, "'%s' - Close position reached. Took %.1fs.", this->name_.c_str(), dur);
 | 
			
		||||
      this->direction_idle_(COVER_CLOSED);
 | 
			
		||||
    }
 | 
			
		||||
  } else if (now - this->start_dir_time_ > this->max_duration_) {
 | 
			
		||||
  }
 | 
			
		||||
  if (now - this->start_dir_time_ > this->max_duration_) {
 | 
			
		||||
    ESP_LOGD(TAG, "'%s' - Max duration reached. Stopping cover.", this->name_.c_str());
 | 
			
		||||
    this->direction_idle_();
 | 
			
		||||
  }
 | 
			
		||||
 
 | 
			
		||||
@@ -18,7 +18,7 @@ _ESP_SDIO_PINS = {
 | 
			
		||||
    11: "Flash Command",
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_ESP32_STRAPPING_PINS = {0, 2, 4, 12, 15}
 | 
			
		||||
_ESP32_STRAPPING_PINS = {0, 2, 5, 12, 15}
 | 
			
		||||
_LOGGER = logging.getLogger(__name__)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -2,9 +2,9 @@
 | 
			
		||||
 | 
			
		||||
#ifdef USE_ESP32
 | 
			
		||||
 | 
			
		||||
#include "ble_uuid.h"
 | 
			
		||||
#include <cstring>
 | 
			
		||||
#include <cstdio>
 | 
			
		||||
#include <cstring>
 | 
			
		||||
#include "ble_uuid.h"
 | 
			
		||||
#include "esphome/core/log.h"
 | 
			
		||||
 | 
			
		||||
namespace esphome {
 | 
			
		||||
@@ -16,8 +16,8 @@ BLEAdvertising::BLEAdvertising() {
 | 
			
		||||
  this->advertising_data_.set_scan_rsp = false;
 | 
			
		||||
  this->advertising_data_.include_name = true;
 | 
			
		||||
  this->advertising_data_.include_txpower = true;
 | 
			
		||||
  this->advertising_data_.min_interval = 0x20;
 | 
			
		||||
  this->advertising_data_.max_interval = 0x40;
 | 
			
		||||
  this->advertising_data_.min_interval = 0;
 | 
			
		||||
  this->advertising_data_.max_interval = 0;
 | 
			
		||||
  this->advertising_data_.appearance = 0x00;
 | 
			
		||||
  this->advertising_data_.manufacturer_len = 0;
 | 
			
		||||
  this->advertising_data_.p_manufacturer_data = nullptr;
 | 
			
		||||
@@ -42,6 +42,17 @@ void BLEAdvertising::remove_service_uuid(ESPBTUUID uuid) {
 | 
			
		||||
                                 this->advertising_uuids_.end());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void BLEAdvertising::set_service_data(const std::vector<uint8_t> &data) {
 | 
			
		||||
  delete[] this->advertising_data_.p_service_data;
 | 
			
		||||
  this->advertising_data_.p_service_data = nullptr;
 | 
			
		||||
  this->advertising_data_.service_data_len = data.size();
 | 
			
		||||
  if (!data.empty()) {
 | 
			
		||||
    // NOLINTNEXTLINE(cppcoreguidelines-owning-memory)
 | 
			
		||||
    this->advertising_data_.p_service_data = new uint8_t[data.size()];
 | 
			
		||||
    memcpy(this->advertising_data_.p_service_data, data.data(), data.size());
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void BLEAdvertising::set_manufacturer_data(const std::vector<uint8_t> &data) {
 | 
			
		||||
  delete[] this->advertising_data_.p_manufacturer_data;
 | 
			
		||||
  this->advertising_data_.p_manufacturer_data = nullptr;
 | 
			
		||||
@@ -85,8 +96,6 @@ void BLEAdvertising::start() {
 | 
			
		||||
    this->scan_response_data_.set_scan_rsp = true;
 | 
			
		||||
    this->scan_response_data_.include_name = true;
 | 
			
		||||
    this->scan_response_data_.include_txpower = true;
 | 
			
		||||
    this->scan_response_data_.min_interval = 0;
 | 
			
		||||
    this->scan_response_data_.max_interval = 0;
 | 
			
		||||
    this->scan_response_data_.manufacturer_len = 0;
 | 
			
		||||
    this->scan_response_data_.appearance = 0;
 | 
			
		||||
    this->scan_response_data_.flag = 0;
 | 
			
		||||
 
 | 
			
		||||
@@ -21,6 +21,7 @@ class BLEAdvertising {
 | 
			
		||||
  void set_scan_response(bool scan_response) { this->scan_response_ = scan_response; }
 | 
			
		||||
  void set_min_preferred_interval(uint16_t interval) { this->advertising_data_.min_interval = interval; }
 | 
			
		||||
  void set_manufacturer_data(const std::vector<uint8_t> &data);
 | 
			
		||||
  void set_service_data(const std::vector<uint8_t> &data);
 | 
			
		||||
 | 
			
		||||
  void start();
 | 
			
		||||
  void stop();
 | 
			
		||||
 
 | 
			
		||||
@@ -90,6 +90,8 @@ void BLEService::stop() {
 | 
			
		||||
    ESP_LOGE(TAG, "esp_ble_gatts_stop_service failed: %d", err);
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  esp32_ble::global_ble->get_advertising()->remove_service_uuid(this->uuid_);
 | 
			
		||||
  esp32_ble::global_ble->get_advertising()->start();
 | 
			
		||||
  this->running_state_ = STOPPING;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -7,11 +7,11 @@
 | 
			
		||||
 | 
			
		||||
#ifdef USE_ESP32
 | 
			
		||||
 | 
			
		||||
#include <esp_bt_defs.h>
 | 
			
		||||
#include <esp_gap_ble_api.h>
 | 
			
		||||
#include <esp_gatt_defs.h>
 | 
			
		||||
#include <esp_gattc_api.h>
 | 
			
		||||
#include <esp_gatts_api.h>
 | 
			
		||||
#include <esp_bt_defs.h>
 | 
			
		||||
 | 
			
		||||
namespace esphome {
 | 
			
		||||
namespace esp32_ble_server {
 | 
			
		||||
 
 | 
			
		||||
@@ -4,7 +4,7 @@ from esphome.components import binary_sensor, output, esp32_ble_server
 | 
			
		||||
from esphome.const import CONF_ID
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
AUTO_LOAD = ["binary_sensor", "output", "esp32_ble_server"]
 | 
			
		||||
AUTO_LOAD = ["esp32_ble_server"]
 | 
			
		||||
CODEOWNERS = ["@jesserockz"]
 | 
			
		||||
CONFLICTS_WITH = ["esp32_ble_beacon"]
 | 
			
		||||
DEPENDENCIES = ["wifi", "esp32"]
 | 
			
		||||
@@ -36,6 +36,9 @@ CONFIG_SCHEMA = cv.Schema(
 | 
			
		||||
        cv.Optional(
 | 
			
		||||
            CONF_AUTHORIZED_DURATION, default="1min"
 | 
			
		||||
        ): cv.positive_time_period_milliseconds,
 | 
			
		||||
        cv.Optional(
 | 
			
		||||
            CONF_WIFI_TIMEOUT, default="1min"
 | 
			
		||||
        ): cv.positive_time_period_milliseconds,
 | 
			
		||||
    }
 | 
			
		||||
).extend(cv.COMPONENT_SCHEMA)
 | 
			
		||||
 | 
			
		||||
@@ -53,6 +56,8 @@ async def to_code(config):
 | 
			
		||||
    cg.add(var.set_identify_duration(config[CONF_IDENTIFY_DURATION]))
 | 
			
		||||
    cg.add(var.set_authorized_duration(config[CONF_AUTHORIZED_DURATION]))
 | 
			
		||||
 | 
			
		||||
    cg.add(var.set_wifi_timeout(config[CONF_WIFI_TIMEOUT]))
 | 
			
		||||
 | 
			
		||||
    if CONF_AUTHORIZER in config and config[CONF_AUTHORIZER] is not None:
 | 
			
		||||
        activator = await cg.get_variable(config[CONF_AUTHORIZER])
 | 
			
		||||
        cg.add(var.set_authorizer(activator))
 | 
			
		||||
 
 | 
			
		||||
@@ -18,6 +18,17 @@ ESP32ImprovComponent::ESP32ImprovComponent() { global_improv_component = this; }
 | 
			
		||||
void ESP32ImprovComponent::setup() {
 | 
			
		||||
  this->service_ = global_ble_server->create_service(improv::SERVICE_UUID, true);
 | 
			
		||||
  this->setup_characteristics();
 | 
			
		||||
 | 
			
		||||
#ifdef USE_BINARY_SENSOR
 | 
			
		||||
  if (this->authorizer_ != nullptr) {
 | 
			
		||||
    this->authorizer_->add_on_state_callback([this](bool state) {
 | 
			
		||||
      if (state) {
 | 
			
		||||
        this->authorized_start_ = millis();
 | 
			
		||||
        this->identify_start_ = 0;
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ESP32ImprovComponent::setup_characteristics() {
 | 
			
		||||
@@ -50,8 +61,10 @@ void ESP32ImprovComponent::setup_characteristics() {
 | 
			
		||||
  BLEDescriptor *capabilities_descriptor = new BLE2902();
 | 
			
		||||
  this->capabilities_->add_descriptor(capabilities_descriptor);
 | 
			
		||||
  uint8_t capabilities = 0x00;
 | 
			
		||||
#ifdef USE_OUTPUT
 | 
			
		||||
  if (this->status_indicator_ != nullptr)
 | 
			
		||||
    capabilities |= improv::CAPABILITY_IDENTIFY;
 | 
			
		||||
#endif
 | 
			
		||||
  this->capabilities_->set_value(capabilities);
 | 
			
		||||
  this->setup_complete_ = true;
 | 
			
		||||
}
 | 
			
		||||
@@ -63,8 +76,7 @@ void ESP32ImprovComponent::loop() {
 | 
			
		||||
 | 
			
		||||
  switch (this->state_) {
 | 
			
		||||
    case improv::STATE_STOPPED:
 | 
			
		||||
      if (this->status_indicator_ != nullptr)
 | 
			
		||||
        this->status_indicator_->turn_off();
 | 
			
		||||
      this->set_status_indicator_state_(false);
 | 
			
		||||
 | 
			
		||||
      if (this->service_->is_created() && this->should_start_ && this->setup_complete_) {
 | 
			
		||||
        if (this->service_->is_running()) {
 | 
			
		||||
@@ -80,18 +92,22 @@ void ESP32ImprovComponent::loop() {
 | 
			
		||||
      }
 | 
			
		||||
      break;
 | 
			
		||||
    case improv::STATE_AWAITING_AUTHORIZATION: {
 | 
			
		||||
      if (this->authorizer_ == nullptr || this->authorizer_->state) {
 | 
			
		||||
#ifdef USE_BINARY_SENSOR
 | 
			
		||||
      if (this->authorizer_ == nullptr ||
 | 
			
		||||
          (this->authorized_start_ != 0 && ((now - this->authorized_start_) < this->authorized_duration_))) {
 | 
			
		||||
        this->set_state_(improv::STATE_AUTHORIZED);
 | 
			
		||||
        this->authorized_start_ = now;
 | 
			
		||||
      } else {
 | 
			
		||||
        if (this->status_indicator_ != nullptr) {
 | 
			
		||||
          if (!this->check_identify_())
 | 
			
		||||
            this->status_indicator_->turn_on();
 | 
			
		||||
        }
 | 
			
		||||
      } else
 | 
			
		||||
#else
 | 
			
		||||
      this->set_state_(improv::STATE_AUTHORIZED);
 | 
			
		||||
#endif
 | 
			
		||||
      {
 | 
			
		||||
        if (!this->check_identify_())
 | 
			
		||||
          this->set_status_indicator_state_(true);
 | 
			
		||||
      }
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    case improv::STATE_AUTHORIZED: {
 | 
			
		||||
#ifdef USE_BINARY_SENSOR
 | 
			
		||||
      if (this->authorizer_ != nullptr) {
 | 
			
		||||
        if (now - this->authorized_start_ > this->authorized_duration_) {
 | 
			
		||||
          ESP_LOGD(TAG, "Authorization timeout");
 | 
			
		||||
@@ -99,25 +115,14 @@ void ESP32ImprovComponent::loop() {
 | 
			
		||||
          return;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      if (this->status_indicator_ != nullptr) {
 | 
			
		||||
        if (!this->check_identify_()) {
 | 
			
		||||
          if ((now % 1000) < 500) {
 | 
			
		||||
            this->status_indicator_->turn_on();
 | 
			
		||||
          } else {
 | 
			
		||||
            this->status_indicator_->turn_off();
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
#endif
 | 
			
		||||
      if (!this->check_identify_()) {
 | 
			
		||||
        this->set_status_indicator_state_((now % 1000) < 500);
 | 
			
		||||
      }
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    case improv::STATE_PROVISIONING: {
 | 
			
		||||
      if (this->status_indicator_ != nullptr) {
 | 
			
		||||
        if ((now % 200) < 100) {
 | 
			
		||||
          this->status_indicator_->turn_on();
 | 
			
		||||
        } else {
 | 
			
		||||
          this->status_indicator_->turn_off();
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      this->set_status_indicator_state_((now % 200) < 100);
 | 
			
		||||
      if (wifi::global_wifi_component->is_connected()) {
 | 
			
		||||
        wifi::global_wifi_component->save_wifi_sta(this->connecting_sta_.get_ssid(),
 | 
			
		||||
                                                   this->connecting_sta_.get_password());
 | 
			
		||||
@@ -142,13 +147,27 @@ void ESP32ImprovComponent::loop() {
 | 
			
		||||
    }
 | 
			
		||||
    case improv::STATE_PROVISIONED: {
 | 
			
		||||
      this->incoming_data_.clear();
 | 
			
		||||
      if (this->status_indicator_ != nullptr)
 | 
			
		||||
        this->status_indicator_->turn_off();
 | 
			
		||||
      this->set_status_indicator_state_(false);
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ESP32ImprovComponent::set_status_indicator_state_(bool state) {
 | 
			
		||||
#ifdef USE_OUTPUT
 | 
			
		||||
  if (this->status_indicator_ == nullptr)
 | 
			
		||||
    return;
 | 
			
		||||
  if (this->status_indicator_state_ == state)
 | 
			
		||||
    return;
 | 
			
		||||
  this->status_indicator_state_ = state;
 | 
			
		||||
  if (state) {
 | 
			
		||||
    this->status_indicator_->turn_on();
 | 
			
		||||
  } else {
 | 
			
		||||
    this->status_indicator_->turn_off();
 | 
			
		||||
  }
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool ESP32ImprovComponent::check_identify_() {
 | 
			
		||||
  uint32_t now = millis();
 | 
			
		||||
 | 
			
		||||
@@ -156,11 +175,7 @@ bool ESP32ImprovComponent::check_identify_() {
 | 
			
		||||
 | 
			
		||||
  if (identify) {
 | 
			
		||||
    uint32_t time = now % 1000;
 | 
			
		||||
    if (time < 600 && time % 200 < 100) {
 | 
			
		||||
      this->status_indicator_->turn_on();
 | 
			
		||||
    } else {
 | 
			
		||||
      this->status_indicator_->turn_off();
 | 
			
		||||
    }
 | 
			
		||||
    this->set_status_indicator_state_(time < 600 && time % 200 < 100);
 | 
			
		||||
  }
 | 
			
		||||
  return identify;
 | 
			
		||||
}
 | 
			
		||||
@@ -174,6 +189,25 @@ void ESP32ImprovComponent::set_state_(improv::State state) {
 | 
			
		||||
    if (state != improv::STATE_STOPPED)
 | 
			
		||||
      this->status_->notify();
 | 
			
		||||
  }
 | 
			
		||||
  std::vector<uint8_t> service_data(8, 0);
 | 
			
		||||
  service_data[0] = 0x77;  // PR
 | 
			
		||||
  service_data[1] = 0x46;  // IM
 | 
			
		||||
  service_data[2] = static_cast<uint8_t>(state);
 | 
			
		||||
 | 
			
		||||
  uint8_t capabilities = 0x00;
 | 
			
		||||
#ifdef USE_OUTPUT
 | 
			
		||||
  if (this->status_indicator_ != nullptr)
 | 
			
		||||
    capabilities |= improv::CAPABILITY_IDENTIFY;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  service_data[3] = capabilities;
 | 
			
		||||
  service_data[4] = 0x00;  // Reserved
 | 
			
		||||
  service_data[5] = 0x00;  // Reserved
 | 
			
		||||
  service_data[6] = 0x00;  // Reserved
 | 
			
		||||
  service_data[7] = 0x00;  // Reserved
 | 
			
		||||
 | 
			
		||||
  esp32_ble::global_ble->get_advertising()->set_service_data(service_data);
 | 
			
		||||
  esp32_ble::global_ble->get_advertising()->start();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ESP32ImprovComponent::set_error_(improv::Error error) {
 | 
			
		||||
@@ -213,8 +247,12 @@ float ESP32ImprovComponent::get_setup_priority() const { return setup_priority::
 | 
			
		||||
 | 
			
		||||
void ESP32ImprovComponent::dump_config() {
 | 
			
		||||
  ESP_LOGCONFIG(TAG, "ESP32 Improv:");
 | 
			
		||||
#ifdef USE_BINARY_SENSOR
 | 
			
		||||
  LOG_BINARY_SENSOR("  ", "Authorizer", this->authorizer_);
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef USE_OUTPUT
 | 
			
		||||
  ESP_LOGCONFIG(TAG, "  Status Indicator: '%s'", YESNO(this->status_indicator_ != nullptr));
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ESP32ImprovComponent::process_incoming_data_() {
 | 
			
		||||
@@ -273,8 +311,10 @@ void ESP32ImprovComponent::process_incoming_data_() {
 | 
			
		||||
void ESP32ImprovComponent::on_wifi_connect_timeout_() {
 | 
			
		||||
  this->set_error_(improv::ERROR_UNABLE_TO_CONNECT);
 | 
			
		||||
  this->set_state_(improv::STATE_AUTHORIZED);
 | 
			
		||||
#ifdef USE_BINARY_SENSOR
 | 
			
		||||
  if (this->authorizer_ != nullptr)
 | 
			
		||||
    this->authorized_start_ = millis();
 | 
			
		||||
#endif
 | 
			
		||||
  ESP_LOGW(TAG, "Timed out trying to connect to given WiFi network");
 | 
			
		||||
  wifi::global_wifi_component->clear_sta();
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,14 +1,22 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "esphome/components/binary_sensor/binary_sensor.h"
 | 
			
		||||
#include "esphome/components/esp32_ble_server/ble_characteristic.h"
 | 
			
		||||
#include "esphome/components/esp32_ble_server/ble_server.h"
 | 
			
		||||
#include "esphome/components/output/binary_output.h"
 | 
			
		||||
#include "esphome/components/wifi/wifi_component.h"
 | 
			
		||||
#include "esphome/core/component.h"
 | 
			
		||||
#include "esphome/core/defines.h"
 | 
			
		||||
#include "esphome/core/helpers.h"
 | 
			
		||||
#include "esphome/core/preferences.h"
 | 
			
		||||
 | 
			
		||||
#include "esphome/components/esp32_ble_server/ble_characteristic.h"
 | 
			
		||||
#include "esphome/components/esp32_ble_server/ble_server.h"
 | 
			
		||||
#include "esphome/components/wifi/wifi_component.h"
 | 
			
		||||
 | 
			
		||||
#ifdef USE_BINARY_SENSOR
 | 
			
		||||
#include "esphome/components/binary_sensor/binary_sensor.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef USE_OUTPUT
 | 
			
		||||
#include "esphome/components/output/binary_output.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
#ifdef USE_ESP32
 | 
			
		||||
@@ -34,11 +42,18 @@ class ESP32ImprovComponent : public Component, public BLEServiceComponent {
 | 
			
		||||
  void stop() override;
 | 
			
		||||
  bool is_active() const { return this->state_ != improv::STATE_STOPPED; }
 | 
			
		||||
 | 
			
		||||
#ifdef USE_BINARY_SENSOR
 | 
			
		||||
  void set_authorizer(binary_sensor::BinarySensor *authorizer) { this->authorizer_ = authorizer; }
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef USE_OUTPUT
 | 
			
		||||
  void set_status_indicator(output::BinaryOutput *status_indicator) { this->status_indicator_ = status_indicator; }
 | 
			
		||||
#endif
 | 
			
		||||
  void set_identify_duration(uint32_t identify_duration) { this->identify_duration_ = identify_duration; }
 | 
			
		||||
  void set_authorized_duration(uint32_t authorized_duration) { this->authorized_duration_ = authorized_duration; }
 | 
			
		||||
 | 
			
		||||
  void set_wifi_timeout(uint32_t wifi_timeout) { this->wifi_timeout_ = wifi_timeout; }
 | 
			
		||||
  uint32_t get_wifi_timeout() const { return this->wifi_timeout_; }
 | 
			
		||||
 | 
			
		||||
 protected:
 | 
			
		||||
  bool should_start_{false};
 | 
			
		||||
  bool setup_complete_{false};
 | 
			
		||||
@@ -48,6 +63,8 @@ class ESP32ImprovComponent : public Component, public BLEServiceComponent {
 | 
			
		||||
  uint32_t authorized_start_{0};
 | 
			
		||||
  uint32_t authorized_duration_;
 | 
			
		||||
 | 
			
		||||
  uint32_t wifi_timeout_{};
 | 
			
		||||
 | 
			
		||||
  std::vector<uint8_t> incoming_data_;
 | 
			
		||||
  wifi::WiFiAP connecting_sta_;
 | 
			
		||||
 | 
			
		||||
@@ -58,12 +75,19 @@ class ESP32ImprovComponent : public Component, public BLEServiceComponent {
 | 
			
		||||
  BLECharacteristic *rpc_response_;
 | 
			
		||||
  BLECharacteristic *capabilities_;
 | 
			
		||||
 | 
			
		||||
#ifdef USE_BINARY_SENSOR
 | 
			
		||||
  binary_sensor::BinarySensor *authorizer_{nullptr};
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef USE_OUTPUT
 | 
			
		||||
  output::BinaryOutput *status_indicator_{nullptr};
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  improv::State state_{improv::STATE_STOPPED};
 | 
			
		||||
  improv::Error error_state_{improv::ERROR_NONE};
 | 
			
		||||
 | 
			
		||||
  bool status_indicator_state_{false};
 | 
			
		||||
  void set_status_indicator_state_(bool state);
 | 
			
		||||
 | 
			
		||||
  void set_state_(improv::State state);
 | 
			
		||||
  void set_error_(improv::Error error);
 | 
			
		||||
  void send_response_(std::vector<uint8_t> &response);
 | 
			
		||||
 
 | 
			
		||||
@@ -137,11 +137,10 @@ def validate_weight_name(value):
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def download_gfonts(value):
 | 
			
		||||
    wght = value[CONF_WEIGHT]
 | 
			
		||||
    if value[CONF_ITALIC]:
 | 
			
		||||
        wght = f"1,{wght}"
 | 
			
		||||
    name = f"{value[CONF_FAMILY]}@{value[CONF_WEIGHT]}"
 | 
			
		||||
    url = f"https://fonts.googleapis.com/css2?family={value[CONF_FAMILY]}:wght@{wght}"
 | 
			
		||||
    name = (
 | 
			
		||||
        f"{value[CONF_FAMILY]}:ital,wght@{int(value[CONF_ITALIC])},{value[CONF_WEIGHT]}"
 | 
			
		||||
    )
 | 
			
		||||
    url = f"https://fonts.googleapis.com/css2?family={name}"
 | 
			
		||||
 | 
			
		||||
    path = _compute_gfonts_local_path(value)
 | 
			
		||||
    if path.is_file():
 | 
			
		||||
 
 | 
			
		||||
@@ -8,12 +8,15 @@ from esphome.const import (
 | 
			
		||||
    CONF_CHANNEL,
 | 
			
		||||
    CONF_SPEED,
 | 
			
		||||
    CONF_DIRECTION,
 | 
			
		||||
    CONF_ADDRESS,
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
DEPENDENCIES = ["i2c"]
 | 
			
		||||
 | 
			
		||||
CODEOWNERS = ["@max246"]
 | 
			
		||||
 | 
			
		||||
MULTI_CONF = True
 | 
			
		||||
 | 
			
		||||
grove_tb6612fng_ns = cg.esphome_ns.namespace("grove_tb6612fng")
 | 
			
		||||
GROVE_TB6612FNG = grove_tb6612fng_ns.class_(
 | 
			
		||||
    "GroveMotorDriveTB6612FNG", cg.Component, i2c.I2CDevice
 | 
			
		||||
@@ -33,6 +36,9 @@ GROVETB6612FNGMotorStandbyAction = grove_tb6612fng_ns.class_(
 | 
			
		||||
GROVETB6612FNGMotorNoStandbyAction = grove_tb6612fng_ns.class_(
 | 
			
		||||
    "GROVETB6612FNGMotorNoStandbyAction", automation.Action
 | 
			
		||||
)
 | 
			
		||||
GROVETB6612FNGMotorChangeAddressAction = grove_tb6612fng_ns.class_(
 | 
			
		||||
    "GROVETB6612FNGMotorChangeAddressAction", automation.Action
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
DIRECTION_TYPE = {
 | 
			
		||||
    "FORWARD": 1,
 | 
			
		||||
@@ -150,3 +156,22 @@ async def grove_tb6612fng_no_standby_to_code(config, action_id, template_arg, ar
 | 
			
		||||
    await cg.register_parented(var, config[CONF_ID])
 | 
			
		||||
 | 
			
		||||
    return var
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@automation.register_action(
 | 
			
		||||
    "grove_tb6612fng.change_address",
 | 
			
		||||
    GROVETB6612FNGMotorChangeAddressAction,
 | 
			
		||||
    cv.Schema(
 | 
			
		||||
        {
 | 
			
		||||
            cv.Required(CONF_ID): cv.use_id(GROVE_TB6612FNG),
 | 
			
		||||
            cv.Required(CONF_ADDRESS): cv.i2c_address,
 | 
			
		||||
        }
 | 
			
		||||
    ),
 | 
			
		||||
)
 | 
			
		||||
async def grove_tb6612fng_change_address_to_code(config, action_id, template_arg, args):
 | 
			
		||||
    var = cg.new_Pvariable(action_id, template_arg)
 | 
			
		||||
    await cg.register_parented(var, config[CONF_ID])
 | 
			
		||||
 | 
			
		||||
    template_channel = await cg.templatable(config[CONF_ADDRESS], args, int)
 | 
			
		||||
    cg.add(var.set_address(template_channel))
 | 
			
		||||
    return var
 | 
			
		||||
 
 | 
			
		||||
@@ -84,8 +84,7 @@ class GroveMotorDriveTB6612FNG : public Component, public i2c::I2CDevice {
 | 
			
		||||
  *************************************************************/
 | 
			
		||||
  void set_i2c_addr(uint8_t addr);
 | 
			
		||||
 | 
			
		||||
  /*************************************************************
 | 
			
		||||
      Description
 | 
			
		||||
  /***********************************change_address
 | 
			
		||||
       Drive a motor.
 | 
			
		||||
      Parameter
 | 
			
		||||
       chl: MOTOR_CHA or MOTOR_CHB
 | 
			
		||||
@@ -204,5 +203,13 @@ class GROVETB6612FNGMotorNoStandbyAction : public Action<Ts...>, public Parented
 | 
			
		||||
  void play(Ts... x) override { this->parent_->not_standby(); }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template<typename... Ts>
 | 
			
		||||
class GROVETB6612FNGMotorChangeAddressAction : public Action<Ts...>, public Parented<GroveMotorDriveTB6612FNG> {
 | 
			
		||||
 public:
 | 
			
		||||
  TEMPLATABLE_VALUE(uint8_t, address)
 | 
			
		||||
 | 
			
		||||
  void play(Ts... x) override { this->parent_->set_i2c_addr(this->address_.value(x...)); }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
}  // namespace grove_tb6612fng
 | 
			
		||||
}  // namespace esphome
 | 
			
		||||
 
 | 
			
		||||
@@ -76,7 +76,7 @@ void HTU21DComponent::update() {
 | 
			
		||||
  if (this->humidity_ != nullptr)
 | 
			
		||||
    this->humidity_->publish_state(humidity);
 | 
			
		||||
  if (this->heater_ != nullptr)
 | 
			
		||||
    this->heater_->publish_state(humidity);
 | 
			
		||||
    this->heater_->publish_state(heater_level);
 | 
			
		||||
  this->status_clear_warning();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -37,6 +37,8 @@ void I2SAudioMicrophone::setup() {
 | 
			
		||||
void I2SAudioMicrophone::start() {
 | 
			
		||||
  if (this->is_failed())
 | 
			
		||||
    return;
 | 
			
		||||
  if (this->state_ == microphone::STATE_RUNNING)
 | 
			
		||||
    return;  // Already running
 | 
			
		||||
  this->state_ = microphone::STATE_STARTING;
 | 
			
		||||
}
 | 
			
		||||
void I2SAudioMicrophone::start_() {
 | 
			
		||||
 
 | 
			
		||||
@@ -158,8 +158,13 @@ void I2SAudioSpeaker::watch_() {
 | 
			
		||||
  if (xQueueReceive(this->event_queue_, &event, 0) == pdTRUE) {
 | 
			
		||||
    switch (event.type) {
 | 
			
		||||
      case TaskEventType::STARTING:
 | 
			
		||||
        ESP_LOGD(TAG, "Starting I2S Audio Speaker");
 | 
			
		||||
        break;
 | 
			
		||||
      case TaskEventType::STARTED:
 | 
			
		||||
        ESP_LOGD(TAG, "Started I2S Audio Speaker");
 | 
			
		||||
        break;
 | 
			
		||||
      case TaskEventType::STOPPING:
 | 
			
		||||
        ESP_LOGD(TAG, "Stopping I2S Audio Speaker");
 | 
			
		||||
        break;
 | 
			
		||||
      case TaskEventType::PLAYING:
 | 
			
		||||
        this->status_clear_warning();
 | 
			
		||||
@@ -170,6 +175,7 @@ void I2SAudioSpeaker::watch_() {
 | 
			
		||||
        this->player_task_handle_ = nullptr;
 | 
			
		||||
        this->parent_->unlock();
 | 
			
		||||
        xQueueReset(this->buffer_queue_);
 | 
			
		||||
        ESP_LOGD(TAG, "Stopped I2S Audio Speaker");
 | 
			
		||||
        break;
 | 
			
		||||
      case TaskEventType::WARNING:
 | 
			
		||||
        ESP_LOGW(TAG, "Error writing to I2S: %s", esp_err_to_name(event.err));
 | 
			
		||||
 
 | 
			
		||||
@@ -1,10 +1,14 @@
 | 
			
		||||
from esphome.components.logger import USB_CDC, USB_SERIAL_JTAG
 | 
			
		||||
from esphome.components import improv_base
 | 
			
		||||
from esphome.components.esp32 import get_esp32_variant
 | 
			
		||||
from esphome.components.esp32.const import (
 | 
			
		||||
    VARIANT_ESP32S3,
 | 
			
		||||
)
 | 
			
		||||
from esphome.components.logger import USB_CDC
 | 
			
		||||
from esphome.const import CONF_BAUD_RATE, CONF_HARDWARE_UART, CONF_ID, CONF_LOGGER
 | 
			
		||||
import esphome.codegen as cg
 | 
			
		||||
import esphome.config_validation as cv
 | 
			
		||||
from esphome.core import CORE
 | 
			
		||||
import esphome.final_validate as fv
 | 
			
		||||
from esphome.components import improv_base
 | 
			
		||||
 | 
			
		||||
AUTO_LOAD = ["improv_base"]
 | 
			
		||||
CODEOWNERS = ["@esphome/core"]
 | 
			
		||||
@@ -30,7 +34,10 @@ def validate_logger(config):
 | 
			
		||||
    if logger_conf[CONF_BAUD_RATE] == 0:
 | 
			
		||||
        raise cv.Invalid("improv_serial requires the logger baud_rate to be not 0")
 | 
			
		||||
    if CORE.using_esp_idf:
 | 
			
		||||
        if logger_conf[CONF_HARDWARE_UART] in [USB_SERIAL_JTAG, USB_CDC]:
 | 
			
		||||
        if (
 | 
			
		||||
            logger_conf[CONF_HARDWARE_UART] == USB_CDC
 | 
			
		||||
            and get_esp32_variant() == VARIANT_ESP32S3
 | 
			
		||||
        ):
 | 
			
		||||
            raise cv.Invalid(
 | 
			
		||||
                "improv_serial does not support the selected logger hardware_uart"
 | 
			
		||||
            )
 | 
			
		||||
 
 | 
			
		||||
@@ -31,26 +31,57 @@ void ImprovSerialComponent::setup() {
 | 
			
		||||
 | 
			
		||||
void ImprovSerialComponent::dump_config() { ESP_LOGCONFIG(TAG, "Improv Serial:"); }
 | 
			
		||||
 | 
			
		||||
int ImprovSerialComponent::available_() {
 | 
			
		||||
optional<uint8_t> ImprovSerialComponent::read_byte_() {
 | 
			
		||||
  optional<uint8_t> byte;
 | 
			
		||||
  uint8_t data = 0;
 | 
			
		||||
#ifdef USE_ARDUINO
 | 
			
		||||
  return this->hw_serial_->available();
 | 
			
		||||
  if (this->hw_serial_->available()) {
 | 
			
		||||
    this->hw_serial_->readBytes(&data, 1);
 | 
			
		||||
    byte = data;
 | 
			
		||||
  }
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef USE_ESP_IDF
 | 
			
		||||
  size_t available;
 | 
			
		||||
  uart_get_buffered_data_len(this->uart_num_, &available);
 | 
			
		||||
  return available;
 | 
			
		||||
  switch (logger::global_logger->get_uart()) {
 | 
			
		||||
    case logger::UART_SELECTION_UART0:
 | 
			
		||||
    case logger::UART_SELECTION_UART1:
 | 
			
		||||
#if !defined(USE_ESP32_VARIANT_ESP32C3) && !defined(USE_ESP32_VARIANT_ESP32C6) && \
 | 
			
		||||
    !defined(USE_ESP32_VARIANT_ESP32S2) && !defined(USE_ESP32_VARIANT_ESP32S3)
 | 
			
		||||
    case logger::UART_SELECTION_UART2:
 | 
			
		||||
#endif  // !USE_ESP32_VARIANT_ESP32C3 && !USE_ESP32_VARIANT_ESP32S2 && !USE_ESP32_VARIANT_ESP32S3
 | 
			
		||||
      if (this->uart_num_ >= 0) {
 | 
			
		||||
        size_t available;
 | 
			
		||||
        uart_get_buffered_data_len(this->uart_num_, &available);
 | 
			
		||||
        if (available) {
 | 
			
		||||
          uart_read_bytes(this->uart_num_, &data, 1, 20 / portTICK_PERIOD_MS);
 | 
			
		||||
          byte = data;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      break;
 | 
			
		||||
#if defined(CONFIG_ESP_CONSOLE_USB_CDC) && (defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3))
 | 
			
		||||
    case logger::UART_SELECTION_USB_CDC:
 | 
			
		||||
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
 | 
			
		||||
      if (esp_usb_console_available_for_read()) {
 | 
			
		||||
#else
 | 
			
		||||
      if (esp_usb_console_read_available()) {
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint8_t ImprovSerialComponent::read_byte_() {
 | 
			
		||||
  uint8_t data;
 | 
			
		||||
#ifdef USE_ARDUINO
 | 
			
		||||
  this->hw_serial_->readBytes(&data, 1);
 | 
			
		||||
        esp_usb_console_read_buf((char *) &data, 1);
 | 
			
		||||
        byte = data;
 | 
			
		||||
      }
 | 
			
		||||
      break;
 | 
			
		||||
#endif  // USE_ESP32_VARIANT_ESP32S2 || USE_ESP32_VARIANT_ESP32S3
 | 
			
		||||
#if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C6) || defined(USE_ESP32_VARIANT_ESP32S3)
 | 
			
		||||
    case logger::UART_SELECTION_USB_SERIAL_JTAG: {
 | 
			
		||||
      if (usb_serial_jtag_read_bytes((char *) &data, 1, 20 / portTICK_PERIOD_MS)) {
 | 
			
		||||
        byte = data;
 | 
			
		||||
      }
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
#endif  // USE_ESP32_VARIANT_ESP32C3 || USE_ESP32_VARIANT_ESP32C6 || USE_ESP32_VARIANT_ESP32S3
 | 
			
		||||
    default:
 | 
			
		||||
      break;
 | 
			
		||||
  }
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef USE_ESP_IDF
 | 
			
		||||
  uart_read_bytes(this->uart_num_, &data, 1, 20 / portTICK_PERIOD_MS);
 | 
			
		||||
#endif
 | 
			
		||||
  return data;
 | 
			
		||||
  return byte;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ImprovSerialComponent::write_data_(std::vector<uint8_t> &data) {
 | 
			
		||||
@@ -59,24 +90,49 @@ void ImprovSerialComponent::write_data_(std::vector<uint8_t> &data) {
 | 
			
		||||
  this->hw_serial_->write(data.data(), data.size());
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef USE_ESP_IDF
 | 
			
		||||
  uart_write_bytes(this->uart_num_, data.data(), data.size());
 | 
			
		||||
  switch (logger::global_logger->get_uart()) {
 | 
			
		||||
    case logger::UART_SELECTION_UART0:
 | 
			
		||||
    case logger::UART_SELECTION_UART1:
 | 
			
		||||
#if !defined(USE_ESP32_VARIANT_ESP32C3) && !defined(USE_ESP32_VARIANT_ESP32C6) && \
 | 
			
		||||
    !defined(USE_ESP32_VARIANT_ESP32S2) && !defined(USE_ESP32_VARIANT_ESP32S3)
 | 
			
		||||
    case logger::UART_SELECTION_UART2:
 | 
			
		||||
#endif  // !USE_ESP32_VARIANT_ESP32C3 && !USE_ESP32_VARIANT_ESP32S2 && !USE_ESP32_VARIANT_ESP32S3
 | 
			
		||||
      uart_write_bytes(this->uart_num_, data.data(), data.size());
 | 
			
		||||
      break;
 | 
			
		||||
#if defined(CONFIG_ESP_CONSOLE_USB_CDC) && (defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3))
 | 
			
		||||
    case logger::UART_SELECTION_USB_CDC: {
 | 
			
		||||
      const char *msg = (char *) data.data();
 | 
			
		||||
      esp_usb_console_write_buf(msg, data.size());
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
#endif  // USE_ESP32_VARIANT_ESP32S2 || USE_ESP32_VARIANT_ESP32S3
 | 
			
		||||
#if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C6) || defined(USE_ESP32_VARIANT_ESP32S3)
 | 
			
		||||
    case logger::UART_SELECTION_USB_SERIAL_JTAG:
 | 
			
		||||
      usb_serial_jtag_write_bytes((char *) data.data(), data.size(), 20 / portTICK_PERIOD_MS);
 | 
			
		||||
      break;
 | 
			
		||||
#endif  // USE_ESP32_VARIANT_ESP32C3 || USE_ESP32_VARIANT_ESP32S3
 | 
			
		||||
    default:
 | 
			
		||||
      break;
 | 
			
		||||
  }
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ImprovSerialComponent::loop() {
 | 
			
		||||
  const uint32_t now = millis();
 | 
			
		||||
  if (now - this->last_read_byte_ > 50) {
 | 
			
		||||
  if (this->last_read_byte_ && (millis() - this->last_read_byte_ > IMPROV_SERIAL_TIMEOUT)) {
 | 
			
		||||
    this->last_read_byte_ = 0;
 | 
			
		||||
    this->rx_buffer_.clear();
 | 
			
		||||
    this->last_read_byte_ = now;
 | 
			
		||||
    ESP_LOGV(TAG, "Improv Serial timeout");
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  while (this->available_()) {
 | 
			
		||||
    uint8_t byte = this->read_byte_();
 | 
			
		||||
    if (this->parse_improv_serial_byte_(byte)) {
 | 
			
		||||
      this->last_read_byte_ = now;
 | 
			
		||||
  auto byte = this->read_byte_();
 | 
			
		||||
  while (byte.has_value()) {
 | 
			
		||||
    if (this->parse_improv_serial_byte_(byte.value())) {
 | 
			
		||||
      this->last_read_byte_ = millis();
 | 
			
		||||
    } else {
 | 
			
		||||
      this->last_read_byte_ = 0;
 | 
			
		||||
      this->rx_buffer_.clear();
 | 
			
		||||
    }
 | 
			
		||||
    byte = this->read_byte_();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (this->state_ == improv::STATE_PROVISIONING) {
 | 
			
		||||
 
 | 
			
		||||
@@ -14,6 +14,13 @@
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef USE_ESP_IDF
 | 
			
		||||
#include <driver/uart.h>
 | 
			
		||||
#if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C6) || defined(USE_ESP32_VARIANT_ESP32S3) || \
 | 
			
		||||
    defined(USE_ESP32_VARIANT_ESP32H2)
 | 
			
		||||
#include <driver/usb_serial_jtag.h>
 | 
			
		||||
#endif
 | 
			
		||||
#if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3)
 | 
			
		||||
#include <esp_private/usb_console.h>
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
namespace esphome {
 | 
			
		||||
@@ -26,6 +33,7 @@ enum ImprovSerialType : uint8_t {
 | 
			
		||||
  TYPE_RPC_RESPONSE = 0x04
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const uint16_t IMPROV_SERIAL_TIMEOUT = 100;
 | 
			
		||||
static const uint8_t IMPROV_SERIAL_VERSION = 1;
 | 
			
		||||
 | 
			
		||||
class ImprovSerialComponent : public Component, public improv_base::ImprovBase {
 | 
			
		||||
@@ -48,8 +56,7 @@ class ImprovSerialComponent : public Component, public improv_base::ImprovBase {
 | 
			
		||||
  std::vector<uint8_t> build_rpc_settings_response_(improv::Command command);
 | 
			
		||||
  std::vector<uint8_t> build_version_info_();
 | 
			
		||||
 | 
			
		||||
  int available_();
 | 
			
		||||
  uint8_t read_byte_();
 | 
			
		||||
  optional<uint8_t> read_byte_();
 | 
			
		||||
  void write_data_(std::vector<uint8_t> &data);
 | 
			
		||||
 | 
			
		||||
#ifdef USE_ARDUINO
 | 
			
		||||
 
 | 
			
		||||
@@ -251,7 +251,7 @@ async def component_to_code(config):
 | 
			
		||||
    # setup board config
 | 
			
		||||
    cg.add_platformio_option("board", config[CONF_BOARD])
 | 
			
		||||
    cg.add_build_flag("-DUSE_LIBRETINY")
 | 
			
		||||
    cg.add_build_flag(f"-DUSE_{config[CONF_COMPONENT_ID]}")
 | 
			
		||||
    cg.add_build_flag(f"-DUSE_{config[CONF_COMPONENT_ID].upper()}")
 | 
			
		||||
    cg.add_build_flag(f"-DUSE_LIBRETINY_VARIANT_{config[CONF_FAMILY]}")
 | 
			
		||||
    cg.add_define("ESPHOME_BOARD", config[CONF_BOARD])
 | 
			
		||||
    cg.add_define("ESPHOME_VARIANT", FAMILY_FRIENDLY[config[CONF_FAMILY]])
 | 
			
		||||
 
 | 
			
		||||
@@ -3,8 +3,21 @@
 | 
			
		||||
 | 
			
		||||
#ifdef USE_ESP_IDF
 | 
			
		||||
#include <driver/uart.h>
 | 
			
		||||
 | 
			
		||||
#if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C6) || defined(USE_ESP32_VARIANT_ESP32S3) || \
 | 
			
		||||
    defined(USE_ESP32_VARIANT_ESP32H2)
 | 
			
		||||
#include <driver/usb_serial_jtag.h>
 | 
			
		||||
#include <esp_vfs_dev.h>
 | 
			
		||||
#include <esp_vfs_usb_serial_jtag.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "freertos/FreeRTOS.h"
 | 
			
		||||
#include "esp_idf_version.h"
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <cstdio>
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
 | 
			
		||||
#endif  // USE_ESP_IDF
 | 
			
		||||
 | 
			
		||||
#if defined(USE_ESP32_FRAMEWORK_ARDUINO) || defined(USE_ESP_IDF)
 | 
			
		||||
@@ -93,6 +106,58 @@ void Logger::log_vprintf_(int level, const char *tag, int line, const __FlashStr
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef USE_ESP_IDF
 | 
			
		||||
void Logger::init_uart_() {
 | 
			
		||||
  uart_config_t uart_config{};
 | 
			
		||||
  uart_config.baud_rate = (int) baud_rate_;
 | 
			
		||||
  uart_config.data_bits = UART_DATA_8_BITS;
 | 
			
		||||
  uart_config.parity = UART_PARITY_DISABLE;
 | 
			
		||||
  uart_config.stop_bits = UART_STOP_BITS_1;
 | 
			
		||||
  uart_config.flow_ctrl = UART_HW_FLOWCTRL_DISABLE;
 | 
			
		||||
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
 | 
			
		||||
  uart_config.source_clk = UART_SCLK_DEFAULT;
 | 
			
		||||
#endif
 | 
			
		||||
  uart_param_config(this->uart_num_, &uart_config);
 | 
			
		||||
  const int uart_buffer_size = tx_buffer_size_;
 | 
			
		||||
  // Install UART driver using an event queue here
 | 
			
		||||
  uart_driver_install(this->uart_num_, uart_buffer_size, uart_buffer_size, 10, nullptr, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3)
 | 
			
		||||
void Logger::init_usb_cdc_() {}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C6) || defined(USE_ESP32_VARIANT_ESP32S3) || \
 | 
			
		||||
    defined(USE_ESP32_VARIANT_ESP32H2)
 | 
			
		||||
void Logger::init_usb_serial_jtag_() {
 | 
			
		||||
  setvbuf(stdin, NULL, _IONBF, 0);  // Disable buffering on stdin
 | 
			
		||||
 | 
			
		||||
  // Minicom, screen, idf_monitor send CR when ENTER key is pressed
 | 
			
		||||
  esp_vfs_dev_usb_serial_jtag_set_rx_line_endings(ESP_LINE_ENDINGS_CR);
 | 
			
		||||
  // Move the caret to the beginning of the next line on '\n'
 | 
			
		||||
  esp_vfs_dev_usb_serial_jtag_set_tx_line_endings(ESP_LINE_ENDINGS_CRLF);
 | 
			
		||||
 | 
			
		||||
  // Enable non-blocking mode on stdin and stdout
 | 
			
		||||
  fcntl(fileno(stdout), F_SETFL, 0);
 | 
			
		||||
  fcntl(fileno(stdin), F_SETFL, 0);
 | 
			
		||||
 | 
			
		||||
  usb_serial_jtag_driver_config_t usb_serial_jtag_config{};
 | 
			
		||||
  usb_serial_jtag_config.rx_buffer_size = 512;
 | 
			
		||||
  usb_serial_jtag_config.tx_buffer_size = 512;
 | 
			
		||||
 | 
			
		||||
  esp_err_t ret = ESP_OK;
 | 
			
		||||
  // Install USB-SERIAL-JTAG driver for interrupt-driven reads and writes
 | 
			
		||||
  ret = usb_serial_jtag_driver_install(&usb_serial_jtag_config);
 | 
			
		||||
  if (ret != ESP_OK) {
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Tell vfs to use usb-serial-jtag driver
 | 
			
		||||
  esp_vfs_usb_serial_jtag_use_driver();
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
int HOT Logger::level_for(const char *tag) {
 | 
			
		||||
  // Uses std::vector<> for low memory footprint, though the vector
 | 
			
		||||
  // could be sorted to minimize lookup times. This feature isn't used that
 | 
			
		||||
@@ -120,19 +185,19 @@ void HOT Logger::log_message_(int level, const char *tag, int offset) {
 | 
			
		||||
#ifdef USE_ESP_IDF
 | 
			
		||||
    if (
 | 
			
		||||
#if defined(USE_ESP32_VARIANT_ESP32S2)
 | 
			
		||||
        uart_ == UART_SELECTION_USB_CDC
 | 
			
		||||
        this->uart_ == UART_SELECTION_USB_CDC
 | 
			
		||||
#elif defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C6) || defined(USE_ESP32_VARIANT_ESP32H2)
 | 
			
		||||
        uart_ == UART_SELECTION_USB_SERIAL_JTAG
 | 
			
		||||
        this->uart_ == UART_SELECTION_USB_SERIAL_JTAG
 | 
			
		||||
#elif defined(USE_ESP32_VARIANT_ESP32S3)
 | 
			
		||||
        uart_ == UART_SELECTION_USB_CDC || uart_ == UART_SELECTION_USB_SERIAL_JTAG
 | 
			
		||||
        this->uart_ == UART_SELECTION_USB_CDC || this->uart_ == UART_SELECTION_USB_SERIAL_JTAG
 | 
			
		||||
#else
 | 
			
		||||
        /* DISABLES CODE */ (false)  // NOLINT
 | 
			
		||||
#endif
 | 
			
		||||
    ) {
 | 
			
		||||
      puts(msg);
 | 
			
		||||
    } else {
 | 
			
		||||
      uart_write_bytes(uart_num_, msg, strlen(msg));
 | 
			
		||||
      uart_write_bytes(uart_num_, "\n", 1);
 | 
			
		||||
      uart_write_bytes(this->uart_num_, msg, strlen(msg));
 | 
			
		||||
      uart_write_bytes(this->uart_num_, "\n", 1);
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
  }
 | 
			
		||||
@@ -209,48 +274,38 @@ void Logger::pre_setup() {
 | 
			
		||||
    }
 | 
			
		||||
#endif  // USE_ARDUINO
 | 
			
		||||
#ifdef USE_ESP_IDF
 | 
			
		||||
    uart_num_ = UART_NUM_0;
 | 
			
		||||
    switch (uart_) {
 | 
			
		||||
    this->uart_num_ = UART_NUM_0;
 | 
			
		||||
    switch (this->uart_) {
 | 
			
		||||
      case UART_SELECTION_UART0:
 | 
			
		||||
        uart_num_ = UART_NUM_0;
 | 
			
		||||
        this->uart_num_ = UART_NUM_0;
 | 
			
		||||
        break;
 | 
			
		||||
      case UART_SELECTION_UART1:
 | 
			
		||||
        uart_num_ = UART_NUM_1;
 | 
			
		||||
        this->uart_num_ = UART_NUM_1;
 | 
			
		||||
        break;
 | 
			
		||||
#if !defined(USE_ESP32_VARIANT_ESP32C3) && !defined(USE_ESP32_VARIANT_ESP32C6) && \
 | 
			
		||||
    !defined(USE_ESP32_VARIANT_ESP32S2) && !defined(USE_ESP32_VARIANT_ESP32S3) && !defined(USE_ESP32_VARIANT_ESP32H2)
 | 
			
		||||
      case UART_SELECTION_UART2:
 | 
			
		||||
        uart_num_ = UART_NUM_2;
 | 
			
		||||
        this->uart_num_ = UART_NUM_2;
 | 
			
		||||
        break;
 | 
			
		||||
#endif  // !USE_ESP32_VARIANT_ESP32C3 && !USE_ESP32_VARIANT_ESP32S2 && !USE_ESP32_VARIANT_ESP32S3 &&
 | 
			
		||||
        // !USE_ESP32_VARIANT_ESP32H2
 | 
			
		||||
#if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3)
 | 
			
		||||
      case UART_SELECTION_USB_CDC:
 | 
			
		||||
        uart_num_ = -1;
 | 
			
		||||
        this->uart_num_ = -1;
 | 
			
		||||
        this->init_usb_cdc_();
 | 
			
		||||
        break;
 | 
			
		||||
#endif  // USE_ESP32_VARIANT_ESP32S2 || USE_ESP32_VARIANT_ESP32S3
 | 
			
		||||
#if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C6) || defined(USE_ESP32_VARIANT_ESP32S3) || \
 | 
			
		||||
    defined(USE_ESP32_VARIANT_ESP32H2)
 | 
			
		||||
      case UART_SELECTION_USB_SERIAL_JTAG:
 | 
			
		||||
        uart_num_ = -1;
 | 
			
		||||
        this->uart_num_ = -1;
 | 
			
		||||
        this->init_usb_serial_jtag_();
 | 
			
		||||
        break;
 | 
			
		||||
#endif  // USE_ESP32_VARIANT_ESP32C3 || USE_ESP32_VARIANT_ESP32C6 || USE_ESP32_VARIANT_ESP32S3 ||
 | 
			
		||||
        // USE_ESP32_VARIANT_ESP32H2
 | 
			
		||||
    }
 | 
			
		||||
    if (uart_num_ >= 0) {
 | 
			
		||||
      uart_config_t uart_config{};
 | 
			
		||||
      uart_config.baud_rate = (int) baud_rate_;
 | 
			
		||||
      uart_config.data_bits = UART_DATA_8_BITS;
 | 
			
		||||
      uart_config.parity = UART_PARITY_DISABLE;
 | 
			
		||||
      uart_config.stop_bits = UART_STOP_BITS_1;
 | 
			
		||||
      uart_config.flow_ctrl = UART_HW_FLOWCTRL_DISABLE;
 | 
			
		||||
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
 | 
			
		||||
      uart_config.source_clk = UART_SCLK_DEFAULT;
 | 
			
		||||
#endif
 | 
			
		||||
      uart_param_config(uart_num_, &uart_config);
 | 
			
		||||
      const int uart_buffer_size = tx_buffer_size_;
 | 
			
		||||
      // Install UART driver using an event queue here
 | 
			
		||||
      uart_driver_install(uart_num_, uart_buffer_size, uart_buffer_size, 10, nullptr, 0);
 | 
			
		||||
    if (this->uart_num_ >= 0) {
 | 
			
		||||
      this->init_uart_();
 | 
			
		||||
    }
 | 
			
		||||
#endif  // USE_ESP_IDF
 | 
			
		||||
  }
 | 
			
		||||
 
 | 
			
		||||
@@ -107,6 +107,16 @@ class Logger : public Component {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 protected:
 | 
			
		||||
#ifdef USE_ESP_IDF
 | 
			
		||||
  void init_uart_();
 | 
			
		||||
#if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3)
 | 
			
		||||
  void init_usb_cdc_();
 | 
			
		||||
#endif
 | 
			
		||||
#if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C6) || defined(USE_ESP32_VARIANT_ESP32S3) || \
 | 
			
		||||
    defined(USE_ESP32_VARIANT_ESP32H2)
 | 
			
		||||
  void init_usb_serial_jtag_();
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
  void write_header_(int level, const char *tag, int line);
 | 
			
		||||
  void write_footer_();
 | 
			
		||||
  void log_message_(int level, const char *tag, int offset = 0);
 | 
			
		||||
 
 | 
			
		||||
@@ -19,9 +19,7 @@ class MQTTBackendLibreTiny final : public MQTTBackend {
 | 
			
		||||
  void set_will(const char *topic, uint8_t qos, bool retain, const char *payload) final {
 | 
			
		||||
    mqtt_client_.setWill(topic, qos, retain, payload);
 | 
			
		||||
  }
 | 
			
		||||
  void set_server(network::IPAddress ip, uint16_t port) final {
 | 
			
		||||
    mqtt_client_.setServer(IPAddress(static_cast<uint32_t>(ip)), port);
 | 
			
		||||
  }
 | 
			
		||||
  void set_server(network::IPAddress ip, uint16_t port) final { mqtt_client_.setServer(IPAddress(ip), port); }
 | 
			
		||||
  void set_server(const char *host, uint16_t port) final { mqtt_client_.setServer(host, port); }
 | 
			
		||||
#if ASYNC_TCP_SSL_ENABLED
 | 
			
		||||
  void set_secure(bool secure) { mqtt_client.setSecure(secure); }
 | 
			
		||||
 
 | 
			
		||||
@@ -3,7 +3,11 @@
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <cstdio>
 | 
			
		||||
#include <array>
 | 
			
		||||
#include "esphome/core/macros.h"
 | 
			
		||||
 | 
			
		||||
#if defined(USE_ESP_IDF) || defined(USE_LIBRETINY) || USE_ARDUINO_VERSION_CODE > VERSION_CODE(3, 0, 0)
 | 
			
		||||
#include <lwip/ip_addr.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if USE_ARDUINO
 | 
			
		||||
#include <Arduino.h>
 | 
			
		||||
@@ -34,7 +38,12 @@ struct IPAddress {
 | 
			
		||||
  }
 | 
			
		||||
  IPAddress(const ip_addr_t *other_ip) { ip_addr_copy(ip_addr_, *other_ip); }
 | 
			
		||||
  IPAddress(const std::string &in_address) { ipaddr_aton(in_address.c_str(), &ip_addr_); }
 | 
			
		||||
  IPAddress(ip4_addr_t *other_ip) { memcpy((void *) &ip_addr_, (void *) other_ip, sizeof(ip4_addr_t)); }
 | 
			
		||||
  IPAddress(ip4_addr_t *other_ip) {
 | 
			
		||||
    memcpy((void *) &ip_addr_, (void *) other_ip, sizeof(ip4_addr_t));
 | 
			
		||||
#if USE_ESP32 && LWIP_IPV6
 | 
			
		||||
    ip_addr_.type = IPADDR_TYPE_V4;
 | 
			
		||||
#endif
 | 
			
		||||
  }
 | 
			
		||||
#if USE_ARDUINO
 | 
			
		||||
  IPAddress(const arduino_ns::IPAddress &other_ip) { ip_addr_set_ip4_u32(&ip_addr_, other_ip); }
 | 
			
		||||
#endif
 | 
			
		||||
@@ -87,7 +96,7 @@ struct IPAddress {
 | 
			
		||||
  bool is_ip6() { return IP_IS_V6(&ip_addr_); }
 | 
			
		||||
  std::string str() const { return ipaddr_ntoa(&ip_addr_); }
 | 
			
		||||
  bool operator==(const IPAddress &other) const { return ip_addr_cmp(&ip_addr_, &other.ip_addr_); }
 | 
			
		||||
  bool operator!=(const IPAddress &other) const { return !(&ip_addr_ == &other.ip_addr_); }
 | 
			
		||||
  bool operator!=(const IPAddress &other) const { return !ip_addr_cmp(&ip_addr_, &other.ip_addr_); }
 | 
			
		||||
  IPAddress &operator+=(uint8_t increase) {
 | 
			
		||||
    if (IP_IS_V4(&ip_addr_)) {
 | 
			
		||||
#if LWIP_IPV6
 | 
			
		||||
 
 | 
			
		||||
@@ -106,4 +106,5 @@ async def output_set_level_to_code(config, action_id, template_arg, args):
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
async def to_code(config):
 | 
			
		||||
    cg.add_define("USE_OUTPUT")
 | 
			
		||||
    cg.add_global(output_ns.using)
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,3 @@
 | 
			
		||||
#ifdef USE_ARDUINO
 | 
			
		||||
 | 
			
		||||
#include "prometheus_handler.h"
 | 
			
		||||
#include "esphome/core/application.h"
 | 
			
		||||
 | 
			
		||||
@@ -89,7 +87,7 @@ void PrometheusHandler::sensor_row_(AsyncResponseStream *stream, sensor::Sensor
 | 
			
		||||
    stream->print(obj->get_unit_of_measurement().c_str());
 | 
			
		||||
    stream->print(F("\"} "));
 | 
			
		||||
    stream->print(value_accuracy_to_string(obj->state, obj->get_accuracy_decimals()).c_str());
 | 
			
		||||
    stream->print('\n');
 | 
			
		||||
    stream->print(F("\n"));
 | 
			
		||||
  } else {
 | 
			
		||||
    // Invalid state
 | 
			
		||||
    stream->print(F("esphome_sensor_failed{id=\""));
 | 
			
		||||
@@ -124,7 +122,7 @@ void PrometheusHandler::binary_sensor_row_(AsyncResponseStream *stream, binary_s
 | 
			
		||||
    stream->print(relabel_name_(obj).c_str());
 | 
			
		||||
    stream->print(F("\"} "));
 | 
			
		||||
    stream->print(obj->state);
 | 
			
		||||
    stream->print('\n');
 | 
			
		||||
    stream->print(F("\n"));
 | 
			
		||||
  } else {
 | 
			
		||||
    // Invalid state
 | 
			
		||||
    stream->print(F("esphome_binary_sensor_failed{id=\""));
 | 
			
		||||
@@ -158,7 +156,7 @@ void PrometheusHandler::fan_row_(AsyncResponseStream *stream, fan::Fan *obj) {
 | 
			
		||||
  stream->print(relabel_name_(obj).c_str());
 | 
			
		||||
  stream->print(F("\"} "));
 | 
			
		||||
  stream->print(obj->state);
 | 
			
		||||
  stream->print('\n');
 | 
			
		||||
  stream->print(F("\n"));
 | 
			
		||||
  // Speed if available
 | 
			
		||||
  if (obj->get_traits().supports_speed()) {
 | 
			
		||||
    stream->print(F("esphome_fan_speed{id=\""));
 | 
			
		||||
@@ -167,7 +165,7 @@ void PrometheusHandler::fan_row_(AsyncResponseStream *stream, fan::Fan *obj) {
 | 
			
		||||
    stream->print(relabel_name_(obj).c_str());
 | 
			
		||||
    stream->print(F("\"} "));
 | 
			
		||||
    stream->print(obj->speed);
 | 
			
		||||
    stream->print('\n');
 | 
			
		||||
    stream->print(F("\n"));
 | 
			
		||||
  }
 | 
			
		||||
  // Oscillation if available
 | 
			
		||||
  if (obj->get_traits().supports_oscillation()) {
 | 
			
		||||
@@ -177,7 +175,7 @@ void PrometheusHandler::fan_row_(AsyncResponseStream *stream, fan::Fan *obj) {
 | 
			
		||||
    stream->print(relabel_name_(obj).c_str());
 | 
			
		||||
    stream->print(F("\"} "));
 | 
			
		||||
    stream->print(obj->oscillating);
 | 
			
		||||
    stream->print('\n');
 | 
			
		||||
    stream->print(F("\n"));
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
@@ -281,7 +279,7 @@ void PrometheusHandler::cover_row_(AsyncResponseStream *stream, cover::Cover *ob
 | 
			
		||||
    stream->print(relabel_name_(obj).c_str());
 | 
			
		||||
    stream->print(F("\"} "));
 | 
			
		||||
    stream->print(obj->position);
 | 
			
		||||
    stream->print('\n');
 | 
			
		||||
    stream->print(F("\n"));
 | 
			
		||||
    if (obj->get_traits().get_supports_tilt()) {
 | 
			
		||||
      stream->print(F("esphome_cover_tilt{id=\""));
 | 
			
		||||
      stream->print(relabel_id_(obj).c_str());
 | 
			
		||||
@@ -289,7 +287,7 @@ void PrometheusHandler::cover_row_(AsyncResponseStream *stream, cover::Cover *ob
 | 
			
		||||
      stream->print(relabel_name_(obj).c_str());
 | 
			
		||||
      stream->print(F("\"} "));
 | 
			
		||||
      stream->print(obj->tilt);
 | 
			
		||||
      stream->print('\n');
 | 
			
		||||
      stream->print(F("\n"));
 | 
			
		||||
    }
 | 
			
		||||
  } else {
 | 
			
		||||
    // Invalid state
 | 
			
		||||
@@ -322,7 +320,7 @@ void PrometheusHandler::switch_row_(AsyncResponseStream *stream, switch_::Switch
 | 
			
		||||
  stream->print(relabel_name_(obj).c_str());
 | 
			
		||||
  stream->print(F("\"} "));
 | 
			
		||||
  stream->print(obj->state);
 | 
			
		||||
  stream->print('\n');
 | 
			
		||||
  stream->print(F("\n"));
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
@@ -346,11 +344,9 @@ void PrometheusHandler::lock_row_(AsyncResponseStream *stream, lock::Lock *obj)
 | 
			
		||||
  stream->print(relabel_name_(obj).c_str());
 | 
			
		||||
  stream->print(F("\"} "));
 | 
			
		||||
  stream->print(obj->state);
 | 
			
		||||
  stream->print('\n');
 | 
			
		||||
  stream->print(F("\n"));
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
}  // namespace prometheus
 | 
			
		||||
}  // namespace esphome
 | 
			
		||||
 | 
			
		||||
#endif  // USE_ARDUINO
 | 
			
		||||
 
 | 
			
		||||
@@ -1,14 +1,12 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#ifdef USE_ARDUINO
 | 
			
		||||
 | 
			
		||||
#include <map>
 | 
			
		||||
#include <utility>
 | 
			
		||||
 | 
			
		||||
#include "esphome/core/entity_base.h"
 | 
			
		||||
#include "esphome/components/web_server_base/web_server_base.h"
 | 
			
		||||
#include "esphome/core/controller.h"
 | 
			
		||||
#include "esphome/core/component.h"
 | 
			
		||||
#include "esphome/core/controller.h"
 | 
			
		||||
#include "esphome/core/entity_base.h"
 | 
			
		||||
 | 
			
		||||
namespace esphome {
 | 
			
		||||
namespace prometheus {
 | 
			
		||||
@@ -119,5 +117,3 @@ class PrometheusHandler : public AsyncWebHandler, public Component {
 | 
			
		||||
 | 
			
		||||
}  // namespace prometheus
 | 
			
		||||
}  // namespace esphome
 | 
			
		||||
 | 
			
		||||
#endif  // USE_ARDUINO
 | 
			
		||||
 
 | 
			
		||||
@@ -7,6 +7,13 @@ namespace pulse_meter {
 | 
			
		||||
 | 
			
		||||
static const char *const TAG = "pulse_meter";
 | 
			
		||||
 | 
			
		||||
void PulseMeterSensor::set_total_pulses(uint32_t pulses) {
 | 
			
		||||
  this->total_pulses_ = pulses;
 | 
			
		||||
  if (this->total_sensor_ != nullptr) {
 | 
			
		||||
    this->total_sensor_->publish_state(this->total_pulses_);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void PulseMeterSensor::setup() {
 | 
			
		||||
  this->pin_->setup();
 | 
			
		||||
  this->isr_pin_ = pin_->to_isr();
 | 
			
		||||
 
 | 
			
		||||
@@ -20,7 +20,8 @@ class PulseMeterSensor : public sensor::Sensor, public Component {
 | 
			
		||||
  void set_timeout_us(uint32_t timeout) { this->timeout_us_ = timeout; }
 | 
			
		||||
  void set_total_sensor(sensor::Sensor *sensor) { this->total_sensor_ = sensor; }
 | 
			
		||||
  void set_filter_mode(InternalFilterMode mode) { this->filter_mode_ = mode; }
 | 
			
		||||
  void set_total_pulses(uint32_t pulses) { this->total_pulses_ = pulses; }
 | 
			
		||||
 | 
			
		||||
  void set_total_pulses(uint32_t pulses);
 | 
			
		||||
 | 
			
		||||
  void setup() override;
 | 
			
		||||
  void loop() override;
 | 
			
		||||
 
 | 
			
		||||
@@ -19,7 +19,7 @@ from esphome.const import (
 | 
			
		||||
)
 | 
			
		||||
from esphome.core import CORE
 | 
			
		||||
 | 
			
		||||
CODEOWNERS = ["@stevebaxter", "@cstaahl"]
 | 
			
		||||
CODEOWNERS = ["@stevebaxter", "@cstaahl", "@TrentHouliston"]
 | 
			
		||||
 | 
			
		||||
pulse_meter_ns = cg.esphome_ns.namespace("pulse_meter")
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -11,6 +11,8 @@ static const uint8_t SM10BIT_ADDR_START_3CH = 0x8;
 | 
			
		||||
static const uint8_t SM10BIT_ADDR_START_2CH = 0x10;
 | 
			
		||||
static const uint8_t SM10BIT_ADDR_START_5CH = 0x18;
 | 
			
		||||
 | 
			
		||||
static const uint8_t SM10BIT_DELAY = 2;
 | 
			
		||||
 | 
			
		||||
// Power current values
 | 
			
		||||
// HEX | Binary | RGB level | White level | Config value
 | 
			
		||||
// 0x0 | 0000   | RGB 10mA  | CW 5mA      | 0
 | 
			
		||||
@@ -37,10 +39,13 @@ void Sm10BitBase::loop() {
 | 
			
		||||
  uint8_t data[12];
 | 
			
		||||
  if (this->pwm_amounts_[0] == 0 && this->pwm_amounts_[1] == 0 && this->pwm_amounts_[2] == 0 &&
 | 
			
		||||
      this->pwm_amounts_[3] == 0 && this->pwm_amounts_[4] == 0) {
 | 
			
		||||
    // Off / Sleep
 | 
			
		||||
    data[0] = this->model_id_ + SM10BIT_ADDR_STANDBY;
 | 
			
		||||
    for (int i = 1; i < 12; i++)
 | 
			
		||||
      data[i] = 0;
 | 
			
		||||
    // First turn all channels off
 | 
			
		||||
    data[0] = this->model_id_ + SM10BIT_ADDR_START_5CH;
 | 
			
		||||
    this->write_buffer_(data, 12);
 | 
			
		||||
    // Then sleep
 | 
			
		||||
    data[0] = this->model_id_ + SM10BIT_ADDR_STANDBY;
 | 
			
		||||
    this->write_buffer_(data, 12);
 | 
			
		||||
  } else if (this->pwm_amounts_[0] == 0 && this->pwm_amounts_[1] == 0 && this->pwm_amounts_[2] == 0 &&
 | 
			
		||||
             (this->pwm_amounts_[3] > 0 || this->pwm_amounts_[4] > 0)) {
 | 
			
		||||
@@ -84,28 +89,42 @@ void Sm10BitBase::set_channel_value_(uint8_t channel, uint16_t value) {
 | 
			
		||||
  this->pwm_amounts_[channel] = value;
 | 
			
		||||
}
 | 
			
		||||
void Sm10BitBase::write_bit_(bool value) {
 | 
			
		||||
  this->clock_pin_->digital_write(false);
 | 
			
		||||
  this->data_pin_->digital_write(value);
 | 
			
		||||
  delayMicroseconds(SM10BIT_DELAY);
 | 
			
		||||
  this->clock_pin_->digital_write(true);
 | 
			
		||||
  delayMicroseconds(SM10BIT_DELAY);
 | 
			
		||||
  this->clock_pin_->digital_write(false);
 | 
			
		||||
  delayMicroseconds(SM10BIT_DELAY);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Sm10BitBase::write_byte_(uint8_t data) {
 | 
			
		||||
  for (uint8_t mask = 0x80; mask; mask >>= 1) {
 | 
			
		||||
    this->write_bit_(data & mask);
 | 
			
		||||
  }
 | 
			
		||||
  this->clock_pin_->digital_write(false);
 | 
			
		||||
  this->data_pin_->digital_write(true);
 | 
			
		||||
 | 
			
		||||
  // ack bit
 | 
			
		||||
  this->data_pin_->pin_mode(gpio::FLAG_INPUT);
 | 
			
		||||
  this->clock_pin_->digital_write(true);
 | 
			
		||||
  delayMicroseconds(SM10BIT_DELAY);
 | 
			
		||||
  this->clock_pin_->digital_write(false);
 | 
			
		||||
  delayMicroseconds(SM10BIT_DELAY);
 | 
			
		||||
  this->data_pin_->pin_mode(gpio::FLAG_OUTPUT);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Sm10BitBase::write_buffer_(uint8_t *buffer, uint8_t size) {
 | 
			
		||||
  this->data_pin_->digital_write(false);
 | 
			
		||||
  delayMicroseconds(SM10BIT_DELAY);
 | 
			
		||||
  this->clock_pin_->digital_write(false);
 | 
			
		||||
  delayMicroseconds(SM10BIT_DELAY);
 | 
			
		||||
 | 
			
		||||
  for (uint32_t i = 0; i < size; i++) {
 | 
			
		||||
    this->write_byte_(buffer[i]);
 | 
			
		||||
  }
 | 
			
		||||
  this->clock_pin_->digital_write(false);
 | 
			
		||||
 | 
			
		||||
  this->clock_pin_->digital_write(true);
 | 
			
		||||
  delayMicroseconds(SM10BIT_DELAY);
 | 
			
		||||
  this->data_pin_->digital_write(true);
 | 
			
		||||
  delayMicroseconds(SM10BIT_DELAY);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}  // namespace sm10bit_base
 | 
			
		||||
 
 | 
			
		||||
@@ -88,11 +88,6 @@ uint64_t bytes_to_uint(const bytes &buffer) {
 | 
			
		||||
  for (auto const value : buffer) {
 | 
			
		||||
    val = (val << 8) + value;
 | 
			
		||||
  }
 | 
			
		||||
  // Some smart meters send 24 bit signed integers. Sign extend to 64 bit if the
 | 
			
		||||
  // 24 bit value is negative.
 | 
			
		||||
  if (buffer.size() == 3 && buffer[0] & 0x80) {
 | 
			
		||||
    val |= 0xFFFFFFFFFF000000;
 | 
			
		||||
  }
 | 
			
		||||
  return val;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -100,19 +95,15 @@ int64_t bytes_to_int(const bytes &buffer) {
 | 
			
		||||
  uint64_t tmp = bytes_to_uint(buffer);
 | 
			
		||||
  int64_t val;
 | 
			
		||||
 | 
			
		||||
  switch (buffer.size()) {
 | 
			
		||||
    case 1:  // int8
 | 
			
		||||
      val = (int8_t) tmp;
 | 
			
		||||
      break;
 | 
			
		||||
    case 2:  // int16
 | 
			
		||||
      val = (int16_t) tmp;
 | 
			
		||||
      break;
 | 
			
		||||
    case 4:  // int32
 | 
			
		||||
      val = (int32_t) tmp;
 | 
			
		||||
      break;
 | 
			
		||||
    default:  // int64
 | 
			
		||||
      val = (int64_t) tmp;
 | 
			
		||||
  // sign extension for abbreviations of leading ones (e.g. 3 byte transmissions, see 6.2.2 of SML protocol definition)
 | 
			
		||||
  // see https://stackoverflow.com/questions/42534749/signed-extension-from-24-bit-to-32-bit-in-c
 | 
			
		||||
  if (buffer.size() < 8) {
 | 
			
		||||
    const int bits = buffer.size() * 8;
 | 
			
		||||
    const uint64_t m = 1u << (bits - 1);
 | 
			
		||||
    tmp = (tmp ^ m) - m;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  val = (int64_t) tmp;
 | 
			
		||||
  return val;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -10,7 +10,7 @@ namespace socket {
 | 
			
		||||
Socket::~Socket() {}
 | 
			
		||||
 | 
			
		||||
std::unique_ptr<Socket> socket_ip(int type, int protocol) {
 | 
			
		||||
#if LWIP_IPV6
 | 
			
		||||
#if ENABLE_IPV6
 | 
			
		||||
  return socket(AF_INET6, type, protocol);
 | 
			
		||||
#else
 | 
			
		||||
  return socket(AF_INET, type, protocol);
 | 
			
		||||
@@ -18,7 +18,7 @@ std::unique_ptr<Socket> socket_ip(int type, int protocol) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
socklen_t set_sockaddr(struct sockaddr *addr, socklen_t addrlen, const std::string &ip_address, uint16_t port) {
 | 
			
		||||
#if LWIP_IPV6
 | 
			
		||||
#if ENABLE_IPV6
 | 
			
		||||
  if (addrlen < sizeof(sockaddr_in6)) {
 | 
			
		||||
    errno = EINVAL;
 | 
			
		||||
    return 0;
 | 
			
		||||
@@ -51,7 +51,7 @@ socklen_t set_sockaddr(struct sockaddr *addr, socklen_t addrlen, const std::stri
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
socklen_t set_sockaddr_any(struct sockaddr *addr, socklen_t addrlen, uint16_t port) {
 | 
			
		||||
#if LWIP_IPV6
 | 
			
		||||
#if ENABLE_IPV6
 | 
			
		||||
  if (addrlen < sizeof(sockaddr_in6)) {
 | 
			
		||||
    errno = EINVAL;
 | 
			
		||||
    return 0;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
#include "esphome/core/log.h"
 | 
			
		||||
#include "tuya_text_sensor.h"
 | 
			
		||||
#include "esphome/core/log.h"
 | 
			
		||||
 | 
			
		||||
namespace esphome {
 | 
			
		||||
namespace tuya {
 | 
			
		||||
@@ -19,6 +19,12 @@ void TuyaTextSensor::setup() {
 | 
			
		||||
        this->publish_state(data);
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      case TuyaDatapointType::ENUM: {
 | 
			
		||||
        std::string data = to_string(datapoint.value_enum);
 | 
			
		||||
        ESP_LOGD(TAG, "MCU reported text sensor %u is: %s", datapoint.id, data.c_str());
 | 
			
		||||
        this->publish_state(data);
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      default:
 | 
			
		||||
        ESP_LOGW(TAG, "Unsupported data type for tuya text sensor %u: %#02hhX", datapoint.id, (uint8_t) datapoint.type);
 | 
			
		||||
        break;
 | 
			
		||||
 
 | 
			
		||||
@@ -281,11 +281,15 @@ void VoiceAssistant::loop() {
 | 
			
		||||
            memmove(this->speaker_buffer_, this->speaker_buffer_ + written, this->speaker_buffer_size_ - written);
 | 
			
		||||
            this->speaker_buffer_size_ -= written;
 | 
			
		||||
            this->speaker_buffer_index_ -= written;
 | 
			
		||||
            this->set_timeout("speaker-timeout", 1000, [this]() { this->speaker_->stop(); });
 | 
			
		||||
            this->set_timeout("speaker-timeout", 2000, [this]() { this->speaker_->stop(); });
 | 
			
		||||
          } else {
 | 
			
		||||
            ESP_LOGW(TAG, "Speaker buffer full.");
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
        if (this->wait_for_stream_end_) {
 | 
			
		||||
          this->cancel_timeout("playing");
 | 
			
		||||
          break;  // We dont want to timeout here as the STREAM_END event will take care of that.
 | 
			
		||||
        }
 | 
			
		||||
        playing = this->speaker_->is_running();
 | 
			
		||||
      }
 | 
			
		||||
#endif
 | 
			
		||||
@@ -295,28 +299,77 @@ void VoiceAssistant::loop() {
 | 
			
		||||
      }
 | 
			
		||||
#endif
 | 
			
		||||
      if (playing) {
 | 
			
		||||
        this->set_timeout("playing", 100, [this]() {
 | 
			
		||||
        this->set_timeout("playing", 2000, [this]() {
 | 
			
		||||
          this->cancel_timeout("speaker-timeout");
 | 
			
		||||
          this->set_state_(State::IDLE, State::IDLE);
 | 
			
		||||
        });
 | 
			
		||||
      }
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    case State::RESPONSE_FINISHED: {
 | 
			
		||||
#ifdef USE_SPEAKER
 | 
			
		||||
      if (this->speaker_ != nullptr) {
 | 
			
		||||
        this->speaker_->stop();
 | 
			
		||||
        this->cancel_timeout("speaker-timeout");
 | 
			
		||||
        this->cancel_timeout("playing");
 | 
			
		||||
        this->speaker_buffer_size_ = 0;
 | 
			
		||||
        this->speaker_buffer_index_ = 0;
 | 
			
		||||
        memset(this->speaker_buffer_, 0, SPEAKER_BUFFER_SIZE);
 | 
			
		||||
      }
 | 
			
		||||
      this->wait_for_stream_end_ = false;
 | 
			
		||||
#endif
 | 
			
		||||
      this->set_state_(State::IDLE, State::IDLE);
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    default:
 | 
			
		||||
      break;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const LogString *voice_assistant_state_to_string(State state) {
 | 
			
		||||
  switch (state) {
 | 
			
		||||
    case State::IDLE:
 | 
			
		||||
      return LOG_STR("IDLE");
 | 
			
		||||
    case State::START_MICROPHONE:
 | 
			
		||||
      return LOG_STR("START_MICROPHONE");
 | 
			
		||||
    case State::STARTING_MICROPHONE:
 | 
			
		||||
      return LOG_STR("STARTING_MICROPHONE");
 | 
			
		||||
    case State::WAIT_FOR_VAD:
 | 
			
		||||
      return LOG_STR("WAIT_FOR_VAD");
 | 
			
		||||
    case State::WAITING_FOR_VAD:
 | 
			
		||||
      return LOG_STR("WAITING_FOR_VAD");
 | 
			
		||||
    case State::START_PIPELINE:
 | 
			
		||||
      return LOG_STR("START_PIPELINE");
 | 
			
		||||
    case State::STARTING_PIPELINE:
 | 
			
		||||
      return LOG_STR("STARTING_PIPELINE");
 | 
			
		||||
    case State::STREAMING_MICROPHONE:
 | 
			
		||||
      return LOG_STR("STREAMING_MICROPHONE");
 | 
			
		||||
    case State::STOP_MICROPHONE:
 | 
			
		||||
      return LOG_STR("STOP_MICROPHONE");
 | 
			
		||||
    case State::STOPPING_MICROPHONE:
 | 
			
		||||
      return LOG_STR("STOPPING_MICROPHONE");
 | 
			
		||||
    case State::AWAITING_RESPONSE:
 | 
			
		||||
      return LOG_STR("AWAITING_RESPONSE");
 | 
			
		||||
    case State::STREAMING_RESPONSE:
 | 
			
		||||
      return LOG_STR("STREAMING_RESPONSE");
 | 
			
		||||
    case State::RESPONSE_FINISHED:
 | 
			
		||||
      return LOG_STR("RESPONSE_FINISHED");
 | 
			
		||||
    default:
 | 
			
		||||
      return LOG_STR("UNKNOWN");
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void VoiceAssistant::set_state_(State state) {
 | 
			
		||||
  State old_state = this->state_;
 | 
			
		||||
  this->state_ = state;
 | 
			
		||||
  ESP_LOGD(TAG, "State changed from %d to %d", static_cast<uint8_t>(old_state), static_cast<uint8_t>(state));
 | 
			
		||||
  ESP_LOGD(TAG, "State changed from %s to %s", LOG_STR_ARG(voice_assistant_state_to_string(old_state)),
 | 
			
		||||
           LOG_STR_ARG(voice_assistant_state_to_string(state)));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void VoiceAssistant::set_state_(State state, State desired_state) {
 | 
			
		||||
  this->set_state_(state);
 | 
			
		||||
  this->desired_state_ = desired_state;
 | 
			
		||||
  ESP_LOGD(TAG, "Desired state set to %d", static_cast<uint8_t>(desired_state));
 | 
			
		||||
  ESP_LOGD(TAG, "Desired state set to %s", LOG_STR_ARG(voice_assistant_state_to_string(desired_state)));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void VoiceAssistant::failed_to_start() {
 | 
			
		||||
@@ -400,6 +453,7 @@ void VoiceAssistant::request_stop() {
 | 
			
		||||
      break;
 | 
			
		||||
    case State::AWAITING_RESPONSE:
 | 
			
		||||
    case State::STREAMING_RESPONSE:
 | 
			
		||||
    case State::RESPONSE_FINISHED:
 | 
			
		||||
      break;  // Let the incoming audio stream finish then it will go to idle.
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -531,6 +585,16 @@ void VoiceAssistant::on_event(const api::VoiceAssistantEventResponse &msg) {
 | 
			
		||||
      this->error_trigger_->trigger(code, message);
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    case api::enums::VOICE_ASSISTANT_TTS_STREAM_START: {
 | 
			
		||||
#ifdef USE_SPEAKER
 | 
			
		||||
      this->wait_for_stream_end_ = true;
 | 
			
		||||
#endif
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    case api::enums::VOICE_ASSISTANT_TTS_STREAM_END: {
 | 
			
		||||
      this->set_state_(State::RESPONSE_FINISHED, State::IDLE);
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    default:
 | 
			
		||||
      ESP_LOGD(TAG, "Unhandled event type: %d", msg.event_type);
 | 
			
		||||
      break;
 | 
			
		||||
 
 | 
			
		||||
@@ -46,6 +46,7 @@ enum class State {
 | 
			
		||||
  STOPPING_MICROPHONE,
 | 
			
		||||
  AWAITING_RESPONSE,
 | 
			
		||||
  STREAMING_RESPONSE,
 | 
			
		||||
  RESPONSE_FINISHED,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class VoiceAssistant : public Component {
 | 
			
		||||
@@ -132,10 +133,10 @@ class VoiceAssistant : public Component {
 | 
			
		||||
  uint8_t *speaker_buffer_;
 | 
			
		||||
  size_t speaker_buffer_index_{0};
 | 
			
		||||
  size_t speaker_buffer_size_{0};
 | 
			
		||||
  bool wait_for_stream_end_{false};
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef USE_MEDIA_PLAYER
 | 
			
		||||
  media_player::MediaPlayer *media_player_{nullptr};
 | 
			
		||||
  bool playing_tts_{false};
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  bool local_output_{false};
 | 
			
		||||
 
 | 
			
		||||
@@ -8,16 +8,16 @@
 | 
			
		||||
#include <user_interface.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include <utility>
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include "lwip/err.h"
 | 
			
		||||
#include <utility>
 | 
			
		||||
#include "lwip/dns.h"
 | 
			
		||||
#include "lwip/err.h"
 | 
			
		||||
 | 
			
		||||
#include "esphome/core/application.h"
 | 
			
		||||
#include "esphome/core/hal.h"
 | 
			
		||||
#include "esphome/core/helpers.h"
 | 
			
		||||
#include "esphome/core/log.h"
 | 
			
		||||
#include "esphome/core/hal.h"
 | 
			
		||||
#include "esphome/core/util.h"
 | 
			
		||||
#include "esphome/core/application.h"
 | 
			
		||||
 | 
			
		||||
#ifdef USE_CAPTIVE_PORTAL
 | 
			
		||||
#include "esphome/components/captive_portal/captive_portal.h"
 | 
			
		||||
@@ -96,7 +96,7 @@ void WiFiComponent::start() {
 | 
			
		||||
#endif
 | 
			
		||||
  }
 | 
			
		||||
#ifdef USE_IMPROV
 | 
			
		||||
  if (esp32_improv::global_improv_component != nullptr) {
 | 
			
		||||
  if (!this->has_sta() && esp32_improv::global_improv_component != nullptr) {
 | 
			
		||||
    if (this->wifi_mode_(true, {}))
 | 
			
		||||
      esp32_improv::global_improv_component->start();
 | 
			
		||||
  }
 | 
			
		||||
@@ -163,8 +163,8 @@ void WiFiComponent::loop() {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
#ifdef USE_IMPROV
 | 
			
		||||
    if (esp32_improv::global_improv_component != nullptr) {
 | 
			
		||||
      if (!this->is_connected()) {
 | 
			
		||||
    if (esp32_improv::global_improv_component != nullptr && !esp32_improv::global_improv_component->is_active()) {
 | 
			
		||||
      if (now - this->last_connected_ > esp32_improv::global_improv_component->get_wifi_timeout()) {
 | 
			
		||||
        if (this->wifi_mode_(true, {}))
 | 
			
		||||
          esp32_improv::global_improv_component->start();
 | 
			
		||||
      }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
"""Constants used by esphome."""
 | 
			
		||||
 | 
			
		||||
__version__ = "2023.11.0-dev"
 | 
			
		||||
__version__ = "2023.10.4"
 | 
			
		||||
 | 
			
		||||
ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_"
 | 
			
		||||
VALID_SUBSTITUTIONS_CHARACTERS = (
 | 
			
		||||
 
 | 
			
		||||
@@ -52,12 +52,12 @@ template<typename... Ts> class XorCondition : public Condition<Ts...> {
 | 
			
		||||
 public:
 | 
			
		||||
  explicit XorCondition(const std::vector<Condition<Ts...> *> &conditions) : conditions_(conditions) {}
 | 
			
		||||
  bool check(Ts... x) override {
 | 
			
		||||
    bool xor_state = false;
 | 
			
		||||
    size_t result = 0;
 | 
			
		||||
    for (auto *condition : this->conditions_) {
 | 
			
		||||
      xor_state = xor_state ^ condition->check(x...);
 | 
			
		||||
      result += condition->check(x...);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return xor_state;
 | 
			
		||||
    return result == 1;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 protected:
 | 
			
		||||
 
 | 
			
		||||
@@ -37,6 +37,7 @@
 | 
			
		||||
#define USE_OTA
 | 
			
		||||
#define USE_OTA_PASSWORD
 | 
			
		||||
#define USE_OTA_STATE_CALLBACK
 | 
			
		||||
#define USE_OUTPUT
 | 
			
		||||
#define USE_POWER_SUPPLY
 | 
			
		||||
#define USE_QR_CODE
 | 
			
		||||
#define USE_SELECT
 | 
			
		||||
@@ -117,6 +118,6 @@
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
// Disabled feature flags
 | 
			
		||||
//#define USE_BSEC  // Requires a library with proprietary license.
 | 
			
		||||
// #define USE_BSEC  // Requires a library with proprietary license.
 | 
			
		||||
 | 
			
		||||
#define USE_DASHBOARD_IMPORT
 | 
			
		||||
 
 | 
			
		||||
@@ -3326,6 +3326,10 @@ text_sensor:
 | 
			
		||||
          canbus_id: mcp2515_can
 | 
			
		||||
          can_id: 23
 | 
			
		||||
          data: [0x10, 0x20, 0x30]
 | 
			
		||||
      - canbus.send:
 | 
			
		||||
          canbus_id: mcp2515_can
 | 
			
		||||
          can_id: 23
 | 
			
		||||
          data: !lambda return {0x10, 0x20, 0x30};
 | 
			
		||||
      - canbus.send:
 | 
			
		||||
          canbus_id: esp32_internal_can
 | 
			
		||||
          can_id: 23
 | 
			
		||||
 
 | 
			
		||||
@@ -26,3 +26,9 @@ sensor:
 | 
			
		||||
    name: ADC
 | 
			
		||||
    pin: GPIO23
 | 
			
		||||
    update_interval: 1s
 | 
			
		||||
 | 
			
		||||
mqtt:
 | 
			
		||||
  broker: test.mosquitto.org
 | 
			
		||||
  port: 1883
 | 
			
		||||
  discovery: true
 | 
			
		||||
  discovery_prefix: homeassistant
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user