import esphome.codegen as cg import esphome.config_validation as cv from esphome import pins from esphome.const import ( CONF_DISABLED_BY_DEFAULT, CONF_FREQUENCY, CONF_ID, CONF_NAME, CONF_PIN, CONF_SCL, CONF_SDA, ESP_PLATFORM_ESP32, CONF_DATA_PINS, CONF_RESET_PIN, CONF_RESOLUTION, CONF_BRIGHTNESS, CONF_CONTRAST, ) ESP_PLATFORMS = [ESP_PLATFORM_ESP32] DEPENDENCIES = ["api"] esp32_camera_ns = cg.esphome_ns.namespace("esp32_camera") ESP32Camera = esp32_camera_ns.class_("ESP32Camera", cg.PollingComponent, cg.Nameable) ESP32CameraFrameSize = esp32_camera_ns.enum("ESP32CameraFrameSize") FRAME_SIZES = { "160X120": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_160X120, "QQVGA": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_160X120, "176X144": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_176X144, "QCIF": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_176X144, "240X176": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_240X176, "HQVGA": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_240X176, "320X240": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_320X240, "QVGA": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_320X240, "400X296": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_400X296, "CIF": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_400X296, "640X480": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_640X480, "VGA": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_640X480, "800X600": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_800X600, "SVGA": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_800X600, "1024X768": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_1024X768, "XGA": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_1024X768, "1280X1024": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_1280X1024, "SXGA": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_1280X1024, "1600X1200": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_1600X1200, "UXGA": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_1600X1200, } CONF_VSYNC_PIN = "vsync_pin" CONF_HREF_PIN = "href_pin" CONF_PIXEL_CLOCK_PIN = "pixel_clock_pin" CONF_EXTERNAL_CLOCK = "external_clock" CONF_I2C_PINS = "i2c_pins" CONF_POWER_DOWN_PIN = "power_down_pin" CONF_MAX_FRAMERATE = "max_framerate" CONF_IDLE_FRAMERATE = "idle_framerate" CONF_JPEG_QUALITY = "jpeg_quality" CONF_VERTICAL_FLIP = "vertical_flip" CONF_HORIZONTAL_MIRROR = "horizontal_mirror" CONF_SATURATION = "saturation" CONF_TEST_PATTERN = "test_pattern" camera_range_param = cv.int_range(min=-2, max=2) CONFIG_SCHEMA = cv.Schema( { cv.GenerateID(): cv.declare_id(ESP32Camera), cv.Required(CONF_NAME): cv.string, cv.Optional(CONF_DISABLED_BY_DEFAULT, default=False): cv.boolean, cv.Required(CONF_DATA_PINS): cv.All([pins.input_pin], cv.Length(min=8, max=8)), cv.Required(CONF_VSYNC_PIN): pins.input_pin, cv.Required(CONF_HREF_PIN): pins.input_pin, cv.Required(CONF_PIXEL_CLOCK_PIN): pins.input_pin, cv.Required(CONF_EXTERNAL_CLOCK): cv.Schema( { cv.Required(CONF_PIN): pins.output_pin, cv.Optional(CONF_FREQUENCY, default="20MHz"): cv.All( cv.frequency, cv.one_of(20e6, 10e6) ), } ), cv.Required(CONF_I2C_PINS): cv.Schema( { cv.Required(CONF_SDA): pins.output_pin, cv.Required(CONF_SCL): pins.output_pin, } ), cv.Optional(CONF_RESET_PIN): pins.output_pin, cv.Optional(CONF_POWER_DOWN_PIN): pins.output_pin, cv.Optional(CONF_MAX_FRAMERATE, default="10 fps"): cv.All( cv.framerate, cv.Range(min=0, min_included=False, max=60) ), cv.Optional(CONF_IDLE_FRAMERATE, default="0.1 fps"): cv.All( cv.framerate, cv.Range(min=0, max=1) ), cv.Optional(CONF_RESOLUTION, default="640X480"): cv.enum( FRAME_SIZES, upper=True ), cv.Optional(CONF_JPEG_QUALITY, default=10): cv.int_range(min=10, max=63), cv.Optional(CONF_CONTRAST, default=0): camera_range_param, cv.Optional(CONF_BRIGHTNESS, default=0): camera_range_param, cv.Optional(CONF_SATURATION, default=0): camera_range_param, cv.Optional(CONF_VERTICAL_FLIP, default=True): cv.boolean, cv.Optional(CONF_HORIZONTAL_MIRROR, default=True): cv.boolean, cv.Optional(CONF_TEST_PATTERN, default=False): cv.boolean, } ).extend(cv.COMPONENT_SCHEMA) SETTERS = { CONF_DATA_PINS: "set_data_pins", CONF_VSYNC_PIN: "set_vsync_pin", CONF_HREF_PIN: "set_href_pin", CONF_PIXEL_CLOCK_PIN: "set_pixel_clock_pin", CONF_RESET_PIN: "set_reset_pin", CONF_POWER_DOWN_PIN: "set_power_down_pin", CONF_JPEG_QUALITY: "set_jpeg_quality", CONF_VERTICAL_FLIP: "set_vertical_flip", CONF_HORIZONTAL_MIRROR: "set_horizontal_mirror", CONF_CONTRAST: "set_contrast", CONF_BRIGHTNESS: "set_brightness", CONF_SATURATION: "set_saturation", CONF_TEST_PATTERN: "set_test_pattern", } async def to_code(config): var = cg.new_Pvariable(config[CONF_ID], config[CONF_NAME]) cg.add(var.set_disabled_by_default(config[CONF_DISABLED_BY_DEFAULT])) await cg.register_component(var, config) for key, setter in SETTERS.items(): if key in config: cg.add(getattr(var, setter)(config[key])) extclk = config[CONF_EXTERNAL_CLOCK] cg.add(var.set_external_clock(extclk[CONF_PIN], extclk[CONF_FREQUENCY])) i2c_pins = config[CONF_I2C_PINS] cg.add(var.set_i2c_pins(i2c_pins[CONF_SDA], i2c_pins[CONF_SCL])) cg.add(var.set_max_update_interval(1000 / config[CONF_MAX_FRAMERATE])) if config[CONF_IDLE_FRAMERATE] == 0: cg.add(var.set_idle_update_interval(0)) else: cg.add(var.set_idle_update_interval(1000 / config[CONF_IDLE_FRAMERATE])) cg.add(var.set_frame_size(config[CONF_RESOLUTION])) cg.add_define("USE_ESP32_CAMERA") cg.add_build_flag("-DBOARD_HAS_PSRAM")