import logging from esphome import core from esphome.components import display, font, time, light, color import esphome.config_validation as cv import esphome.codegen as cg import esphome.cpp_generator as cpp from esphome.const import ( CONF_ID, CONF_NAME, CONF_RAW_DATA_ID, CONF_TYPE, CONF_TIME_ID, CONF_SEGMENTS, CONF_ADDRESSABLE_LIGHT_ID, CONF_HOUR, CONF_HOURS, CONF_MINUTE, CONF_MINUTES, CONF_BRIGHTNESS, CONF_UPDATE_INTERVAL, ) from esphome.core import CORE, HexInt _LOGGER = logging.getLogger(__name__) CONF_DISPLAY_ID = "display_id" CONF_LINE_START_X = "x1" CONF_LINE_START_Y = "y1" CONF_LINE_END_X = "x2" CONF_LINE_END_Y = "y2" CONF_LINE = "line" CONF_COLOR_ON = "color_on" CONF_COLOR_OFF = "color_off" DATA_VECTOR_SEGMENTS_HOUR = "data_vector_segments_hour" DATA_VECTOR_SEGMENTS_MINUTE = "data_vector_segments_minute" DATA_VECTOR_SEGMENTS = "data_vector_segments_ptr" CONF_WORDCLOCK_STATIC_SEGMENTS = "static_segments" CONF_HOUR_OFFSET = "hour_offset" CONF_FADE_LENGTH = "fade_length" DEPENDENCIES = ["display", "time"] MULTI_CONF = False int8 = cg.global_ns.namespace("int8_t") wordclock_ns = cg.esphome_ns.namespace("wordclock") SegmentCoords = wordclock_ns.struct("SegmentCoords") Wordclock = wordclock_ns.class_( "Wordclock", cg.PollingComponent ) WORDCLOCK_SEGMENT_SCHEMA = { cv.Required(CONF_NAME): cv.string_strict, cv.Required(CONF_LINE): { cv.Required(CONF_LINE_START_X): cv.int_, cv.Required(CONF_LINE_START_Y): cv.int_, cv.Required(CONF_LINE_END_X): cv.int_, cv.Optional(CONF_LINE_END_Y): cv.int_, }, } WORDCLOCK_HOUR_SCHEMA = { cv.Required(CONF_HOUR): cv.uint16_t, cv.Required(CONF_SEGMENTS): cv.ensure_list(cv.string_strict), } WORDCLOCK_MINUTE_SCHEMA = { cv.Required(CONF_MINUTE): cv.uint16_t, cv.Required(CONF_HOUR_OFFSET): cv.int_range(-1,1), cv.Required(CONF_SEGMENTS): cv.ensure_list(cv.string_strict), } WORDCLOCK_SCHEMA = cv.Schema( { cv.GenerateID(): cv.declare_id(Wordclock), cv.Required(CONF_DISPLAY_ID): cv.use_id( display.DisplayBuffer ), cv.Required(CONF_TIME_ID): cv.use_id( time.RealTimeClock ), cv.Required(CONF_ADDRESSABLE_LIGHT_ID): cv.use_id( light.AddressableLightState ), cv.Optional(CONF_BRIGHTNESS, default=1.0): cv.percentage, cv.Optional(CONF_COLOR_ON): cv.use_id(color.ColorStruct), cv.Optional(CONF_COLOR_OFF): cv.use_id(color.ColorStruct), cv.Optional(CONF_WORDCLOCK_STATIC_SEGMENTS): cv.ensure_list(cv.string_strict), cv.Required(CONF_SEGMENTS): cv.ensure_list(WORDCLOCK_SEGMENT_SCHEMA), cv.Required(CONF_MINUTES): cv.ensure_list(WORDCLOCK_MINUTE_SCHEMA), cv.Required(CONF_HOURS): cv.ensure_list(WORDCLOCK_HOUR_SCHEMA), # cv.Optional( # CONF_FADE_LENGTH, default="700ms" # ): cv., cv.Optional( CONF_FADE_LENGTH, default="700ms" ): cv.positive_time_period_milliseconds, cv.Optional( CONF_UPDATE_INTERVAL, default="16ms" ): cv.positive_time_period_milliseconds, # cv.GenerateID(DATA_VECTOR_SEGMENTS_HOUR): cv.declare_id(cg.std_vector.template(cg.std_vector.template(cg.uint16))), # cv.GenerateID(DATA_VECTOR_SEGMENTS_MINUTE): cv.declare_id(cg.std_vector.template(cg.std_vector.template(cg.uint16))), cv.GenerateID(DATA_VECTOR_SEGMENTS): cv.declare_id(cg.std_vector.template(cg.uint16)), } ) CONFIG_SCHEMA = WORDCLOCK_SCHEMA async def to_code(config): wrapped_display = await cg.get_variable(config[CONF_DISPLAY_ID]) wrapped_time = await cg.get_variable(config[CONF_TIME_ID]) wrapped_light_state = await cg.get_variable(config[CONF_ADDRESSABLE_LIGHT_ID]) var = cg.new_Pvariable(config[CONF_ID], wrapped_time, wrapped_display, wrapped_light_state) if CONF_COLOR_ON in config: wrapped_color_on = await cg.get_variable(config[CONF_COLOR_ON]) cg.add(var.set_on_color(wrapped_color_on)) if CONF_COLOR_OFF in config: wrapped_color_off = await cg.get_variable(config[CONF_COLOR_OFF]) cg.add(var.set_off_color(wrapped_color_off)) # segments_vector_ptr = cg.new_Pvariable(config[DATA_VECTOR_SEGMENTS]) # void Wordclock::setup_transitions(uint32_t milliseconds) { # this->on_transformer->setup(0, this->brightness, milliseconds); # this->off_transformer->setup(this->brightness, 0, milliseconds); # } cg.add(var.setup_transitions(config[CONF_FADE_LENGTH])) cg.add(var.set_brightness(int(config[CONF_BRIGHTNESS] * 255))) SEGMENT_MAP = dict() for idx, segment in enumerate(config[CONF_SEGMENTS]): SEGMENT_MAP[segment[CONF_NAME]] = idx line = segment[CONF_LINE] x1 = line[CONF_LINE_START_X] y1 = line[CONF_LINE_START_Y] x2 = line[CONF_LINE_END_X] y2 = line.get(CONF_LINE_END_Y, y1) exp = cg.StructInitializer(SegmentCoords, ("x1", x1), ("y1", y1), ("x2", x2), ("y2", y2),) cg.add(var.add_segment(exp)) if CONF_WORDCLOCK_STATIC_SEGMENTS in config: for segment_name in config[CONF_WORDCLOCK_STATIC_SEGMENTS]: cg.add(var.add_static(SEGMENT_MAP[segment_name])) for idx, hour in enumerate(config[CONF_HOURS]): segment_ids = [SEGMENT_MAP[a] for a in hour[CONF_SEGMENTS]] cg.add(var.add_hour(hour[CONF_HOUR], cg.std_vector.template(cg.uint16).new(segment_ids))) # segments_vector_ptr = segments_vector_ptr.new(segment_ids) # foo = await cg.get_variable(config[DATA_VECTOR_SEGMENTS]) # foo = cg.std_vector.template(cg.uint16).new(segment_ids) # del foo for idx, minute in enumerate(config[CONF_MINUTES]): segment_ids = [SEGMENT_MAP[a] for a in minute[CONF_SEGMENTS]] cg.add(var.add_minute(minute[CONF_MINUTE], minute[CONF_HOUR_OFFSET], cg.std_vector.template(cg.uint16).new(segment_ids))) # segments_vector_ptr = segments_vector_ptr.new(segment_ids) # segments_vector_ptr = cg.new_Pvariable(config[DATA_VECTOR_SEGMENTS], segment_ids) # foo = await cg.get_variable(config[DATA_VECTOR_SEGMENTS]) # foo = cg.std_vector.template(cg.uint16).new(segment_ids) # segments_vector = cg.new_Pvariable(core.ID(None, type=cg.std_vector.template(cg.uint16)), segment_ids) # del foo await cg.register_component(var, config) # hours = [] # for idx, hour in enumerate(config[CONF_HOURS]): # segment_ids = [SEGMENT_MAP[a] for a in hour[CONF_SEGMENTS]] # exp = cg.std_vector.template(cg.uint16)(segment_ids) # hours.append(exp) # hours_array = cg.new_variable(config[DATA_VECTOR_SEGMENTS_HOUR], cg.std_vector.template(cg.std_vector.template(cg.uint16))(hours)) # minutes = [] # for idx, hour in enumerate(config[CONF_MINUTES]): # segment_ids = [SEGMENT_MAP[a] for a in hour[CONF_SEGMENTS]] # exp = cg.std_vector.template(cg.uint16)(segment_ids) # minutes.append(exp) # minutes_array = cg.new_variable(config[DATA_VECTOR_SEGMENTS_MINUTE], cg.std_vector.template(cg.std_vector.template(cg.uint16))(minutes)) # for idx, hour in enumerate(config[CONF_HOURS]): # exp = cg.std_vector.template(cg.uint16)(segment_ids) # cg.add(var.add_hour(hour[CONF_HOUR], cpp.UnaryOpExpression("&", hours_array[idx]))) # for idx, minute in enumerate(config[CONF_MINUTES]): # exp = cg.std_vector.template(cg.uint16)(segment_ids) # cg.add(var.add_minute(minute[CONF_MINUTE], cpp.UnaryOpExpression("&", minutes_array[idx]))) # for idx, minute in enumerate(config[CONF_MINUTES]): # cg.add(var.add_hour_offset(minute[CONF_MINUTE], minute[CONF_HOUR_OFFSET]))