esphome 2024.11.2__py3-none-any.whl → 2024.12.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (192) hide show
  1. esphome/__main__.py +1 -1
  2. esphome/components/adc/adc_sensor.h +7 -8
  3. esphome/components/adc/adc_sensor_common.cpp +24 -0
  4. esphome/components/adc/{adc_sensor.cpp → adc_sensor_esp32.cpp} +10 -179
  5. esphome/components/adc/adc_sensor_esp8266.cpp +58 -0
  6. esphome/components/adc/adc_sensor_libretiny.cpp +48 -0
  7. esphome/components/adc/adc_sensor_rp2040.cpp +93 -0
  8. esphome/components/alarm_control_panel/alarm_control_panel_call.cpp +3 -4
  9. esphome/components/animation/__init__.py +1 -2
  10. esphome/components/apds9306/apds9306.cpp +2 -1
  11. esphome/components/audio/audio.h +1 -1
  12. esphome/components/bk72xx/__init__.py +1 -1
  13. esphome/components/cse7766/cse7766.cpp +1 -1
  14. esphome/components/datetime/datetime_entity.cpp +1 -3
  15. esphome/components/deep_sleep/deep_sleep_esp32.cpp +2 -2
  16. esphome/components/dht/dht.cpp +2 -1
  17. esphome/components/display/display.cpp +10 -6
  18. esphome/components/display/display.h +14 -0
  19. esphome/components/display_menu_base/__init__.py +0 -2
  20. esphome/components/display_menu_base/display_menu_base.cpp +1 -1
  21. esphome/components/dsmr/dsmr.cpp +1 -1
  22. esphome/components/esp32/__init__.py +100 -22
  23. esphome/components/esp32/boards.py +222 -14
  24. esphome/components/esp32_ble/__init__.py +22 -2
  25. esphome/components/esp32_ble/ble.cpp +39 -12
  26. esphome/components/esp32_ble/ble.h +2 -0
  27. esphome/components/esp32_ble/ble_advertising.cpp +1 -1
  28. esphome/components/esp32_ble/ble_uuid.cpp +9 -10
  29. esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp +4 -1
  30. esphome/components/esp32_camera_web_server/camera_web_server.h +1 -1
  31. esphome/components/esp32_rmt_led_strip/light.py +3 -3
  32. esphome/components/esp8266/__init__.py +5 -7
  33. esphome/components/ezo/ezo.cpp +14 -26
  34. esphome/components/font/__init__.py +10 -25
  35. esphome/components/font/font.cpp +5 -3
  36. esphome/components/graphical_display_menu/__init__.py +2 -0
  37. esphome/components/haier/hon_climate.cpp +79 -80
  38. esphome/components/hbridge/switch/__init__.py +44 -0
  39. esphome/components/hbridge/switch/hbridge_switch.cpp +95 -0
  40. esphome/components/hbridge/switch/hbridge_switch.h +50 -0
  41. esphome/components/hitachi_ac344/hitachi_ac344.cpp +4 -2
  42. esphome/components/hitachi_ac424/hitachi_ac424.cpp +4 -2
  43. esphome/components/homeassistant/number/homeassistant_number.cpp +3 -0
  44. esphome/components/hx711/hx711.cpp +1 -1
  45. esphome/components/hx711/hx711.h +1 -1
  46. esphome/components/i2c/i2c_bus_esp_idf.cpp +2 -2
  47. esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp +61 -59
  48. esphome/components/i2s_audio/speaker/i2s_audio_speaker.h +8 -17
  49. esphome/components/ili9xxx/display.py +1 -2
  50. esphome/components/ili9xxx/ili9xxx_display.cpp +3 -2
  51. esphome/components/image/__init__.py +1 -2
  52. esphome/components/logger/logger.cpp +1 -1
  53. esphome/components/ltr501/ltr501.cpp +1 -1
  54. esphome/components/lvgl/defines.py +9 -2
  55. esphome/components/lvgl/lv_validation.py +8 -3
  56. esphome/components/lvgl/lvgl_esphome.cpp +1 -1
  57. esphome/components/lvgl/lvgl_esphome.h +19 -0
  58. esphome/components/lvgl/widgets/animimg.py +12 -17
  59. esphome/components/lvgl/widgets/img.py +1 -3
  60. esphome/components/lvgl/widgets/line.py +6 -0
  61. esphome/components/lvgl/widgets/msgbox.py +2 -1
  62. esphome/components/matrix_keypad/__init__.py +15 -3
  63. esphome/components/matrix_keypad/matrix_keypad.cpp +4 -0
  64. esphome/components/matrix_keypad/matrix_keypad.h +5 -0
  65. esphome/components/max31865/max31865.cpp +4 -2
  66. esphome/components/modbus_controller/modbus_controller.cpp +24 -24
  67. esphome/components/modbus_controller/modbus_controller.h +22 -22
  68. esphome/components/modbus_controller/number/modbus_number.cpp +8 -8
  69. esphome/components/modbus_controller/number/modbus_number.h +4 -4
  70. esphome/components/modbus_controller/output/modbus_output.cpp +7 -6
  71. esphome/components/modbus_controller/output/modbus_output.h +5 -5
  72. esphome/components/modbus_controller/select/modbus_select.cpp +4 -3
  73. esphome/components/modbus_controller/select/modbus_select.h +4 -4
  74. esphome/components/modbus_controller/switch/modbus_switch.cpp +5 -5
  75. esphome/components/modbus_controller/switch/modbus_switch.h +2 -2
  76. esphome/components/mqtt/__init__.py +4 -0
  77. esphome/components/mqtt/mqtt_alarm_control_panel.cpp +2 -5
  78. esphome/components/mqtt/mqtt_backend_esp32.cpp +3 -3
  79. esphome/components/mqtt/mqtt_client.cpp +4 -0
  80. esphome/components/mqtt/mqtt_client.h +6 -0
  81. esphome/components/mqtt/mqtt_climate.cpp +13 -3
  82. esphome/components/mqtt/mqtt_sensor.cpp +2 -0
  83. esphome/components/network/ip_address.h +1 -1
  84. esphome/components/nextion/__init__.py +2 -0
  85. esphome/components/nextion/automation.h +76 -0
  86. esphome/components/nextion/base_component.py +1 -0
  87. esphome/components/nextion/binary_sensor/__init__.py +43 -2
  88. esphome/components/nextion/display.py +15 -0
  89. esphome/components/nextion/nextion.cpp +8 -5
  90. esphome/components/nextion/nextion.h +7 -0
  91. esphome/components/nextion/nextion_upload_idf.cpp +2 -2
  92. esphome/components/nextion/sensor/__init__.py +38 -5
  93. esphome/components/nextion/switch/__init__.py +38 -2
  94. esphome/components/nextion/text_sensor/__init__.py +37 -2
  95. esphome/components/nfc/ndef_record.cpp +3 -3
  96. esphome/components/online_image/__init__.py +1 -0
  97. esphome/components/online_image/png_image.cpp +4 -0
  98. esphome/components/opentherm/hub.cpp +6 -7
  99. esphome/components/opentherm/opentherm.cpp +18 -34
  100. esphome/components/opentherm/opentherm.h +4 -5
  101. esphome/components/ota/automation.h +1 -1
  102. esphome/components/output/float_output.cpp +1 -1
  103. esphome/components/pca6416a/pca6416a.cpp +5 -3
  104. esphome/components/pca9554/pca9554.cpp +4 -4
  105. esphome/components/pipsolar/pipsolar.cpp +2 -2
  106. esphome/components/pipsolar/switch/pipsolar_switch.cpp +2 -2
  107. esphome/components/pn532/pn532_mifare_ultralight.cpp +2 -2
  108. esphome/components/pn7150/pn7150_mifare_ultralight.cpp +2 -2
  109. esphome/components/pn7160/pn7160_mifare_ultralight.cpp +2 -2
  110. esphome/components/qmc5883l/qmc5883l.cpp +45 -19
  111. esphome/components/qmc5883l/qmc5883l.h +1 -1
  112. esphome/components/qspi_dbi/qspi_dbi.cpp +2 -1
  113. esphome/components/remote_base/raw_protocol.cpp +1 -1
  114. esphome/components/remote_receiver/__init__.py +5 -6
  115. esphome/components/rotary_encoder/rotary_encoder.cpp +3 -1
  116. esphome/components/rp2040/__init__.py +1 -1
  117. esphome/components/rtl87xx/__init__.py +1 -1
  118. esphome/components/safe_mode/automation.h +1 -1
  119. esphome/components/seeed_mr60bha2/__init__.py +41 -0
  120. esphome/components/seeed_mr60bha2/seeed_mr60bha2.cpp +173 -0
  121. esphome/components/seeed_mr60bha2/seeed_mr60bha2.h +61 -0
  122. esphome/components/seeed_mr60bha2/sensor.py +57 -0
  123. esphome/components/seeed_mr60fda2/__init__.py +41 -0
  124. esphome/components/seeed_mr60fda2/binary_sensor.py +33 -0
  125. esphome/components/seeed_mr60fda2/button/__init__.py +45 -0
  126. esphome/components/seeed_mr60fda2/button/get_radar_parameters_button.cpp +9 -0
  127. esphome/components/seeed_mr60fda2/button/get_radar_parameters_button.h +18 -0
  128. esphome/components/seeed_mr60fda2/button/reset_radar_button.cpp +9 -0
  129. esphome/components/seeed_mr60fda2/button/reset_radar_button.h +18 -0
  130. esphome/components/seeed_mr60fda2/seeed_mr60fda2.cpp +368 -0
  131. esphome/components/seeed_mr60fda2/seeed_mr60fda2.h +101 -0
  132. esphome/components/seeed_mr60fda2/select/__init__.py +59 -0
  133. esphome/components/seeed_mr60fda2/select/height_threshold_select.cpp +15 -0
  134. esphome/components/seeed_mr60fda2/select/height_threshold_select.h +18 -0
  135. esphome/components/seeed_mr60fda2/select/install_height_select.cpp +15 -0
  136. esphome/components/seeed_mr60fda2/select/install_height_select.h +18 -0
  137. esphome/components/seeed_mr60fda2/select/sensitivity_select.cpp +15 -0
  138. esphome/components/seeed_mr60fda2/select/sensitivity_select.h +18 -0
  139. esphome/components/sen5x/sensor.py +5 -6
  140. esphome/components/sgp30/sensor.py +8 -9
  141. esphome/components/sgp30/sgp30.cpp +2 -6
  142. esphome/components/shelly_dimmer/shelly_dimmer.cpp +1 -1
  143. esphome/components/sim800l/sim800l.cpp +1 -1
  144. esphome/components/sntp/sntp_component.cpp +14 -20
  145. esphome/components/sntp/sntp_component.h +6 -9
  146. esphome/components/sntp/time.py +4 -7
  147. esphome/components/sprinkler/sprinkler.cpp +2 -2
  148. esphome/components/st7735/st7735.cpp +1 -1
  149. esphome/components/st7789v/st7789v.cpp +1 -1
  150. esphome/components/st7920/st7920.cpp +2 -3
  151. esphome/components/stepper/stepper.h +0 -1
  152. esphome/components/sun_gtil2/sun_gtil2.cpp +1 -1
  153. esphome/components/switch/binary_sensor/__init__.py +31 -0
  154. esphome/components/switch/binary_sensor/switch_binary_sensor.cpp +17 -0
  155. esphome/components/switch/binary_sensor/switch_binary_sensor.h +22 -0
  156. esphome/components/sx1509/sx1509_gpio_pin.cpp +2 -1
  157. esphome/components/sx1509/sx1509_gpio_pin.h +5 -5
  158. esphome/components/uart/uart.h +1 -1
  159. esphome/components/udp/udp_component.cpp +32 -16
  160. esphome/components/ufire_ec/sensor.py +4 -4
  161. esphome/components/uln2003/uln2003.cpp +4 -1
  162. esphome/components/waveshare_epaper/display.py +8 -0
  163. esphome/components/waveshare_epaper/waveshare_epaper.cpp +191 -0
  164. esphome/components/waveshare_epaper/waveshare_epaper.h +56 -0
  165. esphome/components/wiegand/__init__.py +3 -4
  166. esphome/components/wifi/__init__.py +42 -0
  167. esphome/components/wifi/wifi_component.cpp +2 -2
  168. esphome/components/wifi/wifi_component.h +82 -1
  169. esphome/components/wifi/wifi_component_esp32_arduino.cpp +1 -1
  170. esphome/components/wifi/wifi_component_esp8266.cpp +1 -1
  171. esphome/components/wifi/wifi_component_esp_idf.cpp +1 -1
  172. esphome/components/wifi/wifi_component_libretiny.cpp +1 -1
  173. esphome/components/wifi/wifi_component_pico_w.cpp +1 -1
  174. esphome/components/wireguard/wireguard.cpp +2 -2
  175. esphome/components/xiaomi_ble/xiaomi_ble.cpp +1 -1
  176. esphome/config_validation.py +15 -11
  177. esphome/const.py +11 -1
  178. esphome/core/component.cpp +1 -1
  179. esphome/core/config.py +1 -2
  180. esphome/core/defines.h +3 -1
  181. esphome/core/helpers.cpp +20 -2
  182. esphome/core/helpers.h +10 -1
  183. esphome/core/optional.h +2 -2
  184. esphome/core/time.cpp +19 -15
  185. esphome/core/time.h +1 -3
  186. esphome/dashboard/web_server.py +6 -0
  187. {esphome-2024.11.2.dist-info → esphome-2024.12.0.dist-info}/METADATA +4 -4
  188. {esphome-2024.11.2.dist-info → esphome-2024.12.0.dist-info}/RECORD +192 -162
  189. {esphome-2024.11.2.dist-info → esphome-2024.12.0.dist-info}/LICENSE +0 -0
  190. {esphome-2024.11.2.dist-info → esphome-2024.12.0.dist-info}/WHEEL +0 -0
  191. {esphome-2024.11.2.dist-info → esphome-2024.12.0.dist-info}/entry_points.txt +0 -0
  192. {esphome-2024.11.2.dist-info → esphome-2024.12.0.dist-info}/top_level.txt +0 -0
@@ -42,12 +42,12 @@ class ModbusSelect : public Component, public select::Select, public SensorItem
42
42
  void control(const std::string &value) override;
43
43
 
44
44
  protected:
45
- std::vector<int64_t> mapping_;
46
- ModbusController *parent_;
45
+ std::vector<int64_t> mapping_{};
46
+ ModbusController *parent_{nullptr};
47
47
  bool use_write_multiple_{false};
48
48
  bool optimistic_{false};
49
- optional<transform_func_t> transform_func_;
50
- optional<write_transform_func_t> write_transform_func_;
49
+ optional<transform_func_t> transform_func_{nullopt};
50
+ optional<write_transform_func_t> write_transform_func_{nullopt};
51
51
  };
52
52
 
53
53
  } // namespace modbus_controller
@@ -80,24 +80,24 @@ void ModbusSwitch::write_state(bool state) {
80
80
  // offset for coil and discrete inputs is the coil/register number not bytes
81
81
  if (this->use_write_multiple_) {
82
82
  std::vector<bool> states{state};
83
- cmd = ModbusCommandItem::create_write_multiple_coils(parent_, this->start_address + this->offset, states);
83
+ cmd = ModbusCommandItem::create_write_multiple_coils(this->parent_, this->start_address + this->offset, states);
84
84
  } else {
85
- cmd = ModbusCommandItem::create_write_single_coil(parent_, this->start_address + this->offset, state);
85
+ cmd = ModbusCommandItem::create_write_single_coil(this->parent_, this->start_address + this->offset, state);
86
86
  }
87
87
  } else {
88
88
  // since offset is in bytes and a register is 16 bits we get the start by adding offset/2
89
89
  if (this->use_write_multiple_) {
90
90
  std::vector<uint16_t> bool_states(1, state ? (0xFFFF & this->bitmask) : 0);
91
- cmd = ModbusCommandItem::create_write_multiple_command(parent_, this->start_address + this->offset / 2, 1,
91
+ cmd = ModbusCommandItem::create_write_multiple_command(this->parent_, this->start_address + this->offset / 2, 1,
92
92
  bool_states);
93
93
  } else {
94
- cmd = ModbusCommandItem::create_write_single_command(parent_, this->start_address + this->offset / 2,
94
+ cmd = ModbusCommandItem::create_write_single_command(this->parent_, this->start_address + this->offset / 2,
95
95
  state ? 0xFFFF & this->bitmask : 0u);
96
96
  }
97
97
  }
98
98
  }
99
99
  this->parent_->queue_command(cmd);
100
- publish_state(state);
100
+ this->publish_state(state);
101
101
  }
102
102
  // ModbusSwitch end
103
103
  } // namespace modbus_controller
@@ -40,8 +40,8 @@ class ModbusSwitch : public Component, public switch_::Switch, public SensorItem
40
40
  void set_use_write_mutiple(bool use_write_multiple) { this->use_write_multiple_ = use_write_multiple; }
41
41
 
42
42
  protected:
43
- ModbusController *parent_;
44
- bool use_write_multiple_;
43
+ ModbusController *parent_{nullptr};
44
+ bool use_write_multiple_{false};
45
45
  optional<transform_func_t> publish_transform_func_{nullopt};
46
46
  optional<write_transform_func_t> write_transform_func_{nullopt};
47
47
  };
@@ -49,6 +49,7 @@ from esphome.const import (
49
49
  CONF_USE_ABBREVIATIONS,
50
50
  CONF_USERNAME,
51
51
  CONF_WILL_MESSAGE,
52
+ CONF_PUBLISH_NAN_AS_NONE,
52
53
  PLATFORM_BK72XX,
53
54
  PLATFORM_ESP32,
54
55
  PLATFORM_ESP8266,
@@ -296,6 +297,7 @@ CONFIG_SCHEMA = cv.All(
296
297
  cv.Optional(CONF_QOS, default=0): cv.mqtt_qos,
297
298
  }
298
299
  ),
300
+ cv.Optional(CONF_PUBLISH_NAN_AS_NONE, default=False): cv.boolean,
299
301
  }
300
302
  ),
301
303
  validate_config,
@@ -449,6 +451,8 @@ async def to_code(config):
449
451
  trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
450
452
  await automation.build_automation(trigger, [], conf)
451
453
 
454
+ cg.add(var.set_publish_nan_as_none(config[CONF_PUBLISH_NAN_AS_NONE]))
455
+
452
456
 
453
457
  MQTT_PUBLISH_ACTION_SCHEMA = cv.Schema(
454
458
  {
@@ -80,8 +80,7 @@ const EntityBase *MQTTAlarmControlPanelComponent::get_entity() const { return th
80
80
 
81
81
  bool MQTTAlarmControlPanelComponent::send_initial_state() { return this->publish_state(); }
82
82
  bool MQTTAlarmControlPanelComponent::publish_state() {
83
- bool success = true;
84
- const char *state_s = "";
83
+ const char *state_s;
85
84
  switch (this->alarm_control_panel_->get_state()) {
86
85
  case ACP_STATE_DISARMED:
87
86
  state_s = "disarmed";
@@ -116,9 +115,7 @@ bool MQTTAlarmControlPanelComponent::publish_state() {
116
115
  default:
117
116
  state_s = "unknown";
118
117
  }
119
- if (!this->publish(this->get_state_topic_(), state_s))
120
- success = false;
121
- return success;
118
+ return this->publish(this->get_state_topic_(), state_s);
122
119
  }
123
120
 
124
121
  } // namespace mqtt
@@ -151,11 +151,11 @@ void MQTTBackendESP32::mqtt_event_handler_(const Event &event) {
151
151
  break;
152
152
  case MQTT_EVENT_DATA: {
153
153
  static std::string topic;
154
- if (event.topic.length() > 0) {
154
+ if (!event.topic.empty()) {
155
155
  topic = event.topic;
156
156
  }
157
157
  ESP_LOGV(TAG, "MQTT_EVENT_DATA %s", topic.c_str());
158
- this->on_message_.call(event.topic.length() > 0 ? topic.c_str() : nullptr, event.data.data(), event.data.size(),
158
+ this->on_message_.call(!event.topic.empty() ? topic.c_str() : nullptr, event.data.data(), event.data.size(),
159
159
  event.current_data_offset, event.total_data_len);
160
160
  } break;
161
161
  case MQTT_EVENT_ERROR:
@@ -184,7 +184,7 @@ void MQTTBackendESP32::mqtt_event_handler(void *handler_args, esp_event_base_t b
184
184
  // queue event to decouple processing
185
185
  if (instance) {
186
186
  auto event = *static_cast<esp_mqtt_event_t *>(event_data);
187
- instance->mqtt_events_.push(Event(event));
187
+ instance->mqtt_events_.emplace(event);
188
188
  }
189
189
  }
190
190
 
@@ -608,6 +608,10 @@ void MQTTClientComponent::set_log_message_template(MQTTMessage &&message) { this
608
608
  const MQTTDiscoveryInfo &MQTTClientComponent::get_discovery_info() const { return this->discovery_info_; }
609
609
  void MQTTClientComponent::set_topic_prefix(const std::string &topic_prefix) { this->topic_prefix_ = topic_prefix; }
610
610
  const std::string &MQTTClientComponent::get_topic_prefix() const { return this->topic_prefix_; }
611
+ void MQTTClientComponent::set_publish_nan_as_none(bool publish_nan_as_none) {
612
+ this->publish_nan_as_none_ = publish_nan_as_none;
613
+ }
614
+ bool MQTTClientComponent::is_publish_nan_as_none() const { return this->publish_nan_as_none_; }
611
615
  void MQTTClientComponent::disable_birth_message() {
612
616
  this->birth_message_.topic = "";
613
617
  this->recalculate_availability_();
@@ -263,6 +263,10 @@ class MQTTClientComponent : public Component {
263
263
  void set_on_connect(mqtt_on_connect_callback_t &&callback);
264
264
  void set_on_disconnect(mqtt_on_disconnect_callback_t &&callback);
265
265
 
266
+ // Publish None state instead of NaN for Home Assistant
267
+ void set_publish_nan_as_none(bool publish_nan_as_none);
268
+ bool is_publish_nan_as_none() const;
269
+
266
270
  protected:
267
271
  void send_device_info_();
268
272
 
@@ -328,6 +332,8 @@ class MQTTClientComponent : public Component {
328
332
  uint32_t connect_begin_;
329
333
  uint32_t last_connected_{0};
330
334
  optional<MQTTClientDisconnectReason> disconnect_reason_{};
335
+
336
+ bool publish_nan_as_none_{false};
331
337
  };
332
338
 
333
339
  extern MQTTClientComponent *global_mqtt_client; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
@@ -257,7 +257,7 @@ const EntityBase *MQTTClimateComponent::get_entity() const { return this->device
257
257
  bool MQTTClimateComponent::publish_state_() {
258
258
  auto traits = this->device_->get_traits();
259
259
  // mode
260
- const char *mode_s = "";
260
+ const char *mode_s;
261
261
  switch (this->device_->mode) {
262
262
  case CLIMATE_MODE_OFF:
263
263
  mode_s = "off";
@@ -280,6 +280,8 @@ bool MQTTClimateComponent::publish_state_() {
280
280
  case CLIMATE_MODE_HEAT_COOL:
281
281
  mode_s = "heat_cool";
282
282
  break;
283
+ default:
284
+ mode_s = "unknown";
283
285
  }
284
286
  bool success = true;
285
287
  if (!this->publish(this->get_mode_state_topic(), mode_s))
@@ -343,6 +345,8 @@ bool MQTTClimateComponent::publish_state_() {
343
345
  case CLIMATE_PRESET_ACTIVITY:
344
346
  payload = "activity";
345
347
  break;
348
+ default:
349
+ payload = "unknown";
346
350
  }
347
351
  }
348
352
  if (this->device_->custom_preset.has_value())
@@ -352,7 +356,7 @@ bool MQTTClimateComponent::publish_state_() {
352
356
  }
353
357
 
354
358
  if (traits.get_supports_action()) {
355
- const char *payload = "unknown";
359
+ const char *payload;
356
360
  switch (this->device_->action) {
357
361
  case CLIMATE_ACTION_OFF:
358
362
  payload = "off";
@@ -372,6 +376,8 @@ bool MQTTClimateComponent::publish_state_() {
372
376
  case CLIMATE_ACTION_FAN:
373
377
  payload = "fan";
374
378
  break;
379
+ default:
380
+ payload = "unknown";
375
381
  }
376
382
  if (!this->publish(this->get_action_state_topic(), payload))
377
383
  success = false;
@@ -411,6 +417,8 @@ bool MQTTClimateComponent::publish_state_() {
411
417
  case CLIMATE_FAN_QUIET:
412
418
  payload = "quiet";
413
419
  break;
420
+ default:
421
+ payload = "unknown";
414
422
  }
415
423
  }
416
424
  if (this->device_->custom_fan_mode.has_value())
@@ -420,7 +428,7 @@ bool MQTTClimateComponent::publish_state_() {
420
428
  }
421
429
 
422
430
  if (traits.get_supports_swing_modes()) {
423
- const char *payload = "";
431
+ const char *payload;
424
432
  switch (this->device_->swing_mode) {
425
433
  case CLIMATE_SWING_OFF:
426
434
  payload = "off";
@@ -434,6 +442,8 @@ bool MQTTClimateComponent::publish_state_() {
434
442
  case CLIMATE_SWING_HORIZONTAL:
435
443
  payload = "horizontal";
436
444
  break;
445
+ default:
446
+ payload = "unknown";
437
447
  }
438
448
  if (!this->publish(this->get_swing_mode_state_topic(), payload))
439
449
  success = false;
@@ -69,6 +69,8 @@ bool MQTTSensorComponent::send_initial_state() {
69
69
  }
70
70
  }
71
71
  bool MQTTSensorComponent::publish_state(float value) {
72
+ if (mqtt::global_mqtt_client->is_publish_nan_as_none() && std::isnan(value))
73
+ return this->publish(this->get_state_topic_(), "None");
72
74
  int8_t accuracy = this->sensor_->get_accuracy_decimals();
73
75
  return this->publish(this->get_state_topic_(), value_accuracy_to_string(value, accuracy));
74
76
  }
@@ -116,7 +116,7 @@ struct IPAddress {
116
116
  operator arduino_ns::IPAddress() const { return ip_addr_get_ip4_u32(&ip_addr_); }
117
117
  #endif
118
118
 
119
- bool is_set() { return !ip_addr_isany(&ip_addr_); }
119
+ bool is_set() { return !ip_addr_isany(&ip_addr_); } // NOLINT(readability-simplify-boolean-expr)
120
120
  bool is_ip4() { return IP_IS_V4(&ip_addr_); }
121
121
  bool is_ip6() { return IP_IS_V6(&ip_addr_); }
122
122
  std::string str() const { return str_lower_case(ipaddr_ntoa(&ip_addr_)); }
@@ -6,3 +6,5 @@ Nextion = nextion_ns.class_("Nextion", cg.PollingComponent, uart.UARTDevice)
6
6
  nextion_ref = Nextion.operator("ref")
7
7
 
8
8
  CONF_NEXTION_ID = "nextion_id"
9
+ CONF_PUBLISH_STATE = "publish_state"
10
+ CONF_SEND_TO_NEXTION = "send_to_nextion"
@@ -5,6 +5,13 @@
5
5
  namespace esphome {
6
6
  namespace nextion {
7
7
 
8
+ class BufferOverflowTrigger : public Trigger<> {
9
+ public:
10
+ explicit BufferOverflowTrigger(Nextion *nextion) {
11
+ nextion->add_buffer_overflow_event_callback([this]() { this->trigger(); });
12
+ }
13
+ };
14
+
8
15
  class SetupTrigger : public Trigger<> {
9
16
  public:
10
17
  explicit SetupTrigger(Nextion *nextion) {
@@ -42,5 +49,74 @@ class TouchTrigger : public Trigger<uint8_t, uint8_t, bool> {
42
49
  }
43
50
  };
44
51
 
52
+ template<typename... Ts> class NextionPublishFloatAction : public Action<Ts...> {
53
+ public:
54
+ explicit NextionPublishFloatAction(NextionComponent *component) : component_(component) {}
55
+
56
+ TEMPLATABLE_VALUE(float, state)
57
+ TEMPLATABLE_VALUE(bool, publish_state)
58
+ TEMPLATABLE_VALUE(bool, send_to_nextion)
59
+
60
+ void play(Ts... x) override {
61
+ this->component_->set_state(this->state_.value(x...), this->publish_state_.value(x...),
62
+ this->send_to_nextion_.value(x...));
63
+ }
64
+
65
+ void set_state(std::function<void(Ts..., float)> state) { this->state_ = state; }
66
+ void set_publish_state(std::function<void(Ts..., bool)> publish_state) { this->publish_state_ = publish_state; }
67
+ void set_send_to_nextion(std::function<void(Ts..., bool)> send_to_nextion) {
68
+ this->send_to_nextion_ = send_to_nextion;
69
+ }
70
+
71
+ protected:
72
+ NextionComponent *component_;
73
+ };
74
+
75
+ template<typename... Ts> class NextionPublishTextAction : public Action<Ts...> {
76
+ public:
77
+ explicit NextionPublishTextAction(NextionComponent *component) : component_(component) {}
78
+
79
+ TEMPLATABLE_VALUE(const char *, state)
80
+ TEMPLATABLE_VALUE(bool, publish_state)
81
+ TEMPLATABLE_VALUE(bool, send_to_nextion)
82
+
83
+ void play(Ts... x) override {
84
+ this->component_->set_state(this->state_.value(x...), this->publish_state_.value(x...),
85
+ this->send_to_nextion_.value(x...));
86
+ }
87
+
88
+ void set_state(std::function<void(Ts..., const char *)> state) { this->state_ = state; }
89
+ void set_publish_state(std::function<void(Ts..., bool)> publish_state) { this->publish_state_ = publish_state; }
90
+ void set_send_to_nextion(std::function<void(Ts..., bool)> send_to_nextion) {
91
+ this->send_to_nextion_ = send_to_nextion;
92
+ }
93
+
94
+ protected:
95
+ NextionComponent *component_;
96
+ };
97
+
98
+ template<typename... Ts> class NextionPublishBoolAction : public Action<Ts...> {
99
+ public:
100
+ explicit NextionPublishBoolAction(NextionComponent *component) : component_(component) {}
101
+
102
+ TEMPLATABLE_VALUE(bool, state)
103
+ TEMPLATABLE_VALUE(bool, publish_state)
104
+ TEMPLATABLE_VALUE(bool, send_to_nextion)
105
+
106
+ void play(Ts... x) override {
107
+ this->component_->set_state(this->state_.value(x...), this->publish_state_.value(x...),
108
+ this->send_to_nextion_.value(x...));
109
+ }
110
+
111
+ void set_state(std::function<void(Ts..., bool)> state) { this->state_ = state; }
112
+ void set_publish_state(std::function<void(Ts..., bool)> publish_state) { this->publish_state_ = publish_state; }
113
+ void set_send_to_nextion(std::function<void(Ts..., bool)> send_to_nextion) {
114
+ this->send_to_nextion_ = send_to_nextion;
115
+ }
116
+
117
+ protected:
118
+ NextionComponent *component_;
119
+ };
120
+
45
121
  } // namespace nextion
46
122
  } // namespace esphome
@@ -18,6 +18,7 @@ CONF_ON_SLEEP = "on_sleep"
18
18
  CONF_ON_WAKE = "on_wake"
19
19
  CONF_ON_SETUP = "on_setup"
20
20
  CONF_ON_PAGE = "on_page"
21
+ CONF_ON_BUFFER_OVERFLOW = "on_buffer_overflow"
21
22
  CONF_TOUCH_SLEEP_TIMEOUT = "touch_sleep_timeout"
22
23
  CONF_WAKE_UP_PAGE = "wake_up_page"
23
24
  CONF_START_UP_PAGE = "start_up_page"
@@ -1,9 +1,16 @@
1
+ from esphome import automation
1
2
  import esphome.codegen as cg
2
3
  import esphome.config_validation as cv
3
4
  from esphome.components import binary_sensor
4
5
 
5
- from esphome.const import CONF_COMPONENT_ID, CONF_PAGE_ID, CONF_ID
6
- from .. import nextion_ns, CONF_NEXTION_ID
6
+ from esphome.const import (
7
+ CONF_ID,
8
+ CONF_STATE,
9
+ CONF_COMPONENT_ID,
10
+ CONF_PAGE_ID,
11
+ )
12
+
13
+ from .. import nextion_ns, CONF_NEXTION_ID, CONF_PUBLISH_STATE, CONF_SEND_TO_NEXTION
7
14
 
8
15
 
9
16
  from ..base_component import (
@@ -19,6 +26,10 @@ NextionBinarySensor = nextion_ns.class_(
19
26
  "NextionBinarySensor", binary_sensor.BinarySensor, cg.PollingComponent
20
27
  )
21
28
 
29
+ NextionPublishBoolAction = nextion_ns.class_(
30
+ "NextionPublishBoolAction", automation.Action
31
+ )
32
+
22
33
  CONFIG_SCHEMA = cv.All(
23
34
  binary_sensor.binary_sensor_schema(NextionBinarySensor)
24
35
  .extend(
@@ -52,3 +63,33 @@ async def to_code(config):
52
63
  if CONF_COMPONENT_NAME in config or CONF_VARIABLE_NAME in config:
53
64
  await setup_component_core_(var, config, ".val")
54
65
  cg.add(hub.register_binarysensor_component(var))
66
+
67
+
68
+ @automation.register_action(
69
+ "binary_sensor.nextion.publish",
70
+ NextionPublishBoolAction,
71
+ cv.Schema(
72
+ {
73
+ cv.Required(CONF_ID): cv.use_id(NextionBinarySensor),
74
+ cv.Required(CONF_STATE): cv.templatable(cv.boolean),
75
+ cv.Optional(CONF_PUBLISH_STATE, default="true"): cv.templatable(cv.boolean),
76
+ cv.Optional(CONF_SEND_TO_NEXTION, default="true"): cv.templatable(
77
+ cv.boolean
78
+ ),
79
+ }
80
+ ),
81
+ )
82
+ async def sensor_nextion_publish_to_code(config, action_id, template_arg, args):
83
+ paren = await cg.get_variable(config[CONF_ID])
84
+ var = cg.new_Pvariable(action_id, template_arg, paren)
85
+
86
+ template_ = await cg.templatable(config[CONF_STATE], args, bool)
87
+ cg.add(var.set_state(template_))
88
+
89
+ template_ = await cg.templatable(config[CONF_PUBLISH_STATE], args, bool)
90
+ cg.add(var.set_publish_state(template_))
91
+
92
+ template_ = await cg.templatable(config[CONF_SEND_TO_NEXTION], args, bool)
93
+ cg.add(var.set_send_to_nextion(template_))
94
+
95
+ return var
@@ -13,6 +13,7 @@ from esphome.const import (
13
13
  from esphome.core import CORE
14
14
  from . import Nextion, nextion_ns, nextion_ref
15
15
  from .base_component import (
16
+ CONF_ON_BUFFER_OVERFLOW,
16
17
  CONF_ON_SLEEP,
17
18
  CONF_ON_WAKE,
18
19
  CONF_ON_SETUP,
@@ -36,6 +37,9 @@ SleepTrigger = nextion_ns.class_("SleepTrigger", automation.Trigger.template())
36
37
  WakeTrigger = nextion_ns.class_("WakeTrigger", automation.Trigger.template())
37
38
  PageTrigger = nextion_ns.class_("PageTrigger", automation.Trigger.template())
38
39
  TouchTrigger = nextion_ns.class_("TouchTrigger", automation.Trigger.template())
40
+ BufferOverflowTrigger = nextion_ns.class_(
41
+ "BufferOverflowTrigger", automation.Trigger.template()
42
+ )
39
43
 
40
44
  CONFIG_SCHEMA = (
41
45
  display.BASIC_DISPLAY_SCHEMA.extend(
@@ -68,6 +72,13 @@ CONFIG_SCHEMA = (
68
72
  cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(TouchTrigger),
69
73
  }
70
74
  ),
75
+ cv.Optional(CONF_ON_BUFFER_OVERFLOW): automation.validate_automation(
76
+ {
77
+ cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(
78
+ BufferOverflowTrigger
79
+ ),
80
+ }
81
+ ),
71
82
  cv.Optional(CONF_TOUCH_SLEEP_TIMEOUT): cv.int_range(min=3, max=65535),
72
83
  cv.Optional(CONF_WAKE_UP_PAGE): cv.uint8_t,
73
84
  cv.Optional(CONF_START_UP_PAGE): cv.uint8_t,
@@ -151,3 +162,7 @@ async def to_code(config):
151
162
  ],
152
163
  conf,
153
164
  )
165
+
166
+ for conf in config.get(CONF_ON_BUFFER_OVERFLOW, []):
167
+ trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
168
+ await automation.build_automation(trigger, [], conf)
@@ -190,6 +190,10 @@ void Nextion::add_touch_event_callback(std::function<void(uint8_t, uint8_t, bool
190
190
  this->touch_callback_.add(std::move(callback));
191
191
  }
192
192
 
193
+ void Nextion::add_buffer_overflow_event_callback(std::function<void()> &&callback) {
194
+ this->buffer_overflow_callback_.add(std::move(callback));
195
+ }
196
+
193
197
  void Nextion::update_all_components() {
194
198
  if ((!this->is_setup() && !this->ignore_is_setup_) || this->is_sleeping())
195
199
  return;
@@ -339,7 +343,7 @@ void Nextion::process_serial_() {
339
343
  }
340
344
  // nextion.tech/instruction-set/
341
345
  void Nextion::process_nextion_commands_() {
342
- if (this->command_data_.length() == 0) {
346
+ if (this->command_data_.empty()) {
343
347
  return;
344
348
  }
345
349
 
@@ -458,7 +462,9 @@ void Nextion::process_nextion_commands_() {
458
462
  this->remove_from_q_();
459
463
  break;
460
464
  case 0x24: // Serial Buffer overflow occurs
461
- ESP_LOGW(TAG, "Nextion reported Serial Buffer overflow!");
465
+ // Buffer will continue to receive the current instruction, all previous instructions are lost.
466
+ ESP_LOGE(TAG, "Nextion reported Serial Buffer overflow!");
467
+ this->buffer_overflow_callback_.call();
462
468
  break;
463
469
  case 0x65: { // touch event return data
464
470
  if (to_process_length != 3) {
@@ -557,13 +563,10 @@ void Nextion::process_nextion_commands_() {
557
563
  break;
558
564
  }
559
565
 
560
- int dataindex = 0;
561
-
562
566
  int value = 0;
563
567
 
564
568
  for (int i = 0; i < 4; ++i) {
565
569
  value += to_process[i] << (8 * i);
566
- ++dataindex;
567
570
  }
568
571
 
569
572
  NextionQueue *nb = this->nextion_queue_.front();
@@ -1134,6 +1134,12 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe
1134
1134
  */
1135
1135
  void add_touch_event_callback(std::function<void(uint8_t, uint8_t, bool)> &&callback);
1136
1136
 
1137
+ /** Add a callback to be notified when the nextion reports a buffer overflow.
1138
+ *
1139
+ * @param callback The void() callback.
1140
+ */
1141
+ void add_buffer_overflow_event_callback(std::function<void()> &&callback);
1142
+
1137
1143
  void update_all_components();
1138
1144
 
1139
1145
  /**
@@ -1323,6 +1329,7 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe
1323
1329
  CallbackManager<void()> wake_callback_{};
1324
1330
  CallbackManager<void(uint8_t)> page_callback_{};
1325
1331
  CallbackManager<void(uint8_t, uint8_t, bool)> touch_callback_{};
1332
+ CallbackManager<void()> buffer_overflow_callback_{};
1326
1333
 
1327
1334
  optional<nextion_writer_t> writer_;
1328
1335
  float brightness_{1.0};
@@ -36,8 +36,8 @@ int Nextion::upload_by_chunks_(esp_http_client_handle_t http_client, uint32_t &r
36
36
  ESP_LOGV(TAG, "Requesting range: %s", range_header);
37
37
  esp_http_client_set_header(http_client, "Range", range_header);
38
38
  ESP_LOGV(TAG, "Opening HTTP connetion");
39
- esp_err_t err;
40
- if ((err = esp_http_client_open(http_client, 0)) != ESP_OK) {
39
+ esp_err_t err = esp_http_client_open(http_client, 0);
40
+ if (err != ESP_OK) {
41
41
  ESP_LOGE(TAG, "Failed to open HTTP connection: %s", esp_err_to_name(err));
42
42
  return -1;
43
43
  }
@@ -1,12 +1,11 @@
1
+ from esphome import automation
1
2
  import esphome.codegen as cg
2
3
  import esphome.config_validation as cv
3
4
  from esphome.components import sensor
4
5
 
5
- from esphome.const import (
6
- CONF_ID,
7
- CONF_COMPONENT_ID,
8
- )
9
- from .. import nextion_ns, CONF_NEXTION_ID
6
+ from esphome.const import CONF_ID, CONF_COMPONENT_ID, CONF_STATE
7
+
8
+ from .. import nextion_ns, CONF_NEXTION_ID, CONF_PUBLISH_STATE, CONF_SEND_TO_NEXTION
10
9
 
11
10
  from ..base_component import (
12
11
  setup_component_core_,
@@ -25,6 +24,10 @@ CODEOWNERS = ["@senexcrenshaw"]
25
24
 
26
25
  NextionSensor = nextion_ns.class_("NextionSensor", sensor.Sensor, cg.PollingComponent)
27
26
 
27
+ NextionPublishFloatAction = nextion_ns.class_(
28
+ "NextionPublishFloatAction", automation.Action
29
+ )
30
+
28
31
 
29
32
  def CheckWaveID(value):
30
33
  value = cv.int_(value)
@@ -95,3 +98,33 @@ async def to_code(config):
95
98
 
96
99
  if CONF_WAVE_MAX_LENGTH in config:
97
100
  cg.add(var.set_wave_max_length(config[CONF_WAVE_MAX_LENGTH]))
101
+
102
+
103
+ @automation.register_action(
104
+ "sensor.nextion.publish",
105
+ NextionPublishFloatAction,
106
+ cv.Schema(
107
+ {
108
+ cv.Required(CONF_ID): cv.use_id(NextionSensor),
109
+ cv.Required(CONF_STATE): cv.templatable(cv.float_),
110
+ cv.Optional(CONF_PUBLISH_STATE, default="true"): cv.templatable(cv.boolean),
111
+ cv.Optional(CONF_SEND_TO_NEXTION, default="true"): cv.templatable(
112
+ cv.boolean
113
+ ),
114
+ }
115
+ ),
116
+ )
117
+ async def sensor_nextion_publish_to_code(config, action_id, template_arg, args):
118
+ paren = await cg.get_variable(config[CONF_ID])
119
+ var = cg.new_Pvariable(action_id, template_arg, paren)
120
+
121
+ template_ = await cg.templatable(config[CONF_STATE], args, float)
122
+ cg.add(var.set_state(template_))
123
+
124
+ template_ = await cg.templatable(config[CONF_PUBLISH_STATE], args, bool)
125
+ cg.add(var.set_publish_state(template_))
126
+
127
+ template_ = await cg.templatable(config[CONF_SEND_TO_NEXTION], args, bool)
128
+ cg.add(var.set_send_to_nextion(template_))
129
+
130
+ return var
@@ -1,9 +1,11 @@
1
+ from esphome import automation
1
2
  import esphome.codegen as cg
2
3
  import esphome.config_validation as cv
3
4
  from esphome.components import switch
4
5
 
5
- from esphome.const import CONF_ID
6
- from .. import nextion_ns, CONF_NEXTION_ID
6
+ from esphome.const import CONF_ID, CONF_STATE
7
+
8
+ from .. import nextion_ns, CONF_NEXTION_ID, CONF_PUBLISH_STATE, CONF_SEND_TO_NEXTION
7
9
 
8
10
  from ..base_component import (
9
11
  setup_component_core_,
@@ -16,6 +18,10 @@ CODEOWNERS = ["@senexcrenshaw"]
16
18
 
17
19
  NextionSwitch = nextion_ns.class_("NextionSwitch", switch.Switch, cg.PollingComponent)
18
20
 
21
+ NextionPublishBoolAction = nextion_ns.class_(
22
+ "NextionPublishBoolAction", automation.Action
23
+ )
24
+
19
25
  CONFIG_SCHEMA = cv.All(
20
26
  switch.switch_schema(NextionSwitch)
21
27
  .extend(CONFIG_SWITCH_COMPONENT_SCHEMA)
@@ -33,3 +39,33 @@ async def to_code(config):
33
39
  cg.add(hub.register_switch_component(var))
34
40
 
35
41
  await setup_component_core_(var, config, ".val")
42
+
43
+
44
+ @automation.register_action(
45
+ "switch.nextion.publish",
46
+ NextionPublishBoolAction,
47
+ cv.Schema(
48
+ {
49
+ cv.Required(CONF_ID): cv.use_id(NextionSwitch),
50
+ cv.Required(CONF_STATE): cv.templatable(cv.boolean),
51
+ cv.Optional(CONF_PUBLISH_STATE, default="true"): cv.templatable(cv.boolean),
52
+ cv.Optional(CONF_SEND_TO_NEXTION, default="true"): cv.templatable(
53
+ cv.boolean
54
+ ),
55
+ }
56
+ ),
57
+ )
58
+ async def sensor_nextion_publish_to_code(config, action_id, template_arg, args):
59
+ paren = await cg.get_variable(config[CONF_ID])
60
+ var = cg.new_Pvariable(action_id, template_arg, paren)
61
+
62
+ template_ = await cg.templatable(config[CONF_STATE], args, bool)
63
+ cg.add(var.set_state(template_))
64
+
65
+ template_ = await cg.templatable(config[CONF_PUBLISH_STATE], args, bool)
66
+ cg.add(var.set_publish_state(template_))
67
+
68
+ template_ = await cg.templatable(config[CONF_SEND_TO_NEXTION], args, bool)
69
+ cg.add(var.set_send_to_nextion(template_))
70
+
71
+ return var