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
@@ -0,0 +1,481 @@
|
|
1
|
+
#include "mipi_spi.h"
|
2
|
+
#include "esphome/core/log.h"
|
3
|
+
|
4
|
+
namespace esphome {
|
5
|
+
namespace mipi_spi {
|
6
|
+
|
7
|
+
void MipiSpi::setup() {
|
8
|
+
ESP_LOGCONFIG(TAG, "Setting up MIPI SPI");
|
9
|
+
this->spi_setup();
|
10
|
+
if (this->dc_pin_ != nullptr) {
|
11
|
+
this->dc_pin_->setup();
|
12
|
+
this->dc_pin_->digital_write(false);
|
13
|
+
}
|
14
|
+
for (auto *pin : this->enable_pins_) {
|
15
|
+
pin->setup();
|
16
|
+
pin->digital_write(true);
|
17
|
+
}
|
18
|
+
if (this->reset_pin_ != nullptr) {
|
19
|
+
this->reset_pin_->setup();
|
20
|
+
this->reset_pin_->digital_write(true);
|
21
|
+
delay(5);
|
22
|
+
this->reset_pin_->digital_write(false);
|
23
|
+
delay(5);
|
24
|
+
this->reset_pin_->digital_write(true);
|
25
|
+
}
|
26
|
+
this->bus_width_ = this->parent_->get_bus_width();
|
27
|
+
|
28
|
+
// need to know when the display is ready for SLPOUT command - will be 120ms after reset
|
29
|
+
auto when = millis() + 120;
|
30
|
+
delay(10);
|
31
|
+
size_t index = 0;
|
32
|
+
auto &vec = this->init_sequence_;
|
33
|
+
while (index != vec.size()) {
|
34
|
+
if (vec.size() - index < 2) {
|
35
|
+
ESP_LOGE(TAG, "Malformed init sequence");
|
36
|
+
this->mark_failed();
|
37
|
+
return;
|
38
|
+
}
|
39
|
+
uint8_t cmd = vec[index++];
|
40
|
+
uint8_t x = vec[index++];
|
41
|
+
if (x == DELAY_FLAG) {
|
42
|
+
ESP_LOGD(TAG, "Delay %dms", cmd);
|
43
|
+
delay(cmd);
|
44
|
+
} else {
|
45
|
+
uint8_t num_args = x & 0x7F;
|
46
|
+
if (vec.size() - index < num_args) {
|
47
|
+
ESP_LOGE(TAG, "Malformed init sequence");
|
48
|
+
this->mark_failed();
|
49
|
+
return;
|
50
|
+
}
|
51
|
+
auto arg_byte = vec[index];
|
52
|
+
switch (cmd) {
|
53
|
+
case SLEEP_OUT: {
|
54
|
+
// are we ready, boots?
|
55
|
+
int duration = when - millis();
|
56
|
+
if (duration > 0) {
|
57
|
+
ESP_LOGD(TAG, "Sleep %dms", duration);
|
58
|
+
delay(duration);
|
59
|
+
}
|
60
|
+
} break;
|
61
|
+
|
62
|
+
case INVERT_ON:
|
63
|
+
this->invert_colors_ = true;
|
64
|
+
break;
|
65
|
+
case MADCTL_CMD:
|
66
|
+
this->madctl_ = arg_byte;
|
67
|
+
break;
|
68
|
+
case PIXFMT:
|
69
|
+
this->pixel_mode_ = arg_byte & 0x11 ? PIXEL_MODE_16 : PIXEL_MODE_18;
|
70
|
+
break;
|
71
|
+
case BRIGHTNESS:
|
72
|
+
this->brightness_ = arg_byte;
|
73
|
+
break;
|
74
|
+
|
75
|
+
default:
|
76
|
+
break;
|
77
|
+
}
|
78
|
+
const auto *ptr = vec.data() + index;
|
79
|
+
ESP_LOGD(TAG, "Command %02X, length %d, byte %02X", cmd, num_args, arg_byte);
|
80
|
+
this->write_command_(cmd, ptr, num_args);
|
81
|
+
index += num_args;
|
82
|
+
if (cmd == SLEEP_OUT)
|
83
|
+
delay(10);
|
84
|
+
}
|
85
|
+
}
|
86
|
+
this->setup_complete_ = true;
|
87
|
+
if (this->draw_from_origin_)
|
88
|
+
check_buffer_();
|
89
|
+
ESP_LOGCONFIG(TAG, "MIPI SPI setup complete");
|
90
|
+
}
|
91
|
+
|
92
|
+
void MipiSpi::update() {
|
93
|
+
if (!this->setup_complete_ || this->is_failed()) {
|
94
|
+
return;
|
95
|
+
}
|
96
|
+
this->do_update_();
|
97
|
+
if (this->buffer_ == nullptr || this->x_low_ > this->x_high_ || this->y_low_ > this->y_high_)
|
98
|
+
return;
|
99
|
+
ESP_LOGV(TAG, "x_low %d, y_low %d, x_high %d, y_high %d", this->x_low_, this->y_low_, this->x_high_, this->y_high_);
|
100
|
+
// Some chips require that the drawing window be aligned on certain boundaries
|
101
|
+
auto dr = this->draw_rounding_;
|
102
|
+
this->x_low_ = this->x_low_ / dr * dr;
|
103
|
+
this->y_low_ = this->y_low_ / dr * dr;
|
104
|
+
this->x_high_ = (this->x_high_ + dr) / dr * dr - 1;
|
105
|
+
this->y_high_ = (this->y_high_ + dr) / dr * dr - 1;
|
106
|
+
if (this->draw_from_origin_) {
|
107
|
+
this->x_low_ = 0;
|
108
|
+
this->y_low_ = 0;
|
109
|
+
this->x_high_ = this->width_ - 1;
|
110
|
+
}
|
111
|
+
int w = this->x_high_ - this->x_low_ + 1;
|
112
|
+
int h = this->y_high_ - this->y_low_ + 1;
|
113
|
+
this->write_to_display_(this->x_low_, this->y_low_, w, h, this->buffer_, this->x_low_, this->y_low_,
|
114
|
+
this->width_ - w - this->x_low_);
|
115
|
+
// invalidate watermarks
|
116
|
+
this->x_low_ = this->width_;
|
117
|
+
this->y_low_ = this->height_;
|
118
|
+
this->x_high_ = 0;
|
119
|
+
this->y_high_ = 0;
|
120
|
+
}
|
121
|
+
|
122
|
+
void MipiSpi::fill(Color color) {
|
123
|
+
if (!this->check_buffer_())
|
124
|
+
return;
|
125
|
+
this->x_low_ = 0;
|
126
|
+
this->y_low_ = 0;
|
127
|
+
this->x_high_ = this->get_width_internal() - 1;
|
128
|
+
this->y_high_ = this->get_height_internal() - 1;
|
129
|
+
switch (this->color_depth_) {
|
130
|
+
case display::COLOR_BITNESS_332: {
|
131
|
+
auto new_color = display::ColorUtil::color_to_332(color, display::ColorOrder::COLOR_ORDER_RGB);
|
132
|
+
memset(this->buffer_, (uint8_t) new_color, this->buffer_bytes_);
|
133
|
+
break;
|
134
|
+
}
|
135
|
+
default: {
|
136
|
+
auto new_color = display::ColorUtil::color_to_565(color);
|
137
|
+
if (((uint8_t) (new_color >> 8)) == ((uint8_t) new_color)) {
|
138
|
+
// Upper and lower is equal can use quicker memset operation. Takes ~20ms.
|
139
|
+
memset(this->buffer_, (uint8_t) new_color, this->buffer_bytes_);
|
140
|
+
} else {
|
141
|
+
auto *ptr_16 = reinterpret_cast<uint16_t *>(this->buffer_);
|
142
|
+
auto len = this->buffer_bytes_ / 2;
|
143
|
+
while (len--) {
|
144
|
+
*ptr_16++ = new_color;
|
145
|
+
}
|
146
|
+
}
|
147
|
+
}
|
148
|
+
}
|
149
|
+
}
|
150
|
+
|
151
|
+
void MipiSpi::draw_absolute_pixel_internal(int x, int y, Color color) {
|
152
|
+
if (x >= this->get_width_internal() || x < 0 || y >= this->get_height_internal() || y < 0) {
|
153
|
+
return;
|
154
|
+
}
|
155
|
+
if (!this->check_buffer_())
|
156
|
+
return;
|
157
|
+
size_t pos = (y * this->width_) + x;
|
158
|
+
switch (this->color_depth_) {
|
159
|
+
case display::COLOR_BITNESS_332: {
|
160
|
+
uint8_t new_color = display::ColorUtil::color_to_332(color);
|
161
|
+
if (this->buffer_[pos] == new_color)
|
162
|
+
return;
|
163
|
+
this->buffer_[pos] = new_color;
|
164
|
+
break;
|
165
|
+
}
|
166
|
+
|
167
|
+
case display::COLOR_BITNESS_565: {
|
168
|
+
auto *ptr_16 = reinterpret_cast<uint16_t *>(this->buffer_);
|
169
|
+
uint8_t hi_byte = static_cast<uint8_t>(color.r & 0xF8) | (color.g >> 5);
|
170
|
+
uint8_t lo_byte = static_cast<uint8_t>((color.g & 0x1C) << 3) | (color.b >> 3);
|
171
|
+
uint16_t new_color = hi_byte | (lo_byte << 8); // big endian
|
172
|
+
if (ptr_16[pos] == new_color)
|
173
|
+
return;
|
174
|
+
ptr_16[pos] = new_color;
|
175
|
+
break;
|
176
|
+
}
|
177
|
+
default:
|
178
|
+
return;
|
179
|
+
}
|
180
|
+
// low and high watermark may speed up drawing from buffer
|
181
|
+
if (x < this->x_low_)
|
182
|
+
this->x_low_ = x;
|
183
|
+
if (y < this->y_low_)
|
184
|
+
this->y_low_ = y;
|
185
|
+
if (x > this->x_high_)
|
186
|
+
this->x_high_ = x;
|
187
|
+
if (y > this->y_high_)
|
188
|
+
this->y_high_ = y;
|
189
|
+
}
|
190
|
+
|
191
|
+
void MipiSpi::reset_params_() {
|
192
|
+
if (!this->is_ready())
|
193
|
+
return;
|
194
|
+
this->write_command_(this->invert_colors_ ? INVERT_ON : INVERT_OFF);
|
195
|
+
if (this->brightness_.has_value())
|
196
|
+
this->write_command_(BRIGHTNESS, this->brightness_.value());
|
197
|
+
}
|
198
|
+
|
199
|
+
void MipiSpi::write_init_sequence_() {
|
200
|
+
size_t index = 0;
|
201
|
+
auto &vec = this->init_sequence_;
|
202
|
+
while (index != vec.size()) {
|
203
|
+
if (vec.size() - index < 2) {
|
204
|
+
ESP_LOGE(TAG, "Malformed init sequence");
|
205
|
+
this->mark_failed();
|
206
|
+
return;
|
207
|
+
}
|
208
|
+
uint8_t cmd = vec[index++];
|
209
|
+
uint8_t x = vec[index++];
|
210
|
+
if (x == DELAY_FLAG) {
|
211
|
+
ESP_LOGV(TAG, "Delay %dms", cmd);
|
212
|
+
delay(cmd);
|
213
|
+
} else {
|
214
|
+
uint8_t num_args = x & 0x7F;
|
215
|
+
if (vec.size() - index < num_args) {
|
216
|
+
ESP_LOGE(TAG, "Malformed init sequence");
|
217
|
+
this->mark_failed();
|
218
|
+
return;
|
219
|
+
}
|
220
|
+
const auto *ptr = vec.data() + index;
|
221
|
+
this->write_command_(cmd, ptr, num_args);
|
222
|
+
index += num_args;
|
223
|
+
}
|
224
|
+
}
|
225
|
+
this->setup_complete_ = true;
|
226
|
+
ESP_LOGCONFIG(TAG, "MIPI SPI setup complete");
|
227
|
+
}
|
228
|
+
|
229
|
+
void MipiSpi::set_addr_window_(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2) {
|
230
|
+
ESP_LOGVV(TAG, "Set addr %d/%d, %d/%d", x1, y1, x2, y2);
|
231
|
+
uint8_t buf[4];
|
232
|
+
x1 += this->offset_width_;
|
233
|
+
x2 += this->offset_width_;
|
234
|
+
y1 += this->offset_height_;
|
235
|
+
y2 += this->offset_height_;
|
236
|
+
put16_be(buf, y1);
|
237
|
+
put16_be(buf + 2, y2);
|
238
|
+
this->write_command_(RASET, buf, sizeof buf);
|
239
|
+
put16_be(buf, x1);
|
240
|
+
put16_be(buf + 2, x2);
|
241
|
+
this->write_command_(CASET, buf, sizeof buf);
|
242
|
+
}
|
243
|
+
|
244
|
+
void MipiSpi::draw_pixels_at(int x_start, int y_start, int w, int h, const uint8_t *ptr, display::ColorOrder order,
|
245
|
+
display::ColorBitness bitness, bool big_endian, int x_offset, int y_offset, int x_pad) {
|
246
|
+
if (!this->setup_complete_ || this->is_failed())
|
247
|
+
return;
|
248
|
+
if (w <= 0 || h <= 0)
|
249
|
+
return;
|
250
|
+
if (bitness != this->color_depth_ || big_endian != (this->bit_order_ == spi::BIT_ORDER_MSB_FIRST)) {
|
251
|
+
Display::draw_pixels_at(x_start, y_start, w, h, ptr, order, bitness, big_endian, x_offset, y_offset, x_pad);
|
252
|
+
return;
|
253
|
+
}
|
254
|
+
if (this->draw_from_origin_) {
|
255
|
+
auto stride = x_offset + w + x_pad;
|
256
|
+
for (int y = 0; y != h; y++) {
|
257
|
+
memcpy(this->buffer_ + ((y + y_start) * this->width_ + x_start) * 2,
|
258
|
+
ptr + ((y + y_offset) * stride + x_offset) * 2, w * 2);
|
259
|
+
}
|
260
|
+
ptr = this->buffer_;
|
261
|
+
w = this->width_;
|
262
|
+
h += y_start;
|
263
|
+
x_start = 0;
|
264
|
+
y_start = 0;
|
265
|
+
x_offset = 0;
|
266
|
+
y_offset = 0;
|
267
|
+
}
|
268
|
+
this->write_to_display_(x_start, y_start, w, h, ptr, x_offset, y_offset, x_pad);
|
269
|
+
}
|
270
|
+
|
271
|
+
void MipiSpi::write_18_from_16_bit_(const uint16_t *ptr, size_t w, size_t h, size_t stride) {
|
272
|
+
stride -= w;
|
273
|
+
uint8_t transfer_buffer[6 * 256];
|
274
|
+
size_t idx = 0; // index into transfer_buffer
|
275
|
+
while (h-- != 0) {
|
276
|
+
for (auto x = w; x-- != 0;) {
|
277
|
+
auto color_val = *ptr++;
|
278
|
+
// deal with byte swapping
|
279
|
+
transfer_buffer[idx++] = (color_val & 0xF8); // Blue
|
280
|
+
transfer_buffer[idx++] = ((color_val & 0x7) << 5) | ((color_val & 0xE000) >> 11); // Green
|
281
|
+
transfer_buffer[idx++] = (color_val >> 5) & 0xF8; // Red
|
282
|
+
if (idx == sizeof(transfer_buffer)) {
|
283
|
+
this->write_array(transfer_buffer, idx);
|
284
|
+
idx = 0;
|
285
|
+
}
|
286
|
+
}
|
287
|
+
ptr += stride;
|
288
|
+
}
|
289
|
+
if (idx != 0)
|
290
|
+
this->write_array(transfer_buffer, idx);
|
291
|
+
}
|
292
|
+
|
293
|
+
void MipiSpi::write_18_from_8_bit_(const uint8_t *ptr, size_t w, size_t h, size_t stride) {
|
294
|
+
stride -= w;
|
295
|
+
uint8_t transfer_buffer[6 * 256];
|
296
|
+
size_t idx = 0; // index into transfer_buffer
|
297
|
+
while (h-- != 0) {
|
298
|
+
for (auto x = w; x-- != 0;) {
|
299
|
+
auto color_val = *ptr++;
|
300
|
+
transfer_buffer[idx++] = color_val & 0xE0; // Red
|
301
|
+
transfer_buffer[idx++] = (color_val << 3) & 0xE0; // Green
|
302
|
+
transfer_buffer[idx++] = color_val << 6; // Blue
|
303
|
+
if (idx == sizeof(transfer_buffer)) {
|
304
|
+
this->write_array(transfer_buffer, idx);
|
305
|
+
idx = 0;
|
306
|
+
}
|
307
|
+
}
|
308
|
+
ptr += stride;
|
309
|
+
}
|
310
|
+
if (idx != 0)
|
311
|
+
this->write_array(transfer_buffer, idx);
|
312
|
+
}
|
313
|
+
|
314
|
+
void MipiSpi::write_16_from_8_bit_(const uint8_t *ptr, size_t w, size_t h, size_t stride) {
|
315
|
+
stride -= w;
|
316
|
+
uint8_t transfer_buffer[6 * 256];
|
317
|
+
size_t idx = 0; // index into transfer_buffer
|
318
|
+
while (h-- != 0) {
|
319
|
+
for (auto x = w; x-- != 0;) {
|
320
|
+
auto color_val = *ptr++;
|
321
|
+
transfer_buffer[idx++] = (color_val & 0xE0) | ((color_val & 0x1C) >> 2);
|
322
|
+
transfer_buffer[idx++] = (color_val & 0x3) << 3;
|
323
|
+
if (idx == sizeof(transfer_buffer)) {
|
324
|
+
this->write_array(transfer_buffer, idx);
|
325
|
+
idx = 0;
|
326
|
+
}
|
327
|
+
}
|
328
|
+
ptr += stride;
|
329
|
+
}
|
330
|
+
if (idx != 0)
|
331
|
+
this->write_array(transfer_buffer, idx);
|
332
|
+
}
|
333
|
+
|
334
|
+
void MipiSpi::write_to_display_(int x_start, int y_start, int w, int h, const uint8_t *ptr, int x_offset, int y_offset,
|
335
|
+
int x_pad) {
|
336
|
+
this->set_addr_window_(x_start, y_start, x_start + w - 1, y_start + h - 1);
|
337
|
+
auto stride = x_offset + w + x_pad;
|
338
|
+
const auto *offset_ptr = ptr;
|
339
|
+
if (this->color_depth_ == display::COLOR_BITNESS_332) {
|
340
|
+
offset_ptr += y_offset * stride + x_offset;
|
341
|
+
} else {
|
342
|
+
stride *= 2;
|
343
|
+
offset_ptr += y_offset * stride + x_offset * 2;
|
344
|
+
}
|
345
|
+
|
346
|
+
switch (this->bus_width_) {
|
347
|
+
case 4:
|
348
|
+
this->enable();
|
349
|
+
if (x_offset == 0 && x_pad == 0 && y_offset == 0) {
|
350
|
+
// we could deal here with a non-zero y_offset, but if x_offset is zero, y_offset probably will be so don't
|
351
|
+
// bother
|
352
|
+
this->write_cmd_addr_data(8, 0x32, 24, WDATA << 8, ptr, w * h * 2, 4);
|
353
|
+
} else {
|
354
|
+
this->write_cmd_addr_data(8, 0x32, 24, WDATA << 8, nullptr, 0, 4);
|
355
|
+
for (int y = 0; y != h; y++) {
|
356
|
+
this->write_cmd_addr_data(0, 0, 0, 0, offset_ptr, w * 2, 4);
|
357
|
+
offset_ptr += stride;
|
358
|
+
}
|
359
|
+
}
|
360
|
+
break;
|
361
|
+
|
362
|
+
case 8:
|
363
|
+
this->write_command_(WDATA);
|
364
|
+
this->enable();
|
365
|
+
if (x_offset == 0 && x_pad == 0 && y_offset == 0) {
|
366
|
+
this->write_cmd_addr_data(0, 0, 0, 0, ptr, w * h * 2, 8);
|
367
|
+
} else {
|
368
|
+
for (int y = 0; y != h; y++) {
|
369
|
+
this->write_cmd_addr_data(0, 0, 0, 0, offset_ptr, w * 2, 8);
|
370
|
+
offset_ptr += stride;
|
371
|
+
}
|
372
|
+
}
|
373
|
+
break;
|
374
|
+
|
375
|
+
default:
|
376
|
+
this->write_command_(WDATA);
|
377
|
+
this->enable();
|
378
|
+
|
379
|
+
if (this->color_depth_ == display::COLOR_BITNESS_565) {
|
380
|
+
// Source buffer is 16-bit RGB565
|
381
|
+
if (this->pixel_mode_ == PIXEL_MODE_18) {
|
382
|
+
// Convert RGB565 to RGB666
|
383
|
+
this->write_18_from_16_bit_(reinterpret_cast<const uint16_t *>(offset_ptr), w, h, stride / 2);
|
384
|
+
} else {
|
385
|
+
// Direct RGB565 output
|
386
|
+
if (x_offset == 0 && x_pad == 0 && y_offset == 0) {
|
387
|
+
this->write_array(ptr, w * h * 2);
|
388
|
+
} else {
|
389
|
+
for (int y = 0; y != h; y++) {
|
390
|
+
this->write_array(offset_ptr, w * 2);
|
391
|
+
offset_ptr += stride;
|
392
|
+
}
|
393
|
+
}
|
394
|
+
}
|
395
|
+
} else {
|
396
|
+
// Source buffer is 8-bit RGB332
|
397
|
+
if (this->pixel_mode_ == PIXEL_MODE_18) {
|
398
|
+
// Convert RGB332 to RGB666
|
399
|
+
this->write_18_from_8_bit_(offset_ptr, w, h, stride);
|
400
|
+
} else {
|
401
|
+
this->write_16_from_8_bit_(offset_ptr, w, h, stride);
|
402
|
+
}
|
403
|
+
break;
|
404
|
+
}
|
405
|
+
}
|
406
|
+
this->disable();
|
407
|
+
}
|
408
|
+
|
409
|
+
void MipiSpi::write_command_(uint8_t cmd, const uint8_t *bytes, size_t len) {
|
410
|
+
ESP_LOGV(TAG, "Command %02X, length %d, bytes %s", cmd, len, format_hex_pretty(bytes, len).c_str());
|
411
|
+
if (this->bus_width_ == 4) {
|
412
|
+
this->enable();
|
413
|
+
this->write_cmd_addr_data(8, 0x02, 24, cmd << 8, bytes, len);
|
414
|
+
this->disable();
|
415
|
+
} else if (this->bus_width_ == 8) {
|
416
|
+
this->dc_pin_->digital_write(false);
|
417
|
+
this->enable();
|
418
|
+
this->write_cmd_addr_data(0, 0, 0, 0, &cmd, 1, 8);
|
419
|
+
this->disable();
|
420
|
+
this->dc_pin_->digital_write(true);
|
421
|
+
if (len != 0) {
|
422
|
+
this->enable();
|
423
|
+
this->write_cmd_addr_data(0, 0, 0, 0, bytes, len, 8);
|
424
|
+
this->disable();
|
425
|
+
}
|
426
|
+
} else {
|
427
|
+
this->dc_pin_->digital_write(false);
|
428
|
+
this->enable();
|
429
|
+
this->write_byte(cmd);
|
430
|
+
this->disable();
|
431
|
+
this->dc_pin_->digital_write(true);
|
432
|
+
if (len != 0) {
|
433
|
+
if (this->spi_16_) {
|
434
|
+
for (size_t i = 0; i != len; i++) {
|
435
|
+
this->enable();
|
436
|
+
this->write_byte(0);
|
437
|
+
this->write_byte(bytes[i]);
|
438
|
+
this->disable();
|
439
|
+
}
|
440
|
+
} else {
|
441
|
+
this->enable();
|
442
|
+
this->write_array(bytes, len);
|
443
|
+
this->disable();
|
444
|
+
}
|
445
|
+
}
|
446
|
+
}
|
447
|
+
}
|
448
|
+
|
449
|
+
void MipiSpi::dump_config() {
|
450
|
+
ESP_LOGCONFIG(TAG, "MIPI_SPI Display");
|
451
|
+
ESP_LOGCONFIG(TAG, " Model: %s", this->model_);
|
452
|
+
ESP_LOGCONFIG(TAG, " Width: %u", this->width_);
|
453
|
+
ESP_LOGCONFIG(TAG, " Height: %u", this->height_);
|
454
|
+
if (this->offset_width_ != 0)
|
455
|
+
ESP_LOGCONFIG(TAG, " Offset width: %u", this->offset_width_);
|
456
|
+
if (this->offset_height_ != 0)
|
457
|
+
ESP_LOGCONFIG(TAG, " Offset height: %u", this->offset_height_);
|
458
|
+
ESP_LOGCONFIG(TAG, " Swap X/Y: %s", YESNO(this->madctl_ & MADCTL_MV));
|
459
|
+
ESP_LOGCONFIG(TAG, " Mirror X: %s", YESNO(this->madctl_ & (MADCTL_MX | MADCTL_XFLIP)));
|
460
|
+
ESP_LOGCONFIG(TAG, " Mirror Y: %s", YESNO(this->madctl_ & (MADCTL_MY | MADCTL_YFLIP)));
|
461
|
+
ESP_LOGCONFIG(TAG, " Color depth: %d bits", this->color_depth_ == display::COLOR_BITNESS_565 ? 16 : 8);
|
462
|
+
ESP_LOGCONFIG(TAG, " Invert colors: %s", YESNO(this->invert_colors_));
|
463
|
+
ESP_LOGCONFIG(TAG, " Color order: %s", this->madctl_ & MADCTL_BGR ? "BGR" : "RGB");
|
464
|
+
ESP_LOGCONFIG(TAG, " Pixel mode: %s", this->pixel_mode_ == PIXEL_MODE_18 ? "18bit" : "16bit");
|
465
|
+
if (this->brightness_.has_value())
|
466
|
+
ESP_LOGCONFIG(TAG, " Brightness: %u", this->brightness_.value());
|
467
|
+
if (this->spi_16_)
|
468
|
+
ESP_LOGCONFIG(TAG, " SPI 16bit: YES");
|
469
|
+
ESP_LOGCONFIG(TAG, " Draw rounding: %u", this->draw_rounding_);
|
470
|
+
if (this->draw_from_origin_)
|
471
|
+
ESP_LOGCONFIG(TAG, " Draw from origin: YES");
|
472
|
+
LOG_PIN(" CS Pin: ", this->cs_);
|
473
|
+
LOG_PIN(" Reset Pin: ", this->reset_pin_);
|
474
|
+
LOG_PIN(" DC Pin: ", this->dc_pin_);
|
475
|
+
ESP_LOGCONFIG(TAG, " SPI Mode: %d", this->mode_);
|
476
|
+
ESP_LOGCONFIG(TAG, " SPI Data rate: %dMHz", static_cast<unsigned>(this->data_rate_ / 1000000));
|
477
|
+
ESP_LOGCONFIG(TAG, " SPI Bus width: %d", this->bus_width_);
|
478
|
+
}
|
479
|
+
|
480
|
+
} // namespace mipi_spi
|
481
|
+
} // namespace esphome
|
@@ -0,0 +1,171 @@
|
|
1
|
+
#pragma once
|
2
|
+
|
3
|
+
#include <utility>
|
4
|
+
|
5
|
+
#include "esphome/components/spi/spi.h"
|
6
|
+
#include "esphome/components/display/display.h"
|
7
|
+
#include "esphome/components/display/display_buffer.h"
|
8
|
+
#include "esphome/components/display/display_color_utils.h"
|
9
|
+
|
10
|
+
namespace esphome {
|
11
|
+
namespace mipi_spi {
|
12
|
+
|
13
|
+
constexpr static const char *const TAG = "display.mipi_spi";
|
14
|
+
static const uint8_t SW_RESET_CMD = 0x01;
|
15
|
+
static const uint8_t SLEEP_OUT = 0x11;
|
16
|
+
static const uint8_t NORON = 0x13;
|
17
|
+
static const uint8_t INVERT_OFF = 0x20;
|
18
|
+
static const uint8_t INVERT_ON = 0x21;
|
19
|
+
static const uint8_t ALL_ON = 0x23;
|
20
|
+
static const uint8_t WRAM = 0x24;
|
21
|
+
static const uint8_t MIPI = 0x26;
|
22
|
+
static const uint8_t DISPLAY_ON = 0x29;
|
23
|
+
static const uint8_t RASET = 0x2B;
|
24
|
+
static const uint8_t CASET = 0x2A;
|
25
|
+
static const uint8_t WDATA = 0x2C;
|
26
|
+
static const uint8_t TEON = 0x35;
|
27
|
+
static const uint8_t MADCTL_CMD = 0x36;
|
28
|
+
static const uint8_t PIXFMT = 0x3A;
|
29
|
+
static const uint8_t BRIGHTNESS = 0x51;
|
30
|
+
static const uint8_t SWIRE1 = 0x5A;
|
31
|
+
static const uint8_t SWIRE2 = 0x5B;
|
32
|
+
static const uint8_t PAGESEL = 0xFE;
|
33
|
+
|
34
|
+
static const uint8_t MADCTL_MY = 0x80; // Bit 7 Bottom to top
|
35
|
+
static const uint8_t MADCTL_MX = 0x40; // Bit 6 Right to left
|
36
|
+
static const uint8_t MADCTL_MV = 0x20; // Bit 5 Swap axes
|
37
|
+
static const uint8_t MADCTL_RGB = 0x00; // Bit 3 Red-Green-Blue pixel order
|
38
|
+
static const uint8_t MADCTL_BGR = 0x08; // Bit 3 Blue-Green-Red pixel order
|
39
|
+
static const uint8_t MADCTL_XFLIP = 0x02; // Mirror the display horizontally
|
40
|
+
static const uint8_t MADCTL_YFLIP = 0x01; // Mirror the display vertically
|
41
|
+
|
42
|
+
static const uint8_t DELAY_FLAG = 0xFF;
|
43
|
+
// store a 16 bit value in a buffer, big endian.
|
44
|
+
static inline void put16_be(uint8_t *buf, uint16_t value) {
|
45
|
+
buf[0] = value >> 8;
|
46
|
+
buf[1] = value;
|
47
|
+
}
|
48
|
+
|
49
|
+
enum PixelMode {
|
50
|
+
PIXEL_MODE_16,
|
51
|
+
PIXEL_MODE_18,
|
52
|
+
};
|
53
|
+
|
54
|
+
class MipiSpi : public display::DisplayBuffer,
|
55
|
+
public spi::SPIDevice<spi::BIT_ORDER_MSB_FIRST, spi::CLOCK_POLARITY_LOW, spi::CLOCK_PHASE_LEADING,
|
56
|
+
spi::DATA_RATE_1MHZ> {
|
57
|
+
public:
|
58
|
+
MipiSpi(size_t width, size_t height, int16_t offset_width, int16_t offset_height, display::ColorBitness color_depth)
|
59
|
+
: width_(width),
|
60
|
+
height_(height),
|
61
|
+
offset_width_(offset_width),
|
62
|
+
offset_height_(offset_height),
|
63
|
+
color_depth_(color_depth) {}
|
64
|
+
void set_model(const char *model) { this->model_ = model; }
|
65
|
+
void update() override;
|
66
|
+
void setup() override;
|
67
|
+
display::ColorOrder get_color_mode() {
|
68
|
+
return this->madctl_ & MADCTL_BGR ? display::COLOR_ORDER_BGR : display::COLOR_ORDER_RGB;
|
69
|
+
}
|
70
|
+
|
71
|
+
void set_reset_pin(GPIOPin *reset_pin) { this->reset_pin_ = reset_pin; }
|
72
|
+
void set_enable_pins(std::vector<GPIOPin *> enable_pins) { this->enable_pins_ = std::move(enable_pins); }
|
73
|
+
void set_dc_pin(GPIOPin *dc_pin) { this->dc_pin_ = dc_pin; }
|
74
|
+
void set_invert_colors(bool invert_colors) {
|
75
|
+
this->invert_colors_ = invert_colors;
|
76
|
+
this->reset_params_();
|
77
|
+
}
|
78
|
+
void set_brightness(uint8_t brightness) {
|
79
|
+
this->brightness_ = brightness;
|
80
|
+
this->reset_params_();
|
81
|
+
}
|
82
|
+
|
83
|
+
void set_draw_from_origin(bool draw_from_origin) { this->draw_from_origin_ = draw_from_origin; }
|
84
|
+
display::DisplayType get_display_type() override { return display::DisplayType::DISPLAY_TYPE_COLOR; }
|
85
|
+
void dump_config() override;
|
86
|
+
|
87
|
+
int get_width_internal() override { return this->width_; }
|
88
|
+
int get_height_internal() override { return this->height_; }
|
89
|
+
bool can_proceed() override { return this->setup_complete_; }
|
90
|
+
void set_init_sequence(const std::vector<uint8_t> &sequence) { this->init_sequence_ = sequence; }
|
91
|
+
void set_draw_rounding(unsigned rounding) { this->draw_rounding_ = rounding; }
|
92
|
+
void set_spi_16(bool spi_16) { this->spi_16_ = spi_16; }
|
93
|
+
|
94
|
+
protected:
|
95
|
+
bool check_buffer_() {
|
96
|
+
if (this->is_failed())
|
97
|
+
return false;
|
98
|
+
if (this->buffer_ != nullptr)
|
99
|
+
return true;
|
100
|
+
auto bytes_per_pixel = this->color_depth_ == display::COLOR_BITNESS_565 ? 2 : 1;
|
101
|
+
this->init_internal_(this->width_ * this->height_ * bytes_per_pixel);
|
102
|
+
if (this->buffer_ == nullptr) {
|
103
|
+
this->mark_failed();
|
104
|
+
return false;
|
105
|
+
}
|
106
|
+
this->buffer_bytes_ = this->width_ * this->height_ * bytes_per_pixel;
|
107
|
+
return true;
|
108
|
+
}
|
109
|
+
void fill(Color color) override;
|
110
|
+
void draw_absolute_pixel_internal(int x, int y, Color color) override;
|
111
|
+
void draw_pixels_at(int x_start, int y_start, int w, int h, const uint8_t *ptr, display::ColorOrder order,
|
112
|
+
display::ColorBitness bitness, bool big_endian, int x_offset, int y_offset, int x_pad) override;
|
113
|
+
void write_18_from_16_bit_(const uint16_t *ptr, size_t w, size_t h, size_t stride);
|
114
|
+
void write_18_from_8_bit_(const uint8_t *ptr, size_t w, size_t h, size_t stride);
|
115
|
+
void write_16_from_8_bit_(const uint8_t *ptr, size_t w, size_t h, size_t stride);
|
116
|
+
void write_to_display_(int x_start, int y_start, int w, int h, const uint8_t *ptr, int x_offset, int y_offset,
|
117
|
+
int x_pad);
|
118
|
+
/**
|
119
|
+
* the RM67162 in quad SPI mode seems to work like this (not in the datasheet, this is deduced from the
|
120
|
+
* sample code.)
|
121
|
+
*
|
122
|
+
* Immediately after enabling /CS send 4 bytes in single-dataline SPI mode:
|
123
|
+
* 0: either 0x2 or 0x32. The first indicates that any subsequent data bytes after the initial 4 will be
|
124
|
+
* sent in 1-dataline SPI. The second indicates quad mode.
|
125
|
+
* 1: 0x00
|
126
|
+
* 2: The command (register address) byte.
|
127
|
+
* 3: 0x00
|
128
|
+
*
|
129
|
+
* This is followed by zero or more data bytes in either 1-wire or 4-wire mode, depending on the first byte.
|
130
|
+
* At the conclusion of the write, de-assert /CS.
|
131
|
+
*
|
132
|
+
* @param cmd
|
133
|
+
* @param bytes
|
134
|
+
* @param len
|
135
|
+
*/
|
136
|
+
void write_command_(uint8_t cmd, const uint8_t *bytes, size_t len);
|
137
|
+
|
138
|
+
void write_command_(uint8_t cmd, uint8_t data) { this->write_command_(cmd, &data, 1); }
|
139
|
+
void write_command_(uint8_t cmd) { this->write_command_(cmd, &cmd, 0); }
|
140
|
+
void reset_params_();
|
141
|
+
void write_init_sequence_();
|
142
|
+
void set_addr_window_(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2);
|
143
|
+
|
144
|
+
GPIOPin *reset_pin_{nullptr};
|
145
|
+
std::vector<GPIOPin *> enable_pins_{};
|
146
|
+
GPIOPin *dc_pin_{nullptr};
|
147
|
+
uint16_t x_low_{1};
|
148
|
+
uint16_t y_low_{1};
|
149
|
+
uint16_t x_high_{0};
|
150
|
+
uint16_t y_high_{0};
|
151
|
+
bool setup_complete_{};
|
152
|
+
|
153
|
+
bool invert_colors_{};
|
154
|
+
size_t width_;
|
155
|
+
size_t height_;
|
156
|
+
int16_t offset_width_;
|
157
|
+
int16_t offset_height_;
|
158
|
+
size_t buffer_bytes_{0};
|
159
|
+
display::ColorBitness color_depth_;
|
160
|
+
PixelMode pixel_mode_{PIXEL_MODE_16};
|
161
|
+
uint8_t bus_width_{};
|
162
|
+
bool spi_16_{};
|
163
|
+
uint8_t madctl_{};
|
164
|
+
bool draw_from_origin_{false};
|
165
|
+
unsigned draw_rounding_{2};
|
166
|
+
optional<uint8_t> brightness_{};
|
167
|
+
const char *model_{"Unknown"};
|
168
|
+
std::vector<uint8_t> init_sequence_{};
|
169
|
+
};
|
170
|
+
} // namespace mipi_spi
|
171
|
+
} // namespace esphome
|