esphome-wordclock/components/wordclock/__init__.py

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]))