feat: wordclock works!
This commit is contained in:
parent
5b0930d616
commit
7f091409cf
8 changed files with 1405 additions and 12 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -5,3 +5,6 @@
|
||||||
/secrets.yaml
|
/secrets.yaml
|
||||||
/secrets.*.yaml
|
/secrets.*.yaml
|
||||||
!/secrets.example.yaml
|
!/secrets.example.yaml
|
||||||
|
/.pio
|
||||||
|
/.vscode
|
||||||
|
__pycache__
|
||||||
|
|
|
||||||
447
components/wordclock/__init__.py
Normal file
447
components/wordclock/__init__.py
Normal file
|
|
@ -0,0 +1,447 @@
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from esphome import core
|
||||||
|
from esphome.components import display, font, time, light
|
||||||
|
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,
|
||||||
|
)
|
||||||
|
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_WORDCLOCK_STATIC_SEGMENTS = "static_segments"
|
||||||
|
CONF_HOUR_OFFSET = "hour_offset"
|
||||||
|
|
||||||
|
# CONF_HOURS_MIDNIGHT = "0"
|
||||||
|
# CONF_HOURS_ONE = "1"
|
||||||
|
# CONF_HOURS_TWO = "2"
|
||||||
|
# CONF_HOURS_THREE = "3"
|
||||||
|
# CONF_HOURS_FOUR = "4"
|
||||||
|
# CONF_HOURS_FIVE = "5"
|
||||||
|
# CONF_HOURS_SIX = "6"
|
||||||
|
# CONF_HOURS_SEVEN = "7"
|
||||||
|
# CONF_HOURS_EIGHT = "8"
|
||||||
|
# CONF_HOURS_NINE = "9"
|
||||||
|
# CONF_HOURS_TEN = "10"
|
||||||
|
# CONF_HOURS_ELEVEN = "11"
|
||||||
|
# CONF_HOURS_TWELVE = "12"
|
||||||
|
# CONF_HOURS_THIRTEEN = "13"
|
||||||
|
# CONF_HOURS_FOURTEEN = "14"
|
||||||
|
# CONF_HOURS_FIFTEEN = "15"
|
||||||
|
# CONF_HOURS_SIXTEEN = "16"
|
||||||
|
# CONF_HOURS_SEVENTEEN = "17"
|
||||||
|
# CONF_HOURS_EIGHTTEEN = "18"
|
||||||
|
# CONF_HOURS_NINETEEN = "19"
|
||||||
|
# CONF_HOURS_TWENTY = "20"
|
||||||
|
# CONF_HOURS_TWENTYONE = "21"
|
||||||
|
# CONF_HOURS_TWENTYTWO = "22"
|
||||||
|
# CONF_HOURS_TWENTYTHREE = "23"
|
||||||
|
|
||||||
|
# CONF_HOURS_MIDNIGHT = "midnight"
|
||||||
|
# CONF_HOURS_ONE = "one"
|
||||||
|
# CONF_HOURS_TWO = "two"
|
||||||
|
# CONF_HOURS_THREE = "three"
|
||||||
|
# CONF_HOURS_FOUR = "four"
|
||||||
|
# CONF_HOURS_FIVE = "five"
|
||||||
|
# CONF_HOURS_SIX = "six"
|
||||||
|
# CONF_HOURS_SEVEN = "seven"
|
||||||
|
# CONF_HOURS_EIGHT = "eight"
|
||||||
|
# CONF_HOURS_NINE = "nine"
|
||||||
|
# CONF_HOURS_TEN = "ten"
|
||||||
|
# CONF_HOURS_ELEVEN = "eleven"
|
||||||
|
# CONF_HOURS_TWELVE = "twelve"
|
||||||
|
# CONF_HOURS_THIRTEEN = "thirteen"
|
||||||
|
# CONF_HOURS_FOURTEEN = "fourteen"
|
||||||
|
# CONF_HOURS_FIFTEEN = "fifteen"
|
||||||
|
# CONF_HOURS_SIXTEEN = "sixteen"
|
||||||
|
# CONF_HOURS_SEVENTEEN = "seventeen"
|
||||||
|
# CONF_HOURS_EIGHTTEEN = "eightteen"
|
||||||
|
# CONF_HOURS_NINETEEN = "nineteen"
|
||||||
|
# CONF_HOURS_TWENTY = "twenty"
|
||||||
|
# CONF_HOURS_TWENTYONE = "twentyone"
|
||||||
|
# CONF_HOURS_TWENTYTWO = "twentytwo"
|
||||||
|
# CONF_HOURS_TWENTYTHREE = "twentythree"
|
||||||
|
|
||||||
|
# CONF_MINUTES_SHARP = "0"
|
||||||
|
# CONF_MINUTES_FIVE = "5"
|
||||||
|
# CONF_MINUTES_TEN = "10"
|
||||||
|
# CONF_MINUTES_FIFTEEN = "15"
|
||||||
|
# CONF_MINUTES_TWENTY = "20"
|
||||||
|
# CONF_MINUTES_TWENTYFIVE = "25"
|
||||||
|
# CONF_MINUTES_THIRTY = "30"
|
||||||
|
# CONF_MINUTES_THIRTYFIVE = "35"
|
||||||
|
# CONF_MINUTES_FORTY = "40"
|
||||||
|
# CONF_MINUTES_FORTYFIVE = "45"
|
||||||
|
# CONF_MINUTES_FIFTY = "50"
|
||||||
|
# CONF_MINUTES_FIFTYFIVE = "55"
|
||||||
|
|
||||||
|
|
||||||
|
DEPENDENCIES = ["display", "time"]
|
||||||
|
MULTI_CONF = False
|
||||||
|
|
||||||
|
|
||||||
|
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_CONFIG_SCHEMA = {
|
||||||
|
# cv.Optional(CONF_WORDCLOCK_STATIC_TEXT): cv.ensure_list(cv.string_strict),
|
||||||
|
# # cv.Required(CONF_LAMBDA): cv.lambda_,
|
||||||
|
# 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),
|
||||||
|
# }
|
||||||
|
|
||||||
|
DATA1 = "data1"
|
||||||
|
DATA_X1 = "data_x1"
|
||||||
|
DATA_X2 = "data_x2"
|
||||||
|
DATA_Y1 = "data_y1"
|
||||||
|
DATA_Y2 = "data_y2"
|
||||||
|
DATA_SEGMENT_COORDS = "data_segment_coords"
|
||||||
|
DATA_MINUTES = "data_minutes"
|
||||||
|
DATA_HOURS = "data_hours"
|
||||||
|
DATA_SEGMENTS_HOUR = "data_segments_hour"
|
||||||
|
DATA_SEGMENTS_MINUTE = "data_segments_minute"
|
||||||
|
DATA3 = "data3"
|
||||||
|
DATA4 = "data4"
|
||||||
|
DATA_VECTOR_SEGMENTS_HOUR = "data_vector_segments_hour"
|
||||||
|
DATA_VECTOR_SEGMENTS_MINUTE = "data_vector_segments_minute"
|
||||||
|
|
||||||
|
int8 = cg.global_ns.namespace("int8_t")
|
||||||
|
uint16_ptr = cg.global_ns.namespace("uint16_t *")
|
||||||
|
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_LAMBDA): cv.lambda_,
|
||||||
|
cv.Optional(CONF_WORDCLOCK_STATIC_SEGMENTS): cv.ensure_list(cv.string_strict),
|
||||||
|
# cv.Required(CONF_LAMBDA): cv.lambda_,
|
||||||
|
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.GenerateID(DATA_X1): cv.declare_id(uint16_ptr),
|
||||||
|
cv.GenerateID(DATA_X2): cv.declare_id(cg.uint8),
|
||||||
|
cv.GenerateID(DATA_Y1): cv.declare_id(cg.uint8),
|
||||||
|
cv.GenerateID(DATA_Y2): cv.declare_id(cg.uint8),
|
||||||
|
cv.GenerateID(DATA_SEGMENT_COORDS): cv.declare_id(SegmentCoords),
|
||||||
|
|
||||||
|
# cv.GenerateID(DATA_MINUTES): cv.declare_id(int8),
|
||||||
|
# cv.GenerateID(DATA_HOURS): cv.declare_id(int8),
|
||||||
|
# cv.GenerateID(DATA_MINUTES): cv.declare_id(uint16_ptr),
|
||||||
|
# cv.GenerateID(DATA_HOURS): cv.declare_id(uint16_ptr),
|
||||||
|
# cv.GenerateID(DATA_SEGMENTS_MINUTE): cv.declare_id(cg.std_vector.template(cg.uint16)),
|
||||||
|
# cv.GenerateID(DATA_SEGMENTS_HOUR): cv.declare_id(cg.std_vector.template(cg.uint16)),
|
||||||
|
|
||||||
|
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(DATA3): cv.declare_id(cg.uint8),
|
||||||
|
# cv.GenerateID(DATA4): cv.declare_id(cg.std_vector.template(cg.int32)),
|
||||||
|
# cv.Required(CONF_WORDCLOCK_CONFIG): cv.ensure_list(WORDCLOCK_CONFIG_SCHEMA),
|
||||||
|
|
||||||
|
# cv.Required(CONF_ID): cv.declare_id(Wordclock_),
|
||||||
|
# cv.Required(CONF_FILE): cv.file_,
|
||||||
|
# cv.Optional(CONF_RESIZE): cv.dimensions,
|
||||||
|
# cv.Optional(CONF_TYPE, default="BINARY"): cv.enum(IMAGE_TYPE, upper=True),
|
||||||
|
# cv.Optional(CONF_DITHER, default="NONE"): cv.one_of(
|
||||||
|
# "NONE", "FLOYDSTEINBERG", upper=True
|
||||||
|
# ),
|
||||||
|
# cv.GenerateID(CONF_RAW_DATA_ID): cv.declare_id(cg.uint8),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
# CONFIG_SCHEMA = cv.All(font.validate_pillow_installed, WORDCLOCK_SCHEMA)
|
||||||
|
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)
|
||||||
|
|
||||||
|
SEGMENT_MAP = dict()
|
||||||
|
for idx, segm in enumerate(config[CONF_SEGMENTS]):
|
||||||
|
print(segm[CONF_NAME])
|
||||||
|
SEGMENT_MAP[segm[CONF_NAME]] = idx
|
||||||
|
|
||||||
|
line_start_x = segm[CONF_LINE][CONF_LINE_START_X]
|
||||||
|
line_end_x = segm[CONF_LINE][CONF_LINE_END_X]
|
||||||
|
line_start_y = segm[CONF_LINE][CONF_LINE_START_Y]
|
||||||
|
line_end_y = segm[CONF_LINE].get(CONF_LINE_END_Y, line_start_y)
|
||||||
|
|
||||||
|
exp = cg.StructInitializer(
|
||||||
|
SegmentCoords,
|
||||||
|
("x1", line_start_x),
|
||||||
|
("x2", line_end_x),
|
||||||
|
("y1", line_start_y),
|
||||||
|
("y2", line_end_y),
|
||||||
|
)
|
||||||
|
cg.add(var.add_segment(exp))
|
||||||
|
|
||||||
|
|
||||||
|
if CONF_WORDCLOCK_STATIC_SEGMENTS in config:
|
||||||
|
|
||||||
|
# cg.static_const_array(config[DATA_SEGMENT_COORDS], accumulator)
|
||||||
|
# print(SEGMENT_MAP)
|
||||||
|
for segment_name in config[CONF_WORDCLOCK_STATIC_SEGMENTS]:
|
||||||
|
cg.add(var.add_static(SEGMENT_MAP[segment_name]))
|
||||||
|
# static_segment_ids = config[CONF_WORDCLOCK_STATIC_SEGMENTS]
|
||||||
|
# exp = cg.std_vector.template(cg.uint16)(static_segment_ids)
|
||||||
|
# cg.add(var.add_static(hour[CONF_HOUR], cpp.UnaryOpExpression("&", exp)))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
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])))
|
||||||
|
|
||||||
|
# minutes = [[],] * 60
|
||||||
|
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])))
|
||||||
|
# segment_ids = [SEGMENT_MAP[a] for a in minute[CONF_SEGMENTS]]
|
||||||
|
# minutes[minute[CONF_MINUTE]] = cg.std_vector.template(cg.int32)()
|
||||||
|
# foo = []
|
||||||
|
# cg.ArrayInitializer()
|
||||||
|
'''exp = cg.std_vector.template(cg.uint16)(segment_ids)'''
|
||||||
|
# exp = cg.ArrayInitializer(minute[CONF_SEGMENTS])
|
||||||
|
'''cg.add(var.add_minute(minute[CONF_MINUTE], exp))'''
|
||||||
|
|
||||||
|
# for segment_str in minute[CONF_SEGMENTS]:
|
||||||
|
# foo.append(SEGMENT_MAP[segment_str])
|
||||||
|
# # minutes[minute[CONF_MINUTE]].push_back(SEGMENT_MAP[segment_str])
|
||||||
|
# minutes[minute[CONF_MINUTE]] = foo
|
||||||
|
# print(minute[CONF_MINUTE])
|
||||||
|
# SEGMENT_MAP[i[CONF_NAME]] = idx
|
||||||
|
# accumulator.append(idx)
|
||||||
|
for idx, minute in enumerate(config[CONF_MINUTES]):
|
||||||
|
cg.add(var.add_hour_offset(minute[CONF_MINUTE], minute[CONF_HOUR_OFFSET]))
|
||||||
|
|
||||||
|
|
||||||
|
await cg.register_component(var, config)
|
||||||
|
"""
|
||||||
|
accumulator = []
|
||||||
|
SEGMENT_MAP = dict()
|
||||||
|
for idx, segm in enumerate(config[CONF_SEGMENTS]):
|
||||||
|
print(segm[CONF_NAME])
|
||||||
|
SEGMENT_MAP[segm[CONF_NAME]] = idx
|
||||||
|
# x1.append()
|
||||||
|
# x2.append()
|
||||||
|
line_start_x = segm[CONF_LINE][CONF_LINE_START_X]
|
||||||
|
line_end_x = segm[CONF_LINE][CONF_LINE_END_X]
|
||||||
|
line_start_y = segm[CONF_LINE][CONF_LINE_START_Y]
|
||||||
|
line_end_y = segm[CONF_LINE].get(CONF_LINE_END_Y, line_start_y)
|
||||||
|
# print(line_start_y)
|
||||||
|
# print(line_end_y)
|
||||||
|
# y1.append(segm[CONF_LINE][CONF_LINE_START_Y])
|
||||||
|
# y2.append(line_end_y)
|
||||||
|
|
||||||
|
exp = cg.StructInitializer(
|
||||||
|
SegmentCoords,
|
||||||
|
("x1", line_start_x),
|
||||||
|
("x2", line_end_x),
|
||||||
|
("y1", line_start_y),
|
||||||
|
("y2", line_end_y),
|
||||||
|
)
|
||||||
|
accumulator.append(exp)
|
||||||
|
|
||||||
|
cg.static_const_array(config[DATA_SEGMENT_COORDS], accumulator)
|
||||||
|
print(SEGMENT_MAP)
|
||||||
|
|
||||||
|
|
||||||
|
minutes = [[],] * 60
|
||||||
|
for idx, minute in enumerate(config[CONF_MINUTES]):
|
||||||
|
# minutes[minute[CONF_MINUTE]] = cg.std_vector.template(cg.int32)()
|
||||||
|
foo = []
|
||||||
|
cg.ArrayInitializer()
|
||||||
|
for segment_str in minute[CONF_SEGMENTS]:
|
||||||
|
foo.append(SEGMENT_MAP[segment_str])
|
||||||
|
# minutes[minute[CONF_MINUTE]].push_back(SEGMENT_MAP[segment_str])
|
||||||
|
minutes[minute[CONF_MINUTE]] = foo
|
||||||
|
print(minute[CONF_MINUTE])
|
||||||
|
# SEGMENT_MAP[i[CONF_NAME]] = idx
|
||||||
|
# accumulator.append(idx)
|
||||||
|
print(minutes)
|
||||||
|
cg.static_const_array(config[DATA_MINUTES], minutes)
|
||||||
|
"""
|
||||||
|
"""
|
||||||
|
hours = [cg.std_vector.template(cg.uint16)()] * 24
|
||||||
|
cg.static_const_array(config[DATA_HOURS], hours)
|
||||||
|
|
||||||
|
for idx, i in enumerate(config[CONF_HOURS]):
|
||||||
|
# for segment_str in i[CONF_SEGMENTS]:
|
||||||
|
# print(config[DATA_HOURS].type)
|
||||||
|
# push = config[DATA_HOURS].get(i[CONF_HOUR]).push_back(SEGMENT_MAP[segment_str])
|
||||||
|
# cg.add(push)
|
||||||
|
# hours[i[CONF_HOUR]] = cg.std_vector.template(cg.int32)()
|
||||||
|
|
||||||
|
print(i[CONF_HOUR])
|
||||||
|
# SEGMENT_MAP[i[CONF_NAME]] = idx
|
||||||
|
# accumulator.append(idx)
|
||||||
|
print(hours)
|
||||||
|
# cg.static_const_array(config[DATA_HOURS], hours)
|
||||||
|
# cg.static_const_array(config[DATA3], hours)
|
||||||
|
# cg.static_const_array(config[DATA4], hours)
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
# prog_arr = cg.progmem_array(config[CONF_RAW_DATA_ID], rhs)
|
||||||
|
# cg.add_global(cg.Statement(f"const int {i[CONF_NAME]} = 0;"))
|
||||||
|
# cg.add_global(f"""
|
||||||
|
# /*
|
||||||
|
# {global_consts}
|
||||||
|
# */
|
||||||
|
# """)
|
||||||
|
|
||||||
|
# from PIL import Image
|
||||||
|
|
||||||
|
# path = CORE.relative_config_path(config[CONF_FILE])
|
||||||
|
# try:
|
||||||
|
# image = Image.open(path)
|
||||||
|
# except Exception as e:
|
||||||
|
# raise core.EsphomeError(f"Could not load image file {path}: {e}")
|
||||||
|
|
||||||
|
# width, height = image.size
|
||||||
|
|
||||||
|
# if CONF_RESIZE in config:
|
||||||
|
# image.thumbnail(config[CONF_RESIZE])
|
||||||
|
# width, height = image.size
|
||||||
|
# else:
|
||||||
|
# if width > 500 or height > 500:
|
||||||
|
# _LOGGER.warning(
|
||||||
|
# "The image you requested is very big. Please consider using"
|
||||||
|
# " the resize parameter."
|
||||||
|
# )
|
||||||
|
|
||||||
|
# dither = Image.NONE if config[CONF_DITHER] == "NONE" else Image.FLOYDSTEINBERG
|
||||||
|
# if config[CONF_TYPE] == "GRAYSCALE":
|
||||||
|
# image = image.convert("L", dither=dither)
|
||||||
|
# pixels = list(image.getdata())
|
||||||
|
# data = [0 for _ in range(height * width)]
|
||||||
|
# pos = 0
|
||||||
|
# for pix in pixels:
|
||||||
|
# data[pos] = pix
|
||||||
|
# pos += 1
|
||||||
|
|
||||||
|
# elif config[CONF_TYPE] == "RGB24":
|
||||||
|
# image = image.convert("RGB")
|
||||||
|
# pixels = list(image.getdata())
|
||||||
|
# data = [0 for _ in range(height * width * 3)]
|
||||||
|
# pos = 0
|
||||||
|
# for pix in pixels:
|
||||||
|
# data[pos] = pix[0]
|
||||||
|
# pos += 1
|
||||||
|
# data[pos] = pix[1]
|
||||||
|
# pos += 1
|
||||||
|
# data[pos] = pix[2]
|
||||||
|
# pos += 1
|
||||||
|
|
||||||
|
# elif config[CONF_TYPE] == "RGB565":
|
||||||
|
# image = image.convert("RGB")
|
||||||
|
# pixels = list(image.getdata())
|
||||||
|
# data = [0 for _ in range(height * width * 3)]
|
||||||
|
# pos = 0
|
||||||
|
# for pix in pixels:
|
||||||
|
# R = pix[0] >> 3
|
||||||
|
# G = pix[1] >> 2
|
||||||
|
# B = pix[2] >> 3
|
||||||
|
# rgb = (R << 11) | (G << 5) | B
|
||||||
|
# data[pos] = rgb >> 8
|
||||||
|
# pos += 1
|
||||||
|
# data[pos] = rgb & 255
|
||||||
|
# pos += 1
|
||||||
|
|
||||||
|
# elif (config[CONF_TYPE] == "BINARY") or (config[CONF_TYPE] == "TRANSPARENT_BINARY"):
|
||||||
|
# image = image.convert("1", dither=dither)
|
||||||
|
# width8 = ((width + 7) // 8) * 8
|
||||||
|
# data = [0 for _ in range(height * width8 // 8)]
|
||||||
|
# for y in range(height):
|
||||||
|
# for x in range(width):
|
||||||
|
# if image.getpixel((x, y)):
|
||||||
|
# continue
|
||||||
|
# pos = x + y * width8
|
||||||
|
# data[pos // 8] |= 0x80 >> (pos % 8)
|
||||||
|
|
||||||
|
# elif config[CONF_TYPE] == "TRANSPARENT_IMAGE":
|
||||||
|
# image = image.convert("RGBA")
|
||||||
|
# width8 = ((width + 7) // 8) * 8
|
||||||
|
# data = [0 for _ in range(height * width8 // 8)]
|
||||||
|
# for y in range(height):
|
||||||
|
# for x in range(width):
|
||||||
|
# if not image.getpixel((x, y))[3]:
|
||||||
|
# continue
|
||||||
|
# pos = x + y * width8
|
||||||
|
# data[pos // 8] |= 0x80 >> (pos % 8)
|
||||||
|
|
||||||
|
# rhs = [HexInt(x) for x in data]
|
||||||
|
# prog_arr = cg.progmem_array(config[CONF_RAW_DATA_ID], rhs)
|
||||||
|
# cg.new_Pvariable(
|
||||||
|
# config[CONF_ID], prog_arr, width, height, IMAGE_TYPE[config[CONF_TYPE]]
|
||||||
|
# )
|
||||||
305
components/wordclock/wordclock.cpp
Normal file
305
components/wordclock/wordclock.cpp
Normal file
|
|
@ -0,0 +1,305 @@
|
||||||
|
#include "wordclock.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace wordclock {
|
||||||
|
|
||||||
|
void Wordclock::setup() {
|
||||||
|
// this->time->update();
|
||||||
|
|
||||||
|
|
||||||
|
// this->light_state->add_effects({this->randomTwinkle});
|
||||||
|
// this->start_idle_animation();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Wordclock::start_idle_animation() {
|
||||||
|
this->display->set_enabled(false);
|
||||||
|
// auto call =
|
||||||
|
this->light_state->turn_on().set_effect("random_twinkle").perform();
|
||||||
|
// call.set_effect("random_twinkle");
|
||||||
|
// call.perform();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Wordclock::end_idle_animation() {
|
||||||
|
this->light_state->turn_off().perform();
|
||||||
|
this->display->set_enabled(true);
|
||||||
|
|
||||||
|
|
||||||
|
// this->light->clear_effect_data();
|
||||||
|
// this->display->get_light()->set_effect_active(false);
|
||||||
|
// auto call1 = this->light_state->turn_on();
|
||||||
|
// call1.set_effect("None");
|
||||||
|
// call1.perform();
|
||||||
|
// this->light->all().set(Color(0xF0FF00));
|
||||||
|
|
||||||
|
// this->display->fill(Color(0));
|
||||||
|
|
||||||
|
// this->light_state->turn_off().perform();
|
||||||
|
// call2.perform();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Wordclock::update() {
|
||||||
|
|
||||||
|
// esphome::addressable_light::AddressableLightDisplay it = *(this->display);
|
||||||
|
// ESP_LOGD("loop", "beep");
|
||||||
|
// ESP_LOGD("loop", "time is now [%02i:%02i:%02i]", this->time->now().hour, this->time->now().minute, this->time->now().second);
|
||||||
|
// ESP_LOGE("wordclock.cpp", "display_ptr: 0x%x", it);
|
||||||
|
// ESP_LOGE("wordclock.cpp", "this: 0x%x", (this));
|
||||||
|
// ESP_LOGE("wordclock.cpp", "this->display: 0x%x", (this->display));
|
||||||
|
// ESP_LOGE("wordclock.cpp", "&this->display: 0x%x", &(this->display));
|
||||||
|
// ESP_LOGE("loop", "time_ptr: %i", this->time);
|
||||||
|
// it.line(0,0,0,0, Color(0x00FF00));
|
||||||
|
|
||||||
|
esphome::time::ESPTime time = this->time->now();
|
||||||
|
this->find_hour(9);
|
||||||
|
this->find_minute(31);
|
||||||
|
|
||||||
|
if (time.is_valid() == false) {
|
||||||
|
if (this->valid_time) {
|
||||||
|
ESP_LOGD("loop", "time is not valid [%02i:%02i:%02i]", time.hour, time.minute, time.second);
|
||||||
|
this->start_idle_animation();
|
||||||
|
this->valid_time = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
if (!this->valid_time) {
|
||||||
|
this->end_idle_animation();
|
||||||
|
this->valid_time = true;
|
||||||
|
ESP_LOGD("wordclock.cpp", "time is now valid [%02i:%02i:%02i]", time.hour, time.minute, time.second);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// for (uint8_t idx = 0;idx < ; idx++) {
|
||||||
|
|
||||||
|
// }
|
||||||
|
|
||||||
|
// std::vector<uint16_t> *minute = this->find_minute(time.minute);
|
||||||
|
// std::vector<uint16_t> *hour = this->find_hour(time.hour);
|
||||||
|
this->display->fill(Color(0x000000));
|
||||||
|
|
||||||
|
int8_t minute = this->find_minute(time.minute);
|
||||||
|
int8_t hour = this->find_hour((time.hour + this->hour_offsets->at(minute)) % 24);
|
||||||
|
|
||||||
|
for (uint16_t segment_idx : *this->static_segments){
|
||||||
|
this->draw_segment(segment_idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint16_t segment_idx : this->minutes->at(minute)){
|
||||||
|
this->draw_segment(segment_idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint16_t segment_idx : this->hours->at(hour)){
|
||||||
|
this->draw_segment(segment_idx);
|
||||||
|
}
|
||||||
|
// this->draw_segment(0);
|
||||||
|
// this->draw_segment(1);
|
||||||
|
// this->draw_segment(4);
|
||||||
|
// this->draw_segment(10);
|
||||||
|
// this->draw_segment(19);
|
||||||
|
// this->light->range(0, 10).fade_to_white(100);
|
||||||
|
// this->display->get_light()->range(18, 35).set(Color(0xf0ff0f));
|
||||||
|
|
||||||
|
// SegmentCoords s = this->segments->at(time);
|
||||||
|
|
||||||
|
|
||||||
|
// ESP_LOGD("wordclock.cpp", "time is now [%02i:%02i:%02i]", time.hour, time.minute, time.second);
|
||||||
|
// ESP_LOGD("wordclock.cpp", "x1: %i, y1: %i, x2: %i, y2: %i", s.x1, s.y1, s.x2, s.y2);
|
||||||
|
|
||||||
|
|
||||||
|
// this->display->draw_pixel_at(0, 0, Color(0xFF0000));
|
||||||
|
// this->display->draw_pixel_at(1, 0, Color(0x00FF00));
|
||||||
|
// this->display->draw_pixel_at(2, 0, Color(0x0000FF));
|
||||||
|
// if (time.second != second) {
|
||||||
|
// second = time.second;
|
||||||
|
// ESP_LOGD("loop", "time is now [%02i:%02i:%02i]", time.hour, time.minute, time.second);
|
||||||
|
// }
|
||||||
|
// if(time.hour != hour || time.minute != minute) {
|
||||||
|
// hour = time.hour;
|
||||||
|
// minute = time.minute;
|
||||||
|
// if (hour >= 0 && time.is_valid() == true){
|
||||||
|
|
||||||
|
// display_time(time.hour, time.minute, CRGB(red, green, blue));
|
||||||
|
|
||||||
|
// ESP_LOGE("loop", "Update Time: %i:%i Brightness: %i RGB: %i-%i-%i", time.hour, time.minute, brightness, red, green, blue);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// if (!this->reading_ && !mode_funcs_.empty()) {
|
||||||
|
// this->reading_ = true;
|
||||||
|
// this->read_mode_(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Wordclock::draw_segment(uint16_t segment_id) {
|
||||||
|
SegmentCoords s = this->segments->at(segment_id);
|
||||||
|
// ESP_LOGD("wordclock.cpp", "x1: %i, y1: %i, x2: %i, y2: %i", s.x1, s.y1, s.x2, s.y2);
|
||||||
|
this->display->line(s.x1, s.y1, s.x2, s.y2, esphome::Color(0xFFFFFF));
|
||||||
|
}
|
||||||
|
// void Wordclock::set_writer(display_writer_t &&writer) {
|
||||||
|
// this->writer_ = writer;
|
||||||
|
// }
|
||||||
|
|
||||||
|
void Wordclock::add_segment(SegmentCoords segment) {
|
||||||
|
// if (!this->segments) {
|
||||||
|
|
||||||
|
// }
|
||||||
|
|
||||||
|
this->segments->push_back(segment);
|
||||||
|
// this->writer_ = writer;
|
||||||
|
}
|
||||||
|
|
||||||
|
// std::vector<uint16_t> * Wordclock::find_hour(uint8_t hour) {
|
||||||
|
// std::vector<uint16_t> *empty_vector; // = new std::vector<uint16_t>();
|
||||||
|
// uint16_t last_defined_hour = -1;
|
||||||
|
// for (int i = 0; i < this->hours->size(); i++) {
|
||||||
|
// if (this->hours->at(i).size()) {
|
||||||
|
// if (hour == i) {
|
||||||
|
// return &(this->hours->at(i));
|
||||||
|
// }
|
||||||
|
// else {
|
||||||
|
// last_defined_hour = i;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// else {
|
||||||
|
// empty_vector = &(this->hours->at(i));
|
||||||
|
// if (hour == i) {
|
||||||
|
// if (last_defined_hour == -1) return empty_vector;
|
||||||
|
// return &(this->hours->at(last_defined_hour));
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return empty_vector;
|
||||||
|
// }
|
||||||
|
|
||||||
|
int8_t Wordclock::find_hour(uint8_t hour) {
|
||||||
|
uint16_t last_defined_hour = -1;
|
||||||
|
for (int i = 0; i < this->hours->size(); i++) {
|
||||||
|
if (this->hours->at(i).size()) {
|
||||||
|
last_defined_hour = i;
|
||||||
|
if (hour == i) {
|
||||||
|
return last_defined_hour;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (hour == i) break;
|
||||||
|
}
|
||||||
|
return last_defined_hour;
|
||||||
|
}
|
||||||
|
|
||||||
|
int8_t Wordclock::find_minute(uint8_t minute) {
|
||||||
|
uint16_t last_defined_minute = -1;
|
||||||
|
for (int i = 0; i < this->minutes->size(); i++) {
|
||||||
|
if (this->minutes->at(i).size()) {
|
||||||
|
last_defined_minute = i;
|
||||||
|
if (minute == i) {
|
||||||
|
return last_defined_minute;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (minute == i) break;
|
||||||
|
}
|
||||||
|
return last_defined_minute;
|
||||||
|
}
|
||||||
|
// std::vector<uint16_t> * Wordclock::find_minute(uint8_t minute) {
|
||||||
|
// std::vector<uint16_t> *empty_vector;// = new std::vector<uint16_t>();
|
||||||
|
// uint16_t last_defined_minute = -1;
|
||||||
|
// for (int i = 0; i < this->minutes->size(); i++) {
|
||||||
|
// if (this->minutes->at(i).size()) {
|
||||||
|
// if (minute == i) {
|
||||||
|
// return &(this->minutes->at(i));
|
||||||
|
// }
|
||||||
|
// else {
|
||||||
|
// last_defined_minute = i;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// else {
|
||||||
|
// empty_vector = &(this->minutes->at(i));
|
||||||
|
// if (minute == i) {
|
||||||
|
// if (last_defined_minute == -1) return empty_vector;
|
||||||
|
// return &(this->minutes->at(last_defined_minute));
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return empty_vector;
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
void Wordclock::add_hour_offset(uint8_t index, int8_t offset) {
|
||||||
|
(*this->hour_offsets)[index] = offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Wordclock::add_hour(uint8_t hour, std::vector<uint16_t> *segments) {
|
||||||
|
for (uint16_t i : *segments){
|
||||||
|
this->hours->at(hour).push_back(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Wordclock::add_minute(uint8_t minute, std::vector<uint16_t> *segments) {
|
||||||
|
for (uint16_t i : *segments){
|
||||||
|
this->minutes->at(minute).push_back(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Wordclock::add_static(uint16_t segment_id) {
|
||||||
|
this->static_segments->push_back(segment_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// uint16_t **
|
||||||
|
|
||||||
|
// Wordclock::Wordclock(std::vector<uint16_t> *minutes, std::vector<uint16_t> *hours, SegmentCoords *segments)
|
||||||
|
// Wordclock::Wordclock(uint16_t **minutes, uint16_t **hours, SegmentCoords *segments)
|
||||||
|
// : PollingComponent(1000) {
|
||||||
|
// // this->minutes = minutes;
|
||||||
|
// // this->hours = hours;
|
||||||
|
// // this->segments = segments;
|
||||||
|
// // std::vector<uint16_t> minutes[60];
|
||||||
|
// // std::vector<uint16_t> hours[24];
|
||||||
|
// }
|
||||||
|
Wordclock::Wordclock()
|
||||||
|
: PollingComponent(1000) {
|
||||||
|
// this->minutes = std::vector<std::vector<uint16_t>>();
|
||||||
|
// // for (int i=0; i<60; i++) this->minutes.push_back(std::vector<uint16_t>());
|
||||||
|
|
||||||
|
// this->hours = std::vector<std::vector<uint16_t>>();
|
||||||
|
// // for (int i=0; i<24; i++) this->minutes.push_back(std::vector<uint16_t>());
|
||||||
|
|
||||||
|
// this->segments = std::vector<SegmentCoords>();
|
||||||
|
}
|
||||||
|
|
||||||
|
Wordclock::Wordclock(esphome::time::RealTimeClock *time, esphome::addressable_light::AddressableLightDisplay *display, esphome::light::AddressableLightState *light_state)
|
||||||
|
: PollingComponent(16) {
|
||||||
|
// ESP_LOGE("wordclock.cpp", "this: 0x%x", (this));
|
||||||
|
// ESP_LOGE("wordclock.cpp", "display: 0x%x", (display));
|
||||||
|
// ESP_LOGE("wordclock.cpp", "&display: 0x%x", (&display));
|
||||||
|
|
||||||
|
this->time = time;
|
||||||
|
this->display = display;
|
||||||
|
this->light = this->display->get_light();
|
||||||
|
this->light_state = light_state;
|
||||||
|
// light::AddressableLight *light = this->display->get_light();
|
||||||
|
|
||||||
|
// light::AddressableRainbowLightEffect *light_addressablerainbowlighteffect;
|
||||||
|
// light::AddressableTwinkleEffect *light_addressabletwinkleeffect;
|
||||||
|
// light::AddressableRandomTwinkleEffect *light_addressablerandomtwinkleeffect;
|
||||||
|
|
||||||
|
// this->rainbow = new light::AddressableRainbowLightEffect("rainbow");
|
||||||
|
// this->rainbow->set_speed(10);
|
||||||
|
// this->rainbow->set_width(50);
|
||||||
|
// this->twinkle = new light::AddressableTwinkleEffect("twinkle");
|
||||||
|
// this->twinkle->set_twinkle_probability(0.05f);
|
||||||
|
// this->twinkle->set_progress_interval(4);
|
||||||
|
// this->randomTwinkle = new light::AddressableRandomTwinkleEffect("random_twinkle");
|
||||||
|
// this->randomTwinkle->set_twinkle_probability(0.05f);
|
||||||
|
// this->randomTwinkle->set_progress_interval(32);
|
||||||
|
|
||||||
|
this->hour_offsets = new std::vector<int8_t>(60, 0);
|
||||||
|
|
||||||
|
this->minutes = new std::vector<std::vector<uint16_t>>(60, std::vector<uint16_t>());
|
||||||
|
// for (int i=0; i<60; i++) this->minutes->push_back(std::vector<uint16_t>());
|
||||||
|
|
||||||
|
this->hours = new std::vector<std::vector<uint16_t>>(24, std::vector<uint16_t>());
|
||||||
|
// for (int i=0; i<24; i++) this->hours->push_back(std::vector<uint16_t>());
|
||||||
|
|
||||||
|
this->segments = new std::vector<SegmentCoords>();
|
||||||
|
this->static_segments = new std::vector<uint16_t>();
|
||||||
|
}
|
||||||
|
} // namespace wordclock
|
||||||
|
} // namespace esphome
|
||||||
227
components/wordclock/wordclock.h
Normal file
227
components/wordclock/wordclock.h
Normal file
|
|
@ -0,0 +1,227 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "esphome.h"
|
||||||
|
// By now only loosely based on https://github.com/leinich/ha-wordclock-esphome
|
||||||
|
|
||||||
|
// esphome dependencies:
|
||||||
|
// needs: esphome time --> id: current_time
|
||||||
|
// needs: esphome fastled --> id: fastledlight
|
||||||
|
|
||||||
|
// #ifdef USE_ESP32
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace wordclock {
|
||||||
|
|
||||||
|
///// Word Table /////
|
||||||
|
// .line(0,0,1,0, color);
|
||||||
|
// .line(2,0,3,0, color);
|
||||||
|
// int WORD_IT_IS[5][2] = {{4,0}, {0,0}, {0,1}, {0,3}, {0,4}};
|
||||||
|
|
||||||
|
// // .line(2,1,8,1, color);
|
||||||
|
// int WORD_QUARTER[8][2] = {{7,0}, {1,2}, {1,3}, {1,4}, {1,5}, {1,6}, {1,7}, {1,8}};
|
||||||
|
// // .line(0,2, 5,2, color);
|
||||||
|
// int WORD_TWENTY[7][2] = {{6,0}, {2,0}, {2,1}, {2,2}, {2,3}, {2,4}, {2,5}};
|
||||||
|
// // .line(6,2, 9,2, color);
|
||||||
|
// int WORD_FIVE_MINUTES[5][2] = {{4,0}, {2,6}, {2,7}, {2,8}, {2,9}};
|
||||||
|
// // .line(0,3, 3,3, color);
|
||||||
|
// int WORD_HALF[5][2] = {{4,0}, {3,0}, {3,1}, {3,2}, {3,3}};
|
||||||
|
// // .line(5,3, 7,3, color);
|
||||||
|
// int WORD_TEN_MINUTES[4][2] = {{3,0}, {3,5}, {3,6}, {3,7}};
|
||||||
|
// // .line(9,3, 10,3, color);
|
||||||
|
// int WORD_TO[3][2] = {{2,0}, {3,9}, {3,10}};
|
||||||
|
// // .line(0,4, 3,4, color);
|
||||||
|
// int WORD_PAST[5][2] = {{4,0}, {4,0}, {4,1}, {4,2}, {4,3}};
|
||||||
|
|
||||||
|
// int WORD_NINE[5][2] = {{4,0}, {4,7}, {4,8}, {4,9}, {4,10}};
|
||||||
|
// int WORD_ONE[4][2] = {{3,0}, {5,0}, {5,1}, {5,2}};
|
||||||
|
// int WORD_SIX[4][2] = {{3,0}, {5,3}, {5,4}, {5,5}};
|
||||||
|
// int WORD_THREE[6][2] = {{5,0}, {5,6}, {5,7}, {5,8}, {5,9}, {5,10}};
|
||||||
|
// int WORD_FOUR[5][2] = {{4,0}, {6,0}, {6,1}, {6,2}, {6,3}};
|
||||||
|
// int WORD_FIVE[5][2] = {{4,0}, {6,4}, {6,5}, {6,6}, {6,7}};
|
||||||
|
// int WORD_TWO[4][2] = {{3,0}, {6,8}, {6,9}, {6,10}};
|
||||||
|
// int WORD_EIGHT[6][2] = {{5,0}, {7,0}, {7,1}, {7,2}, {7,3}, {7,4}};
|
||||||
|
// int WORD_ELEVEN[7][2] = {{6,0}, {7,5}, {7,6}, {7,7}, {7,8}, {7,9}, {7,10}};
|
||||||
|
// int WORD_SEVEN[6][2] = {{5,0}, {8,0}, {8,1}, {8,2}, {8,3}, {8,4}};
|
||||||
|
// int WORD_TWELFE[7][2] = {{6,0}, {8,5}, {8,6}, {8,7}, {8,8}, {8,9}, {8,10}};
|
||||||
|
// int WORD_TEN[4][2] = {{3,0}, {9,0}, {9,1}, {9,2}};
|
||||||
|
// int WORD_OCLOCK[7][2] = {{6,0}, {9,5}, {9,6}, {9,7}, {9,8}, {9,9}, {9,10}};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// using display_writer_t = std::function<void(esphome::Dieplay::Display &)>;
|
||||||
|
|
||||||
|
|
||||||
|
struct SegmentCoords {
|
||||||
|
uint16_t x1;
|
||||||
|
uint16_t x2;
|
||||||
|
uint16_t y1;
|
||||||
|
uint16_t y2;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class Wordclock : public esphome::PollingComponent {
|
||||||
|
public:
|
||||||
|
Wordclock();
|
||||||
|
Wordclock(esphome::time::RealTimeClock *time, esphome::addressable_light::AddressableLightDisplay *display, esphome::light::AddressableLightState *light_state);
|
||||||
|
void add_segment(SegmentCoords segment);
|
||||||
|
void add_hour(uint8_t index, std::vector<uint16_t> *segments);
|
||||||
|
void add_minute(uint8_t index, std::vector<uint16_t> *segments);
|
||||||
|
void add_static(uint16_t segment_id);
|
||||||
|
void add_hour_offset(uint8_t index, int8_t offset);
|
||||||
|
void setup();
|
||||||
|
void update();
|
||||||
|
// void setup() override {
|
||||||
|
|
||||||
|
// }
|
||||||
|
|
||||||
|
// void set_writer(display_writer_t &&writer);
|
||||||
|
|
||||||
|
// void display_word(const int word[][2], const CRGB& c) {
|
||||||
|
// for (int i=1; i < word[0][0] + 1; i++) {
|
||||||
|
// leds[map_coords_to_strip(word[i][0], word[i][1])].setRGB(c.r, c.g, c.b);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// void display_minutes(int minutes, const CRGB& color) {
|
||||||
|
// int five_minute_chunk = minutes / 5;
|
||||||
|
|
||||||
|
// switch (five_minute_chunk)
|
||||||
|
// {
|
||||||
|
// case 0: // sharp
|
||||||
|
// display_word(WORD_OCLOCK, color); ESP_LOGD("minute", "oclock "); break;
|
||||||
|
// case 1: // five past
|
||||||
|
// display_word(WORD_FIVE_MINUTES, color); ESP_LOGD("minute", "five past "); break;
|
||||||
|
// case 2: // ten past
|
||||||
|
// display_word(WORD_TEN_MINUTES, color); ESP_LOGD("minute", "ten past "); break;
|
||||||
|
// case 3: // quarter past
|
||||||
|
// display_word(WORD_QUARTER, color); ESP_LOGD("minute", "quarter past "); break;
|
||||||
|
// case 4: // twenty past
|
||||||
|
// display_word(WORD_TWENTY, color); ESP_LOGD("minute", "twenty past "); break;
|
||||||
|
// case 5: // twenty five past
|
||||||
|
// display_word(WORD_TWENTY, color); display_word(WORD_FIVE_MINUTES, color);
|
||||||
|
// ESP_LOGD("minute", "twenty five past "); break;
|
||||||
|
// case 6: // half past
|
||||||
|
// display_word(WORD_HALF, color); ESP_LOGD("minute", "half past "); break;
|
||||||
|
// case 7: // twenty five to
|
||||||
|
// display_word(WORD_TWENTY, color); display_word(WORD_FIVE_MINUTES, color);
|
||||||
|
// ESP_LOGD("minute", "twenty five to "); break;
|
||||||
|
// case 8: // twenty to
|
||||||
|
// display_word(WORD_TWENTY, color); ESP_LOGD("minute", "twenty to "); break;
|
||||||
|
// case 9: // quarter to
|
||||||
|
// display_word(WORD_QUARTER, color); ESP_LOGD("minute", "quarter to "); break;
|
||||||
|
// case 10: // ten to
|
||||||
|
// display_word(WORD_TEN_MINUTES, color); ESP_LOGD("minute", "ten to "); break;
|
||||||
|
// case 11: // five to
|
||||||
|
// display_word(WORD_FIVE_MINUTES, color); ESP_LOGD("minute", "five to "); break;
|
||||||
|
// default:
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// if (five_minute_chunk > 6) {
|
||||||
|
// display_word(WORD_TO, color);
|
||||||
|
// } else if (five_minute_chunk > 0) {
|
||||||
|
// display_word(WORD_PAST, color);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// void display_hour(int hour, int minutes, const CRGB& color) {
|
||||||
|
// int five_minute_chunk = minutes / 5;
|
||||||
|
// if (five_minute_chunk > 6) {
|
||||||
|
// hour += 1;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// switch (hour % 12)
|
||||||
|
// {
|
||||||
|
// case 0: // twelve
|
||||||
|
// display_word(WORD_TWELFE, color); ESP_LOGD("hour", "twelve "); break;
|
||||||
|
// case 1: // one
|
||||||
|
// display_word(WORD_ONE, color); ESP_LOGD("hour", "one "); break;
|
||||||
|
// case 2: // two
|
||||||
|
// display_word(WORD_TWO, color); ESP_LOGD("hour", "two "); break;
|
||||||
|
// case 3: // three
|
||||||
|
// display_word(WORD_THREE, color); ESP_LOGD("hour", "three "); break;
|
||||||
|
// case 4: // four
|
||||||
|
// display_word(WORD_FOUR, color); ESP_LOGD("hour", "four "); break;
|
||||||
|
// case 5: // five
|
||||||
|
// display_word(WORD_FIVE, color); ESP_LOGD("hour", "five "); break;
|
||||||
|
// case 6: // six
|
||||||
|
// display_word(WORD_SIX, color); ESP_LOGD("hour", "six "); break;
|
||||||
|
// case 7: // seven
|
||||||
|
// display_word(WORD_SEVEN, color); ESP_LOGD("hour", "seven "); break;
|
||||||
|
// case 8: // eight
|
||||||
|
// display_word(WORD_EIGHT, color); ESP_LOGD("hour", "eight "); break;
|
||||||
|
// case 9: // nine
|
||||||
|
// display_word(WORD_NINE, color); ESP_LOGD("hour", "nine "); break;
|
||||||
|
// case 10: // ten
|
||||||
|
// display_word(WORD_TEN, color); ESP_LOGD("hour", "ten "); break;
|
||||||
|
// case 11: // eleven
|
||||||
|
// display_word(WORD_ELEVEN, color); ESP_LOGD("hour", "eleven "); break;
|
||||||
|
// default:
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// void display_time(int hour, int minutes, const CRGB& color) {
|
||||||
|
// // clear_all_leds();
|
||||||
|
// display_word(WORD_IT_IS, color);
|
||||||
|
// display_hour(hour, minutes, color);
|
||||||
|
// display_minutes(minutes, color);
|
||||||
|
// // FastLED.show();
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// void loop() override {
|
||||||
|
// // auto time = id(current_time).now();
|
||||||
|
// // https://www.esphome.io/api/classesphome_1_1light_1_1_light_color_values.html LightColorValues Class
|
||||||
|
// // auto fastledlight2 = id(fastledlight).current_values;
|
||||||
|
// //convert float 0.0 till 1.0 into int 0 till 255
|
||||||
|
// red = (int) (fastledlight2.get_red() * 125);
|
||||||
|
// green = (int) (fastledlight2.get_green() * 125);
|
||||||
|
// blue = (int) (fastledlight2.get_blue() * 125);
|
||||||
|
// brightness = 0;
|
||||||
|
// //check if light is on and set brightness
|
||||||
|
// if (fastledlight2.get_state() > 0 ) {
|
||||||
|
// brightness = (int) (fastledlight2.get_brightness()*125);
|
||||||
|
// } else {
|
||||||
|
// // ESP_LOGD("loop", "fastledlight state off - b: %i rgb %i %i %i", brightness, red, green, blue); delay(100);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// FastLED.setBrightness(brightness);
|
||||||
|
// FastLED.show();
|
||||||
|
// //check if valid time. Blink red,green,blue until valid time is present
|
||||||
|
|
||||||
|
// }
|
||||||
|
protected:
|
||||||
|
void draw_segment(uint16_t segment_id);
|
||||||
|
int8_t find_hour(uint8_t hour);
|
||||||
|
int8_t find_minute(uint8_t minute);
|
||||||
|
// std::vector<uint16_t> * find_hour(uint8_t hour);
|
||||||
|
// std::vector<uint16_t> * find_minute(uint8_t minute);
|
||||||
|
std::vector<std::vector<uint16_t>> *minutes;
|
||||||
|
std::vector<std::vector<uint16_t>> *hours;
|
||||||
|
std::vector<uint16_t> *static_segments;
|
||||||
|
std::vector<int8_t> *hour_offsets;
|
||||||
|
|
||||||
|
void start_idle_animation();
|
||||||
|
void end_idle_animation();
|
||||||
|
|
||||||
|
// uint16_t **minutes;
|
||||||
|
// uint16_t **hours;
|
||||||
|
|
||||||
|
bool valid_time{true};
|
||||||
|
std::vector<SegmentCoords> *segments;
|
||||||
|
esphome::time::RealTimeClock *time;
|
||||||
|
esphome::light::AddressableLight *light;
|
||||||
|
esphome::light::AddressableLightState *light_state;
|
||||||
|
esphome::addressable_light::AddressableLightDisplay *display;
|
||||||
|
light::AddressableRainbowLightEffect *rainbow;
|
||||||
|
light::AddressableTwinkleEffect *twinkle;
|
||||||
|
light::AddressableRandomTwinkleEffect *randomTwinkle;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace wordclock
|
||||||
|
} // namespace esphome
|
||||||
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
esphome:
|
esphome:
|
||||||
name: "display_thing"
|
name: "display-thing"
|
||||||
|
|
||||||
esp8266:
|
esp8266:
|
||||||
board: d1_mini
|
board: d1_mini
|
||||||
|
|
@ -26,8 +26,8 @@ ota:
|
||||||
|
|
||||||
logger:
|
logger:
|
||||||
# esp8266_store_log_strings_in_flash: false
|
# esp8266_store_log_strings_in_flash: false
|
||||||
web_server:
|
# web_server:
|
||||||
port: 80
|
# port: 80
|
||||||
|
|
||||||
light:
|
light:
|
||||||
- name: NeoPixel Strip 1
|
- name: NeoPixel Strip 1
|
||||||
|
|
@ -36,8 +36,10 @@ light:
|
||||||
type: GRB
|
type: GRB
|
||||||
variant: WS2812
|
variant: WS2812
|
||||||
pin: GPIO3
|
pin: GPIO3
|
||||||
num_leds: 200
|
num_leds: 199
|
||||||
# default_transition_length: 0.2s
|
restore_mode: ALWAYS_ON
|
||||||
|
default_transition_length: 0s
|
||||||
|
color_correct: [100%, 100%, 100%]
|
||||||
method:
|
method:
|
||||||
type: esp8266_dma
|
type: esp8266_dma
|
||||||
|
|
||||||
|
|
@ -47,18 +49,48 @@ display:
|
||||||
addressable_light_id: neopixel_strip_1
|
addressable_light_id: neopixel_strip_1
|
||||||
width: 18
|
width: 18
|
||||||
height: 11
|
height: 11
|
||||||
rotation: 0°
|
rotation: 270°
|
||||||
update_interval: 16ms
|
update_interval: 16ms
|
||||||
|
pixel_mapper: |-
|
||||||
|
int mapping_even[] = {0, 2, 4, 6,8,10,11,13,15,17, 16,16,16,16, 16,16,16,16};
|
||||||
|
int mapping_odd[] = {17,15,13,11,9, 7, 6, 4, 2, 0, 16,16,16,16, 16,16,16,16};
|
||||||
|
if (x > 9) return -1;
|
||||||
|
if (y % 2 == 0) {
|
||||||
|
return (y * 18 + mapping_even[x]); // mapping_even[y];
|
||||||
|
} else {
|
||||||
|
return (y * 18 + mapping_odd[x]); // mapping_odd[y];
|
||||||
|
//return (y * 18 + 17 - x); // mapping_odd[y];
|
||||||
|
}
|
||||||
|
//if (x % 2 == 0) {
|
||||||
|
// return (x * 8) + y;
|
||||||
|
//}
|
||||||
|
//return (x * 8) + (7 - y);
|
||||||
lambda: |-
|
lambda: |-
|
||||||
// Draw a bulls-eye pattern
|
|
||||||
Color red = Color(0xFF0000);
|
Color red = Color(0xFF0000);
|
||||||
Color green = Color(0x00FF00);
|
Color green = Color(0x00FF00);
|
||||||
Color blue = Color(0x0000FF);
|
Color blue = Color(0x0000FF);
|
||||||
it.rectangle(0, 0, 18, 11, red);
|
Color turquoise = Color(0x00FFFF);
|
||||||
it.rectangle(1, 1, 17, 10, green);
|
it.draw_pixel_at(0,0, green);
|
||||||
it.rectangle(2, 2, 16, 9, blue);
|
it.draw_pixel_at(10,0, red);
|
||||||
it.rectangle(3, 3, 15, 8, red);
|
it.draw_pixel_at(0,9, turquoise);
|
||||||
|
it.draw_pixel_at(10,9, blue);
|
||||||
|
//it.line(0,0, 11,0, red);
|
||||||
|
//it.line(0,1, 11,1, green);
|
||||||
|
//it.line(0,2, 11,2, blue);
|
||||||
|
//it.line(0,3, 11,3, red);
|
||||||
|
//it.line(0,4, 11,4, green);
|
||||||
|
//it.line(0,5, 11,5, blue);
|
||||||
|
//it.line(0,6, 11,6, red);
|
||||||
|
//it.line(0,7, 11,7, green);
|
||||||
|
//it.line(0,8, 11,8, blue);
|
||||||
|
//it.line(0,9, 11,9, red);
|
||||||
|
//it.line(0,10, 9,10, green);
|
||||||
|
//it.line(0,11, 9,11, blue);
|
||||||
|
// it.line(5,14, 10,14, green);
|
||||||
|
//it.rectangle(0, 0, 17, 10, red);
|
||||||
|
//it.rectangle(1, 1, 16, 9, green);
|
||||||
|
//it.rectangle(2, 2, 15, 8, blue);
|
||||||
|
//it.rectangle(3, 3, 14, 7, red);
|
||||||
|
|
||||||
time:
|
time:
|
||||||
- platform: sntp
|
- platform: sntp
|
||||||
|
|
|
||||||
154
image_test.yaml
Normal file
154
image_test.yaml
Normal file
|
|
@ -0,0 +1,154 @@
|
||||||
|
esphome:
|
||||||
|
name: "display-thing"
|
||||||
|
|
||||||
|
esp8266:
|
||||||
|
board: d1_mini
|
||||||
|
framework:
|
||||||
|
version: recommended
|
||||||
|
|
||||||
|
external_components:
|
||||||
|
- source:
|
||||||
|
type: local
|
||||||
|
path: components
|
||||||
|
components: [ wordclock, addressable_light ]
|
||||||
|
|
||||||
|
wifi:
|
||||||
|
ssid: !secret wifi_ssid
|
||||||
|
password: !secret wifi_password
|
||||||
|
ap:
|
||||||
|
ssid: "${devicename}"
|
||||||
|
password: !secret ap_password
|
||||||
|
manual_ip:
|
||||||
|
static_ip: !secret manualip_static_ip
|
||||||
|
gateway: !secret manualip_gateway
|
||||||
|
subnet: !secret manualip_subnet
|
||||||
|
dns1: 1.1.1.1
|
||||||
|
dns2: 1.0.0.1
|
||||||
|
|
||||||
|
api:
|
||||||
|
|
||||||
|
# ota:
|
||||||
|
# password: "${devicename}"
|
||||||
|
|
||||||
|
logger:
|
||||||
|
# esp8266_store_log_strings_in_flash: false
|
||||||
|
web_server:
|
||||||
|
port: 80
|
||||||
|
|
||||||
|
light:
|
||||||
|
- name: NeoPixel Strip 1
|
||||||
|
id: neopixel_strip_1
|
||||||
|
platform: neopixelbus
|
||||||
|
type: GRB
|
||||||
|
variant: WS2812
|
||||||
|
pin: GPIO3
|
||||||
|
num_leds: 199
|
||||||
|
restore_mode: ALWAYS_ON
|
||||||
|
default_transition_length: 0s
|
||||||
|
color_correct: [100%, 100%, 100%]
|
||||||
|
method:
|
||||||
|
type: esp8266_dma
|
||||||
|
|
||||||
|
display:
|
||||||
|
- platform: addressable_light
|
||||||
|
id: led_matrix_display
|
||||||
|
addressable_light_id: neopixel_strip_1
|
||||||
|
width: 18
|
||||||
|
height: 11
|
||||||
|
rotation: 270°
|
||||||
|
update_interval: 16ms
|
||||||
|
auto_clear_enabled: false
|
||||||
|
pixel_mapper: |-
|
||||||
|
int mapping_even[] = {0, 2, 4, 6,8,10,11,13,15,17, 16,16,16,16, 16,16,16,16};
|
||||||
|
int mapping_odd[] = {17,15,13,11,9, 7, 6, 4, 2, 0, 16,16,16,16, 16,16,16,16};
|
||||||
|
if (x > 9) return -1;
|
||||||
|
if (y % 2 == 0) {
|
||||||
|
return (y * 18 + mapping_even[x]); // mapping_even[y];
|
||||||
|
} else {
|
||||||
|
return (y * 18 + mapping_odd[x]); // mapping_odd[y];
|
||||||
|
}
|
||||||
|
# lambda: |-
|
||||||
|
# it.fill(Color(0));
|
||||||
|
# it.image(0, 0, id(foo));
|
||||||
|
# //it.line(0,0,5,5, Color(0x00FF00));
|
||||||
|
|
||||||
|
# image:
|
||||||
|
# - id: foo
|
||||||
|
# file: ./test.png
|
||||||
|
# type: RGB24
|
||||||
|
# resize: 18x11
|
||||||
|
|
||||||
|
|
||||||
|
time:
|
||||||
|
- platform: sntp
|
||||||
|
id: current_time
|
||||||
|
timezone: !secret timezone
|
||||||
|
|
||||||
|
|
||||||
|
wordclock:
|
||||||
|
time_id: current_time
|
||||||
|
display_id: led_matrix_display
|
||||||
|
static_segments: ["IT", "IS"]
|
||||||
|
segments:
|
||||||
|
- {name: "IT", line: {x1: 0, x2: 1, y1: 0}}
|
||||||
|
- {name: "IS", line: {x1: 3, x2: 4, y1: 0}}
|
||||||
|
- {name: "AM", line: {x1: 7, x2: 8, y1: 0}}
|
||||||
|
- {name: "PM", line: {x1: 9, x2: 10, y1: 0}}
|
||||||
|
- {name: "QUARTER", line: {x1: 2, x2: 8, y1: 1}}
|
||||||
|
- {name: "TWENTY", line: {x1: 0, x2: 5, y1: 2}}
|
||||||
|
- {name: "FIVE_MINUTES", line: {x1: 6, x2: 9, y1: 2}}
|
||||||
|
- {name: "HALF", line: {x1: 0, x2: 3, y1: 3}}
|
||||||
|
- {name: "TEN_MINUTES", line: {x1: 5, x2: 7, y1: 3}}
|
||||||
|
- {name: "TO", line: {x1: 9, x2: 10, y1: 3}}
|
||||||
|
- {name: "PAST", line: {x1: 0, x2: 3, y1: 4}}
|
||||||
|
- {name: "NINE", line: {x1: 7, x2: 10, y1: 4}}
|
||||||
|
- {name: "ONE", line: {x1: 0, x2: 2, y1: 5}}
|
||||||
|
- {name: "SIX", line: {x1: 3, x2: 5, y1: 5}}
|
||||||
|
- {name: "THREE", line: {x1: 6, x2: 10, y1: 5}}
|
||||||
|
- {name: "FOUR", line: {x1: 0, x2: 3, y1: 6}}
|
||||||
|
- {name: "FIVE", line: {x1: 4, x2: 7, y1: 6}}
|
||||||
|
- {name: "TWO", line: {x1: 8, x2: 10, y1: 6}}
|
||||||
|
- {name: "EIGHT", line: {x1: 0, x2: 4, y1: 7}}
|
||||||
|
- {name: "ELEVEN", line: {x1: 5, x2: 10, y1: 7}}
|
||||||
|
- {name: "SEVEN", line: {x1: 0, x2: 4, y1: 8}}
|
||||||
|
- {name: "TWELVE", line: {x1: 5, x2: 10, y1: 8}}
|
||||||
|
- {name: "TEN", line: {x1: 0, x2: 2, y1: 9}}
|
||||||
|
- {name: "OCLOCK", line: {x1: 5, x2: 10, y1: 9}}
|
||||||
|
minutes:
|
||||||
|
- {minute: 0, segments: ["OCLOCK"]}
|
||||||
|
- {minute: 5, segments: ["FIVE_MINUTES", "PAST"]}
|
||||||
|
- {minute: 10, segments: ["TEN_MINUTES", "PAST"]}
|
||||||
|
- {minute: 15, segments: ["QUARTER", "PAST"]}
|
||||||
|
- {minute: 20, segments: ["TWENTY", "PAST"]}
|
||||||
|
- {minute: 25, segments: ["TWENTY", "FIVE_MINUTES", "PAST"]}
|
||||||
|
- {minute: 30, segments: ["HALF", "PAST"]}
|
||||||
|
- {minute: 35, segments: ["TWENTY", "FIVE_MINUTES", "TO"]}
|
||||||
|
- {minute: 40, segments: ["TWENTY", "TO"]}
|
||||||
|
- {minute: 45, segments: ["QUARTER", "TO"]}
|
||||||
|
- {minute: 50, segments: ["TEN_MINUTES", "TO"]}
|
||||||
|
- {minute: 55, segments: ["FIVE_MINUTES", "TO"]}
|
||||||
|
hours:
|
||||||
|
- {hour: 0, segments: ["TWELVE", "AM"]}
|
||||||
|
- {hour: 1, segments: ["ONE", "AM"]}
|
||||||
|
- {hour: 2, segments: ["TWO", "AM"]}
|
||||||
|
- {hour: 3, segments: ["THREE", "AM"]}
|
||||||
|
- {hour: 4, segments: ["FOUR", "AM"]}
|
||||||
|
- {hour: 5, segments: ["FIVE", "AM"]}
|
||||||
|
- {hour: 6, segments: ["SIX", "AM"]}
|
||||||
|
- {hour: 7, segments: ["SEVEN", "AM"]}
|
||||||
|
- {hour: 8, segments: ["EIGHT", "AM"]}
|
||||||
|
- {hour: 9, segments: ["NINE", "AM"]}
|
||||||
|
- {hour: 10, segments: ["TEN", "AM"]}
|
||||||
|
- {hour: 11, segments: ["ELEVEN", "AM"]}
|
||||||
|
- {hour: 12, segments: ["TWELVE", "PM"]}
|
||||||
|
- {hour: 13, segments: ["ONE", "PM"]}
|
||||||
|
- {hour: 14, segments: ["TWO", "PM"]}
|
||||||
|
- {hour: 15, segments: ["THREE", "PM"]}
|
||||||
|
- {hour: 16, segments: ["FOUR", "PM"]}
|
||||||
|
- {hour: 17, segments: ["FIVE", "PM"]}
|
||||||
|
- {hour: 18, segments: ["SIX", "PM"]}
|
||||||
|
- {hour: 19, segments: ["SEVEN", "PM"]}
|
||||||
|
- {hour: 20, segments: ["EIGHT", "PM"]}
|
||||||
|
- {hour: 21, segments: ["NINE", "PM"]}
|
||||||
|
- {hour: 22, segments: ["TEN", "PM"]}
|
||||||
|
- {hour: 23, segments: ["ELEVEN", "PM"]}
|
||||||
225
image_test_3leds.yaml
Normal file
225
image_test_3leds.yaml
Normal file
|
|
@ -0,0 +1,225 @@
|
||||||
|
esphome:
|
||||||
|
name: "display-thing"
|
||||||
|
# on_boot:
|
||||||
|
# priority: 600
|
||||||
|
# # ...
|
||||||
|
# then:
|
||||||
|
# - light.turn_on:
|
||||||
|
# id: neopixel_strip_1
|
||||||
|
# brightness: 100%
|
||||||
|
# effect: random_twinkle
|
||||||
|
|
||||||
|
esp8266:
|
||||||
|
board: d1_mini
|
||||||
|
framework:
|
||||||
|
version: recommended
|
||||||
|
|
||||||
|
external_components:
|
||||||
|
- source:
|
||||||
|
type: local
|
||||||
|
path: components
|
||||||
|
components: [ wordclock ]
|
||||||
|
# components: [ wordclock, addressable_light ]
|
||||||
|
|
||||||
|
wifi:
|
||||||
|
ssid: !secret wifi_ssid
|
||||||
|
password: !secret wifi_password
|
||||||
|
ap:
|
||||||
|
ssid: "WordClock Configuration"
|
||||||
|
password: !secret ap_password
|
||||||
|
manual_ip:
|
||||||
|
static_ip: !secret manualip_static_ip
|
||||||
|
gateway: !secret manualip_gateway
|
||||||
|
subnet: !secret manualip_subnet
|
||||||
|
dns1: 1.1.1.1
|
||||||
|
dns2: 1.0.0.1
|
||||||
|
|
||||||
|
captive_portal:
|
||||||
|
|
||||||
|
api:
|
||||||
|
|
||||||
|
ota:
|
||||||
|
password: "wordclock"
|
||||||
|
|
||||||
|
logger:
|
||||||
|
# esp8266_store_log_strings_in_flash: false
|
||||||
|
# web_server:
|
||||||
|
# port: 80
|
||||||
|
|
||||||
|
time:
|
||||||
|
- platform: sntp
|
||||||
|
id: current_time
|
||||||
|
timezone: !secret timezone
|
||||||
|
on_time_sync:
|
||||||
|
then:
|
||||||
|
- logger.log: "synced system clock"
|
||||||
|
# - light.turn_on:
|
||||||
|
# id: neopixel_strip_1
|
||||||
|
# effect: "None"
|
||||||
|
# - light.turn_off:
|
||||||
|
# id: neopixel_strip_1
|
||||||
|
light:
|
||||||
|
- name: NeoPixel Strip 1
|
||||||
|
id: neopixel_strip_1
|
||||||
|
platform: neopixelbus
|
||||||
|
type: GRB
|
||||||
|
variant: WS2812
|
||||||
|
pin: GPIO3
|
||||||
|
num_leds: 198
|
||||||
|
restore_mode: ALWAYS_OFF
|
||||||
|
# default_transition_length: 0.7s
|
||||||
|
# color_correct: [100%, 100%, 100%]
|
||||||
|
method:
|
||||||
|
type: esp8266_dma
|
||||||
|
|
||||||
|
effects:
|
||||||
|
# - random:
|
||||||
|
# - pulse:
|
||||||
|
# - strobe:
|
||||||
|
# - flicker:
|
||||||
|
- addressable_rainbow:
|
||||||
|
name: "rainbow"
|
||||||
|
# - addressable_color_wipe:
|
||||||
|
# - addressable_scan:
|
||||||
|
- addressable_twinkle:
|
||||||
|
name: "twinkle"
|
||||||
|
- addressable_random_twinkle:
|
||||||
|
name: "random_twinkle"
|
||||||
|
# - addressable_fireworks:
|
||||||
|
# - addressable_flicker:
|
||||||
|
# - wled:
|
||||||
|
|
||||||
|
|
||||||
|
display:
|
||||||
|
- platform: addressable_light
|
||||||
|
id: led_matrix_display
|
||||||
|
addressable_light_id: neopixel_strip_1
|
||||||
|
width: 18
|
||||||
|
height: 11
|
||||||
|
rotation: 270°
|
||||||
|
update_interval: 16ms
|
||||||
|
auto_clear_enabled: false
|
||||||
|
pixel_mapper: |-
|
||||||
|
int mapping_even[] = {0, 2, 4, 6,8,10,11,13,15,17, 16,16,16,16, 16,16,16,16};
|
||||||
|
int mapping_odd[] = {17,15,13,11,9, 7, 6, 4, 2, 0, 16,16,16,16, 16,16,16,16};
|
||||||
|
if (x > 9) return -1;
|
||||||
|
if (y % 2 == 0) {
|
||||||
|
return (y * 18 + mapping_even[x]); // mapping_even[y];
|
||||||
|
} else {
|
||||||
|
return (y * 18 + mapping_odd[x]); // mapping_odd[y];
|
||||||
|
}
|
||||||
|
# lambda: |-
|
||||||
|
# //ESP_LOGE("lambda", "display_ptr: %i", &it);
|
||||||
|
# //it.fill(Color(0xff00ff));
|
||||||
|
# //it.line(0,0,0,0, Color(0x00FF00));
|
||||||
|
|
||||||
|
|
||||||
|
wordclock:
|
||||||
|
time_id: current_time
|
||||||
|
display_id: led_matrix_display
|
||||||
|
addressable_light_id: neopixel_strip_1
|
||||||
|
static_segments: ["IT", "IS"]
|
||||||
|
segments:
|
||||||
|
- {name: "IT", line: {x1: 0, x2: 1, y1: 0}}
|
||||||
|
- {name: "IS", line: {x1: 3, x2: 4, y1: 0}}
|
||||||
|
- {name: "AM", line: {x1: 7, x2: 8, y1: 0}}
|
||||||
|
- {name: "PM", line: {x1: 9, x2: 10, y1: 0}}
|
||||||
|
- {name: "QUARTER", line: {x1: 2, x2: 8, y1: 1}}
|
||||||
|
- {name: "TWENTY", line: {x1: 0, x2: 5, y1: 2}}
|
||||||
|
- {name: "FIVE_MINUTES", line: {x1: 6, x2: 9, y1: 2}}
|
||||||
|
- {name: "HALF", line: {x1: 0, x2: 3, y1: 3}}
|
||||||
|
- {name: "TEN_MINUTES", line: {x1: 5, x2: 7, y1: 3}}
|
||||||
|
- {name: "TO", line: {x1: 9, x2: 10, y1: 3}}
|
||||||
|
- {name: "PAST", line: {x1: 0, x2: 3, y1: 4}}
|
||||||
|
- {name: "NINE", line: {x1: 7, x2: 10, y1: 4}}
|
||||||
|
- {name: "ONE", line: {x1: 0, x2: 2, y1: 5}}
|
||||||
|
- {name: "SIX", line: {x1: 3, x2: 5, y1: 5}}
|
||||||
|
- {name: "THREE", line: {x1: 6, x2: 10, y1: 5}}
|
||||||
|
- {name: "FOUR", line: {x1: 0, x2: 3, y1: 6}}
|
||||||
|
- {name: "FIVE", line: {x1: 4, x2: 7, y1: 6}}
|
||||||
|
- {name: "TWO", line: {x1: 8, x2: 10, y1: 6}}
|
||||||
|
- {name: "EIGHT", line: {x1: 0, x2: 4, y1: 7}}
|
||||||
|
- {name: "ELEVEN", line: {x1: 5, x2: 10, y1: 7}}
|
||||||
|
- {name: "SEVEN", line: {x1: 0, x2: 4, y1: 8}}
|
||||||
|
- {name: "TWELVE", line: {x1: 5, x2: 10, y1: 8}}
|
||||||
|
- {name: "TEN", line: {x1: 0, x2: 2, y1: 9}}
|
||||||
|
- {name: "OCLOCK", line: {x1: 5, x2: 10, y1: 9}}
|
||||||
|
minutes:
|
||||||
|
- {minute: 0, hour_offset: 0, segments: ["OCLOCK"]}
|
||||||
|
- {minute: 5, hour_offset: 0, segments: ["FIVE_MINUTES", "PAST"]}
|
||||||
|
- {minute: 10, hour_offset: 0, segments: ["TEN_MINUTES", "PAST"]}
|
||||||
|
- {minute: 15, hour_offset: 0, segments: ["QUARTER", "PAST"]}
|
||||||
|
- {minute: 20, hour_offset: 0, segments: ["TWENTY", "PAST"]}
|
||||||
|
- {minute: 25, hour_offset: 0, segments: ["TWENTY", "FIVE_MINUTES", "PAST"]}
|
||||||
|
- {minute: 30, hour_offset: 0, segments: ["HALF", "PAST"]}
|
||||||
|
- {minute: 35, hour_offset: 1, segments: ["TWENTY", "FIVE_MINUTES", "TO"]}
|
||||||
|
- {minute: 40, hour_offset: 1, segments: ["TWENTY", "TO"]}
|
||||||
|
- {minute: 45, hour_offset: 1, segments: ["QUARTER", "TO"]}
|
||||||
|
- {minute: 50, hour_offset: 1, segments: ["TEN_MINUTES", "TO"]}
|
||||||
|
- {minute: 55, hour_offset: 1, segments: ["FIVE_MINUTES", "TO"]}
|
||||||
|
hours:
|
||||||
|
- {hour: 0, segments: "TWELVE"}
|
||||||
|
- {hour: 1, segments: "ONE"}
|
||||||
|
- {hour: 2, segments: "TWO"}
|
||||||
|
- {hour: 3, segments: "THREE"}
|
||||||
|
- {hour: 4, segments: "FOUR"}
|
||||||
|
- {hour: 5, segments: "FIVE"}
|
||||||
|
- {hour: 6, segments: "SIX"}
|
||||||
|
- {hour: 7, segments: "SEVEN"}
|
||||||
|
- {hour: 8, segments: "EIGHT"}
|
||||||
|
- {hour: 9, segments: "NINE"}
|
||||||
|
- {hour: 10, segments: "TEN"}
|
||||||
|
- {hour: 11, segments: "ELEVEN"}
|
||||||
|
- {hour: 12, segments: "TWELVE"}
|
||||||
|
- {hour: 13, segments: "ONE"}
|
||||||
|
- {hour: 14, segments: "TWO"}
|
||||||
|
- {hour: 15, segments: "THREE"}
|
||||||
|
- {hour: 16, segments: "FOUR"}
|
||||||
|
- {hour: 17, segments: "FIVE"}
|
||||||
|
- {hour: 18, segments: "SIX"}
|
||||||
|
- {hour: 19, segments: "SEVEN"}
|
||||||
|
- {hour: 20, segments: "EIGHT"}
|
||||||
|
- {hour: 21, segments: "NINE"}
|
||||||
|
- {hour: 22, segments: "TEN"}
|
||||||
|
- {hour: 23, segments: "ELEVEN"}
|
||||||
|
# hours:
|
||||||
|
# - {hour: 0, segments: ["TWELVE", "AM"]}
|
||||||
|
# - {hour: 1, segments: ["ONE", "AM"]}
|
||||||
|
# - {hour: 2, segments: ["TWO", "AM"]}
|
||||||
|
# - {hour: 3, segments: ["THREE", "AM"]}
|
||||||
|
# - {hour: 4, segments: ["FOUR", "AM"]}
|
||||||
|
# - {hour: 5, segments: ["FIVE", "AM"]}
|
||||||
|
# - {hour: 6, segments: ["SIX", "AM"]}
|
||||||
|
# - {hour: 7, segments: ["SEVEN", "AM"]}
|
||||||
|
# - {hour: 8, segments: ["EIGHT", "AM"]}
|
||||||
|
# - {hour: 9, segments: ["NINE", "AM"]}
|
||||||
|
# - {hour: 10, segments: ["TEN", "AM"]}
|
||||||
|
# - {hour: 11, segments: ["ELEVEN", "AM"]}
|
||||||
|
# - {hour: 12, segments: ["TWELVE", "PM"]}
|
||||||
|
# - {hour: 13, segments: ["ONE", "PM"]}
|
||||||
|
# - {hour: 14, segments: ["TWO", "PM"]}
|
||||||
|
# - {hour: 15, segments: ["THREE", "PM"]}
|
||||||
|
# - {hour: 16, segments: ["FOUR", "PM"]}
|
||||||
|
# - {hour: 17, segments: ["FIVE", "PM"]}
|
||||||
|
# - {hour: 18, segments: ["SIX", "PM"]}
|
||||||
|
# - {hour: 19, segments: ["SEVEN", "PM"]}
|
||||||
|
# - {hour: 20, segments: ["EIGHT", "PM"]}
|
||||||
|
# - {hour: 21, segments: ["NINE", "PM"]}
|
||||||
|
# - {hour: 22, segments: ["TEN", "PM"]}
|
||||||
|
# - {hour: 23, segments: ["ELEVEN", "PM"]}
|
||||||
|
# minutes:
|
||||||
|
# - {minute: 0, segments: ["A"]}
|
||||||
|
# - {minute: 5, segments: ["B"]}
|
||||||
|
# - {minute: 10, segments: ["A"]}
|
||||||
|
# - {minute: 15, segments: ["B"]}
|
||||||
|
# - {minute: 20, segments: ["A"]}
|
||||||
|
# - {minute: 25, segments: ["B"]}
|
||||||
|
# - {minute: 30, segments: ["A"]}
|
||||||
|
# - {minute: 35, segments: ["B"]}
|
||||||
|
# - {minute: 40, segments: ["A"]}
|
||||||
|
# - {minute: 45, segments: ["B"]}
|
||||||
|
# - {minute: 50, segments: ["A"]}
|
||||||
|
# - {minute: 55, segments: ["B"]}
|
||||||
|
# hours:
|
||||||
|
# - {hour: 0, segments: ["C"]}
|
||||||
|
|
||||||
BIN
test.png
Normal file
BIN
test.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 780 B |
Loading…
Add table
Add a link
Reference in a new issue