diff --git a/.gitignore b/.gitignore index 53dc580..d8b4157 100644 --- a/.gitignore +++ b/.gitignore @@ -3,11 +3,3 @@ # You can modify this file to suit your needs. /.esphome/ /secrets.yaml -/secrets.*.yaml -!/secrets.example.yaml -/.pio -/.vscode -__pycache__ -/_ignored -esp32_test.code-workspace -case/d1_mini_esp32.FCStd1 diff --git a/case/d1_mini_esp32-Body.stl b/case/d1_mini_esp32-Body.stl deleted file mode 100644 index 64adf67..0000000 Binary files a/case/d1_mini_esp32-Body.stl and /dev/null differ diff --git a/case/d1_mini_esp32.FCStd b/case/d1_mini_esp32.FCStd deleted file mode 100644 index 0473ad4..0000000 Binary files a/case/d1_mini_esp32.FCStd and /dev/null differ diff --git a/components/wordclock/__init__.py b/components/wordclock/__init__.py deleted file mode 100644 index 449526b..0000000 --- a/components/wordclock/__init__.py +++ /dev/null @@ -1,153 +0,0 @@ -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.positive_time_period_milliseconds, - cv.Optional( - CONF_UPDATE_INTERVAL, default="16ms" - ): cv.positive_time_period_milliseconds, - 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)) - - 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))) - - 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))) - - await cg.register_component(var, config) diff --git a/components/wordclock/wordclock.cpp b/components/wordclock/wordclock.cpp deleted file mode 100644 index 57b932c..0000000 --- a/components/wordclock/wordclock.cpp +++ /dev/null @@ -1,184 +0,0 @@ - -#include "wordclock.h" - -namespace esphome { -namespace wordclock { - -void Wordclock::setup() { - this->valid_time = this->time->now().is_valid(); - if (!this->valid_time) { - this->start_idle_animation(); - } -} - -void Wordclock::update() { - esphome::time::ESPTime time = this->time->now(); - - if (!time.is_valid()) { - if (this->valid_time) { - ESP_LOGD("wordclock.cpp", "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) { - ESP_LOGD("wordclock.cpp", "time is valid [%02i:%02i:%02i]", time.hour, time.minute, time.second); - this->end_idle_animation(); - this->valid_time = true; - return; - } - bool dirty = false; - - int8_t minute = this->find_minute(time.minute); - int8_t hour = this->find_hour((time.hour + this->minutes->at(minute).hour_offset) % 24); - - if (hour != this->current_hour) { - this->current_hour = hour; - dirty = true; - } - if (minute != this->current_minute) { - this->current_minute = minute; - dirty = true; - } - - if (dirty) { - this->previous_segments->clear(); - - for (uint16_t segment_idx : *this->current_segments) { - this->previous_segments->push_back(segment_idx); - } - - this->current_segments->clear(); - - for (uint16_t segment_idx : *this->static_segments) { - this->current_segments->push_back(segment_idx); - } - - for (uint16_t segment_idx : *(this->minutes->at(minute).segments)) { - this->current_segments->push_back(segment_idx); - } - - for (uint16_t segment_idx : *(this->hours->at(hour).segments)) { - this->current_segments->push_back(segment_idx); - } - - std::sort(this->current_segments->begin(), this->current_segments->end()); - - this->find_difference(this->previous_segments, this->current_segments); - - this->on_transformer->reset(); - this->off_transformer->reset(); - } - - this->current_position = 0; - uint8_t transition_progress = this->on_transformer->apply().value_or(255); - Color removed_color = this->on_color.gradient(this->off_color, transition_progress); - - for (uint16_t segment_idx : *this->removed_segments) { - this->disable_segment_effect(segment_idx, this->off_color, transition_progress); - } - for (uint16_t segment_idx : *this->added_segments) { - this->enable_segment_effect(segment_idx, this->off_color, transition_progress); - } - for (uint16_t segment_idx : *this->staying_segments) { - this->apply_segment_effect(segment_idx); - } - } -} - -void Wordclock::find_difference(std::vector *a_vec, std::vector *b_vec) { - this->added_segments->clear(); - this->removed_segments->clear(); - this->staying_segments->clear(); - - auto a = a_vec->begin(); - auto b = b_vec->begin(); - - while (!(a == a_vec->end() && b == b_vec->end())) { - if (a == a_vec->end()) { this->added_segments-> push_back(*b); b++; } - else if (b == b_vec->end()) { this->removed_segments->push_back(*a); a++; } - else if (*a > *b) { this->added_segments-> push_back(*b); b++; } - else if (*a < *b) { this->removed_segments->push_back(*a); a++; } - else if (*a == *b) { this->staying_segments->push_back(*a); a++; b++; } - } -} - -Color Wordclock::get_next_color_base_(uint32_t position, uint32_t speed, uint16_t width, const Color ¤t_color) { - esphome::light::ESPHSVColor hsv; - hsv.value = 255; - hsv.saturation = 240; - hsv.hue = ((millis() * speed + (position * (0xFFFF / width))) % 0xFFFF) >> 8; - return hsv.to_rgb(); -} - -Color Wordclock::get_next_color(uint32_t position, const Color ¤t_color) { - if (this->effect_active) { - uint32_t speed_ = 3; - uint16_t width_ = 100; // Original width_ = 50 - return get_next_color_base_(position, speed_, width_, current_color); - } - else { - return Color(this->on_color); - } -} - -int8_t Wordclock::find_hour(uint8_t target_value) { - std::vector *elements = this->hours; - for (int i = 0; i < elements->size(); i++) { - if (elements->at(i).hour == target_value) { - return i; - } else if (elements->at(i).hour > target_value) { - return i - 1; - } - } - return elements->size() - 1; -} - -int8_t Wordclock::find_minute(uint8_t target_value) { - std::vector *elements = this->minutes; - for (int i = 0; i < elements->size(); i++) { - if (elements->at(i).minute == target_value) { - return i; - } else if (elements->at(i).minute > target_value) { - return i - 1; - } - } - return elements->size() - 1; -} - -void Wordclock::setup_transitions(uint32_t milliseconds) { - this->on_transformer->setup(0, 255, milliseconds); - this->off_transformer->setup(255, 0, milliseconds); -} - -Wordclock::Wordclock( - esphome::time::RealTimeClock *time, - esphome::addressable_light::AddressableLightDisplay *display, - esphome::light::AddressableLightState *light_state) { - - this->time = time; - this->display = display; - this->light_state = light_state; - - this->light_state->set_default_transition_length(1); - - this->minutes = new std::vector(); - this->hours = new std::vector(); - - this->segments = new std::vector(); - this->static_segments = new std::vector(); - - this->previous_segments = new std::vector(); - this->current_segments = new std::vector(); - - this->added_segments = new std::vector(); - this->removed_segments = new std::vector(); - this->staying_segments = new std::vector(); - - this->on_transformer = new BrightnessTransitionTransformer(); - this->off_transformer = new BrightnessTransitionTransformer(); -} -} // namespace wordclock -} // namespace esphome diff --git a/components/wordclock/wordclock.h b/components/wordclock/wordclock.h deleted file mode 100644 index 0530e4d..0000000 --- a/components/wordclock/wordclock.h +++ /dev/null @@ -1,223 +0,0 @@ -#pragma once - -#include "esphome.h" -// #include "esphome/components/sensor/sensor.h" - -namespace esphome { -namespace wordclock { - -struct Minute { - uint8_t minute; - uint8_t hour_offset; - std::vector *segments; -}; - -struct Hour { - uint8_t hour; - std::vector *segments; -}; - -struct SegmentCoords { - uint16_t x1; - uint16_t y1; - uint16_t x2; - uint16_t y2; -}; - -class BrightnessTransitionTransformer { -public: - virtual ~BrightnessTransitionTransformer() = default; - - void setup(const uint8_t start_values, const uint8_t target_values, uint32_t length) { - this->start_time_ = millis(); - this->length_ = length; - this->start_values_ = start_values; - this->target_values_ = target_values; - this->start(); - } - virtual bool is_finished() { return this->get_progress_() >= 1.0f; } - virtual void start() {} - // virtual optional apply() = 0; - virtual optional apply() { - float v = BrightnessTransitionTransformer::smoothed_progress(this->get_progress_()); - return esphome::lerp(v, this->start_values_, this->target_values_); - } - virtual void stop() {} - void reset() { - this->start_time_ = millis(); - } - const uint8_t &get_start_values() const { return this->start_values_; } - const uint8_t &get_target_values() const { return this->target_values_; } - -protected: - // The progress of this transition, on a scale of 0 to 1. - float get_progress_() { - uint32_t now = esphome::millis(); - if (now < this->start_time_) - return 0.0f; - if (now >= this->start_time_ + this->length_) - return 1.0f; - return clamp((now - this->start_time_) / float(this->length_), 0.0f, 1.0f); - } - - static float smoothed_progress(float x) { return x * x * x * (x * (x * 6.0f - 15.0f) + 10.0f); } - - uint32_t start_time_; - uint32_t length_; - uint8_t start_values_; - uint8_t target_values_; -}; - -class Wordclock : public esphome::PollingComponent { -public: - Wordclock( - esphome::time::RealTimeClock *time, - esphome::addressable_light::AddressableLightDisplay *display, - esphome::light::AddressableLightState *light_state - ); - - void setup(); - void update(); - void set_brightness(uint8_t brightness) { - this->brightness = brightness; - } - bool get_effect_active() { return this->effect_active; } - void set_effect_active(bool x) { this->effect_active = x; } - - bool get_effect_width() { return this->effect_width; } - void set_effect_width(bool x) { this->effect_width = x; } - - bool get_effect_speed() { return this->effect_speed; } - void set_effect_speed(bool x) { this->effect_speed = x; } - - void set_on_color(Color on_color) { - this->on_color = on_color; - } - void set_off_color(Color off_color) { - this->off_color = off_color; - } - void setup_transitions(uint32_t milliseconds); - - void add_segment(SegmentCoords segment) { - this->segments->push_back(segment); - } - - void add_static(uint16_t segment_id) { - this->static_segments->push_back(segment_id); - } - - void add_hour(uint8_t hour, std::vector *segments_ptr) { - this->hours->push_back(Hour{ - .hour = hour, - .segments = segments_ptr, - }); - } - - void add_minute(uint8_t minute, uint8_t hour_offset, std::vector *segments_ptr) { - this->minutes->push_back(Minute{ - .minute = minute, - .hour_offset = hour_offset, - .segments = segments_ptr, - }); - } - - Color on_color {Color(0xFFFFFF)}; - Color off_color {Color(0x000000)}; - uint8_t brightness{255}; - -protected: - // ESPHome Components - esphome::time::RealTimeClock *time; - esphome::light::AddressableLightState *light_state; - esphome::addressable_light::AddressableLightDisplay *display; - - // Time related state - bool valid_time{false}; - int8_t current_hour{-1}; - int8_t current_minute{-1}; - - // Segments Configuration - std::vector *segments; - std::vector *static_segments; - std::vector *minutes; - std::vector *hours; - - BrightnessTransitionTransformer *off_transformer; - BrightnessTransitionTransformer *on_transformer; - - std::vector *added_segments; - std::vector *removed_segments; - std::vector *staying_segments; - - std::vector *current_segments; - std::vector *previous_segments; - - uint32_t current_position{0}; - bool effect_active{true}; - uint32_t effect_speed{12}; - uint16_t effect_width{50}; - Color get_next_color_base_(uint32_t position, uint32_t speed, uint16_t width, const Color ¤t_color); - Color get_next_color(uint32_t position, const Color ¤t_color); - - - // Utils - int8_t find_hour(uint8_t target_value); - int8_t find_minute(uint8_t target_value); - void find_difference(std::vector *a_vec, std::vector *b_vec); - - void segment_effect_base(uint16_t segment_id, bool to_effect, Color base_color, uint8_t transition_progress) { - SegmentCoords s = this->segments->at(segment_id); - int x1 = s.x1; int y1 = s.y1; int x2 = s.x2; int y2 = s.y2; - Color color_to_draw; - Color effect_color; - - const int32_t dx = abs(x2 - x1), sx = x1 < x2 ? 1 : -1; - const int32_t dy = -abs(y2 - y1), sy = y1 < y2 ? 1 : -1; - int32_t err = dx + dy; - while (true) { - effect_color = this->get_next_color(x1 + y1, Color(0)) * this->brightness; - if (to_effect) { - color_to_draw = base_color.gradient(effect_color, transition_progress); - } else { - color_to_draw = effect_color.gradient(base_color, transition_progress); - } - this->display->draw_pixel_at(x1, y1, color_to_draw); - if (x1 == x2 && y1 == y2) break; - int32_t e2 = 2 * err; - if (e2 >= dy) { - err += dy; - x1 += sx; - } - if (e2 <= dx) { - err += dx; - y1 += sy; - } - } - } - - void enable_segment_effect(uint16_t segment_id, Color off_color, uint8_t transition_progress) { - segment_effect_base(segment_id, true, off_color, transition_progress); - } - void disable_segment_effect(uint16_t segment_id, Color off_color, uint8_t transition_progress) { - segment_effect_base(segment_id, false, off_color, transition_progress); - } - void apply_segment_effect(uint16_t segment_id) { - segment_effect_base(segment_id, true, Color(0), 255); - } - void start_idle_animation() { - this->display->fill(this->off_color); - this->display->set_enabled(false); - this->light_state->turn_on().set_effect("random_twinkle").perform(); - } - - void end_idle_animation() { - this->light_state->turn_off().perform(); - this->display->set_enabled(true); - this->display->fill(this->off_color); - this->previous_segments->clear(); - this->current_segments->clear(); - } -}; -} // namespace wordclock -} // namespace esphome - diff --git a/devlog.md b/devlog.md deleted file mode 100644 index 2a687de..0000000 --- a/devlog.md +++ /dev/null @@ -1,9 +0,0 @@ -# Wordclock Development Log - - -## Feature "make speed and width of rainbow effect user-configurable" [2023-06-10 17:13] - -[17:16] Step - add attributes, getters, and setters for effect-speed and -width. - - [x] add attr/funcs to header file. - - [x] add inputs to yaml. - - \ No newline at end of file diff --git a/display_test.yaml b/display_test.yaml deleted file mode 100644 index 9a0f27f..0000000 --- a/display_test.yaml +++ /dev/null @@ -1,98 +0,0 @@ -esphome: - name: "display-thing" - -esp8266: - board: d1_mini - framework: - version: recommended - -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 - 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: |- - Color red = Color(0xFF0000); - Color green = Color(0x00FF00); - Color blue = Color(0x0000FF); - Color turquoise = Color(0x00FFFF); - it.draw_pixel_at(0,0, green); - it.draw_pixel_at(10,0, 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: - - platform: sntp - id: current_time - timezone: !secret timezone diff --git a/flake.lock b/flake.lock deleted file mode 100644 index 48ccbe4..0000000 --- a/flake.lock +++ /dev/null @@ -1,64 +0,0 @@ -{ - "nodes": { - "nixpkgs": { - "locked": { - "lastModified": 1683777345, - "narHash": "sha256-V2p/A4RpEGqEZussOnHYMU6XglxBJGCODdzoyvcwig8=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "635a306fc8ede2e34cb3dd0d6d0a5d49362150ed", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixpkgs-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, - "root": { - "inputs": { - "nixpkgs": "nixpkgs", - "systems": "systems", - "utils": "utils" - } - }, - "systems": { - "locked": { - "lastModified": 1680978846, - "narHash": "sha256-Gtqg8b/v49BFDpDetjclCYXm8mAnTrUzR0JnE2nv5aw=", - "owner": "nix-systems", - "repo": "x86_64-linux", - "rev": "2ecfcac5e15790ba6ce360ceccddb15ad16d08a8", - "type": "github" - }, - "original": { - "owner": "nix-systems", - "repo": "x86_64-linux", - "type": "github" - } - }, - "utils": { - "inputs": { - "systems": [ - "systems" - ] - }, - "locked": { - "lastModified": 1681202837, - "narHash": "sha256-H+Rh19JDwRtpVPAWp64F+rlEtxUWBAQW28eAi3SRSzg=", - "owner": "numtide", - "repo": "flake-utils", - "rev": "cfacdce06f30d2b68473a46042957675eebb3401", - "type": "github" - }, - "original": { - "owner": "numtide", - "repo": "flake-utils", - "type": "github" - } - } - }, - "root": "root", - "version": 7 -} diff --git a/flake.nix b/flake.nix deleted file mode 100644 index 208d1ce..0000000 --- a/flake.nix +++ /dev/null @@ -1,67 +0,0 @@ -{ - description = "EspHome Word Clock"; - inputs = { - systems.url = "github:nix-systems/x86_64-linux"; - nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; - # nixpkgs.url = "github:NixOS/nixpkgs/22.11"; - utils.url = "github:numtide/flake-utils"; - utils.inputs.systems.follows = "systems"; - }; - outputs = { self, nixpkgs, utils, ... }: utils.lib.eachDefaultSystem ( - system: - let pkgs = import nixpkgs { inherit system; }; - in { - - # This block here is used when running `nix develop` - devShells.default = pkgs.mkShell rec { - # Update the name to something that suites your project. - name = "esphome-wordclock"; - - # build environment dependencies - packages = with pkgs; [ - esphome - ]; - - # Setting up the environment variables you need during development. - - # Todo figure out why I can't use clang on Asahi but can on Darwin - # Use "clang++" for most systems but OSX Asahi requires g++ for some reason or a runtime error occurs - shellHook = let - # This is for an icon that is used below for the command line input below - icon = "f121"; - in '' - export PS1="$(echo -e '\u${icon}') {\[$(tput sgr0)\]\[\033[38;5;228m\]\w\[$(tput sgr0)\]\[\033[38;5;15m\]} (${name}) \\$ \[$(tput sgr0)\]" - # export COMPILER="clang++" - #export COMPILER="g++" - echo "test"; - ''; - }; - # This is used when running `nix build` - # packages.default = pkgs.llvmPackages_14.stdenv.mkDerivation rec { - packages.default = pkgs.esphome.stdenv.mkDerivation rec { - name = "esphome-wordclock"; - version = "2.0.0"; - src = self; - - # buildInputs = [ pkgs.esphome ]; - - # buildPhase = "COMPILER='clang++' make"; - - # installPhase = '' - # mkdir -p $out/bin; - # install -t $out/bin worm - # ''; - - # meta = with inputs.utils.lib; { - # homepage = "https://github.com/icecreammatt/ssu-cs315-worm"; - # description = '' - # Terminal CLI Worm Game - # ''; - # }; - }; - # packages.x86_64-linux.hello = nixpkgs.legacyPackages.x86_64-linux.hello; - - # packages.x86_64-linux.default = self.packages.x86_64-linux.hello; - - }); -} diff --git a/image_test.yaml b/image_test.yaml deleted file mode 100644 index f3662f4..0000000 --- a/image_test.yaml +++ /dev/null @@ -1,154 +0,0 @@ -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"]} \ No newline at end of file diff --git a/secrets.example.yaml b/secrets.example.yaml deleted file mode 100644 index a6373f1..0000000 --- a/secrets.example.yaml +++ /dev/null @@ -1,7 +0,0 @@ -wifi_password: secret -wifi_ssid: example -manualip_static_ip: 192.168.1.177 -manualip_gateway: 192.168.1.1 -manualip_subnet: 255.255.255.0 -timezone: Europe/Zurich -ap_password: "password for internal fallback accesspoint" diff --git a/susannes_wordclock.yaml b/susannes_wordclock.yaml deleted file mode 100644 index 4680d96..0000000 --- a/susannes_wordclock.yaml +++ /dev/null @@ -1,186 +0,0 @@ -esphome: - name: "wordclock" - -esp8266: - board: d1_mini - framework: - version: recommended -# esp32: -# board: ttgo-t7-v13-mini32 -# framework: -# type: arduino - - -external_components: - - source: - type: local - path: components - components: [ wordclock ] - -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: - -select: - - platform: template - name: "Template select" - restore_value: true - set_action: - - lambda: |- - return id(wordclock_1)->set_effect_active(false); - optimistic: true - options: - - effect - - color - initial_option: effect - -web_server: - port: 80 - version: 1 - -time: - - platform: sntp - id: current_time - timezone: !secret timezone - -light: - - name: NeoPixel Strip 1 - id: neopixel_strip_1 - platform: neopixelbus - type: GRB - variant: WS2812 - pin: GPIO3 - # pin: GPIO22 - num_leds: 198 - restore_mode: ALWAYS_OFF - method: - type: esp8266_dma - # type: esp32_i2s - - effects: - - addressable_random_twinkle: - name: "random_twinkle" - - -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]); - } else { - return (y * 18 + mapping_odd[x]); - } - -color: - - id: col_on - red: 90% - green: 50% - blue: 0% - - id: col_off - red: 0% - green: 0% - blue: 0% - -wordclock: - id: wordclock_1 - time_id: current_time - display_id: led_matrix_display - addressable_light_id: neopixel_strip_1 - brightness: 100% - color_on: col_on - color_off: col_off - update_interval: 16ms - 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"} - - \ No newline at end of file diff --git a/susannes_wordclock_esp32.yaml b/susannes_wordclock_esp32.yaml deleted file mode 100644 index 38987ce..0000000 --- a/susannes_wordclock_esp32.yaml +++ /dev/null @@ -1,327 +0,0 @@ -esphome: - name: "wordclock" - -esp32: - # board: ttgo-t7-v13-mini32 - board: wemos_d1_mini32 - framework: - type: arduino - -external_components: - - source: - type: local - path: components - components: [ wordclock ] - -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: - -switch: - - platform: template - name: "5 Rainbow ON/OFF" - # lambda: |- - # return id(wordclock_1)->get_effect_active(); - restore_state: true - optimistic: true - restore_mode: RESTORE_DEFAULT_ON - turn_on_action: - - lambda: |- - id(wordclock_1)->set_effect_active(true); - turn_off_action: - - lambda: |- - id(wordclock_1)->set_effect_active(false); - -# on_...: -# - globals.set: -# id: my_global_var -# value: '10' - - -# output: -# - platform: template -# id: dummy_out -# type: float -# write_action: -# - lambda: |- -# return id(wordclock_1)->set_effect_active(true); - # Example configuration entry -globals: - - id: my_global_int - type: int - restore_value: no - initial_value: '0' - # Example for global string variable - - id: my_global_string - type: std::string - restore_value: no # Strings cannot be saved/restored - initial_value: '"Global value is"' - -number: - - platform: template - name: "1 Red" - optimistic: true - restore_value: true - initial_value: 255 - # lambda: |- - # return id(wordclock_1)->on_color.red; - on_value: - - lambda: |- - id(wordclock_1)->on_color.red = x; - set_action: - - lambda: |- - id(wordclock_1)->on_color.red = x; - min_value: 0 - max_value: 255 - step: 1 - - platform: template - name: "2 Green" - optimistic: true - restore_value: true - initial_value: 255 - # lambda: |- - # return id(wordclock_1)->on_color.green; - on_value: - - lambda: |- - id(wordclock_1)->on_color.green = x; - set_action: - - lambda: |- - id(wordclock_1)->on_color.green = x; - min_value: 0 - max_value: 255 - step: 1 - - platform: template - name: "3 Blue" - optimistic: true - restore_value: true - initial_value: 255 - # lambda: |- - # return id(wordclock_1)->on_color.blue; - on_value: - - lambda: |- - id(wordclock_1)->on_color.blue = x; - set_action: - - lambda: |- - id(wordclock_1)->on_color.blue = x; - min_value: 0 - max_value: 255 - step: 1 - - platform: template - name: "4 Brightness" - optimistic: true - restore_value: true - initial_value: 255 - # lambda: |- - # return id(wordclock_1)->brightness; - on_value: - - lambda: |- - id(wordclock_1)->brightness = x; - set_action: - - lambda: |- - id(wordclock_1)->brightness = x; - min_value: 0 - max_value: 255 - step: 1 - - platform: template - name: "6 Rainbow Speed" - optimistic: true - restore_value: true - initial_value: 12 - on_value: - - lambda: |- - id(wordclock_1)->set_effect_speed(x); - set_action: - - lambda: |- - id(wordclock_1)->set_effect_speed(x); - min_value: 1 - max_value: 4096 - step: 1 - - platform: template - name: "7 Rainbow Width" - optimistic: true - restore_value: true - initial_value: 50 - on_value: - - lambda: |- - id(wordclock_1)->set_effect_width(x); - set_action: - - lambda: |- - id(wordclock_1)->set_effect_width(x); - min_value: 1 - max_value: 65535 - step: 1 - -# select: -# - platform: template -# name: "Rainbow ON/OFF" -# restore_value: true -# set_action: -# - lambda: |- -# return id(wordclock_1)->set_color_value(x); -# optimistic: true -# options: -# - effect -# - color -# initial_option: effect -# - platform: template -# name: "Template select" -# restore_value: true -# set_action: -# - lambda: |- -# return id(wordclock_1)->set_color_value(x); -# optimistic: true -# options: -# - effect -# - color -# initial_option: effect - - -web_server: - port: 80 - version: 2 - local: true - -time: - - platform: sntp - id: current_time - timezone: !secret timezone - - -light: - - name: NeoPixel Strip 1 - id: neopixel_strip_1 - platform: neopixelbus - type: GRB - variant: WS2812 - pin: GPIO22 - num_leds: 198 - restore_mode: ALWAYS_OFF - internal: true - method: - type: esp32_i2s - effects: - - addressable_random_twinkle: - name: "random_twinkle" - -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]); - } else { - return (y * 18 + mapping_odd[x]); - } - -color: - - id: col_on - red: 90% - green: 50% - blue: 0% - - id: col_off - red: 0% - green: 0% - blue: 0% - -wordclock: - id: wordclock_1 - time_id: current_time - display_id: led_matrix_display - addressable_light_id: neopixel_strip_1 - brightness: 100% - color_on: col_on - color_off: col_off - update_interval: 16ms - 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"} - - \ No newline at end of file diff --git a/test.png b/test.png deleted file mode 100644 index a6acecd..0000000 Binary files a/test.png and /dev/null differ diff --git a/wordclock.h b/wordclock.h deleted file mode 100644 index 95feeb5..0000000 --- a/wordclock.h +++ /dev/null @@ -1,228 +0,0 @@ -#include "esphome.h" -#include - -// 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 - -///// Random Stuff ///// - -#ifndef WORDCLOCK_NUM_LEDS -#define WORDCLOCK_NUM_LEDS 198 -#endif - -#ifndef WORDCLOCK_DATA_PIN -#define WORDCLOCK_DATA_PIN 22 -#endif - -/* NOTE: -This section is about mapping LED indices to -positions in the grid. - -On EVEN rows, the LED strip is running along the -matrix indices, but the physical positions of the -LEDs on the strip did not align with the letter -cutouts. - -On ODD rows, the string is running backwards, because -it is snaking its way back and forth. */ -int mapping_even[] = {0, 2, 4, 6,8,10,11,13,15,17}; -int mapping_odd[] = {17,15,13,11,9, 7, 6, 4, 2, 0}; -int map_coords_to_strip(int row, int column) { - if (column % 2) { - return (10 - column) * 18 + mapping_odd[row]; - } else { - return (10 - column) * 18 + mapping_even [row]; - } -} - -///// Word Table ///// -int WORD_IT_IS[5][2] = {{4,0}, {0,0}, {0,1}, {0,3}, {0,4}}; - -int WORD_QUARTER[8][2] = {{7,0}, {1,2}, {1,3}, {1,4}, {1,5}, {1,6}, {1,7}, {1,8}}; -int WORD_TWENTY[7][2] = {{6,0}, {2,0}, {2,1}, {2,2}, {2,3}, {2,4}, {2,5}}; -int WORD_FIVE_MINUTES[5][2] = {{4,0}, {2,6}, {2,7}, {2,8}, {2,9}}; -int WORD_HALF[5][2] = {{4,0}, {3,0}, {3,1}, {3,2}, {3,3}}; -int WORD_TEN_MINUTES[4][2] = {{3,0}, {3,5}, {3,6}, {3,7}}; - -int WORD_TO[3][2] = {{2,0}, {3,9}, {3,10}}; -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}}; - -// TODO: It's probably unnecessary to have the "API" in CustomAPIDevice, since this -// component doesn't actually register any services anymore. -class Wordclock : public Component, public CustomAPIDevice { - public: - CRGB leds[WORDCLOCK_NUM_LEDS]; - int hour = -1; - int minute = -1; - int second = -1; - int red = 124; - int green = 124; - int blue = 124; - int brightness = 50; - - void setup() override { - FastLED.addLeds(leds, WORDCLOCK_NUM_LEDS); - FastLED.setBrightness(brightness); - clear_all_leds(); - FastLED.show(); - // TODO: Set up some kind of initialization sequence. But it should be based on an effect or similarly supporting the - // cooperative multithreading. delay() calls are uncalled for. - } - - void clear_all_leds() { - for(int i = 0; i < WORDCLOCK_NUM_LEDS; i++) { - leds[i].setRGB(0, 0, 0); - } - } - - 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) { - display_word(WORD_IT_IS, color); - display_hour(hour, minutes, color); - display_minutes(minutes, color); - } - - 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 - if (time.is_valid() == false) { - ESP_LOGD("loop", "time is not valid"); - // do something to show that the clock isn't dead. Maybe I can instantiate and effect and use that for this. - } - else { - 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){ - - clear_all_leds(); - display_time(time.hour, time.minute, CRGB(red, green, blue)); - FastLED.show(); - - ESP_LOGE("loop", "Update Time: %i:%i Brightness: %i RGB: %i-%i-%i", time.hour, time.minute, brightness, red, green, blue); - } - } - } - } -}; diff --git a/wordclock.yaml b/wordclock.yaml deleted file mode 100644 index d3250e1..0000000 --- a/wordclock.yaml +++ /dev/null @@ -1,74 +0,0 @@ -esphome: - name: "${devicename}" - platformio_options: - build_flags: - - -DWORDCLOCK_DATA_PIN=22 - - -DWORDCLOCK_NUM_LEDS=198 - includes: - - wordclock.h - -external_components: - - source: - type: local - path: components - components: [ wordcl ] - -esp8266: - board: d1_mini - framework: - version: recommended - -# esp32: -# board: ttgo-t7-v13-mini32 -# framework: -# type: arduino - -substitutions: - devicename: wordclock - friendly_name: "Wordclock" - light_friendly_name: "Wordclock 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: - - platform: fastled_clockless - id: fastledlight - chipset: WS2812 - pin: 23 - num_leds: 198 - rgb_order: GRB - name: ${light_friendly_name} - restore_mode: ALWAYS_ON - -time: - - platform: sntp - id: current_time - timezone: !secret timezone - -custom_component: - - lambda: |- - auto wordclock = new Wordclock(); - return {wordclock}; - components: - - id: wordclock diff --git a/wordclock8266.yaml b/wordclock8266.yaml deleted file mode 100644 index 5986c77..0000000 --- a/wordclock8266.yaml +++ /dev/null @@ -1,89 +0,0 @@ -esphome: - name: "wordclock" - -esp8266: - board: d1_mini - framework: - version: recommended - -external_components: - - source: - type: local - path: components - components: [ wordcl ] - -# substitutions: -# devicename: wordclock -# friendly_name: "Wordclock" -# light_friendly_name: "Wordclock 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 - -wordclock: - -light: - - name: neopixel - id: neopixel_1 - platform: neopixelbus - type: GRB - variant: WS2812 - pin: GPIO3 - num_leds: 30 - default_transition_length: 0.2s - # restore_mode: RESTORE_DEFAULT_ON - method: - type: esp8266_dma - on_turn_on: - then: - - light.turn_on: - id: neopixel_1 - brightness: 35% - effect: rainbow - effects: - # - random: - # - pulse: - # - strobe: - # - flicker: - - addressable_rainbow: - name: rainbow - # - addressable_color_wipe: - # - addressable_scan: - # - addressable_twinkle: - # - addressable_random_twinkle: - # - addressable_fireworks: - # - addressable_flicker: - # - wled: - - - - -# time: -# - platform: sntp -# id: current_time -# timezone: !secret timezone - -# - light.turn_on: -# id: light_1 -# brightness: 100% -# effect: addressable_rainbow \ No newline at end of file diff --git a/wordclock_new.yaml b/wordclock_new.yaml deleted file mode 100644 index cdaf34e..0000000 --- a/wordclock_new.yaml +++ /dev/null @@ -1,29 +0,0 @@ -esphome: - name: wordclock-livingroom - -esp32: - board: ttgo-t7-v13-mini32 - framework: - type: arduino - -# Enable logging -logger: - -# Enable Home Assistant API -api: - password: "" - -ota: - password: "" - -wifi: - ssid: "wifithing" - password: "lostandfound1" - - # Enable fallback hotspot (captive portal) in case wifi connection fails - ap: - ssid: "Wordclock-Livingroom" - password: "wGfGBPnJcbzE" - -captive_portal: - \ No newline at end of file