esphome 2024.9.2__py3-none-any.whl → 2024.10.0b1__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 (188) hide show
  1. esphome/components/aic3204/__init__.py +0 -0
  2. esphome/components/aic3204/aic3204.cpp +173 -0
  3. esphome/components/aic3204/aic3204.h +88 -0
  4. esphome/components/aic3204/audio_dac.py +52 -0
  5. esphome/components/aic3204/automation.h +23 -0
  6. esphome/components/alarm_control_panel/__init__.py +3 -4
  7. esphome/components/animation/__init__.py +16 -12
  8. esphome/components/api/api_connection.cpp +2 -0
  9. esphome/components/api/api_connection.h +3 -1
  10. esphome/components/api/api_frame_helper.cpp +2 -1
  11. esphome/components/api/api_frame_helper.h +2 -1
  12. esphome/components/api/api_server.cpp +2 -0
  13. esphome/components/api/api_server.h +3 -1
  14. esphome/components/api/custom_api_device.h +3 -2
  15. esphome/components/api/homeassistant_service.h +4 -3
  16. esphome/components/api/list_entities.cpp +2 -0
  17. esphome/components/api/list_entities.h +3 -2
  18. esphome/components/api/subscribe_state.cpp +2 -0
  19. esphome/components/api/subscribe_state.h +3 -2
  20. esphome/components/audio_dac/__init__.py +57 -0
  21. esphome/components/audio_dac/audio_dac.h +23 -0
  22. esphome/components/audio_dac/automation.h +43 -0
  23. esphome/components/bang_bang/bang_bang_climate.cpp +5 -2
  24. esphome/components/bedjet/bedjet_codec.cpp +4 -2
  25. esphome/components/binary_sensor/__init__.py +3 -4
  26. esphome/components/button/__init__.py +3 -4
  27. esphome/components/ch422g/__init__.py +26 -17
  28. esphome/components/ch422g/ch422g.cpp +66 -49
  29. esphome/components/ch422g/ch422g.h +17 -19
  30. esphome/components/climate/__init__.py +3 -4
  31. esphome/components/cover/__init__.py +4 -5
  32. esphome/components/cse7766/cse7766.cpp +11 -0
  33. esphome/components/cse7766/cse7766.h +4 -0
  34. esphome/components/cse7766/sensor.py +13 -1
  35. esphome/components/cst816/touchscreen/__init__.py +7 -4
  36. esphome/components/cst816/touchscreen/cst816_touchscreen.cpp +20 -19
  37. esphome/components/cst816/touchscreen/cst816_touchscreen.h +2 -0
  38. esphome/components/datetime/__init__.py +21 -14
  39. esphome/components/datetime/datetime_base.h +8 -1
  40. esphome/components/datetime/datetime_entity.cpp +2 -0
  41. esphome/components/datetime/datetime_entity.h +2 -0
  42. esphome/components/datetime/time_entity.cpp +2 -0
  43. esphome/components/datetime/time_entity.h +2 -0
  44. esphome/components/esp32/__init__.py +20 -4
  45. esphome/components/esp32_improv/__init__.py +82 -1
  46. esphome/components/esp32_improv/automation.h +72 -0
  47. esphome/components/esp32_improv/esp32_improv_component.cpp +13 -5
  48. esphome/components/esp32_improv/esp32_improv_component.h +15 -0
  49. esphome/components/ethernet/__init__.py +5 -0
  50. esphome/components/ethernet/ethernet_component.cpp +13 -0
  51. esphome/components/ethernet/ethernet_component.h +1 -0
  52. esphome/components/fan/__init__.py +3 -4
  53. esphome/components/gp2y1010au0f/__init__.py +0 -0
  54. esphome/components/gp2y1010au0f/gp2y1010au0f.cpp +67 -0
  55. esphome/components/gp2y1010au0f/gp2y1010au0f.h +52 -0
  56. esphome/components/gp2y1010au0f/sensor.py +61 -0
  57. esphome/components/gpio_expander/__init__.py +0 -0
  58. esphome/components/gpio_expander/cached_gpio.h +38 -0
  59. esphome/components/grove_gas_mc_v2/__init__.py +0 -0
  60. esphome/components/grove_gas_mc_v2/grove_gas_mc_v2.cpp +88 -0
  61. esphome/components/grove_gas_mc_v2/grove_gas_mc_v2.h +39 -0
  62. esphome/components/grove_gas_mc_v2/sensor.py +77 -0
  63. esphome/components/haier/climate.py +4 -3
  64. esphome/components/haier/haier_base.cpp +63 -8
  65. esphome/components/haier/haier_base.h +29 -3
  66. esphome/components/haier/hon_climate.cpp +122 -65
  67. esphome/components/haier/hon_climate.h +18 -2
  68. esphome/components/haier/smartair2_climate.cpp +21 -21
  69. esphome/components/haier/switch/__init__.py +91 -0
  70. esphome/components/haier/switch/beeper.cpp +14 -0
  71. esphome/components/haier/switch/beeper.h +18 -0
  72. esphome/components/haier/switch/display.cpp +14 -0
  73. esphome/components/haier/switch/display.h +18 -0
  74. esphome/components/haier/switch/health_mode.cpp +14 -0
  75. esphome/components/haier/switch/health_mode.h +18 -0
  76. esphome/components/haier/switch/quiet_mode.cpp +14 -0
  77. esphome/components/haier/switch/quiet_mode.h +18 -0
  78. esphome/components/hmac_md5/hmac_md5.cpp +2 -0
  79. esphome/components/hmac_md5/hmac_md5.h +2 -1
  80. esphome/components/i2s_audio/speaker/__init__.py +19 -0
  81. esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp +1 -1
  82. esphome/components/i2s_audio/speaker/i2s_audio_speaker.h +2 -0
  83. esphome/components/ili9xxx/ili9xxx_display.h +1 -0
  84. esphome/components/image/__init__.py +12 -12
  85. esphome/components/image/image.cpp +44 -0
  86. esphome/components/image/image.h +17 -2
  87. esphome/components/inkplate6/display.py +2 -0
  88. esphome/components/inkplate6/inkplate.h +30 -2
  89. esphome/components/light/__init__.py +3 -4
  90. esphome/components/lock/__init__.py +3 -4
  91. esphome/components/lvgl/__init__.py +16 -5
  92. esphome/components/lvgl/defines.py +1 -0
  93. esphome/components/lvgl/hello_world.py +64 -0
  94. esphome/components/lvgl/lv_validation.py +159 -3
  95. esphome/components/lvgl/lvgl_esphome.cpp +0 -43
  96. esphome/components/lvgl/lvgl_esphome.h +0 -4
  97. esphome/components/lvgl/styles.py +3 -2
  98. esphome/components/lvgl/text/__init__.py +3 -3
  99. esphome/components/lvgl/widgets/__init__.py +2 -0
  100. esphome/components/lvgl/widgets/animimg.py +3 -4
  101. esphome/components/lvgl/widgets/dropdown.py +5 -1
  102. esphome/components/lvgl/widgets/meter.py +16 -11
  103. esphome/components/md5/__init__.py +6 -0
  104. esphome/components/md5/md5.cpp +2 -0
  105. esphome/components/md5/md5.h +2 -0
  106. esphome/components/micro_wake_word/__init__.py +7 -0
  107. esphome/components/mics_4514/sensor.py +11 -26
  108. esphome/components/modbus_controller/__init__.py +7 -5
  109. esphome/components/modbus_controller/binary_sensor/__init__.py +6 -6
  110. esphome/components/modbus_controller/number/__init__.py +5 -6
  111. esphome/components/modbus_controller/output/__init__.py +10 -14
  112. esphome/components/modbus_controller/select/__init__.py +1 -1
  113. esphome/components/modbus_controller/sensor/__init__.py +7 -7
  114. esphome/components/modbus_controller/switch/__init__.py +6 -7
  115. esphome/components/modbus_controller/text_sensor/__init__.py +8 -9
  116. esphome/components/mqtt/__init__.py +3 -0
  117. esphome/components/mqtt/mqtt_client.cpp +2 -0
  118. esphome/components/mqtt/mqtt_client.h +2 -0
  119. esphome/components/nau7802/__init__.py +0 -0
  120. esphome/components/nau7802/nau7802.cpp +323 -0
  121. esphome/components/nau7802/nau7802.h +121 -0
  122. esphome/components/nau7802/sensor.py +134 -0
  123. esphome/components/nextion/base_component.py +1 -0
  124. esphome/components/nextion/display.py +4 -0
  125. esphome/components/nextion/nextion.cpp +19 -4
  126. esphome/components/nextion/nextion.h +16 -0
  127. esphome/components/npi19/__init__.py +0 -0
  128. esphome/components/npi19/npi19.cpp +111 -0
  129. esphome/components/npi19/npi19.h +30 -0
  130. esphome/components/npi19/sensor.py +52 -0
  131. esphome/components/number/__init__.py +3 -5
  132. esphome/components/online_image/__init__.py +1 -1
  133. esphome/components/online_image/online_image.h +1 -2
  134. esphome/components/opentherm/__init__.py +57 -0
  135. esphome/components/opentherm/hub.cpp +277 -0
  136. esphome/components/opentherm/hub.h +110 -0
  137. esphome/components/opentherm/opentherm.cpp +568 -0
  138. esphome/components/opentherm/opentherm.h +347 -0
  139. esphome/components/pulse_counter/pulse_counter_sensor.cpp +8 -1
  140. esphome/components/pulse_counter/pulse_counter_sensor.h +1 -0
  141. esphome/components/radon_eye_ble/radon_eye_listener.cpp +10 -3
  142. esphome/components/remote_transmitter/__init__.py +18 -2
  143. esphome/components/remote_transmitter/remote_transmitter.h +6 -0
  144. esphome/components/remote_transmitter/remote_transmitter_esp32.cpp +2 -0
  145. esphome/components/remote_transmitter/remote_transmitter_esp8266.cpp +2 -0
  146. esphome/components/remote_transmitter/remote_transmitter_libretiny.cpp +2 -0
  147. esphome/components/select/__init__.py +3 -4
  148. esphome/components/sensor/__init__.py +3 -4
  149. esphome/components/st7701s/st7701s.cpp +21 -8
  150. esphome/components/st7701s/st7701s.h +2 -0
  151. esphome/components/switch/__init__.py +3 -4
  152. esphome/components/tca9555/__init__.py +72 -0
  153. esphome/components/tca9555/tca9555.cpp +140 -0
  154. esphome/components/tca9555/tca9555.h +64 -0
  155. esphome/components/tcs34725/tcs34725.cpp +62 -64
  156. esphome/components/tem3200/__init__.py +0 -0
  157. esphome/components/tem3200/sensor.py +55 -0
  158. esphome/components/tem3200/tem3200.cpp +151 -0
  159. esphome/components/tem3200/tem3200.h +30 -0
  160. esphome/components/template/binary_sensor/__init__.py +19 -6
  161. esphome/components/text/__init__.py +3 -4
  162. esphome/components/text_sensor/__init__.py +3 -4
  163. esphome/components/thermostat/climate.py +11 -9
  164. esphome/components/thermostat/thermostat_climate.cpp +21 -15
  165. esphome/components/tm1638/binary_sensor/__init__.py +3 -2
  166. esphome/components/tm1638/display.py +5 -5
  167. esphome/components/tm1638/output/__init__.py +3 -2
  168. esphome/components/tm1638/switch/__init__.py +3 -2
  169. esphome/components/update/__init__.py +3 -4
  170. esphome/components/valve/__init__.py +3 -4
  171. esphome/components/web_server/__init__.py +78 -22
  172. esphome/components/web_server/server_index_v3.h +3989 -3979
  173. esphome/components/web_server/web_server.cpp +212 -33
  174. esphome/components/web_server/web_server.h +10 -1
  175. esphome/components/wifi/wifi_component_esp_idf.cpp +4 -5
  176. esphome/config_validation.py +1 -0
  177. esphome/const.py +12 -2
  178. esphome/core/defines.h +4 -2
  179. esphome/core/helpers.cpp +46 -10
  180. esphome/core/helpers.h +8 -0
  181. esphome/core/ring_buffer.cpp +12 -2
  182. esphome/core/ring_buffer.h +3 -0
  183. {esphome-2024.9.2.dist-info → esphome-2024.10.0b1.dist-info}/METADATA +5 -3
  184. {esphome-2024.9.2.dist-info → esphome-2024.10.0b1.dist-info}/RECORD +188 -139
  185. {esphome-2024.9.2.dist-info → esphome-2024.10.0b1.dist-info}/LICENSE +0 -0
  186. {esphome-2024.9.2.dist-info → esphome-2024.10.0b1.dist-info}/WHEEL +0 -0
  187. {esphome-2024.9.2.dist-info → esphome-2024.10.0b1.dist-info}/entry_points.txt +0 -0
  188. {esphome-2024.9.2.dist-info → esphome-2024.10.0b1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,57 @@
1
+ from esphome import automation
2
+ from esphome.automation import maybe_simple_id
3
+ import esphome.codegen as cg
4
+ import esphome.config_validation as cv
5
+ from esphome.const import CONF_ID, CONF_VOLUME
6
+ from esphome.core import coroutine_with_priority
7
+
8
+ CODEOWNERS = ["@kbx81"]
9
+ IS_PLATFORM_COMPONENT = True
10
+
11
+ audio_dac_ns = cg.esphome_ns.namespace("audio_dac")
12
+ AudioDac = audio_dac_ns.class_("AudioDac")
13
+
14
+ MuteOffAction = audio_dac_ns.class_("MuteOffAction", automation.Action)
15
+ MuteOnAction = audio_dac_ns.class_("MuteOnAction", automation.Action)
16
+ SetVolumeAction = audio_dac_ns.class_("SetVolumeAction", automation.Action)
17
+
18
+
19
+ MUTE_ACTION_SCHEMA = maybe_simple_id(
20
+ {
21
+ cv.GenerateID(): cv.use_id(AudioDac),
22
+ }
23
+ )
24
+
25
+ SET_VOLUME_ACTION_SCHEMA = cv.maybe_simple_value(
26
+ {
27
+ cv.GenerateID(): cv.use_id(AudioDac),
28
+ cv.Required(CONF_VOLUME): cv.templatable(cv.percentage),
29
+ },
30
+ key=CONF_VOLUME,
31
+ )
32
+
33
+
34
+ @automation.register_action("audio_dac.mute_off", MuteOffAction, MUTE_ACTION_SCHEMA)
35
+ @automation.register_action("audio_dac.mute_on", MuteOnAction, MUTE_ACTION_SCHEMA)
36
+ async def audio_dac_mute_action_to_code(config, action_id, template_arg, args):
37
+ paren = await cg.get_variable(config[CONF_ID])
38
+ return cg.new_Pvariable(action_id, template_arg, paren)
39
+
40
+
41
+ @automation.register_action(
42
+ "audio_dac.set_volume", SetVolumeAction, SET_VOLUME_ACTION_SCHEMA
43
+ )
44
+ async def audio_dac_set_volume_to_code(config, action_id, template_arg, args):
45
+ paren = await cg.get_variable(config[CONF_ID])
46
+ var = cg.new_Pvariable(action_id, template_arg, paren)
47
+
48
+ template_ = await cg.templatable(config.get(CONF_VOLUME), args, float)
49
+ cg.add(var.set_volume(template_))
50
+
51
+ return var
52
+
53
+
54
+ @coroutine_with_priority(100.0)
55
+ async def to_code(config):
56
+ cg.add_define("USE_AUDIO_DAC")
57
+ cg.add_global(audio_dac_ns.using)
@@ -0,0 +1,23 @@
1
+ #pragma once
2
+
3
+ #include "esphome/core/defines.h"
4
+ #include "esphome/core/hal.h"
5
+
6
+ namespace esphome {
7
+ namespace audio_dac {
8
+
9
+ class AudioDac {
10
+ public:
11
+ virtual bool set_mute_off() = 0;
12
+ virtual bool set_mute_on() = 0;
13
+ virtual bool set_volume(float volume) = 0;
14
+
15
+ virtual bool is_muted() = 0;
16
+ virtual float volume() = 0;
17
+
18
+ protected:
19
+ bool is_muted_{false};
20
+ };
21
+
22
+ } // namespace audio_dac
23
+ } // namespace esphome
@@ -0,0 +1,43 @@
1
+ #pragma once
2
+
3
+ #include "esphome/core/automation.h"
4
+ #include "esphome/core/component.h"
5
+ #include "audio_dac.h"
6
+
7
+ namespace esphome {
8
+ namespace audio_dac {
9
+
10
+ template<typename... Ts> class MuteOffAction : public Action<Ts...> {
11
+ public:
12
+ explicit MuteOffAction(AudioDac *audio_dac) : audio_dac_(audio_dac) {}
13
+
14
+ void play(Ts... x) override { this->audio_dac_->set_mute_off(); }
15
+
16
+ protected:
17
+ AudioDac *audio_dac_;
18
+ };
19
+
20
+ template<typename... Ts> class MuteOnAction : public Action<Ts...> {
21
+ public:
22
+ explicit MuteOnAction(AudioDac *audio_dac) : audio_dac_(audio_dac) {}
23
+
24
+ void play(Ts... x) override { this->audio_dac_->set_mute_on(); }
25
+
26
+ protected:
27
+ AudioDac *audio_dac_;
28
+ };
29
+
30
+ template<typename... Ts> class SetVolumeAction : public Action<Ts...> {
31
+ public:
32
+ explicit SetVolumeAction(AudioDac *audio_dac) : audio_dac_(audio_dac) {}
33
+
34
+ TEMPLATABLE_VALUE(float, volume)
35
+
36
+ void play(Ts... x) override { this->audio_dac_->set_volume(this->volume_.value(x...)); }
37
+
38
+ protected:
39
+ AudioDac *audio_dac_;
40
+ };
41
+
42
+ } // namespace audio_dac
43
+ } // namespace esphome
@@ -157,8 +157,11 @@ void BangBangClimate::switch_to_action_(climate::ClimateAction action) {
157
157
  default:
158
158
  trig = nullptr;
159
159
  }
160
- assert(trig != nullptr);
161
- trig->trigger();
160
+ if (trig != nullptr) {
161
+ trig->trigger();
162
+ } else {
163
+ ESP_LOGW(TAG, "trig not set - unsupported action");
164
+ }
162
165
  this->action = action;
163
166
  this->prev_trigger_ = trig;
164
167
  this->publish_state();
@@ -13,8 +13,10 @@ float bedjet_temp_to_f(const uint8_t temp) {
13
13
 
14
14
  /** Cleans up the packet before sending. */
15
15
  BedjetPacket *BedjetCodec::clean_packet_() {
16
- // So far no commands require more than 2 bytes of data.
17
- assert(this->packet_.data_length <= 2);
16
+ // So far no commands require more than 2 bytes of data
17
+ if (this->packet_.data_length > 2) {
18
+ ESP_LOGW(TAG, "Packet may be malformed");
19
+ }
18
20
  for (int i = this->packet_.data_length; i < 2; i++) {
19
21
  this->packet_.data[i] = '\0';
20
22
  }
@@ -25,7 +25,7 @@ from esphome.const import (
25
25
  CONF_STATE,
26
26
  CONF_TIMING,
27
27
  CONF_TRIGGER_ID,
28
- CONF_WEB_SERVER_ID,
28
+ CONF_WEB_SERVER,
29
29
  DEVICE_CLASS_BATTERY,
30
30
  DEVICE_CLASS_BATTERY_CHARGING,
31
31
  DEVICE_CLASS_CARBON_MONOXIDE,
@@ -543,9 +543,8 @@ async def setup_binary_sensor_core_(var, config):
543
543
  mqtt_ = cg.new_Pvariable(mqtt_id, var)
544
544
  await mqtt.register_mqtt_component(mqtt_, config)
545
545
 
546
- if (webserver_id := config.get(CONF_WEB_SERVER_ID)) is not None:
547
- web_server_ = await cg.get_variable(webserver_id)
548
- web_server.add_entity_to_sorting_list(web_server_, var, config)
546
+ if web_server_config := config.get(CONF_WEB_SERVER):
547
+ await web_server.add_entity_config(var, web_server_config)
549
548
 
550
549
 
551
550
  async def register_binary_sensor(var, config):
@@ -11,7 +11,7 @@ from esphome.const import (
11
11
  CONF_MQTT_ID,
12
12
  CONF_ON_PRESS,
13
13
  CONF_TRIGGER_ID,
14
- CONF_WEB_SERVER_ID,
14
+ CONF_WEB_SERVER,
15
15
  DEVICE_CLASS_EMPTY,
16
16
  DEVICE_CLASS_IDENTIFY,
17
17
  DEVICE_CLASS_RESTART,
@@ -97,9 +97,8 @@ async def setup_button_core_(var, config):
97
97
  mqtt_ = cg.new_Pvariable(mqtt_id, var)
98
98
  await mqtt.register_mqtt_component(mqtt_, config)
99
99
 
100
- if (webserver_id := config.get(CONF_WEB_SERVER_ID)) is not None:
101
- web_server_ = await cg.get_variable(webserver_id)
102
- web_server.add_entity_to_sorting_list(web_server_, var, config)
100
+ if web_server_config := config.get(CONF_WEB_SERVER):
101
+ await web_server.add_entity_config(var, web_server_config)
103
102
 
104
103
 
105
104
  async def register_button(var, config):
@@ -1,18 +1,20 @@
1
1
  from esphome import pins
2
2
  import esphome.codegen as cg
3
3
  from esphome.components import i2c
4
+ from esphome.components.i2c import I2CBus
4
5
  import esphome.config_validation as cv
5
6
  from esphome.const import (
7
+ CONF_I2C_ID,
6
8
  CONF_ID,
7
9
  CONF_INPUT,
8
10
  CONF_INVERTED,
9
11
  CONF_MODE,
10
12
  CONF_NUMBER,
13
+ CONF_OPEN_DRAIN,
11
14
  CONF_OUTPUT,
12
- CONF_RESTORE_VALUE,
13
15
  )
14
16
 
15
- CODEOWNERS = ["@jesterret"]
17
+ CODEOWNERS = ["@jesterret", "@clydebarrow"]
16
18
  DEPENDENCIES = ["i2c"]
17
19
  MULTI_CONF = True
18
20
  ch422g_ns = cg.esphome_ns.namespace("ch422g")
@@ -23,29 +25,36 @@ CH422GGPIOPin = ch422g_ns.class_(
23
25
  )
24
26
 
25
27
  CONF_CH422G = "ch422g"
26
- CONFIG_SCHEMA = (
27
- cv.Schema(
28
- {
29
- cv.Required(CONF_ID): cv.declare_id(CH422GComponent),
30
- cv.Optional(CONF_RESTORE_VALUE, default=False): cv.boolean,
31
- }
32
- )
33
- .extend(cv.COMPONENT_SCHEMA)
34
- .extend(i2c.i2c_device_schema(0x24))
35
- )
28
+
29
+ # Note that no address is configurable - each register in the CH422G has a dedicated i2c address
30
+ CONFIG_SCHEMA = cv.Schema(
31
+ {
32
+ cv.GenerateID(CONF_ID): cv.declare_id(CH422GComponent),
33
+ cv.GenerateID(CONF_I2C_ID): cv.use_id(I2CBus),
34
+ }
35
+ ).extend(cv.COMPONENT_SCHEMA)
36
36
 
37
37
 
38
38
  async def to_code(config):
39
39
  var = cg.new_Pvariable(config[CONF_ID])
40
- cg.add(var.set_restore_value(config[CONF_RESTORE_VALUE]))
41
40
  await cg.register_component(var, config)
42
- await i2c.register_i2c_device(var, config)
41
+ # Can't use register_i2c_device because there is no CONF_ADDRESS
42
+ parent = await cg.get_variable(config[CONF_I2C_ID])
43
+ cg.add(var.set_i2c_bus(parent))
44
+
45
+
46
+ # This is used as a final validation step so that modes have been fully transformed.
47
+ def pin_mode_check(pin_config, _):
48
+ if pin_config[CONF_MODE][CONF_INPUT] and pin_config[CONF_NUMBER] >= 8:
49
+ raise cv.Invalid("CH422G only supports input on pins 0-7")
50
+ if pin_config[CONF_MODE][CONF_OPEN_DRAIN] and pin_config[CONF_NUMBER] < 8:
51
+ raise cv.Invalid("CH422G only supports open drain output on pins 8-11")
43
52
 
44
53
 
45
54
  CH422G_PIN_SCHEMA = pins.gpio_base_schema(
46
55
  CH422GGPIOPin,
47
- cv.int_range(min=0, max=7),
48
- modes=[CONF_INPUT, CONF_OUTPUT],
56
+ cv.int_range(min=0, max=11),
57
+ modes=[CONF_INPUT, CONF_OUTPUT, CONF_OPEN_DRAIN],
49
58
  ).extend(
50
59
  {
51
60
  cv.Required(CONF_CH422G): cv.use_id(CH422GComponent),
@@ -53,7 +62,7 @@ CH422G_PIN_SCHEMA = pins.gpio_base_schema(
53
62
  )
54
63
 
55
64
 
56
- @pins.PIN_SCHEMA_REGISTRY.register(CONF_CH422G, CH422G_PIN_SCHEMA)
65
+ @pins.PIN_SCHEMA_REGISTRY.register(CONF_CH422G, CH422G_PIN_SCHEMA, pin_mode_check)
57
66
  async def ch422g_pin_to_code(config):
58
67
  var = cg.new_Pvariable(config[CONF_ID])
59
68
  parent = await cg.get_variable(config[CONF_CH422G])
@@ -4,33 +4,33 @@
4
4
  namespace esphome {
5
5
  namespace ch422g {
6
6
 
7
- const uint8_t CH422G_REG_IN = 0x26;
8
- const uint8_t CH422G_REG_OUT = 0x38;
9
- const uint8_t OUT_REG_DEFAULT_VAL = 0xdf;
7
+ static const uint8_t CH422G_REG_MODE = 0x24;
8
+ static const uint8_t CH422G_MODE_OUTPUT = 0x01; // enables output mode on 0-7
9
+ static const uint8_t CH422G_MODE_OPEN_DRAIN = 0x04; // enables open drain mode on 8-11
10
+ static const uint8_t CH422G_REG_IN = 0x26; // read reg for input bits
11
+ static const uint8_t CH422G_REG_OUT = 0x38; // write reg for output bits 0-7
12
+ static const uint8_t CH422G_REG_OUT_UPPER = 0x23; // write reg for output bits 8-11
10
13
 
11
14
  static const char *const TAG = "ch422g";
12
15
 
13
16
  void CH422GComponent::setup() {
14
17
  ESP_LOGCONFIG(TAG, "Setting up CH422G...");
15
- // Test to see if device exists
16
- if (!this->read_inputs_()) {
18
+ // set outputs before mode
19
+ this->write_outputs_();
20
+ // Set mode and check for errors
21
+ if (!this->set_mode_(this->mode_value_) || !this->read_inputs_()) {
17
22
  ESP_LOGE(TAG, "CH422G not detected at 0x%02X", this->address_);
18
23
  this->mark_failed();
19
24
  return;
20
25
  }
21
26
 
22
- // restore defaults over whatever got saved on last boot
23
- if (!this->restore_value_) {
24
- this->write_output_(OUT_REG_DEFAULT_VAL);
25
- }
26
-
27
- ESP_LOGD(TAG, "Initialization complete. Warning: %d, Error: %d", this->status_has_warning(),
28
- this->status_has_error());
27
+ ESP_LOGCONFIG(TAG, "Initialization complete. Warning: %d, Error: %d", this->status_has_warning(),
28
+ this->status_has_error());
29
29
  }
30
30
 
31
31
  void CH422GComponent::loop() {
32
32
  // Clear all the previously read flags.
33
- this->pin_read_cache_ = 0x00;
33
+ this->pin_read_flags_ = 0x00;
34
34
  }
35
35
 
36
36
  void CH422GComponent::dump_config() {
@@ -41,68 +41,82 @@ void CH422GComponent::dump_config() {
41
41
  }
42
42
  }
43
43
 
44
- // ch422g doesn't have any flag support (needs docs?)
45
- void CH422GComponent::pin_mode(uint8_t pin, gpio::Flags flags) {}
44
+ void CH422GComponent::pin_mode(uint8_t pin, gpio::Flags flags) {
45
+ if (pin < 8) {
46
+ if (flags & gpio::FLAG_OUTPUT) {
47
+ this->mode_value_ |= CH422G_MODE_OUTPUT;
48
+ }
49
+ } else {
50
+ if (flags & gpio::FLAG_OPEN_DRAIN) {
51
+ this->mode_value_ |= CH422G_MODE_OPEN_DRAIN;
52
+ }
53
+ }
54
+ }
46
55
 
47
56
  bool CH422GComponent::digital_read(uint8_t pin) {
48
- if (this->pin_read_cache_ == 0 || this->pin_read_cache_ & (1 << pin)) {
57
+ if (this->pin_read_flags_ == 0 || this->pin_read_flags_ & (1 << pin)) {
49
58
  // Read values on first access or in case it's being read again in the same loop
50
59
  this->read_inputs_();
51
60
  }
52
61
 
53
- this->pin_read_cache_ |= (1 << pin);
54
- return this->state_mask_ & (1 << pin);
62
+ this->pin_read_flags_ |= (1 << pin);
63
+ return (this->input_bits_ & (1 << pin)) != 0;
55
64
  }
56
65
 
57
66
  void CH422GComponent::digital_write(uint8_t pin, bool value) {
58
67
  if (value) {
59
- this->write_output_(this->state_mask_ | (1 << pin));
68
+ this->output_bits_ |= (1 << pin);
60
69
  } else {
61
- this->write_output_(this->state_mask_ & ~(1 << pin));
70
+ this->output_bits_ &= ~(1 << pin);
62
71
  }
72
+ this->write_outputs_();
63
73
  }
64
74
 
65
75
  bool CH422GComponent::read_inputs_() {
66
76
  if (this->is_failed()) {
67
77
  return false;
68
78
  }
69
-
70
- uint8_t temp = 0;
71
- if ((this->last_error_ = this->read(&temp, 1)) != esphome::i2c::ERROR_OK) {
72
- this->status_set_warning(str_sprintf("read_inputs_(): I2C I/O error: %d", (int) this->last_error_).c_str());
73
- return false;
79
+ uint8_t result;
80
+ // reading inputs requires the chip to be in input mode, possibly temporarily.
81
+ if (this->mode_value_ & CH422G_MODE_OUTPUT) {
82
+ this->set_mode_(this->mode_value_ & ~CH422G_MODE_OUTPUT);
83
+ result = this->read_reg_(CH422G_REG_IN);
84
+ this->set_mode_(this->mode_value_);
85
+ } else {
86
+ result = this->read_reg_(CH422G_REG_IN);
74
87
  }
88
+ this->input_bits_ = result;
89
+ this->status_clear_warning();
90
+ return true;
91
+ }
75
92
 
76
- uint8_t output = 0;
77
- if ((this->last_error_ = this->bus_->read(CH422G_REG_IN, &output, 1)) != esphome::i2c::ERROR_OK) {
78
- this->status_set_warning(str_sprintf("read_inputs_(): I2C I/O error: %d", (int) this->last_error_).c_str());
93
+ // Write a register. Can't use the standard write_byte() method because there is no single pre-configured i2c address.
94
+ bool CH422GComponent::write_reg_(uint8_t reg, uint8_t value) {
95
+ auto err = this->bus_->write(reg, &value, 1);
96
+ if (err != i2c::ERROR_OK) {
97
+ this->status_set_warning(str_sprintf("write failed for register 0x%X, error %d", reg, err).c_str());
79
98
  return false;
80
99
  }
81
-
82
- this->state_mask_ = output;
83
100
  this->status_clear_warning();
84
-
85
101
  return true;
86
102
  }
87
103
 
88
- bool CH422GComponent::write_output_(uint8_t value) {
89
- const uint8_t temp = 1;
90
- if ((this->last_error_ = this->write(&temp, 1, false)) != esphome::i2c::ERROR_OK) {
91
- this->status_set_warning(str_sprintf("write_output_(): I2C I/O error: %d", (int) this->last_error_).c_str());
92
- return false;
104
+ uint8_t CH422GComponent::read_reg_(uint8_t reg) {
105
+ uint8_t value;
106
+ auto err = this->bus_->read(reg, &value, 1);
107
+ if (err != i2c::ERROR_OK) {
108
+ this->status_set_warning(str_sprintf("read failed for register 0x%X, error %d", reg, err).c_str());
109
+ return 0;
93
110
  }
111
+ this->status_clear_warning();
112
+ return value;
113
+ }
94
114
 
95
- uint8_t write_mask = value;
96
- if ((this->last_error_ = this->bus_->write(CH422G_REG_OUT, &write_mask, 1)) != esphome::i2c::ERROR_OK) {
97
- this->status_set_warning(
98
- str_sprintf("write_output_(): I2C I/O error: %d for write_mask: %d", (int) this->last_error_, (int) write_mask)
99
- .c_str());
100
- return false;
101
- }
115
+ bool CH422GComponent::set_mode_(uint8_t mode) { return this->write_reg_(CH422G_REG_MODE, mode); }
102
116
 
103
- this->state_mask_ = value;
104
- this->status_clear_warning();
105
- return true;
117
+ bool CH422GComponent::write_outputs_() {
118
+ return this->write_reg_(CH422G_REG_OUT, static_cast<uint8_t>(this->output_bits_)) &&
119
+ this->write_reg_(CH422G_REG_OUT_UPPER, static_cast<uint8_t>(this->output_bits_ >> 8));
106
120
  }
107
121
 
108
122
  float CH422GComponent::get_setup_priority() const { return setup_priority::IO; }
@@ -111,12 +125,15 @@ float CH422GComponent::get_setup_priority() const { return setup_priority::IO; }
111
125
  // before other components call our digital_read() method.
112
126
  float CH422GComponent::get_loop_priority() const { return 9.0f; } // Just after WIFI
113
127
 
114
- void CH422GGPIOPin::setup() { pin_mode(flags_); }
115
128
  void CH422GGPIOPin::pin_mode(gpio::Flags flags) { this->parent_->pin_mode(this->pin_, flags); }
116
- bool CH422GGPIOPin::digital_read() { return this->parent_->digital_read(this->pin_) != this->inverted_; }
129
+ bool CH422GGPIOPin::digital_read() { return this->parent_->digital_read(this->pin_) ^ this->inverted_; }
117
130
 
118
- void CH422GGPIOPin::digital_write(bool value) { this->parent_->digital_write(this->pin_, value != this->inverted_); }
131
+ void CH422GGPIOPin::digital_write(bool value) { this->parent_->digital_write(this->pin_, value ^ this->inverted_); }
119
132
  std::string CH422GGPIOPin::dump_summary() const { return str_sprintf("EXIO%u via CH422G", pin_); }
133
+ void CH422GGPIOPin::set_flags(gpio::Flags flags) {
134
+ flags_ = flags;
135
+ this->parent_->pin_mode(this->pin_, flags);
136
+ }
120
137
 
121
138
  } // namespace ch422g
122
139
  } // namespace esphome
@@ -23,32 +23,30 @@ class CH422GComponent : public Component, public i2c::I2CDevice {
23
23
  void pin_mode(uint8_t pin, gpio::Flags flags);
24
24
 
25
25
  float get_setup_priority() const override;
26
-
27
26
  float get_loop_priority() const override;
28
-
29
27
  void dump_config() override;
30
28
 
31
- void set_restore_value(bool restore_value) { this->restore_value_ = restore_value; }
32
-
33
29
  protected:
30
+ bool write_reg_(uint8_t reg, uint8_t value);
31
+ uint8_t read_reg_(uint8_t reg);
32
+ bool set_mode_(uint8_t mode);
34
33
  bool read_inputs_();
35
-
36
- bool write_output_(uint8_t value);
34
+ bool write_outputs_();
37
35
 
38
36
  /// The mask to write as output state - 1 means HIGH, 0 means LOW
39
- uint8_t state_mask_{0x00};
37
+ uint16_t output_bits_{0x00};
40
38
  /// Flags to check if read previously during this loop
41
- uint8_t pin_read_cache_ = {0x00};
42
- /// Storage for last I2C error seen
43
- esphome::i2c::ErrorCode last_error_;
44
- /// Whether we want to override stored values on expander
45
- bool restore_value_{false};
39
+ uint8_t pin_read_flags_ = {0x00};
40
+ /// Copy of last read values
41
+ uint8_t input_bits_ = {0x00};
42
+ /// Copy of the mode value
43
+ uint8_t mode_value_{};
46
44
  };
47
45
 
48
- /// Helper class to expose a CH422G pin as an internal input GPIO pin.
46
+ /// Helper class to expose a CH422G pin as a GPIO pin.
49
47
  class CH422GGPIOPin : public GPIOPin {
50
48
  public:
51
- void setup() override;
49
+ void setup() override{};
52
50
  void pin_mode(gpio::Flags flags) override;
53
51
  bool digital_read() override;
54
52
  void digital_write(bool value) override;
@@ -57,13 +55,13 @@ class CH422GGPIOPin : public GPIOPin {
57
55
  void set_parent(CH422GComponent *parent) { parent_ = parent; }
58
56
  void set_pin(uint8_t pin) { pin_ = pin; }
59
57
  void set_inverted(bool inverted) { inverted_ = inverted; }
60
- void set_flags(gpio::Flags flags) { flags_ = flags; }
58
+ void set_flags(gpio::Flags flags);
61
59
 
62
60
  protected:
63
- CH422GComponent *parent_;
64
- uint8_t pin_;
65
- bool inverted_;
66
- gpio::Flags flags_;
61
+ CH422GComponent *parent_{};
62
+ uint8_t pin_{};
63
+ bool inverted_{};
64
+ gpio::Flags flags_{};
67
65
  };
68
66
 
69
67
  } // namespace ch422g
@@ -43,7 +43,7 @@ from esphome.const import (
43
43
  CONF_TEMPERATURE_STEP,
44
44
  CONF_TRIGGER_ID,
45
45
  CONF_VISUAL,
46
- CONF_WEB_SERVER_ID,
46
+ CONF_WEB_SERVER,
47
47
  )
48
48
  from esphome.core import CORE, coroutine_with_priority
49
49
  from esphome.cpp_helpers import setup_entity
@@ -408,9 +408,8 @@ async def setup_climate_core_(var, config):
408
408
  trigger, [(ClimateCall.operator("ref"), "x")], conf
409
409
  )
410
410
 
411
- if (webserver_id := config.get(CONF_WEB_SERVER_ID)) is not None:
412
- web_server_ = await cg.get_variable(webserver_id)
413
- web_server.add_entity_to_sorting_list(web_server_, var, config)
411
+ if web_server_config := config.get(CONF_WEB_SERVER):
412
+ await web_server.add_entity_config(var, web_server_config)
414
413
 
415
414
 
416
415
  async def register_climate(var, config):
@@ -17,7 +17,7 @@ from esphome.const import (
17
17
  CONF_TILT_COMMAND_TOPIC,
18
18
  CONF_TILT_STATE_TOPIC,
19
19
  CONF_TRIGGER_ID,
20
- CONF_WEB_SERVER_ID,
20
+ CONF_WEB_SERVER,
21
21
  DEVICE_CLASS_AWNING,
22
22
  DEVICE_CLASS_BLIND,
23
23
  DEVICE_CLASS_CURTAIN,
@@ -137,10 +137,6 @@ async def setup_cover_core_(var, config):
137
137
  trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
138
138
  await automation.build_automation(trigger, [], conf)
139
139
 
140
- if (webserver_id := config.get(CONF_WEB_SERVER_ID)) is not None:
141
- web_server_ = await cg.get_variable(webserver_id)
142
- web_server.add_entity_to_sorting_list(web_server_, var, config)
143
-
144
140
  if (mqtt_id := config.get(CONF_MQTT_ID)) is not None:
145
141
  mqtt_ = cg.new_Pvariable(mqtt_id, var)
146
142
  await mqtt.register_mqtt_component(mqtt_, config)
@@ -156,6 +152,9 @@ async def setup_cover_core_(var, config):
156
152
  if (tilt_command_topic := config.get(CONF_TILT_COMMAND_TOPIC)) is not None:
157
153
  cg.add(mqtt_.set_custom_tilt_command_topic(tilt_command_topic))
158
154
 
155
+ if web_server_config := config.get(CONF_WEB_SERVER):
156
+ await web_server.add_entity_config(var, web_server_config)
157
+
159
158
 
160
159
  async def register_cover(var, config):
161
160
  if not CORE.has_id(config[CONF_ID]):
@@ -147,6 +147,7 @@ void CSE7766Component::parse_data_() {
147
147
  float power = 0.0f;
148
148
  if (power_cycle_exceeds_range) {
149
149
  // Datasheet: power cycle exceeding range means active power is 0
150
+ have_power = true;
150
151
  if (this->power_sensor_ != nullptr) {
151
152
  this->power_sensor_->publish_state(0.0f);
152
153
  }
@@ -178,6 +179,15 @@ void CSE7766Component::parse_data_() {
178
179
  if (this->apparent_power_sensor_ != nullptr) {
179
180
  this->apparent_power_sensor_->publish_state(apparent_power);
180
181
  }
182
+ if (have_power && this->reactive_power_sensor_ != nullptr) {
183
+ const float reactive_power = apparent_power - power;
184
+ if (reactive_power < 0.0f) {
185
+ ESP_LOGD(TAG, "Impossible reactive power: %.4f is negative", reactive_power);
186
+ this->reactive_power_sensor_->publish_state(0.0f);
187
+ } else {
188
+ this->reactive_power_sensor_->publish_state(reactive_power);
189
+ }
190
+ }
181
191
  if (this->power_factor_sensor_ != nullptr && (have_power || power_cycle_exceeds_range)) {
182
192
  float pf = NAN;
183
193
  if (apparent_power > 0) {
@@ -232,6 +242,7 @@ void CSE7766Component::dump_config() {
232
242
  LOG_SENSOR(" ", "Power", this->power_sensor_);
233
243
  LOG_SENSOR(" ", "Energy", this->energy_sensor_);
234
244
  LOG_SENSOR(" ", "Apparent Power", this->apparent_power_sensor_);
245
+ LOG_SENSOR(" ", "Reactive Power", this->reactive_power_sensor_);
235
246
  LOG_SENSOR(" ", "Power Factor", this->power_factor_sensor_);
236
247
  this->check_uart_settings(4800);
237
248
  }
@@ -16,6 +16,9 @@ class CSE7766Component : public Component, public uart::UARTDevice {
16
16
  void set_apparent_power_sensor(sensor::Sensor *apparent_power_sensor) {
17
17
  apparent_power_sensor_ = apparent_power_sensor;
18
18
  }
19
+ void set_reactive_power_sensor(sensor::Sensor *reactive_power_sensor) {
20
+ reactive_power_sensor_ = reactive_power_sensor;
21
+ }
19
22
  void set_power_factor_sensor(sensor::Sensor *power_factor_sensor) { power_factor_sensor_ = power_factor_sensor; }
20
23
 
21
24
  void loop() override;
@@ -35,6 +38,7 @@ class CSE7766Component : public Component, public uart::UARTDevice {
35
38
  sensor::Sensor *power_sensor_{nullptr};
36
39
  sensor::Sensor *energy_sensor_{nullptr};
37
40
  sensor::Sensor *apparent_power_sensor_{nullptr};
41
+ sensor::Sensor *reactive_power_sensor_{nullptr};
38
42
  sensor::Sensor *power_factor_sensor_{nullptr};
39
43
  uint32_t cf_pulses_total_{0};
40
44
  uint16_t cf_pulses_last_{0};