esphome 2025.4.2__py3-none-any.whl → 2025.5.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.
- esphome/__main__.py +16 -14
- esphome/components/ac_dimmer/ac_dimmer.cpp +3 -2
- esphome/components/adc/__init__.py +51 -34
- esphome/components/airthings_wave_base/__init__.py +1 -1
- esphome/components/alarm_control_panel/__init__.py +37 -2
- esphome/components/am43/cover/__init__.py +4 -5
- esphome/components/analog_threshold/analog_threshold_binary_sensor.cpp +6 -4
- esphome/components/analog_threshold/analog_threshold_binary_sensor.h +4 -5
- esphome/components/analog_threshold/binary_sensor.py +10 -8
- esphome/components/anova/climate.py +4 -5
- esphome/components/api/__init__.py +25 -8
- esphome/components/api/api_connection.cpp +416 -662
- esphome/components/api/api_connection.h +256 -57
- esphome/components/api/api_frame_helper.cpp +232 -177
- esphome/components/api/api_frame_helper.h +61 -8
- esphome/components/api/api_noise_context.h +13 -4
- esphome/components/api/api_pb2.cpp +1422 -1
- esphome/components/api/api_pb2.h +255 -1
- esphome/components/api/api_pb2_service.cpp +162 -49
- esphome/components/api/api_pb2_service.h +90 -51
- esphome/components/api/api_pb2_size.h +361 -0
- esphome/components/api/api_server.cpp +110 -34
- esphome/components/api/api_server.h +8 -0
- esphome/components/api/proto.h +86 -17
- esphome/components/as7341/as7341.h +1 -1
- esphome/components/at581x/at581x.h +4 -4
- esphome/components/atm90e32/__init__.py +1 -0
- esphome/components/atm90e32/atm90e32.cpp +576 -199
- esphome/components/atm90e32/atm90e32.h +128 -31
- esphome/components/atm90e32/atm90e32_reg.h +4 -2
- esphome/components/atm90e32/button/__init__.py +62 -10
- esphome/components/atm90e32/button/atm90e32_button.cpp +63 -4
- esphome/components/atm90e32/button/atm90e32_button.h +36 -4
- esphome/components/atm90e32/number/__init__.py +130 -0
- esphome/components/atm90e32/number/atm90e32_number.h +16 -0
- esphome/components/atm90e32/sensor.py +21 -4
- esphome/components/atm90e32/text_sensor/__init__.py +48 -0
- esphome/components/audio/__init__.py +96 -49
- esphome/components/audio/audio.h +48 -0
- esphome/components/audio/audio_decoder.cpp +1 -1
- esphome/components/audio/audio_resampler.cpp +2 -0
- esphome/components/audio/audio_resampler.h +1 -0
- esphome/components/ballu/climate.py +2 -9
- esphome/components/bang_bang/climate.py +5 -6
- esphome/components/bedjet/bedjet_hub.cpp +1 -0
- esphome/components/bedjet/climate/__init__.py +3 -8
- esphome/components/bedjet/fan/__init__.py +2 -11
- esphome/components/binary/fan/__init__.py +13 -16
- esphome/components/binary_sensor/__init__.py +13 -10
- esphome/components/bl0906/constants.h +16 -16
- esphome/components/ble_client/text_sensor/__init__.py +3 -5
- esphome/components/bluetooth_proxy/bluetooth_connection.cpp +4 -6
- esphome/components/bluetooth_proxy/bluetooth_proxy.cpp +136 -21
- esphome/components/bluetooth_proxy/bluetooth_proxy.h +7 -0
- esphome/components/button/__init__.py +11 -8
- esphome/components/canbus/canbus.cpp +3 -0
- esphome/components/canbus/canbus.h +16 -0
- esphome/components/ccs811/sensor.py +9 -6
- esphome/components/climate/__init__.py +35 -2
- esphome/components/climate/climate_mode.h +1 -1
- esphome/components/climate/climate_traits.h +63 -57
- esphome/components/climate_ir/__init__.py +57 -17
- esphome/components/climate_ir_lg/climate.py +2 -5
- esphome/components/climate_ir_lg/climate_ir_lg.cpp +7 -7
- esphome/components/climate_ir_lg/climate_ir_lg.h +1 -1
- esphome/components/color/__init__.py +2 -0
- esphome/components/const/__init__.py +5 -0
- esphome/components/coolix/climate.py +2 -9
- esphome/components/copy/cover/__init__.py +10 -9
- esphome/components/copy/fan/__init__.py +11 -9
- esphome/components/copy/lock/__init__.py +11 -9
- esphome/components/copy/text/__init__.py +9 -6
- esphome/components/cover/__init__.py +37 -2
- esphome/components/cse7766/cse7766.cpp +2 -1
- esphome/components/cst226/binary_sensor/__init__.py +28 -0
- esphome/components/cst226/binary_sensor/cs226_button.h +22 -0
- esphome/components/cst226/binary_sensor/cstt6_button.cpp +19 -0
- esphome/components/cst226/touchscreen/cst226_touchscreen.cpp +27 -5
- esphome/components/cst226/touchscreen/cst226_touchscreen.h +10 -10
- esphome/components/current_based/cover.py +37 -36
- esphome/components/current_based/current_based_cover.cpp +2 -1
- esphome/components/daikin/climate.py +2 -9
- esphome/components/daikin/daikin.cpp +15 -9
- esphome/components/daikin/daikin.h +5 -5
- esphome/components/daikin_arc/climate.py +2 -7
- esphome/components/daikin_brc/climate.py +3 -5
- esphome/components/dallas_temp/dallas_temp.cpp +17 -24
- esphome/components/dallas_temp/dallas_temp.h +0 -1
- esphome/components/daly_bms/daly_bms.cpp +2 -1
- esphome/components/debug/debug_component.cpp +6 -1
- esphome/components/debug/debug_component.h +8 -0
- esphome/components/debug/debug_esp32.cpp +109 -254
- esphome/components/debug/sensor.py +14 -0
- esphome/components/deep_sleep/deep_sleep_esp32.cpp +13 -1
- esphome/components/delonghi/climate.py +2 -9
- esphome/components/demo/__init__.py +18 -20
- esphome/components/dfrobot_sen0395/switch/__init__.py +21 -22
- esphome/components/dps310/sensor.py +6 -6
- esphome/components/ee895/sensor.py +9 -9
- esphome/components/emmeti/climate.py +2 -9
- esphome/components/endstop/cover.py +17 -16
- esphome/components/endstop/endstop_cover.cpp +2 -1
- esphome/components/ens160_base/__init__.py +12 -9
- esphome/components/esp32/__init__.py +60 -3
- esphome/components/esp32/core.cpp +11 -5
- esphome/components/esp32/gpio.cpp +86 -24
- esphome/components/esp32/gpio.py +15 -16
- esphome/components/esp32/gpio_esp32.py +1 -2
- esphome/components/esp32/gpio_esp32_c2.py +1 -1
- esphome/components/esp32/gpio_esp32_c3.py +1 -1
- esphome/components/esp32/gpio_esp32_c6.py +1 -1
- esphome/components/esp32/gpio_esp32_h2.py +1 -1
- esphome/components/esp32_ble/ble.cpp +1 -0
- esphome/components/esp32_ble/ble.h +5 -3
- esphome/components/esp32_ble/ble_advertising.cpp +2 -1
- esphome/components/esp32_ble/ble_advertising.h +1 -0
- esphome/components/esp32_ble_server/__init__.py +3 -0
- esphome/components/esp32_ble_tracker/__init__.py +7 -1
- esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp +192 -118
- esphome/components/esp32_ble_tracker/esp32_ble_tracker.h +29 -3
- esphome/components/esp32_camera/__init__.py +1 -1
- esphome/components/esp32_camera/esp32_camera.cpp +2 -10
- esphome/components/esp32_camera/esp32_camera.h +1 -1
- esphome/components/esp32_can/esp32_can.cpp +1 -1
- esphome/components/esp32_improv/esp32_improv_component.cpp +1 -1
- esphome/components/esp32_rmt_led_strip/led_strip.cpp +1 -1
- esphome/components/esp32_rmt_led_strip/led_strip.h +7 -5
- esphome/components/esp32_rmt_led_strip/light.py +9 -1
- esphome/components/esp32_touch/esp32_touch.cpp +1 -1
- esphome/components/esp8266/gpio.cpp +69 -8
- esphome/components/ethernet/ethernet_component.cpp +1 -1
- esphome/components/event/__init__.py +13 -10
- esphome/components/factory_reset/switch/__init__.py +7 -21
- esphome/components/fan/__init__.py +52 -5
- esphome/components/fastled_base/__init__.py +1 -4
- esphome/components/fastled_base/fastled_light.cpp +1 -1
- esphome/components/feedback/cover.py +38 -33
- esphome/components/feedback/feedback_cover.cpp +2 -1
- esphome/components/fujitsu_general/climate.py +2 -9
- esphome/components/gcja5/gcja5.cpp +2 -1
- esphome/components/gpio/one_wire/gpio_one_wire.cpp +45 -43
- esphome/components/gpio/one_wire/gpio_one_wire.h +2 -1
- esphome/components/gpio_expander/cached_gpio.h +22 -7
- esphome/components/gps/__init__.py +47 -17
- esphome/components/gps/gps.cpp +42 -23
- esphome/components/gps/gps.h +17 -13
- esphome/components/graph/__init__.py +1 -2
- esphome/components/gree/climate.py +4 -6
- esphome/components/gree/gree.cpp +16 -2
- esphome/components/gree/gree.h +2 -2
- esphome/components/growatt_solar/growatt_solar.cpp +2 -1
- esphome/components/haier/climate.py +37 -34
- esphome/components/hbridge/fan/__init__.py +19 -17
- esphome/components/he60r/cover.py +4 -5
- esphome/components/heatpumpir/climate.py +3 -6
- esphome/components/hitachi_ac344/climate.py +2 -9
- esphome/components/hitachi_ac424/climate.py +2 -9
- esphome/components/hm3301/hm3301.h +1 -1
- esphome/components/hte501/sensor.py +6 -6
- esphome/components/http_request/__init__.py +39 -6
- esphome/components/http_request/http_request.cpp +20 -0
- esphome/components/http_request/http_request.h +57 -15
- esphome/components/http_request/http_request_arduino.cpp +22 -6
- esphome/components/http_request/http_request_arduino.h +4 -3
- esphome/components/http_request/http_request_host.cpp +141 -0
- esphome/components/http_request/http_request_host.h +37 -0
- esphome/components/http_request/http_request_idf.cpp +35 -3
- esphome/components/http_request/http_request_idf.h +10 -3
- esphome/components/http_request/httplib.h +9691 -0
- esphome/components/http_request/update/__init__.py +11 -8
- esphome/components/hyt271/sensor.py +6 -6
- esphome/components/i2c/i2c.h +4 -0
- esphome/components/i2c/i2c_bus_esp_idf.cpp +1 -1
- esphome/components/i2s_audio/__init__.py +131 -22
- esphome/components/i2s_audio/i2s_audio.h +44 -4
- esphome/components/i2s_audio/media_player/__init__.py +19 -9
- esphome/components/i2s_audio/microphone/__init__.py +63 -5
- esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp +351 -61
- esphome/components/i2s_audio/microphone/i2s_audio_microphone.h +40 -6
- esphome/components/i2s_audio/speaker/__init__.py +31 -5
- esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp +155 -19
- esphome/components/i2s_audio/speaker/i2s_audio_speaker.h +17 -4
- esphome/components/ili9xxx/ili9xxx_init.h +1 -1
- esphome/components/image/__init__.py +37 -17
- esphome/components/image/image.cpp +25 -8
- esphome/components/internal_temperature/internal_temperature.cpp +6 -4
- esphome/components/key_collector/__init__.py +35 -0
- esphome/components/key_collector/key_collector.cpp +8 -0
- esphome/components/key_collector/key_collector.h +10 -0
- esphome/components/kuntze/kuntze.cpp +2 -1
- esphome/components/ld2410/ld2410.h +1 -1
- esphome/components/ld2450/ld2450.h +1 -1
- esphome/components/light/__init__.py +57 -0
- esphome/components/lock/__init__.py +51 -4
- esphome/components/lock/automation.h +2 -13
- esphome/components/logger/__init__.py +22 -0
- esphome/components/logger/logger.cpp +154 -103
- esphome/components/logger/logger.h +211 -36
- esphome/components/logger/task_log_buffer.cpp +138 -0
- esphome/components/logger/task_log_buffer.h +69 -0
- esphome/components/lvgl/__init__.py +13 -5
- esphome/components/lvgl/automation.py +50 -1
- esphome/components/lvgl/defines.py +0 -1
- esphome/components/lvgl/lvgl_esphome.cpp +5 -1
- esphome/components/lvgl/text/__init__.py +1 -2
- esphome/components/mapping/__init__.py +134 -0
- esphome/components/matrix_keypad/matrix_keypad.cpp +2 -1
- esphome/components/max7219digit/max7219digit.cpp +28 -27
- esphome/components/mdns/__init__.py +11 -5
- esphome/components/mdns/mdns_component.cpp +11 -5
- esphome/components/mdns/mdns_component.h +3 -2
- esphome/components/mdns/mdns_esp32.cpp +4 -3
- esphome/components/mdns/mdns_esp8266.cpp +4 -2
- esphome/components/mdns/mdns_libretiny.cpp +4 -2
- esphome/components/mdns/mdns_rp2040.cpp +4 -2
- esphome/components/media_player/__init__.py +33 -1
- esphome/components/mhz19/sensor.py +11 -7
- esphome/components/micro_wake_word/__init__.py +99 -31
- esphome/components/micro_wake_word/automation.h +54 -0
- esphome/components/micro_wake_word/micro_wake_word.cpp +331 -319
- esphome/components/micro_wake_word/micro_wake_word.h +58 -105
- esphome/components/micro_wake_word/preprocessor_settings.h +19 -2
- esphome/components/micro_wake_word/streaming_model.cpp +158 -41
- esphome/components/micro_wake_word/streaming_model.h +85 -13
- esphome/components/microphone/__init__.py +139 -9
- esphome/components/microphone/automation.h +14 -2
- esphome/components/microphone/microphone.cpp +21 -0
- esphome/components/microphone/microphone.h +14 -5
- esphome/components/microphone/microphone_source.cpp +95 -0
- esphome/components/microphone/microphone_source.h +80 -0
- esphome/components/mics_4514/sensor.py +25 -14
- esphome/components/midea/climate.py +3 -4
- esphome/components/midea_ir/climate.py +3 -5
- esphome/components/mipi_spi/__init__.py +15 -0
- esphome/components/mipi_spi/display.py +474 -0
- esphome/components/mipi_spi/mipi_spi.cpp +481 -0
- esphome/components/mipi_spi/mipi_spi.h +171 -0
- esphome/components/mipi_spi/models/__init__.py +65 -0
- esphome/components/mipi_spi/models/amoled.py +72 -0
- esphome/components/mipi_spi/models/commands.py +82 -0
- esphome/components/mipi_spi/models/cyd.py +10 -0
- esphome/components/mipi_spi/models/ili.py +749 -0
- esphome/components/mipi_spi/models/jc.py +260 -0
- esphome/components/mipi_spi/models/lanbon.py +15 -0
- esphome/components/mipi_spi/models/lilygo.py +60 -0
- esphome/components/mipi_spi/models/waveshare.py +139 -0
- esphome/components/mitsubishi/climate.py +2 -5
- esphome/components/mitsubishi/mitsubishi.cpp +9 -9
- esphome/components/mixer/speaker/mixer_speaker.cpp +12 -22
- esphome/components/mixer/speaker/mixer_speaker.h +1 -3
- esphome/components/mlx90393/sensor.py +5 -0
- esphome/components/mlx90393/sensor_mlx90393.cpp +195 -13
- esphome/components/mlx90393/sensor_mlx90393.h +21 -4
- esphome/components/modbus/modbus.cpp +2 -1
- esphome/components/mqtt/__init__.py +1 -1
- esphome/components/mqtt/mqtt_client.cpp +6 -2
- esphome/components/mqtt/mqtt_const.h +4 -0
- esphome/components/mqtt/mqtt_fan.cpp +39 -0
- esphome/components/mqtt/mqtt_fan.h +2 -0
- esphome/components/ms5611/sensor.py +6 -6
- esphome/components/ms8607/sensor.py +3 -3
- esphome/components/network/__init__.py +1 -1
- esphome/components/nextion/base_component.py +17 -16
- esphome/components/nextion/display.py +11 -2
- esphome/components/nextion/nextion.cpp +39 -1
- esphome/components/nextion/nextion.h +50 -0
- esphome/components/noblex/climate.py +2 -9
- esphome/components/number/__init__.py +12 -9
- esphome/components/one_wire/one_wire_bus.cpp +14 -10
- esphome/components/one_wire/one_wire_bus.h +14 -8
- esphome/components/online_image/bmp_image.cpp +48 -11
- esphome/components/online_image/bmp_image.h +2 -0
- esphome/components/opentherm/binary_sensor/__init__.py +2 -4
- esphome/components/opentherm/number/__init__.py +11 -20
- esphome/components/opentherm/sensor/__init__.py +3 -3
- esphome/components/opentherm/switch/__init__.py +3 -5
- esphome/components/output/lock/__init__.py +11 -9
- esphome/components/packages/__init__.py +33 -31
- esphome/components/packet_transport/__init__.py +201 -0
- esphome/components/packet_transport/binary_sensor.py +19 -0
- esphome/components/packet_transport/packet_transport.cpp +534 -0
- esphome/components/packet_transport/packet_transport.h +154 -0
- esphome/components/packet_transport/sensor.py +19 -0
- esphome/components/pca9685/pca9685_output.cpp +2 -1
- esphome/components/pid/climate.py +2 -4
- esphome/components/pm2005/__init__.py +1 -0
- esphome/components/pm2005/pm2005.cpp +123 -0
- esphome/components/pm2005/pm2005.h +46 -0
- esphome/components/pm2005/sensor.py +86 -0
- esphome/components/pmsa003i/pmsa003i.cpp +43 -16
- esphome/components/pmsa003i/pmsa003i.h +25 -25
- esphome/components/pmsx003/pmsx003.cpp +195 -230
- esphome/components/pmsx003/pmsx003.h +51 -33
- esphome/components/pmsx003/sensor.py +21 -11
- esphome/components/pn7150/pn7150.h +2 -2
- esphome/components/pn7160/pn7160.h +2 -2
- esphome/components/prometheus/prometheus_handler.cpp +174 -0
- esphome/components/prometheus/prometheus_handler.h +17 -0
- esphome/components/psram/__init__.py +7 -5
- esphome/components/pulse_meter/pulse_meter_sensor.cpp +32 -12
- esphome/components/pulse_meter/pulse_meter_sensor.h +5 -5
- esphome/components/pzem004t/pzem004t.cpp +2 -1
- esphome/components/qspi_dbi/__init__.py +0 -1
- esphome/components/qspi_dbi/display.py +2 -1
- esphome/components/qspi_dbi/models.py +1 -2
- esphome/components/remote_base/__init__.py +91 -0
- esphome/components/remote_base/beo4_protocol.cpp +153 -0
- esphome/components/remote_base/beo4_protocol.h +43 -0
- esphome/components/remote_base/gobox_protocol.cpp +131 -0
- esphome/components/remote_base/gobox_protocol.h +54 -0
- esphome/components/remote_receiver/remote_receiver_esp32.cpp +16 -9
- esphome/components/resampler/speaker/resampler_speaker.cpp +12 -10
- esphome/components/resampler/speaker/resampler_speaker.h +1 -1
- esphome/components/rf_bridge/rf_bridge.cpp +2 -1
- esphome/components/scd30/sensor.py +2 -3
- esphome/components/scd4x/sensor.py +4 -5
- esphome/components/sdp3x/sensor.py +2 -1
- esphome/components/sds011/sds011.cpp +2 -1
- esphome/components/select/__init__.py +19 -20
- esphome/components/sen5x/sen5x.cpp +55 -36
- esphome/components/sen5x/sensor.py +1 -1
- esphome/components/senseair/sensor.py +3 -3
- esphome/components/sensor/__init__.py +158 -14
- esphome/components/sensor/filter.cpp +23 -0
- esphome/components/sensor/filter.h +22 -0
- esphome/components/sgp30/sensor.py +14 -16
- esphome/components/sgp4x/sensor.py +1 -1
- esphome/components/sht4x/sht4x.cpp +43 -22
- esphome/components/sht4x/sht4x.h +1 -1
- esphome/components/shtcx/sensor.py +6 -6
- esphome/components/slow_pwm/slow_pwm_output.cpp +2 -1
- esphome/components/sml/text_sensor/__init__.py +4 -6
- esphome/components/sound_level/__init__.py +0 -0
- esphome/components/sound_level/sensor.py +97 -0
- esphome/components/sound_level/sound_level.cpp +194 -0
- esphome/components/sound_level/sound_level.h +73 -0
- esphome/components/speaker/media_player/__init__.py +4 -8
- esphome/components/speaker/media_player/speaker_media_player.cpp +0 -18
- esphome/components/speaker/media_player/speaker_media_player.h +0 -11
- esphome/components/speaker/speaker.h +4 -7
- esphome/components/speed/fan/__init__.py +17 -16
- esphome/components/spi/spi.h +11 -1
- esphome/components/sprinkler/__init__.py +18 -19
- esphome/components/sprinkler/sprinkler.cpp +6 -5
- esphome/components/switch/__init__.py +32 -42
- esphome/components/syslog/__init__.py +41 -0
- esphome/components/syslog/esphome_syslog.cpp +49 -0
- esphome/components/syslog/esphome_syslog.h +27 -0
- esphome/components/t6615/sensor.py +3 -3
- esphome/components/t6615/t6615.cpp +2 -1
- esphome/components/tca9555/tca9555.cpp +11 -6
- esphome/components/tcl112/climate.py +2 -9
- esphome/components/template/alarm_control_panel/__init__.py +7 -6
- esphome/components/template/alarm_control_panel/template_alarm_control_panel.cpp +21 -17
- esphome/components/template/alarm_control_panel/template_alarm_control_panel.h +2 -1
- esphome/components/template/cover/__init__.py +27 -21
- esphome/components/template/fan/__init__.py +14 -12
- esphome/components/template/lock/__init__.py +20 -25
- esphome/components/template/lock/automation.h +18 -0
- esphome/components/template/text/__init__.py +4 -3
- esphome/components/template/valve/__init__.py +32 -21
- esphome/components/template/valve/automation.h +24 -0
- esphome/components/text/__init__.py +32 -1
- esphome/components/text_sensor/__init__.py +24 -29
- esphome/components/thermostat/climate.py +5 -5
- esphome/components/time_based/cover.py +17 -16
- esphome/components/time_based/time_based_cover.cpp +2 -1
- esphome/components/tm1638/switch/__init__.py +10 -7
- esphome/components/tormatic/cover.py +4 -5
- esphome/components/toshiba/climate.py +3 -5
- esphome/components/touchscreen/touchscreen.cpp +3 -1
- esphome/components/tuya/climate/__init__.py +5 -6
- esphome/components/tuya/cover/__init__.py +6 -11
- esphome/components/tuya/select/__init__.py +15 -5
- esphome/components/tuya/select/tuya_select.cpp +6 -1
- esphome/components/tuya/select/tuya_select.h +5 -1
- esphome/components/uart/packet_transport/__init__.py +20 -0
- esphome/components/uart/packet_transport/uart_transport.cpp +88 -0
- esphome/components/uart/packet_transport/uart_transport.h +41 -0
- esphome/components/uart/switch/uart_switch.cpp +2 -1
- esphome/components/udp/__init__.py +126 -128
- esphome/components/udp/automation.h +40 -0
- esphome/components/udp/binary_sensor.py +3 -25
- esphome/components/udp/packet_transport/__init__.py +29 -0
- esphome/components/udp/packet_transport/udp_transport.cpp +36 -0
- esphome/components/udp/packet_transport/udp_transport.h +28 -0
- esphome/components/udp/sensor.py +3 -25
- esphome/components/udp/udp_component.cpp +26 -470
- esphome/components/udp/udp_component.h +21 -128
- esphome/components/update/__init__.py +31 -1
- esphome/components/uponor_smatrix/climate/__init__.py +4 -9
- esphome/components/uponor_smatrix/climate/uponor_smatrix_climate.cpp +2 -1
- esphome/components/uponor_smatrix/uponor_smatrix.cpp +2 -1
- esphome/components/uptime/text_sensor/__init__.py +47 -7
- esphome/components/uptime/text_sensor/uptime_text_sensor.cpp +12 -7
- esphome/components/uptime/text_sensor/uptime_text_sensor.h +19 -0
- esphome/components/valve/__init__.py +34 -3
- esphome/components/valve/automation.h +1 -19
- esphome/components/vl53l0x/sensor.py +11 -0
- esphome/components/vl53l0x/vl53l0x_sensor.cpp +5 -1
- esphome/components/vl53l0x/vl53l0x_sensor.h +2 -1
- esphome/components/voice_assistant/__init__.py +36 -10
- esphome/components/voice_assistant/voice_assistant.cpp +170 -144
- esphome/components/voice_assistant/voice_assistant.h +26 -25
- esphome/components/waveshare_epaper/display.py +6 -0
- esphome/components/waveshare_epaper/waveshare_epaper.cpp +439 -37
- esphome/components/waveshare_epaper/waveshare_epaper.h +60 -11
- esphome/components/weikai/weikai.cpp +0 -52
- esphome/components/whirlpool/climate.py +3 -5
- esphome/components/whynter/climate.py +3 -5
- esphome/components/xpt2046/touchscreen/xpt2046.cpp +1 -1
- esphome/components/yashima/climate.py +6 -6
- esphome/components/zhlt01/climate.py +2 -7
- esphome/config.py +13 -13
- esphome/config_validation.py +38 -58
- esphome/const.py +15 -1
- esphome/core/__init__.py +2 -0
- esphome/core/application.cpp +27 -10
- esphome/core/application.h +9 -1
- esphome/core/automation.h +4 -3
- esphome/core/component.cpp +28 -7
- esphome/core/component.h +10 -1
- esphome/core/defines.h +23 -17
- esphome/core/doxygen.h +13 -0
- esphome/core/macros.h +4 -0
- esphome/core/scheduler.cpp +7 -1
- esphome/cpp_generator.py +6 -2
- esphome/dashboard/web_server.py +3 -3
- esphome/helpers.py +39 -0
- esphome/loader.py +4 -0
- esphome/log.py +15 -19
- esphome/mqtt.py +23 -10
- esphome/platformio_api.py +1 -1
- esphome/schema_extractors.py +0 -1
- esphome/voluptuous_schema.py +3 -1
- esphome/vscode.py +15 -0
- esphome/wizard.py +47 -37
- esphome/zeroconf.py +7 -3
- {esphome-2025.4.2.dist-info → esphome-2025.5.0.dist-info}/METADATA +10 -11
- {esphome-2025.4.2.dist-info → esphome-2025.5.0.dist-info}/RECORD +444 -383
- {esphome-2025.4.2.dist-info → esphome-2025.5.0.dist-info}/WHEEL +1 -1
- {esphome-2025.4.2.dist-info → esphome-2025.5.0.dist-info}/entry_points.txt +0 -0
- {esphome-2025.4.2.dist-info → esphome-2025.5.0.dist-info}/licenses/LICENSE +0 -0
- {esphome-2025.4.2.dist-info → esphome-2025.5.0.dist-info}/top_level.txt +0 -0
@@ -1,7 +1,7 @@
|
|
1
1
|
#include "atm90e32.h"
|
2
|
-
#include "atm90e32_reg.h"
|
3
|
-
#include "esphome/core/log.h"
|
4
2
|
#include <cinttypes>
|
3
|
+
#include <cmath>
|
4
|
+
#include "esphome/core/log.h"
|
5
5
|
|
6
6
|
namespace esphome {
|
7
7
|
namespace atm90e32 {
|
@@ -11,115 +11,84 @@ void ATM90E32Component::loop() {
|
|
11
11
|
if (this->get_publish_interval_flag_()) {
|
12
12
|
this->set_publish_interval_flag_(false);
|
13
13
|
for (uint8_t phase = 0; phase < 3; phase++) {
|
14
|
-
if (this->phase_[phase].voltage_sensor_ != nullptr)
|
14
|
+
if (this->phase_[phase].voltage_sensor_ != nullptr)
|
15
15
|
this->phase_[phase].voltage_ = this->get_phase_voltage_(phase);
|
16
|
-
|
17
|
-
|
18
|
-
for (uint8_t phase = 0; phase < 3; phase++) {
|
19
|
-
if (this->phase_[phase].current_sensor_ != nullptr) {
|
16
|
+
|
17
|
+
if (this->phase_[phase].current_sensor_ != nullptr)
|
20
18
|
this->phase_[phase].current_ = this->get_phase_current_(phase);
|
21
|
-
|
22
|
-
|
23
|
-
for (uint8_t phase = 0; phase < 3; phase++) {
|
24
|
-
if (this->phase_[phase].power_sensor_ != nullptr) {
|
19
|
+
|
20
|
+
if (this->phase_[phase].power_sensor_ != nullptr)
|
25
21
|
this->phase_[phase].active_power_ = this->get_phase_active_power_(phase);
|
26
|
-
|
27
|
-
|
28
|
-
for (uint8_t phase = 0; phase < 3; phase++) {
|
29
|
-
if (this->phase_[phase].power_factor_sensor_ != nullptr) {
|
22
|
+
|
23
|
+
if (this->phase_[phase].power_factor_sensor_ != nullptr)
|
30
24
|
this->phase_[phase].power_factor_ = this->get_phase_power_factor_(phase);
|
31
|
-
|
32
|
-
|
33
|
-
for (uint8_t phase = 0; phase < 3; phase++) {
|
34
|
-
if (this->phase_[phase].reactive_power_sensor_ != nullptr) {
|
25
|
+
|
26
|
+
if (this->phase_[phase].reactive_power_sensor_ != nullptr)
|
35
27
|
this->phase_[phase].reactive_power_ = this->get_phase_reactive_power_(phase);
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
28
|
+
|
29
|
+
if (this->phase_[phase].apparent_power_sensor_ != nullptr)
|
30
|
+
this->phase_[phase].apparent_power_ = this->get_phase_apparent_power_(phase);
|
31
|
+
|
32
|
+
if (this->phase_[phase].forward_active_energy_sensor_ != nullptr)
|
40
33
|
this->phase_[phase].forward_active_energy_ = this->get_phase_forward_active_energy_(phase);
|
41
|
-
|
42
|
-
|
43
|
-
for (uint8_t phase = 0; phase < 3; phase++) {
|
44
|
-
if (this->phase_[phase].reverse_active_energy_sensor_ != nullptr) {
|
34
|
+
|
35
|
+
if (this->phase_[phase].reverse_active_energy_sensor_ != nullptr)
|
45
36
|
this->phase_[phase].reverse_active_energy_ = this->get_phase_reverse_active_energy_(phase);
|
46
|
-
|
47
|
-
|
48
|
-
for (uint8_t phase = 0; phase < 3; phase++) {
|
49
|
-
if (this->phase_[phase].phase_angle_sensor_ != nullptr) {
|
37
|
+
|
38
|
+
if (this->phase_[phase].phase_angle_sensor_ != nullptr)
|
50
39
|
this->phase_[phase].phase_angle_ = this->get_phase_angle_(phase);
|
51
|
-
|
52
|
-
|
53
|
-
for (uint8_t phase = 0; phase < 3; phase++) {
|
54
|
-
if (this->phase_[phase].harmonic_active_power_sensor_ != nullptr) {
|
40
|
+
|
41
|
+
if (this->phase_[phase].harmonic_active_power_sensor_ != nullptr)
|
55
42
|
this->phase_[phase].harmonic_active_power_ = this->get_phase_harmonic_active_power_(phase);
|
56
|
-
|
57
|
-
|
58
|
-
for (uint8_t phase = 0; phase < 3; phase++) {
|
59
|
-
if (this->phase_[phase].peak_current_sensor_ != nullptr) {
|
43
|
+
|
44
|
+
if (this->phase_[phase].peak_current_sensor_ != nullptr)
|
60
45
|
this->phase_[phase].peak_current_ = this->get_phase_peak_current_(phase);
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
for (uint8_t phase = 0; phase < 3; phase++) {
|
65
|
-
if (this->phase_[phase].voltage_sensor_ != nullptr) {
|
46
|
+
|
47
|
+
// After the local store is collected we can publish them trusting they are within +-1 hardware sampling
|
48
|
+
if (this->phase_[phase].voltage_sensor_ != nullptr)
|
66
49
|
this->phase_[phase].voltage_sensor_->publish_state(this->get_local_phase_voltage_(phase));
|
67
|
-
|
68
|
-
|
69
|
-
for (uint8_t phase = 0; phase < 3; phase++) {
|
70
|
-
if (this->phase_[phase].current_sensor_ != nullptr) {
|
50
|
+
|
51
|
+
if (this->phase_[phase].current_sensor_ != nullptr)
|
71
52
|
this->phase_[phase].current_sensor_->publish_state(this->get_local_phase_current_(phase));
|
72
|
-
|
73
|
-
|
74
|
-
for (uint8_t phase = 0; phase < 3; phase++) {
|
75
|
-
if (this->phase_[phase].power_sensor_ != nullptr) {
|
53
|
+
|
54
|
+
if (this->phase_[phase].power_sensor_ != nullptr)
|
76
55
|
this->phase_[phase].power_sensor_->publish_state(this->get_local_phase_active_power_(phase));
|
77
|
-
|
78
|
-
|
79
|
-
for (uint8_t phase = 0; phase < 3; phase++) {
|
80
|
-
if (this->phase_[phase].power_factor_sensor_ != nullptr) {
|
56
|
+
|
57
|
+
if (this->phase_[phase].power_factor_sensor_ != nullptr)
|
81
58
|
this->phase_[phase].power_factor_sensor_->publish_state(this->get_local_phase_power_factor_(phase));
|
82
|
-
|
83
|
-
|
84
|
-
for (uint8_t phase = 0; phase < 3; phase++) {
|
85
|
-
if (this->phase_[phase].reactive_power_sensor_ != nullptr) {
|
59
|
+
|
60
|
+
if (this->phase_[phase].reactive_power_sensor_ != nullptr)
|
86
61
|
this->phase_[phase].reactive_power_sensor_->publish_state(this->get_local_phase_reactive_power_(phase));
|
87
|
-
|
88
|
-
|
89
|
-
|
62
|
+
|
63
|
+
if (this->phase_[phase].apparent_power_sensor_ != nullptr)
|
64
|
+
this->phase_[phase].apparent_power_sensor_->publish_state(this->get_local_phase_apparent_power_(phase));
|
65
|
+
|
90
66
|
if (this->phase_[phase].forward_active_energy_sensor_ != nullptr) {
|
91
67
|
this->phase_[phase].forward_active_energy_sensor_->publish_state(
|
92
68
|
this->get_local_phase_forward_active_energy_(phase));
|
93
69
|
}
|
94
|
-
|
95
|
-
for (uint8_t phase = 0; phase < 3; phase++) {
|
70
|
+
|
96
71
|
if (this->phase_[phase].reverse_active_energy_sensor_ != nullptr) {
|
97
72
|
this->phase_[phase].reverse_active_energy_sensor_->publish_state(
|
98
73
|
this->get_local_phase_reverse_active_energy_(phase));
|
99
74
|
}
|
100
|
-
|
101
|
-
|
102
|
-
if (this->phase_[phase].phase_angle_sensor_ != nullptr) {
|
75
|
+
|
76
|
+
if (this->phase_[phase].phase_angle_sensor_ != nullptr)
|
103
77
|
this->phase_[phase].phase_angle_sensor_->publish_state(this->get_local_phase_angle_(phase));
|
104
|
-
|
105
|
-
}
|
106
|
-
for (uint8_t phase = 0; phase < 3; phase++) {
|
78
|
+
|
107
79
|
if (this->phase_[phase].harmonic_active_power_sensor_ != nullptr) {
|
108
80
|
this->phase_[phase].harmonic_active_power_sensor_->publish_state(
|
109
81
|
this->get_local_phase_harmonic_active_power_(phase));
|
110
82
|
}
|
111
|
-
|
112
|
-
|
113
|
-
if (this->phase_[phase].peak_current_sensor_ != nullptr) {
|
83
|
+
|
84
|
+
if (this->phase_[phase].peak_current_sensor_ != nullptr)
|
114
85
|
this->phase_[phase].peak_current_sensor_->publish_state(this->get_local_phase_peak_current_(phase));
|
115
|
-
}
|
116
86
|
}
|
117
|
-
if (this->freq_sensor_ != nullptr)
|
87
|
+
if (this->freq_sensor_ != nullptr)
|
118
88
|
this->freq_sensor_->publish_state(this->get_frequency_());
|
119
|
-
|
120
|
-
if (this->chip_temperature_sensor_ != nullptr)
|
89
|
+
|
90
|
+
if (this->chip_temperature_sensor_ != nullptr)
|
121
91
|
this->chip_temperature_sensor_->publish_state(this->get_chip_temperature_());
|
122
|
-
}
|
123
92
|
}
|
124
93
|
}
|
125
94
|
|
@@ -130,82 +99,30 @@ void ATM90E32Component::update() {
|
|
130
99
|
}
|
131
100
|
this->set_publish_interval_flag_(true);
|
132
101
|
this->status_clear_warning();
|
133
|
-
}
|
134
102
|
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
void ATM90E32Component::run_offset_calibrations() {
|
142
|
-
// Run the calibrations and
|
143
|
-
// Setup voltage and current calibration offsets for PHASE A
|
144
|
-
this->offset_phase_[PHASEA].voltage_offset_ = calibrate_voltage_offset_phase(PHASEA);
|
145
|
-
this->phase_[PHASEA].voltage_offset_ = this->offset_phase_[PHASEA].voltage_offset_;
|
146
|
-
this->write16_(ATM90E32_REGISTER_UOFFSETA, this->phase_[PHASEA].voltage_offset_); // C Voltage offset
|
147
|
-
this->offset_phase_[PHASEA].current_offset_ = calibrate_current_offset_phase(PHASEA);
|
148
|
-
this->phase_[PHASEA].current_offset_ = this->offset_phase_[PHASEA].current_offset_;
|
149
|
-
this->write16_(ATM90E32_REGISTER_IOFFSETA, this->phase_[PHASEA].current_offset_); // C Current offset
|
150
|
-
// Setup voltage and current calibration offsets for PHASE B
|
151
|
-
this->offset_phase_[PHASEB].voltage_offset_ = calibrate_voltage_offset_phase(PHASEB);
|
152
|
-
this->phase_[PHASEB].voltage_offset_ = this->offset_phase_[PHASEB].voltage_offset_;
|
153
|
-
this->write16_(ATM90E32_REGISTER_UOFFSETB, this->phase_[PHASEB].voltage_offset_); // C Voltage offset
|
154
|
-
this->offset_phase_[PHASEB].current_offset_ = calibrate_current_offset_phase(PHASEB);
|
155
|
-
this->phase_[PHASEB].current_offset_ = this->offset_phase_[PHASEB].current_offset_;
|
156
|
-
this->write16_(ATM90E32_REGISTER_IOFFSETB, this->phase_[PHASEB].current_offset_); // C Current offset
|
157
|
-
// Setup voltage and current calibration offsets for PHASE C
|
158
|
-
this->offset_phase_[PHASEC].voltage_offset_ = calibrate_voltage_offset_phase(PHASEC);
|
159
|
-
this->phase_[PHASEC].voltage_offset_ = this->offset_phase_[PHASEC].voltage_offset_;
|
160
|
-
this->write16_(ATM90E32_REGISTER_UOFFSETC, this->phase_[PHASEC].voltage_offset_); // C Voltage offset
|
161
|
-
this->offset_phase_[PHASEC].current_offset_ = calibrate_current_offset_phase(PHASEC);
|
162
|
-
this->phase_[PHASEC].current_offset_ = this->offset_phase_[PHASEC].current_offset_;
|
163
|
-
this->write16_(ATM90E32_REGISTER_IOFFSETC, this->phase_[PHASEC].current_offset_); // C Current offset
|
164
|
-
this->pref_.save(&this->offset_phase_);
|
165
|
-
ESP_LOGI(TAG, "PhaseA Vo=%5d PhaseB Vo=%5d PhaseC Vo=%5d", this->offset_phase_[PHASEA].voltage_offset_,
|
166
|
-
this->offset_phase_[PHASEB].voltage_offset_, this->offset_phase_[PHASEC].voltage_offset_);
|
167
|
-
ESP_LOGI(TAG, "PhaseA Io=%5d PhaseB Io=%5d PhaseC Io=%5d", this->offset_phase_[PHASEA].current_offset_,
|
168
|
-
this->offset_phase_[PHASEB].current_offset_, this->offset_phase_[PHASEC].current_offset_);
|
169
|
-
}
|
170
|
-
|
171
|
-
void ATM90E32Component::clear_offset_calibrations() {
|
172
|
-
// Clear the calibrations and
|
173
|
-
this->offset_phase_[PHASEA].voltage_offset_ = 0;
|
174
|
-
this->phase_[PHASEA].voltage_offset_ = this->offset_phase_[PHASEA].voltage_offset_;
|
175
|
-
this->write16_(ATM90E32_REGISTER_UOFFSETA, this->phase_[PHASEA].voltage_offset_); // C Voltage offset
|
176
|
-
this->offset_phase_[PHASEA].current_offset_ = 0;
|
177
|
-
this->phase_[PHASEA].current_offset_ = this->offset_phase_[PHASEA].current_offset_;
|
178
|
-
this->write16_(ATM90E32_REGISTER_IOFFSETA, this->phase_[PHASEA].current_offset_); // C Current offset
|
179
|
-
this->offset_phase_[PHASEB].voltage_offset_ = 0;
|
180
|
-
this->phase_[PHASEB].voltage_offset_ = this->offset_phase_[PHASEB].voltage_offset_;
|
181
|
-
this->write16_(ATM90E32_REGISTER_UOFFSETB, this->phase_[PHASEB].voltage_offset_); // C Voltage offset
|
182
|
-
this->offset_phase_[PHASEB].current_offset_ = 0;
|
183
|
-
this->phase_[PHASEB].current_offset_ = this->offset_phase_[PHASEB].current_offset_;
|
184
|
-
this->write16_(ATM90E32_REGISTER_IOFFSETB, this->phase_[PHASEB].current_offset_); // C Current offset
|
185
|
-
this->offset_phase_[PHASEC].voltage_offset_ = 0;
|
186
|
-
this->phase_[PHASEC].voltage_offset_ = this->offset_phase_[PHASEC].voltage_offset_;
|
187
|
-
this->write16_(ATM90E32_REGISTER_UOFFSETC, this->phase_[PHASEC].voltage_offset_); // C Voltage offset
|
188
|
-
this->offset_phase_[PHASEC].current_offset_ = 0;
|
189
|
-
this->phase_[PHASEC].current_offset_ = this->offset_phase_[PHASEC].current_offset_;
|
190
|
-
this->write16_(ATM90E32_REGISTER_IOFFSETC, this->phase_[PHASEC].current_offset_); // C Current offset
|
191
|
-
this->pref_.save(&this->offset_phase_);
|
192
|
-
ESP_LOGI(TAG, "PhaseA Vo=%5d PhaseB Vo=%5d PhaseC Vo=%5d", this->offset_phase_[PHASEA].voltage_offset_,
|
193
|
-
this->offset_phase_[PHASEB].voltage_offset_, this->offset_phase_[PHASEC].voltage_offset_);
|
194
|
-
ESP_LOGI(TAG, "PhaseA Io=%5d PhaseB Io=%5d PhaseC Io=%5d", this->offset_phase_[PHASEA].current_offset_,
|
195
|
-
this->offset_phase_[PHASEB].current_offset_, this->offset_phase_[PHASEC].current_offset_);
|
103
|
+
#ifdef USE_TEXT_SENSOR
|
104
|
+
this->check_phase_status();
|
105
|
+
this->check_over_current();
|
106
|
+
this->check_freq_status();
|
107
|
+
#endif
|
196
108
|
}
|
197
109
|
|
198
110
|
void ATM90E32Component::setup() {
|
199
111
|
ESP_LOGCONFIG(TAG, "Setting up ATM90E32 Component...");
|
200
112
|
this->spi_setup();
|
201
|
-
|
202
|
-
uint32_t hash = fnv1_hash(App.get_friendly_name());
|
203
|
-
this->pref_ = global_preferences->make_preference<Calibration[3]>(hash, true);
|
204
|
-
this->restore_calibrations_();
|
205
|
-
}
|
113
|
+
|
206
114
|
uint16_t mmode0 = 0x87; // 3P4W 50Hz
|
115
|
+
uint16_t high_thresh = 0;
|
116
|
+
uint16_t low_thresh = 0;
|
117
|
+
|
207
118
|
if (line_freq_ == 60) {
|
208
119
|
mmode0 |= 1 << 12; // sets 12th bit to 1, 60Hz
|
120
|
+
// for freq threshold registers
|
121
|
+
high_thresh = 6300; // 63.00 Hz
|
122
|
+
low_thresh = 5700; // 57.00 Hz
|
123
|
+
} else {
|
124
|
+
high_thresh = 5300; // 53.00 Hz
|
125
|
+
low_thresh = 4700; // 47.00 Hz
|
209
126
|
}
|
210
127
|
|
211
128
|
if (current_phases_ == 2) {
|
@@ -216,34 +133,84 @@ void ATM90E32Component::setup() {
|
|
216
133
|
this->write16_(ATM90E32_REGISTER_SOFTRESET, 0x789A); // Perform soft reset
|
217
134
|
delay(6); // Wait for the minimum 5ms + 1ms
|
218
135
|
this->write16_(ATM90E32_REGISTER_CFGREGACCEN, 0x55AA); // enable register config access
|
219
|
-
if (this->
|
136
|
+
if (!this->validate_spi_read_(0x55AA, "setup()")) {
|
220
137
|
ESP_LOGW(TAG, "Could not initialize ATM90E32 IC, check SPI settings");
|
221
138
|
this->mark_failed();
|
222
139
|
return;
|
223
140
|
}
|
224
141
|
|
225
142
|
this->write16_(ATM90E32_REGISTER_METEREN, 0x0001); // Enable Metering
|
226
|
-
this->write16_(ATM90E32_REGISTER_SAGPEAKDETCFG, 0xFF3F); // Peak Detector time
|
143
|
+
this->write16_(ATM90E32_REGISTER_SAGPEAKDETCFG, 0xFF3F); // Peak Detector time (15:8) 255ms, Sag Period (7:0) 63ms
|
227
144
|
this->write16_(ATM90E32_REGISTER_PLCONSTH, 0x0861); // PL Constant MSB (default) = 140625000
|
228
145
|
this->write16_(ATM90E32_REGISTER_PLCONSTL, 0xC468); // PL Constant LSB (default)
|
229
|
-
this->write16_(ATM90E32_REGISTER_ZXCONFIG, 0xD654); // ZX2, ZX1, ZX0 pin config
|
146
|
+
this->write16_(ATM90E32_REGISTER_ZXCONFIG, 0xD654); // Zero crossing (ZX2, ZX1, ZX0) pin config
|
230
147
|
this->write16_(ATM90E32_REGISTER_MMODE0, mmode0); // Mode Config (frequency set in main program)
|
231
148
|
this->write16_(ATM90E32_REGISTER_MMODE1, pga_gain_); // PGA Gain Configuration for Current Channels
|
149
|
+
this->write16_(ATM90E32_REGISTER_FREQHITH, high_thresh); // Frequency high threshold
|
150
|
+
this->write16_(ATM90E32_REGISTER_FREQLOTH, low_thresh); // Frequency low threshold
|
232
151
|
this->write16_(ATM90E32_REGISTER_PSTARTTH, 0x1D4C); // All Active Startup Power Threshold - 0.02A/0.00032 = 7500
|
233
152
|
this->write16_(ATM90E32_REGISTER_QSTARTTH, 0x1D4C); // All Reactive Startup Power Threshold - 50%
|
234
153
|
this->write16_(ATM90E32_REGISTER_SSTARTTH, 0x1D4C); // All Reactive Startup Power Threshold - 50%
|
235
154
|
this->write16_(ATM90E32_REGISTER_PPHASETH, 0x02EE); // Each Phase Active Phase Threshold - 0.002A/0.00032 = 750
|
236
155
|
this->write16_(ATM90E32_REGISTER_QPHASETH, 0x02EE); // Each phase Reactive Phase Threshold - 10%
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
156
|
+
|
157
|
+
if (this->enable_offset_calibration_) {
|
158
|
+
// Initialize flash storage for offset calibrations
|
159
|
+
uint32_t o_hash = fnv1_hash(std::string("_offset_calibration_") + this->cs_->dump_summary());
|
160
|
+
this->offset_pref_ = global_preferences->make_preference<OffsetCalibration[3]>(o_hash, true);
|
161
|
+
this->restore_offset_calibrations_();
|
162
|
+
|
163
|
+
// Initialize flash storage for power offset calibrations
|
164
|
+
uint32_t po_hash = fnv1_hash(std::string("_power_offset_calibration_") + this->cs_->dump_summary());
|
165
|
+
this->power_offset_pref_ = global_preferences->make_preference<PowerOffsetCalibration[3]>(po_hash, true);
|
166
|
+
this->restore_power_offset_calibrations_();
|
167
|
+
} else {
|
168
|
+
ESP_LOGI(TAG, "[CALIBRATION] Power & Voltage/Current offset calibration is disabled. Using config file values.");
|
169
|
+
for (uint8_t phase = 0; phase < 3; ++phase) {
|
170
|
+
this->write16_(this->voltage_offset_registers[phase],
|
171
|
+
static_cast<uint16_t>(this->offset_phase_[phase].voltage_offset_));
|
172
|
+
this->write16_(this->current_offset_registers[phase],
|
173
|
+
static_cast<uint16_t>(this->offset_phase_[phase].current_offset_));
|
174
|
+
this->write16_(this->power_offset_registers[phase],
|
175
|
+
static_cast<uint16_t>(this->power_offset_phase_[phase].active_power_offset));
|
176
|
+
this->write16_(this->reactive_power_offset_registers[phase],
|
177
|
+
static_cast<uint16_t>(this->power_offset_phase_[phase].reactive_power_offset));
|
178
|
+
}
|
179
|
+
}
|
180
|
+
|
181
|
+
if (this->enable_gain_calibration_) {
|
182
|
+
// Initialize flash storage for gain calibration
|
183
|
+
uint32_t g_hash = fnv1_hash(std::string("_gain_calibration_") + this->cs_->dump_summary());
|
184
|
+
this->gain_calibration_pref_ = global_preferences->make_preference<GainCalibration[3]>(g_hash, true);
|
185
|
+
this->restore_gain_calibrations_();
|
186
|
+
|
187
|
+
if (this->using_saved_calibrations_) {
|
188
|
+
ESP_LOGI(TAG, "[CALIBRATION] Successfully restored gain calibration from memory.");
|
189
|
+
} else {
|
190
|
+
for (uint8_t phase = 0; phase < 3; ++phase) {
|
191
|
+
this->write16_(voltage_gain_registers[phase], this->phase_[phase].voltage_gain_);
|
192
|
+
this->write16_(current_gain_registers[phase], this->phase_[phase].ct_gain_);
|
193
|
+
}
|
194
|
+
}
|
195
|
+
} else {
|
196
|
+
ESP_LOGI(TAG, "[CALIBRATION] Gain calibration is disabled. Using config file values.");
|
197
|
+
|
198
|
+
for (uint8_t phase = 0; phase < 3; ++phase) {
|
199
|
+
this->write16_(voltage_gain_registers[phase], this->phase_[phase].voltage_gain_);
|
200
|
+
this->write16_(current_gain_registers[phase], this->phase_[phase].ct_gain_);
|
201
|
+
}
|
202
|
+
}
|
203
|
+
|
204
|
+
// Sag threshold (78%)
|
205
|
+
uint16_t sagth = calculate_voltage_threshold(line_freq_, this->phase_[0].voltage_gain_, 0.78f);
|
206
|
+
// Overvoltage threshold (122%)
|
207
|
+
uint16_t ovth = calculate_voltage_threshold(line_freq_, this->phase_[0].voltage_gain_, 1.22f);
|
208
|
+
|
209
|
+
// Write to registers
|
210
|
+
this->write16_(ATM90E32_REGISTER_SAGTH, sagth);
|
211
|
+
this->write16_(ATM90E32_REGISTER_OVTH, ovth);
|
212
|
+
|
213
|
+
this->write16_(ATM90E32_REGISTER_CFGREGACCEN, 0x0000); // end configuration
|
247
214
|
}
|
248
215
|
|
249
216
|
void ATM90E32Component::dump_config() {
|
@@ -257,6 +224,7 @@ void ATM90E32Component::dump_config() {
|
|
257
224
|
LOG_SENSOR(" ", "Current A", this->phase_[PHASEA].current_sensor_);
|
258
225
|
LOG_SENSOR(" ", "Power A", this->phase_[PHASEA].power_sensor_);
|
259
226
|
LOG_SENSOR(" ", "Reactive Power A", this->phase_[PHASEA].reactive_power_sensor_);
|
227
|
+
LOG_SENSOR(" ", "Apparent Power A", this->phase_[PHASEA].apparent_power_sensor_);
|
260
228
|
LOG_SENSOR(" ", "PF A", this->phase_[PHASEA].power_factor_sensor_);
|
261
229
|
LOG_SENSOR(" ", "Active Forward Energy A", this->phase_[PHASEA].forward_active_energy_sensor_);
|
262
230
|
LOG_SENSOR(" ", "Active Reverse Energy A", this->phase_[PHASEA].reverse_active_energy_sensor_);
|
@@ -267,22 +235,24 @@ void ATM90E32Component::dump_config() {
|
|
267
235
|
LOG_SENSOR(" ", "Current B", this->phase_[PHASEB].current_sensor_);
|
268
236
|
LOG_SENSOR(" ", "Power B", this->phase_[PHASEB].power_sensor_);
|
269
237
|
LOG_SENSOR(" ", "Reactive Power B", this->phase_[PHASEB].reactive_power_sensor_);
|
238
|
+
LOG_SENSOR(" ", "Apparent Power B", this->phase_[PHASEB].apparent_power_sensor_);
|
270
239
|
LOG_SENSOR(" ", "PF B", this->phase_[PHASEB].power_factor_sensor_);
|
271
240
|
LOG_SENSOR(" ", "Active Forward Energy B", this->phase_[PHASEB].forward_active_energy_sensor_);
|
272
241
|
LOG_SENSOR(" ", "Active Reverse Energy B", this->phase_[PHASEB].reverse_active_energy_sensor_);
|
273
|
-
LOG_SENSOR(" ", "Harmonic Power
|
274
|
-
LOG_SENSOR(" ", "Phase Angle
|
275
|
-
LOG_SENSOR(" ", "Peak Current
|
242
|
+
LOG_SENSOR(" ", "Harmonic Power B", this->phase_[PHASEB].harmonic_active_power_sensor_);
|
243
|
+
LOG_SENSOR(" ", "Phase Angle B", this->phase_[PHASEB].phase_angle_sensor_);
|
244
|
+
LOG_SENSOR(" ", "Peak Current B", this->phase_[PHASEB].peak_current_sensor_);
|
276
245
|
LOG_SENSOR(" ", "Voltage C", this->phase_[PHASEC].voltage_sensor_);
|
277
246
|
LOG_SENSOR(" ", "Current C", this->phase_[PHASEC].current_sensor_);
|
278
247
|
LOG_SENSOR(" ", "Power C", this->phase_[PHASEC].power_sensor_);
|
279
248
|
LOG_SENSOR(" ", "Reactive Power C", this->phase_[PHASEC].reactive_power_sensor_);
|
249
|
+
LOG_SENSOR(" ", "Apparent Power C", this->phase_[PHASEC].apparent_power_sensor_);
|
280
250
|
LOG_SENSOR(" ", "PF C", this->phase_[PHASEC].power_factor_sensor_);
|
281
251
|
LOG_SENSOR(" ", "Active Forward Energy C", this->phase_[PHASEC].forward_active_energy_sensor_);
|
282
252
|
LOG_SENSOR(" ", "Active Reverse Energy C", this->phase_[PHASEC].reverse_active_energy_sensor_);
|
283
|
-
LOG_SENSOR(" ", "Harmonic Power
|
284
|
-
LOG_SENSOR(" ", "Phase Angle
|
285
|
-
LOG_SENSOR(" ", "Peak Current
|
253
|
+
LOG_SENSOR(" ", "Harmonic Power C", this->phase_[PHASEC].harmonic_active_power_sensor_);
|
254
|
+
LOG_SENSOR(" ", "Phase Angle C", this->phase_[PHASEC].phase_angle_sensor_);
|
255
|
+
LOG_SENSOR(" ", "Peak Current C", this->phase_[PHASEC].peak_current_sensor_);
|
286
256
|
LOG_SENSOR(" ", "Frequency", this->freq_sensor_);
|
287
257
|
LOG_SENSOR(" ", "Chip Temp", this->chip_temperature_sensor_);
|
288
258
|
}
|
@@ -298,7 +268,7 @@ uint16_t ATM90E32Component::read16_(uint16_t a_register) {
|
|
298
268
|
uint8_t data[2];
|
299
269
|
uint16_t output;
|
300
270
|
this->enable();
|
301
|
-
delay_microseconds_safe(
|
271
|
+
delay_microseconds_safe(1); // min delay between CS low and first SCK is 200ns - 1ms is plenty
|
302
272
|
this->write_byte(addrh);
|
303
273
|
this->write_byte(addrl);
|
304
274
|
this->read_array(data, 2);
|
@@ -328,8 +298,7 @@ void ATM90E32Component::write16_(uint16_t a_register, uint16_t val) {
|
|
328
298
|
this->write_byte16(a_register);
|
329
299
|
this->write_byte16(val);
|
330
300
|
this->disable();
|
331
|
-
|
332
|
-
ESP_LOGW(TAG, "SPI write error 0x%04X val 0x%04X", a_register, val);
|
301
|
+
this->validate_spi_read_(val, "write16()");
|
333
302
|
}
|
334
303
|
|
335
304
|
float ATM90E32Component::get_local_phase_voltage_(uint8_t phase) { return this->phase_[phase].voltage_; }
|
@@ -340,6 +309,8 @@ float ATM90E32Component::get_local_phase_active_power_(uint8_t phase) { return t
|
|
340
309
|
|
341
310
|
float ATM90E32Component::get_local_phase_reactive_power_(uint8_t phase) { return this->phase_[phase].reactive_power_; }
|
342
311
|
|
312
|
+
float ATM90E32Component::get_local_phase_apparent_power_(uint8_t phase) { return this->phase_[phase].apparent_power_; }
|
313
|
+
|
343
314
|
float ATM90E32Component::get_local_phase_power_factor_(uint8_t phase) { return this->phase_[phase].power_factor_; }
|
344
315
|
|
345
316
|
float ATM90E32Component::get_local_phase_forward_active_energy_(uint8_t phase) {
|
@@ -360,8 +331,7 @@ float ATM90E32Component::get_local_phase_peak_current_(uint8_t phase) { return t
|
|
360
331
|
|
361
332
|
float ATM90E32Component::get_phase_voltage_(uint8_t phase) {
|
362
333
|
const uint16_t voltage = this->read16_(ATM90E32_REGISTER_URMS + phase);
|
363
|
-
|
364
|
-
ESP_LOGW(TAG, "SPI URMS voltage register read error.");
|
334
|
+
this->validate_spi_read_(voltage, "get_phase_voltage()");
|
365
335
|
return (float) voltage / 100;
|
366
336
|
}
|
367
337
|
|
@@ -371,8 +341,7 @@ float ATM90E32Component::get_phase_voltage_avg_(uint8_t phase) {
|
|
371
341
|
uint16_t voltage = 0;
|
372
342
|
for (uint8_t i = 0; i < reads; i++) {
|
373
343
|
voltage = this->read16_(ATM90E32_REGISTER_URMS + phase);
|
374
|
-
|
375
|
-
ESP_LOGW(TAG, "SPI URMS voltage register read error.");
|
344
|
+
this->validate_spi_read_(voltage, "get_phase_voltage_avg_()");
|
376
345
|
accumulation += voltage;
|
377
346
|
}
|
378
347
|
voltage = accumulation / reads;
|
@@ -386,8 +355,7 @@ float ATM90E32Component::get_phase_current_avg_(uint8_t phase) {
|
|
386
355
|
uint16_t current = 0;
|
387
356
|
for (uint8_t i = 0; i < reads; i++) {
|
388
357
|
current = this->read16_(ATM90E32_REGISTER_IRMS + phase);
|
389
|
-
|
390
|
-
ESP_LOGW(TAG, "SPI IRMS current register read error.");
|
358
|
+
this->validate_spi_read_(current, "get_phase_current_avg_()");
|
391
359
|
accumulation += current;
|
392
360
|
}
|
393
361
|
current = accumulation / reads;
|
@@ -397,8 +365,7 @@ float ATM90E32Component::get_phase_current_avg_(uint8_t phase) {
|
|
397
365
|
|
398
366
|
float ATM90E32Component::get_phase_current_(uint8_t phase) {
|
399
367
|
const uint16_t current = this->read16_(ATM90E32_REGISTER_IRMS + phase);
|
400
|
-
|
401
|
-
ESP_LOGW(TAG, "SPI IRMS current register read error.");
|
368
|
+
this->validate_spi_read_(current, "get_phase_current_()");
|
402
369
|
return (float) current / 1000;
|
403
370
|
}
|
404
371
|
|
@@ -412,11 +379,15 @@ float ATM90E32Component::get_phase_reactive_power_(uint8_t phase) {
|
|
412
379
|
return val * 0.00032f;
|
413
380
|
}
|
414
381
|
|
382
|
+
float ATM90E32Component::get_phase_apparent_power_(uint8_t phase) {
|
383
|
+
const int val = this->read32_(ATM90E32_REGISTER_SMEAN + phase, ATM90E32_REGISTER_SMEANLSB + phase);
|
384
|
+
return val * 0.00032f;
|
385
|
+
}
|
386
|
+
|
415
387
|
float ATM90E32Component::get_phase_power_factor_(uint8_t phase) {
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
return (float) powerfactor / 1000;
|
388
|
+
uint16_t powerfactor = this->read16_(ATM90E32_REGISTER_PFMEAN + phase); // unsigned to compare to lastspidata
|
389
|
+
this->validate_spi_read_(powerfactor, "get_phase_power_factor_()");
|
390
|
+
return (float) ((int16_t) powerfactor) / 1000; // make it signed again
|
420
391
|
}
|
421
392
|
|
422
393
|
float ATM90E32Component::get_phase_forward_active_energy_(uint8_t phase) {
|
@@ -426,17 +397,19 @@ float ATM90E32Component::get_phase_forward_active_energy_(uint8_t phase) {
|
|
426
397
|
} else {
|
427
398
|
this->phase_[phase].cumulative_forward_active_energy_ = val;
|
428
399
|
}
|
429
|
-
|
400
|
+
// 0.01CF resolution = 0.003125 Wh per count
|
401
|
+
return ((float) this->phase_[phase].cumulative_forward_active_energy_ * (10.0f / 3200.0f));
|
430
402
|
}
|
431
403
|
|
432
404
|
float ATM90E32Component::get_phase_reverse_active_energy_(uint8_t phase) {
|
433
|
-
const uint16_t val = this->read16_(ATM90E32_REGISTER_ANENERGY);
|
405
|
+
const uint16_t val = this->read16_(ATM90E32_REGISTER_ANENERGY + phase);
|
434
406
|
if (UINT32_MAX - this->phase_[phase].cumulative_reverse_active_energy_ > val) {
|
435
407
|
this->phase_[phase].cumulative_reverse_active_energy_ += val;
|
436
408
|
} else {
|
437
409
|
this->phase_[phase].cumulative_reverse_active_energy_ = val;
|
438
410
|
}
|
439
|
-
|
411
|
+
// 0.01CF resolution = 0.003125 Wh per count
|
412
|
+
return ((float) this->phase_[phase].cumulative_reverse_active_energy_ * (10.0f / 3200.0f));
|
440
413
|
}
|
441
414
|
|
442
415
|
float ATM90E32Component::get_phase_harmonic_active_power_(uint8_t phase) {
|
@@ -446,15 +419,15 @@ float ATM90E32Component::get_phase_harmonic_active_power_(uint8_t phase) {
|
|
446
419
|
|
447
420
|
float ATM90E32Component::get_phase_angle_(uint8_t phase) {
|
448
421
|
uint16_t val = this->read16_(ATM90E32_REGISTER_PANGLE + phase) / 10.0;
|
449
|
-
return (
|
422
|
+
return (val > 180) ? (float) (val - 360.0f) : (float) val;
|
450
423
|
}
|
451
424
|
|
452
425
|
float ATM90E32Component::get_phase_peak_current_(uint8_t phase) {
|
453
426
|
int16_t val = (float) this->read16_(ATM90E32_REGISTER_IPEAK + phase);
|
454
427
|
if (!this->peak_current_signed_)
|
455
|
-
val = abs(val);
|
428
|
+
val = std::abs(val);
|
456
429
|
// phase register * phase current gain value / 1000 * 2^13
|
457
|
-
return (
|
430
|
+
return (val * this->phase_[phase].ct_gain_ / 8192000.0);
|
458
431
|
}
|
459
432
|
|
460
433
|
float ATM90E32Component::get_frequency_() {
|
@@ -467,29 +440,433 @@ float ATM90E32Component::get_chip_temperature_() {
|
|
467
440
|
return (float) ctemp;
|
468
441
|
}
|
469
442
|
|
470
|
-
|
443
|
+
void ATM90E32Component::run_gain_calibrations() {
|
444
|
+
if (!this->enable_gain_calibration_) {
|
445
|
+
ESP_LOGW(TAG, "[CALIBRATION] Gain calibration is disabled! Enable it first with enable_gain_calibration: true");
|
446
|
+
return;
|
447
|
+
}
|
448
|
+
|
449
|
+
float ref_voltages[3] = {
|
450
|
+
this->get_reference_voltage(0),
|
451
|
+
this->get_reference_voltage(1),
|
452
|
+
this->get_reference_voltage(2),
|
453
|
+
};
|
454
|
+
float ref_currents[3] = {this->get_reference_current(0), this->get_reference_current(1),
|
455
|
+
this->get_reference_current(2)};
|
456
|
+
|
457
|
+
ESP_LOGI(TAG, "[CALIBRATION] ");
|
458
|
+
ESP_LOGI(TAG, "[CALIBRATION] ========================= Gain Calibration =========================");
|
459
|
+
ESP_LOGI(TAG, "[CALIBRATION] ---------------------------------------------------------------------");
|
460
|
+
ESP_LOGI(TAG,
|
461
|
+
"[CALIBRATION] | Phase | V_meas (V) | I_meas (A) | V_ref | I_ref | V_gain (old→new) | I_gain (old→new) |");
|
462
|
+
ESP_LOGI(TAG, "[CALIBRATION] ---------------------------------------------------------------------");
|
463
|
+
|
464
|
+
for (uint8_t phase = 0; phase < 3; phase++) {
|
465
|
+
float measured_voltage = this->get_phase_voltage_avg_(phase);
|
466
|
+
float measured_current = this->get_phase_current_avg_(phase);
|
467
|
+
|
468
|
+
float ref_voltage = ref_voltages[phase];
|
469
|
+
float ref_current = ref_currents[phase];
|
470
|
+
|
471
|
+
uint16_t current_voltage_gain = this->read16_(voltage_gain_registers[phase]);
|
472
|
+
uint16_t current_current_gain = this->read16_(current_gain_registers[phase]);
|
473
|
+
|
474
|
+
bool did_voltage = false;
|
475
|
+
bool did_current = false;
|
476
|
+
|
477
|
+
// Voltage calibration
|
478
|
+
if (ref_voltage <= 0.0f) {
|
479
|
+
ESP_LOGW(TAG, "[CALIBRATION] Phase %s - Skipping voltage calibration: reference voltage is 0.",
|
480
|
+
phase_labels[phase]);
|
481
|
+
} else if (measured_voltage == 0.0f) {
|
482
|
+
ESP_LOGW(TAG, "[CALIBRATION] Phase %s - Skipping voltage calibration: measured voltage is 0.",
|
483
|
+
phase_labels[phase]);
|
484
|
+
} else {
|
485
|
+
uint32_t new_voltage_gain = static_cast<uint16_t>((ref_voltage / measured_voltage) * current_voltage_gain);
|
486
|
+
if (new_voltage_gain == 0) {
|
487
|
+
ESP_LOGW(TAG, "[CALIBRATION] Phase %s - Voltage gain would be 0. Check reference and measured voltage.",
|
488
|
+
phase_labels[phase]);
|
489
|
+
} else {
|
490
|
+
if (new_voltage_gain >= 65535) {
|
491
|
+
ESP_LOGW(
|
492
|
+
TAG,
|
493
|
+
"[CALIBRATION] Phase %s - Voltage gain exceeds 65535. You may need a higher output voltage transformer.",
|
494
|
+
phase_labels[phase]);
|
495
|
+
new_voltage_gain = 65535;
|
496
|
+
}
|
497
|
+
this->gain_phase_[phase].voltage_gain = static_cast<uint16_t>(new_voltage_gain);
|
498
|
+
did_voltage = true;
|
499
|
+
}
|
500
|
+
}
|
501
|
+
|
502
|
+
// Current calibration
|
503
|
+
if (ref_current == 0.0f) {
|
504
|
+
ESP_LOGW(TAG, "[CALIBRATION] Phase %s - Skipping current calibration: reference current is 0.",
|
505
|
+
phase_labels[phase]);
|
506
|
+
} else if (measured_current == 0.0f) {
|
507
|
+
ESP_LOGW(TAG, "[CALIBRATION] Phase %s - Skipping current calibration: measured current is 0.",
|
508
|
+
phase_labels[phase]);
|
509
|
+
} else {
|
510
|
+
uint32_t new_current_gain = static_cast<uint16_t>((ref_current / measured_current) * current_current_gain);
|
511
|
+
if (new_current_gain == 0) {
|
512
|
+
ESP_LOGW(TAG, "[CALIBRATION] Phase %s - Current gain would be 0. Check reference and measured current.",
|
513
|
+
phase_labels[phase]);
|
514
|
+
} else {
|
515
|
+
if (new_current_gain >= 65535) {
|
516
|
+
ESP_LOGW(TAG, "[CALIBRATION] Phase %s - Current gain exceeds 65535. You may need to turn up pga gain.",
|
517
|
+
phase_labels[phase]);
|
518
|
+
new_current_gain = 65535;
|
519
|
+
}
|
520
|
+
this->gain_phase_[phase].current_gain = static_cast<uint16_t>(new_current_gain);
|
521
|
+
did_current = true;
|
522
|
+
}
|
523
|
+
}
|
524
|
+
|
525
|
+
// Final row output
|
526
|
+
ESP_LOGI(TAG, "[CALIBRATION] | %c | %9.2f | %9.4f | %5.2f | %6.4f | %5u → %-5u | %5u → %-5u |",
|
527
|
+
'A' + phase, measured_voltage, measured_current, ref_voltage, ref_current, current_voltage_gain,
|
528
|
+
did_voltage ? this->gain_phase_[phase].voltage_gain : current_voltage_gain, current_current_gain,
|
529
|
+
did_current ? this->gain_phase_[phase].current_gain : current_current_gain);
|
530
|
+
}
|
531
|
+
|
532
|
+
ESP_LOGI(TAG, "[CALIBRATION] =====================================================================\n");
|
533
|
+
|
534
|
+
this->save_gain_calibration_to_memory_();
|
535
|
+
this->write_gains_to_registers_();
|
536
|
+
this->verify_gain_writes_();
|
537
|
+
}
|
538
|
+
|
539
|
+
void ATM90E32Component::save_gain_calibration_to_memory_() {
|
540
|
+
bool success = this->gain_calibration_pref_.save(&this->gain_phase_);
|
541
|
+
if (success) {
|
542
|
+
this->using_saved_calibrations_ = true;
|
543
|
+
ESP_LOGI(TAG, "[CALIBRATION] Gain calibration saved to memory.");
|
544
|
+
} else {
|
545
|
+
this->using_saved_calibrations_ = false;
|
546
|
+
ESP_LOGE(TAG, "[CALIBRATION] Failed to save gain calibration to memory!");
|
547
|
+
}
|
548
|
+
}
|
549
|
+
|
550
|
+
void ATM90E32Component::run_offset_calibrations() {
|
551
|
+
if (!this->enable_offset_calibration_) {
|
552
|
+
ESP_LOGW(TAG, "[CALIBRATION] Offset calibration is disabled! Enable it first with enable_offset_calibration: true");
|
553
|
+
return;
|
554
|
+
}
|
555
|
+
|
556
|
+
for (uint8_t phase = 0; phase < 3; phase++) {
|
557
|
+
int16_t voltage_offset = calibrate_offset(phase, true);
|
558
|
+
int16_t current_offset = calibrate_offset(phase, false);
|
559
|
+
|
560
|
+
this->write_offsets_to_registers_(phase, voltage_offset, current_offset);
|
561
|
+
|
562
|
+
ESP_LOGI(TAG, "[CALIBRATION] Phase %c - offset_voltage: %d, offset_current: %d", 'A' + phase, voltage_offset,
|
563
|
+
current_offset);
|
564
|
+
}
|
565
|
+
|
566
|
+
this->offset_pref_.save(&this->offset_phase_); // Save to flash
|
567
|
+
}
|
568
|
+
|
569
|
+
void ATM90E32Component::run_power_offset_calibrations() {
|
570
|
+
if (!this->enable_offset_calibration_) {
|
571
|
+
ESP_LOGW(
|
572
|
+
TAG,
|
573
|
+
"[CALIBRATION] Offset power calibration is disabled! Enable it first with enable_offset_calibration: true");
|
574
|
+
return;
|
575
|
+
}
|
576
|
+
|
577
|
+
for (uint8_t phase = 0; phase < 3; ++phase) {
|
578
|
+
int16_t active_offset = calibrate_power_offset(phase, false);
|
579
|
+
int16_t reactive_offset = calibrate_power_offset(phase, true);
|
580
|
+
|
581
|
+
this->write_power_offsets_to_registers_(phase, active_offset, reactive_offset);
|
582
|
+
|
583
|
+
ESP_LOGI(TAG, "[CALIBRATION] Phase %c - offset_active_power: %d, offset_reactive_power: %d", 'A' + phase,
|
584
|
+
active_offset, reactive_offset);
|
585
|
+
}
|
586
|
+
|
587
|
+
this->power_offset_pref_.save(&this->power_offset_phase_); // Save to flash
|
588
|
+
}
|
589
|
+
|
590
|
+
void ATM90E32Component::write_gains_to_registers_() {
|
591
|
+
this->write16_(ATM90E32_REGISTER_CFGREGACCEN, 0x55AA);
|
592
|
+
|
593
|
+
for (int phase = 0; phase < 3; phase++) {
|
594
|
+
this->write16_(voltage_gain_registers[phase], this->gain_phase_[phase].voltage_gain);
|
595
|
+
this->write16_(current_gain_registers[phase], this->gain_phase_[phase].current_gain);
|
596
|
+
}
|
597
|
+
|
598
|
+
this->write16_(ATM90E32_REGISTER_CFGREGACCEN, 0x0000);
|
599
|
+
}
|
600
|
+
|
601
|
+
void ATM90E32Component::write_offsets_to_registers_(uint8_t phase, int16_t voltage_offset, int16_t current_offset) {
|
602
|
+
// Save to runtime
|
603
|
+
this->offset_phase_[phase].voltage_offset_ = voltage_offset;
|
604
|
+
this->phase_[phase].voltage_offset_ = voltage_offset;
|
605
|
+
|
606
|
+
// Save to flash-storable struct
|
607
|
+
this->offset_phase_[phase].current_offset_ = current_offset;
|
608
|
+
this->phase_[phase].current_offset_ = current_offset;
|
609
|
+
|
610
|
+
// Write to registers
|
611
|
+
this->write16_(ATM90E32_REGISTER_CFGREGACCEN, 0x55AA);
|
612
|
+
this->write16_(voltage_offset_registers[phase], static_cast<uint16_t>(voltage_offset));
|
613
|
+
this->write16_(current_offset_registers[phase], static_cast<uint16_t>(current_offset));
|
614
|
+
this->write16_(ATM90E32_REGISTER_CFGREGACCEN, 0x0000);
|
615
|
+
}
|
616
|
+
|
617
|
+
void ATM90E32Component::write_power_offsets_to_registers_(uint8_t phase, int16_t p_offset, int16_t q_offset) {
|
618
|
+
// Save to runtime
|
619
|
+
this->phase_[phase].active_power_offset_ = p_offset;
|
620
|
+
this->phase_[phase].reactive_power_offset_ = q_offset;
|
621
|
+
|
622
|
+
// Save to flash-storable struct
|
623
|
+
this->power_offset_phase_[phase].active_power_offset = p_offset;
|
624
|
+
this->power_offset_phase_[phase].reactive_power_offset = q_offset;
|
625
|
+
|
626
|
+
// Write to registers
|
627
|
+
this->write16_(ATM90E32_REGISTER_CFGREGACCEN, 0x55AA);
|
628
|
+
this->write16_(this->power_offset_registers[phase], static_cast<uint16_t>(p_offset));
|
629
|
+
this->write16_(this->reactive_power_offset_registers[phase], static_cast<uint16_t>(q_offset));
|
630
|
+
this->write16_(ATM90E32_REGISTER_CFGREGACCEN, 0x0000);
|
631
|
+
}
|
632
|
+
|
633
|
+
void ATM90E32Component::restore_gain_calibrations_() {
|
634
|
+
if (this->gain_calibration_pref_.load(&this->gain_phase_)) {
|
635
|
+
ESP_LOGI(TAG, "[CALIBRATION] Restoring saved gain calibrations to registers:");
|
636
|
+
|
637
|
+
for (uint8_t phase = 0; phase < 3; phase++) {
|
638
|
+
uint16_t v_gain = this->gain_phase_[phase].voltage_gain;
|
639
|
+
uint16_t i_gain = this->gain_phase_[phase].current_gain;
|
640
|
+
ESP_LOGI(TAG, "[CALIBRATION] Phase %c - Voltage Gain: %u, Current Gain: %u", 'A' + phase, v_gain, i_gain);
|
641
|
+
}
|
642
|
+
|
643
|
+
this->write_gains_to_registers_();
|
644
|
+
|
645
|
+
if (this->verify_gain_writes_()) {
|
646
|
+
this->using_saved_calibrations_ = true;
|
647
|
+
ESP_LOGI(TAG, "[CALIBRATION] Gain calibration loaded and verified successfully.");
|
648
|
+
} else {
|
649
|
+
this->using_saved_calibrations_ = false;
|
650
|
+
ESP_LOGE(TAG, "[CALIBRATION] Gain verification failed! Calibration may not be applied correctly.");
|
651
|
+
}
|
652
|
+
} else {
|
653
|
+
this->using_saved_calibrations_ = false;
|
654
|
+
ESP_LOGW(TAG, "[CALIBRATION] No stored gain calibrations found. Using config file values.");
|
655
|
+
}
|
656
|
+
}
|
657
|
+
|
658
|
+
void ATM90E32Component::restore_offset_calibrations_() {
|
659
|
+
if (this->offset_pref_.load(&this->offset_phase_)) {
|
660
|
+
ESP_LOGI(TAG, "[CALIBRATION] Successfully restored offset calibration from memory.");
|
661
|
+
|
662
|
+
for (uint8_t phase = 0; phase < 3; phase++) {
|
663
|
+
auto &offset = this->offset_phase_[phase];
|
664
|
+
write_offsets_to_registers_(phase, offset.voltage_offset_, offset.current_offset_);
|
665
|
+
ESP_LOGI(TAG, "[CALIBRATION] Phase %c - offset_voltage:: %d, offset_current: %d", 'A' + phase,
|
666
|
+
offset.voltage_offset_, offset.current_offset_);
|
667
|
+
}
|
668
|
+
} else {
|
669
|
+
ESP_LOGW(TAG, "[CALIBRATION] No stored offset calibrations found. Using default values.");
|
670
|
+
}
|
671
|
+
}
|
672
|
+
|
673
|
+
void ATM90E32Component::restore_power_offset_calibrations_() {
|
674
|
+
if (this->power_offset_pref_.load(&this->power_offset_phase_)) {
|
675
|
+
ESP_LOGI(TAG, "[CALIBRATION] Successfully restored power offset calibration from memory.");
|
676
|
+
|
677
|
+
for (uint8_t phase = 0; phase < 3; ++phase) {
|
678
|
+
auto &offset = this->power_offset_phase_[phase];
|
679
|
+
write_power_offsets_to_registers_(phase, offset.active_power_offset, offset.reactive_power_offset);
|
680
|
+
ESP_LOGI(TAG, "[CALIBRATION] Phase %c - offset_active_power: %d, offset_reactive_power: %d", 'A' + phase,
|
681
|
+
offset.active_power_offset, offset.reactive_power_offset);
|
682
|
+
}
|
683
|
+
} else {
|
684
|
+
ESP_LOGW(TAG, "[CALIBRATION] No stored power offsets found. Using default values.");
|
685
|
+
}
|
686
|
+
}
|
687
|
+
|
688
|
+
void ATM90E32Component::clear_gain_calibrations() {
|
689
|
+
ESP_LOGI(TAG, "[CALIBRATION] Clearing stored gain calibrations and restoring config-defined values...");
|
690
|
+
|
691
|
+
for (int phase = 0; phase < 3; phase++) {
|
692
|
+
gain_phase_[phase].voltage_gain = this->phase_[phase].voltage_gain_;
|
693
|
+
gain_phase_[phase].current_gain = this->phase_[phase].ct_gain_;
|
694
|
+
}
|
695
|
+
|
696
|
+
bool success = this->gain_calibration_pref_.save(&this->gain_phase_);
|
697
|
+
this->using_saved_calibrations_ = false;
|
698
|
+
|
699
|
+
if (success) {
|
700
|
+
ESP_LOGI(TAG, "[CALIBRATION] Gain calibrations cleared. Config values restored:");
|
701
|
+
for (int phase = 0; phase < 3; phase++) {
|
702
|
+
ESP_LOGI(TAG, "[CALIBRATION] Phase %c - Voltage Gain: %u, Current Gain: %u", 'A' + phase,
|
703
|
+
gain_phase_[phase].voltage_gain, gain_phase_[phase].current_gain);
|
704
|
+
}
|
705
|
+
} else {
|
706
|
+
ESP_LOGE(TAG, "[CALIBRATION] Failed to clear gain calibrations!");
|
707
|
+
}
|
708
|
+
|
709
|
+
this->write_gains_to_registers_(); // Apply them to the chip immediately
|
710
|
+
}
|
711
|
+
|
712
|
+
void ATM90E32Component::clear_offset_calibrations() {
|
713
|
+
for (uint8_t phase = 0; phase < 3; phase++) {
|
714
|
+
this->write_offsets_to_registers_(phase, 0, 0);
|
715
|
+
}
|
716
|
+
|
717
|
+
this->offset_pref_.save(&this->offset_phase_); // Save cleared values to flash memory
|
718
|
+
|
719
|
+
ESP_LOGI(TAG, "[CALIBRATION] Offsets cleared.");
|
720
|
+
}
|
721
|
+
|
722
|
+
void ATM90E32Component::clear_power_offset_calibrations() {
|
723
|
+
for (uint8_t phase = 0; phase < 3; phase++) {
|
724
|
+
this->write_power_offsets_to_registers_(phase, 0, 0);
|
725
|
+
}
|
726
|
+
|
727
|
+
this->power_offset_pref_.save(&this->power_offset_phase_);
|
728
|
+
|
729
|
+
ESP_LOGI(TAG, "[CALIBRATION] Power offsets cleared.");
|
730
|
+
}
|
731
|
+
|
732
|
+
int16_t ATM90E32Component::calibrate_offset(uint8_t phase, bool voltage) {
|
471
733
|
const uint8_t num_reads = 5;
|
472
734
|
uint64_t total_value = 0;
|
473
|
-
|
474
|
-
|
475
|
-
|
735
|
+
|
736
|
+
for (uint8_t i = 0; i < num_reads; ++i) {
|
737
|
+
uint32_t reading = voltage ? this->read32_(ATM90E32_REGISTER_URMS + phase, ATM90E32_REGISTER_URMSLSB + phase)
|
738
|
+
: this->read32_(ATM90E32_REGISTER_IRMS + phase, ATM90E32_REGISTER_IRMSLSB + phase);
|
739
|
+
total_value += reading;
|
476
740
|
}
|
741
|
+
|
477
742
|
const uint32_t average_value = total_value / num_reads;
|
478
|
-
const uint32_t
|
479
|
-
const uint32_t
|
480
|
-
return
|
743
|
+
const uint32_t shifted = average_value >> 7;
|
744
|
+
const uint32_t offset = ~shifted + 1;
|
745
|
+
return static_cast<int16_t>(offset); // Takes lower 16 bits
|
481
746
|
}
|
482
747
|
|
483
|
-
|
748
|
+
int16_t ATM90E32Component::calibrate_power_offset(uint8_t phase, bool reactive) {
|
484
749
|
const uint8_t num_reads = 5;
|
485
750
|
uint64_t total_value = 0;
|
486
|
-
|
487
|
-
|
488
|
-
|
751
|
+
|
752
|
+
for (uint8_t i = 0; i < num_reads; ++i) {
|
753
|
+
uint32_t reading = reactive ? this->read32_(ATM90E32_REGISTER_QMEAN + phase, ATM90E32_REGISTER_QMEANLSB + phase)
|
754
|
+
: this->read32_(ATM90E32_REGISTER_PMEAN + phase, ATM90E32_REGISTER_PMEANLSB + phase);
|
755
|
+
total_value += reading;
|
489
756
|
}
|
757
|
+
|
490
758
|
const uint32_t average_value = total_value / num_reads;
|
491
|
-
const uint32_t
|
492
|
-
return
|
759
|
+
const uint32_t power_offset = ~average_value + 1;
|
760
|
+
return static_cast<int16_t>(power_offset); // Takes the lower 16 bits
|
761
|
+
}
|
762
|
+
|
763
|
+
bool ATM90E32Component::verify_gain_writes_() {
|
764
|
+
bool success = true;
|
765
|
+
for (uint8_t phase = 0; phase < 3; phase++) {
|
766
|
+
uint16_t read_voltage = this->read16_(voltage_gain_registers[phase]);
|
767
|
+
uint16_t read_current = this->read16_(current_gain_registers[phase]);
|
768
|
+
|
769
|
+
if (read_voltage != this->gain_phase_[phase].voltage_gain ||
|
770
|
+
read_current != this->gain_phase_[phase].current_gain) {
|
771
|
+
ESP_LOGE(TAG, "[CALIBRATION] Mismatch detected for Phase %s!", phase_labels[phase]);
|
772
|
+
success = false;
|
773
|
+
}
|
774
|
+
}
|
775
|
+
return success; // Return true if all writes were successful, false otherwise
|
776
|
+
}
|
777
|
+
|
778
|
+
#ifdef USE_TEXT_SENSOR
|
779
|
+
void ATM90E32Component::check_phase_status() {
|
780
|
+
uint16_t state0 = this->read16_(ATM90E32_REGISTER_EMMSTATE0);
|
781
|
+
uint16_t state1 = this->read16_(ATM90E32_REGISTER_EMMSTATE1);
|
782
|
+
|
783
|
+
for (int phase = 0; phase < 3; phase++) {
|
784
|
+
std::string status;
|
785
|
+
|
786
|
+
if (state0 & over_voltage_flags[phase])
|
787
|
+
status += "Over Voltage; ";
|
788
|
+
if (state1 & voltage_sag_flags[phase])
|
789
|
+
status += "Voltage Sag; ";
|
790
|
+
if (state1 & phase_loss_flags[phase])
|
791
|
+
status += "Phase Loss; ";
|
792
|
+
|
793
|
+
auto *sensor = this->phase_status_text_sensor_[phase];
|
794
|
+
const char *phase_name = sensor ? sensor->get_name().c_str() : "Unknown Phase";
|
795
|
+
if (!status.empty()) {
|
796
|
+
status.pop_back(); // remove space
|
797
|
+
status.pop_back(); // remove semicolon
|
798
|
+
ESP_LOGW(TAG, "%s: %s", phase_name, status.c_str());
|
799
|
+
if (sensor != nullptr)
|
800
|
+
sensor->publish_state(status);
|
801
|
+
} else {
|
802
|
+
if (sensor != nullptr)
|
803
|
+
sensor->publish_state("Okay");
|
804
|
+
}
|
805
|
+
}
|
806
|
+
}
|
807
|
+
|
808
|
+
void ATM90E32Component::check_freq_status() {
|
809
|
+
uint16_t state1 = this->read16_(ATM90E32_REGISTER_EMMSTATE1);
|
810
|
+
|
811
|
+
std::string freq_status;
|
812
|
+
|
813
|
+
if (state1 & ATM90E32_STATUS_S1_FREQHIST) {
|
814
|
+
freq_status = "HIGH";
|
815
|
+
} else if (state1 & ATM90E32_STATUS_S1_FREQLOST) {
|
816
|
+
freq_status = "LOW";
|
817
|
+
} else {
|
818
|
+
freq_status = "Normal";
|
819
|
+
}
|
820
|
+
ESP_LOGW(TAG, "Frequency status: %s", freq_status.c_str());
|
821
|
+
|
822
|
+
if (this->freq_status_text_sensor_ != nullptr) {
|
823
|
+
this->freq_status_text_sensor_->publish_state(freq_status);
|
824
|
+
}
|
825
|
+
}
|
826
|
+
|
827
|
+
void ATM90E32Component::check_over_current() {
|
828
|
+
constexpr float max_current_threshold = 65.53f;
|
829
|
+
|
830
|
+
for (uint8_t phase = 0; phase < 3; phase++) {
|
831
|
+
float current_val =
|
832
|
+
this->phase_[phase].current_sensor_ != nullptr ? this->phase_[phase].current_sensor_->state : 0.0f;
|
833
|
+
|
834
|
+
if (current_val > max_current_threshold) {
|
835
|
+
ESP_LOGW(TAG, "Over current detected on Phase %c: %.2f A", 'A' + phase, current_val);
|
836
|
+
ESP_LOGW(TAG, "You may need to half your gain_ct: value & multiply the current and power values by 2");
|
837
|
+
if (this->phase_status_text_sensor_[phase] != nullptr) {
|
838
|
+
this->phase_status_text_sensor_[phase]->publish_state("Over Current; ");
|
839
|
+
}
|
840
|
+
}
|
841
|
+
}
|
842
|
+
}
|
843
|
+
#endif
|
844
|
+
|
845
|
+
uint16_t ATM90E32Component::calculate_voltage_threshold(int line_freq, uint16_t ugain, float multiplier) {
|
846
|
+
// this assumes that 60Hz electrical systems use 120V mains,
|
847
|
+
// which is usually, but not always the case
|
848
|
+
float nominal_voltage = (line_freq == 60) ? 120.0f : 220.0f;
|
849
|
+
float target_voltage = nominal_voltage * multiplier;
|
850
|
+
|
851
|
+
float peak_01v = target_voltage * 100.0f * std::sqrt(2.0f); // convert RMS → peak, scale to 0.01V
|
852
|
+
float divider = (2.0f * ugain) / 32768.0f;
|
853
|
+
|
854
|
+
float threshold = peak_01v / divider;
|
855
|
+
|
856
|
+
return static_cast<uint16_t>(threshold);
|
857
|
+
}
|
858
|
+
|
859
|
+
bool ATM90E32Component::validate_spi_read_(uint16_t expected, const char *context) {
|
860
|
+
uint16_t last = this->read16_(ATM90E32_REGISTER_LASTSPIDATA);
|
861
|
+
if (last != expected) {
|
862
|
+
if (context != nullptr) {
|
863
|
+
ESP_LOGW(TAG, "[%s] SPI read mismatch: expected 0x%04X, got 0x%04X", context, expected, last);
|
864
|
+
} else {
|
865
|
+
ESP_LOGW(TAG, "SPI read mismatch: expected 0x%04X, got 0x%04X", expected, last);
|
866
|
+
}
|
867
|
+
return false;
|
868
|
+
}
|
869
|
+
return true;
|
493
870
|
}
|
494
871
|
|
495
872
|
} // namespace atm90e32
|