203 lines
7.6 KiB
Python
203 lines
7.6 KiB
Python
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]))
|
|
|