diff --git a/common/homethingBase.yaml b/common/homethingBase.yaml new file mode 100644 index 00000000..8d488dc3 --- /dev/null +++ b/common/homethingBase.yaml @@ -0,0 +1,13 @@ +external_components: #include homething, and esphome-components + - source: + type: git + url: https://github.com/landonr/homeThing + ref: main + # type: local + # path: components + refresh: 0s + components: [homeThingDisplayState, homeThing] + - source: github://pr#5214 # used to load images on compile + components: [ image ] + - source: github://pr#5254 # used to load fonts on compile + components: [ font, external_files ] \ No newline at end of file diff --git a/common/homethingMediaPlayerComponents.yaml b/common/homethingMediaPlayerComponents.yaml new file mode 100644 index 00000000..df63f6f1 --- /dev/null +++ b/common/homethingMediaPlayerComponents.yaml @@ -0,0 +1,14 @@ +external_components: + - source: + type: git + url: https://github.com/landonr/esphome-components + ref: main + refresh: 0s + components: [ + homeassistant_component, + homeassistant_media_player, + media_player_source, + media_player_source_sonos, + media_player_source_spotify, + media_player_source_custom + ] \ No newline at end of file diff --git a/components/homeThing/__init__.py b/components/homeThing/__init__.py index a68d706d..b5f59f98 100644 --- a/components/homeThing/__init__.py +++ b/components/homeThing/__init__.py @@ -1,10 +1,12 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome import automation -from esphome.components import display, font, color, binary_sensor, sensor, switch, light, text_sensor, number, cover, time, button, image +from esphome.components import display, binary_sensor, sensor, switch, light, text_sensor, number, cover, time, button from esphome.components.light import LightState -from esphome.const import CONF_ID, CONF_TRIGGER_ID, CONF_MODE, CONF_RED, CONF_BLUE, CONF_GREEN, CONF_NAME, CONF_TYPE, CONF_TIME_ID +from esphome.const import CONF_ID, CONF_TRIGGER_ID, CONF_MODE, CONF_NAME, CONF_TYPE, CONF_TIME_ID from esphome.components.homeassistant_media_player import homeassistant_media_player_ns +from esphome.components.homeThingDisplayState import homething_display_state_ns +# from esphome.components.homeThingApp import homething_app_ns homething_menu_base_ns = cg.esphome_ns.namespace("homething_menu_base") HomeThingMenuBase = homething_menu_base_ns.class_("HomeThingMenuBase", cg.PollingComponent) @@ -14,23 +16,20 @@ HomeThingMenuSettings = homething_menu_base_ns.class_("HomeThingMenuSettings") HomeThingMenuAnimation = homething_menu_base_ns.class_("HomeThingMenuAnimation") HomeThingMenuDisplay = homething_menu_base_ns.class_("HomeThingMenuDisplay") -HomeThingMenuDisplayState = homething_menu_base_ns.class_("HomeThingMenuDisplayState") HomeThingMenuHeader = homething_menu_base_ns.class_("HomeThingMenuHeader") -HomeThingMenuTextHelpers = homething_menu_base_ns.class_("HomeThingMenuTextHelpers") HomeThingMenuRefactor = homething_menu_base_ns.class_("HomeThingMenuRefactor") -HomeThingMenuNowPlaying = homething_menu_base_ns.class_("HomeThingMenuNowPlaying") -HomeThingColorPalette = homething_menu_base_ns.class_("HomeThingColorPalette") HomeThingMenuBaseConstPtr = HomeThingMenuBase.operator("ptr").operator("const") HomeThingDisplayMenuOnRedrawTrigger = homething_menu_base_ns.class_("HomeThingDisplayMenuOnRedrawTrigger", automation.Trigger) +homething_app_ns = cg.esphome_ns.namespace("homething_menu_app") + AUTO_LOAD = ["sensor"] -DEPENDENCIES = ["wifi", "api"] +DEPENDENCIES = ["wifi", "api", "homeThingDisplayState"] CONF_DISPLAY = "display" CONF_MENU_DISPLAY = "menu_display" CONF_DISPLAY_STATE = "display_state" -CONF_TEXT_HELPERS = "text_helpers" CONF_REFACTOR = "refactor_me" CONF_NOW_PLAYING = "now_playing" CONF_API = "api_connected" @@ -53,6 +52,7 @@ CONF_COVER = "cover" CONF_NUMBER = "number" CONF_BUTTON = "button" +CONF_APPS = "apps" # battery settings CONF_CHARGING = "charging" @@ -73,59 +73,18 @@ CONF_LOCK_AFTER = "lock_after" CONF_DISPLAY_TIMEOUT_WHILE_CHARGING = "display_timeout_while_charging" -# display state -CONF_OFF = "off" -CONF_ON = "on" -CONF_ALWAYS = "always" -CONF_FONT_SMALL = "font_small" -CONF_FONT_MEDIUM = "font_medium" -CONF_FONT_LARGE = "font_large" -CONF_FONT_LARGE_HEAVY = "font_large_heavy" -CONF_FONT_MATERIAL_LARGE = "font_material_large" -CONF_FONT_MATERIAL_SMALL = "font_material_small" -CONF_LAUNCH_IMAGE = "launch_image" -CONF_DRAW_NOW_PLAYING_BOTTOM_MENU = "draw_now_playing_bottom_menu" -CONF_HEADER_HEIGHT = "header_height" -CONF_MARGIN_SIZE = "margin_size" -CONF_BOTTOM_BAR_MARGIN = "bottom_bar_margin" -CONF_SLIDER_MARGIN_SIZE = "slider_margin_size" -CONF_ICON_SIZE = "icon_size" -CONF_SCROLL_BAR_WIDTH = "scroll_bar_width" -CONF_BOOT_LOGO_SIZE = "boot_logo_size" -CONF_NOW_PLAYING_MAX_LINES = "now_playing_max_lines" -CONF_FONT_SIZE_WIDTH_RATIO = "font_size_width_ratio" -CONF_DRAW_SHUFFLE = "draw_shuffle" -CONF_DRAW_REPEAT = "draw_repeat" -CONF_DRAW_HEADER_TIME = "draw_header_time" -CONF_DRAW_BATTERY_LEVEL = "draw_battery_level" -CONF_DARK_MODE = "dark_mode" -CONF_DRAW_VOLUME_LEVEL = "draw_volume_level" -CONF_BOOT_DEVICE_NAME = "boot_device_name" - -# colors -CONF_COLORS = "colors" -CONF_GRAY_DARK = "gray_dark" -CONF_GRAY_DARK_2 = "gray_dark_2" -CONF_GRAY = "gray" -CONF_ACCENT_PRIMARY = "accent_primary" -CONF_BLACK = "black" -CONF_WHITE = "white" -CONF_PINK = "pink" -CONF_YELLOW = "yellow" - BOOT_SCHEMA = cv.Schema( { cv.GenerateID(): cv.declare_id(HomeThingMenuBoot), cv.Optional(CONF_API, default="api_connected"): cv.use_id(binary_sensor.BinarySensor), + cv.Optional(CONF_MEDIA_PLAYERS): cv.use_id(homeassistant_media_player_ns.HomeAssistantMediaPlayerGroup), } ) MENU_DISPLAY_SCHEMA = cv.Schema( { cv.GenerateID(): cv.declare_id(HomeThingMenuDisplay), - cv.GenerateID(CONF_TEXT_HELPERS): cv.declare_id(HomeThingMenuTextHelpers), cv.GenerateID(CONF_REFACTOR): cv.declare_id(HomeThingMenuRefactor), - cv.GenerateID(CONF_NOW_PLAYING): cv.declare_id(HomeThingMenuNowPlaying), cv.GenerateID(CONF_HEADER): cv.use_id(HomeThingMenuHeader), } ) @@ -157,77 +116,6 @@ } ) -COLOR_PALETTE_IDS = [ - CONF_GRAY_DARK, - CONF_GRAY_DARK_2, - CONF_GRAY, - CONF_ACCENT_PRIMARY, - CONF_BLUE, - CONF_GREEN, - CONF_BLACK, - CONF_WHITE, - CONF_PINK, - CONF_RED, - CONF_YELLOW -] - -COLOR_SCHEMA = cv.Schema( - { - cv.GenerateID(): cv.declare_id(HomeThingColorPalette), - cv.Optional(CONF_GRAY_DARK): cv.use_id(color.ColorStruct), - cv.Optional(CONF_GRAY_DARK_2): cv.use_id(color.ColorStruct), - cv.Optional(CONF_GRAY): cv.use_id(color.ColorStruct), - cv.Optional(CONF_ACCENT_PRIMARY): cv.use_id(color.ColorStruct), - cv.Optional(CONF_BLUE): cv.use_id(color.ColorStruct), - cv.Optional(CONF_GREEN): cv.use_id(color.ColorStruct), - cv.Optional(CONF_BLACK): cv.use_id(color.ColorStruct), - cv.Optional(CONF_WHITE): cv.use_id(color.ColorStruct), - cv.Optional(CONF_PINK): cv.use_id(color.ColorStruct), - cv.Optional(CONF_RED): cv.use_id(color.ColorStruct), - cv.Optional(CONF_YELLOW): cv.use_id(color.ColorStruct), - }, - cv.has_at_least_one_key() -) - -DisplayIconEnabledState = homething_menu_base_ns.enum("DisplayIconEnabledState") - -DISPLAY_ICON_MODES = { - CONF_OFF: DisplayIconEnabledState.OFF, - CONF_ON: DisplayIconEnabledState.ON, - CONF_ALWAYS: DisplayIconEnabledState.ALWAYS, -} - -DISPLAY_STATE_SCHEMA = cv.Schema( - { - cv.GenerateID(): cv.declare_id(HomeThingMenuDisplayState), - cv.Required(CONF_FONT_SMALL): cv.use_id(font.Font), - cv.Required(CONF_FONT_MEDIUM): cv.use_id(font.Font), - cv.Required(CONF_FONT_LARGE): cv.use_id(font.Font), - cv.Required(CONF_FONT_LARGE_HEAVY): cv.use_id(font.Font), - cv.Required(CONF_FONT_MATERIAL_LARGE): cv.use_id(font.Font), - cv.Required(CONF_FONT_MATERIAL_SMALL): cv.use_id(font.Font), - cv.Optional(CONF_LAUNCH_IMAGE, default={}): cv.use_id(image.Image_), - cv.Optional(CONF_HEADER_HEIGHT, default=16): cv.int_, - cv.Optional(CONF_MARGIN_SIZE, default=4): cv.int_, - cv.Optional(CONF_BOTTOM_BAR_MARGIN, default=1): cv.int_, - cv.Optional(CONF_SLIDER_MARGIN_SIZE, default=8): cv.int_, - cv.Optional(CONF_ICON_SIZE, default=18): cv.int_, - cv.Optional(CONF_SCROLL_BAR_WIDTH, default=6): cv.int_, - cv.Optional(CONF_BOOT_LOGO_SIZE, default=48): cv.int_, - cv.Optional(CONF_NOW_PLAYING_MAX_LINES, default=5): cv.int_, - cv.Optional(CONF_FONT_SIZE_WIDTH_RATIO, default=0.6): cv.float_, - cv.Optional(CONF_DRAW_SHUFFLE, default=CONF_ON): cv.enum(DISPLAY_ICON_MODES), - cv.Optional(CONF_DRAW_REPEAT, default=CONF_ON): cv.enum(DISPLAY_ICON_MODES), - cv.Optional(CONF_DRAW_HEADER_TIME, default=True): cv.boolean, - cv.Optional(CONF_DRAW_BATTERY_LEVEL, default=False): cv.boolean, - cv.Optional(CONF_DARK_MODE, default=True): cv.boolean, - cv.Optional(CONF_DRAW_VOLUME_LEVEL, default=False): cv.boolean, - cv.Optional(CONF_DRAW_NOW_PLAYING_BOTTOM_MENU, default=False): cv.boolean, - cv.Optional(CONF_BOOT_DEVICE_NAME, default="homeThing"): cv.string, - cv.Optional(CONF_COLORS, default={}): COLOR_SCHEMA, - } -) - HEADER_SCHEMA = cv.Schema( { cv.GenerateID(): cv.declare_id(HomeThingMenuHeader), @@ -315,10 +203,12 @@ cv.Optional(CONF_SLEEP_SWITCH): cv.use_id(switch.Switch), cv.Optional(CONF_BATTERY): BATTERY_SCHEMA, cv.Optional(CONF_BACKLIGHT): cv.use_id(light.LightState), - cv.Required(CONF_DISPLAY_STATE): DISPLAY_STATE_SCHEMA, + cv.Required(CONF_DISPLAY_STATE): cv.use_id(homething_display_state_ns.HomeThingDisplayState), cv.Optional(CONF_HEADER, default={}): HEADER_SCHEMA, cv.Optional(CONF_MENU_DISPLAY, default={}): MENU_DISPLAY_SCHEMA, - cv.Optional(CONF_MEDIA_PLAYERS): cv.use_id(homeassistant_media_player_ns.HomeAssistantMediaPlayerGroup), + cv.Optional(CONF_APPS): cv.All( + cv.ensure_list(cv.use_id(homething_app_ns.HomeThingApp)), cv.Length(min=1) + ), cv.Optional(CONF_BOOT, default={}): BOOT_SCHEMA, cv.Optional(CONF_ON_REDRAW): automation.validate_automation( { @@ -333,7 +223,7 @@ ), } ).extend(cv.polling_component_schema("1s")), - cv.has_at_least_one_key(CONF_MEDIA_PLAYERS, CONF_HOME_SCREEN, CONF_SCREENS) + cv.has_at_least_one_key(CONF_HOME_SCREEN, CONF_SCREENS) ) async def ids_to_code(config, var, types): @@ -363,62 +253,14 @@ async def menu_settings_to_code(config): keys_to_code(config, menu_settings, MENU_SETTING_TYPES) return menu_settings -DISPLAY_STATE_IDS = [ - CONF_FONT_SMALL, - CONF_FONT_MEDIUM, - CONF_FONT_LARGE, - CONF_FONT_LARGE_HEAVY, - CONF_FONT_MATERIAL_LARGE, - CONF_FONT_MATERIAL_SMALL, - CONF_LAUNCH_IMAGE -] - -DISPLAY_STATE_TYPES = [ - CONF_DRAW_NOW_PLAYING_BOTTOM_MENU, - CONF_HEADER_HEIGHT, - CONF_MARGIN_SIZE, - CONF_BOTTOM_BAR_MARGIN, - CONF_SLIDER_MARGIN_SIZE, - CONF_ICON_SIZE, - CONF_SCROLL_BAR_WIDTH, - CONF_BOOT_LOGO_SIZE, - CONF_NOW_PLAYING_MAX_LINES, - CONF_FONT_SIZE_WIDTH_RATIO, - CONF_DRAW_SHUFFLE, - CONF_DRAW_REPEAT, - CONF_DRAW_HEADER_TIME, - CONF_DRAW_BATTERY_LEVEL, - CONF_DARK_MODE, - CONF_DRAW_VOLUME_LEVEL, - CONF_BOOT_DEVICE_NAME -] - -async def display_state_to_code(config): - - display_state = cg.new_Pvariable(config[CONF_ID]) - keys_to_code(config, display_state, DISPLAY_STATE_TYPES) - await ids_to_code(config, display_state, DISPLAY_STATE_IDS) - - if CONF_COLORS in config: - color_palette = cg.new_Pvariable(config[CONF_COLORS][CONF_ID]) - await ids_to_code(config[CONF_COLORS], color_palette, COLOR_PALETTE_IDS) - cg.add(display_state.set_color_palette(color_palette)) - return display_state - -async def text_helpers_to_code(config, display_buffer, display_state): - text_helpers = cg.new_Pvariable(config) - cg.add(text_helpers.set_display_buffer(display_buffer)) - cg.add(text_helpers.set_display_state(display_state)) - return text_helpers - MENU_BOOT_IDS = [ CONF_API, CONF_MEDIA_PLAYERS ] -async def menu_boot_to_code(config, display_buffer, display_state, menu_header, text_helpers): - menu_boot = cg.new_Pvariable(config[CONF_ID], display_buffer, display_state, menu_header, text_helpers) - await ids_to_code(config, menu_boot, MENU_BOOT_IDS) +async def menu_boot_to_code(config, display_buffer, display_state, menu_header): + menu_boot = cg.new_Pvariable(config[CONF_BOOT][CONF_ID], display_buffer, display_state, menu_header) + await ids_to_code(config[CONF_BOOT], menu_boot, MENU_BOOT_IDS) return menu_boot BATTERY_IDS = [ @@ -430,38 +272,20 @@ async def battery_to_code(config, var): if CONF_BATTERY in config: await ids_to_code(config[CONF_BATTERY], var, BATTERY_IDS) -NOW_PLAYING_IDS = [ - CONF_MEDIA_PLAYERS -] -MENU_HEADER_IDS = [ - CONF_MEDIA_PLAYERS -] -MENU_DISPLAY_IDS = [ - CONF_MEDIA_PLAYERS -] - -async def menu_display_to_code(config, display_buffer): +async def menu_display_to_code(config, display_buffer, display_state): menu_display_conf = config[CONF_MENU_DISPLAY] - display_state = await display_state_to_code(config[CONF_DISPLAY_STATE]) - text_helpers = await text_helpers_to_code(menu_display_conf[CONF_TEXT_HELPERS], display_buffer, display_state) - refactor = cg.new_Pvariable(menu_display_conf[CONF_REFACTOR], display_buffer, display_state, text_helpers) - menu_header = cg.new_Pvariable(menu_display_conf[CONF_HEADER], display_buffer, display_state, text_helpers) - await ids_to_code(config, menu_header, MENU_HEADER_IDS) + refactor = cg.new_Pvariable(menu_display_conf[CONF_REFACTOR], display_buffer, display_state) + menu_header = cg.new_Pvariable(menu_display_conf[CONF_HEADER], display_buffer, display_state) if CONF_TIME_ID in config[CONF_HEADER]: time_ = await cg.get_variable(config[CONF_HEADER][CONF_TIME_ID]) cg.add(menu_header.set_time_id(time_)) await battery_to_code(config, menu_header) - menu_boot = await menu_boot_to_code(config[CONF_BOOT], display_buffer, display_state, menu_header, text_helpers) + menu_boot = await menu_boot_to_code(config, display_buffer, display_state, menu_header) await ids_to_code(config, menu_boot, MENU_BOOT_IDS) - menu_display = cg.new_Pvariable(menu_display_conf[CONF_ID], menu_boot, display_buffer, display_state, text_helpers, refactor, menu_header) - await ids_to_code(config, menu_display, MENU_DISPLAY_IDS) - - if CONF_MEDIA_PLAYERS in config: - now_playing = cg.new_Pvariable(menu_display_conf[CONF_NOW_PLAYING], display_buffer, display_state, text_helpers) - await ids_to_code(config, now_playing, NOW_PLAYING_IDS) - cg.add(menu_display.set_now_playing(now_playing)) + menu_display = cg.new_Pvariable(menu_display_conf[CONF_ID], menu_boot, display_buffer, display_state, refactor, menu_header) + return menu_display async def menu_screen_to_code(config): @@ -506,13 +330,13 @@ async def menu_screen_to_code(config): MENU_IDS = [ CONF_BACKLIGHT, - CONF_SLEEP_SWITCH, - CONF_MEDIA_PLAYERS + CONF_SLEEP_SWITCH ] async def to_code(config): display_buffer = await cg.get_variable(config[CONF_DISPLAY]) - menu_display = await menu_display_to_code(config, display_buffer) + display_state = await cg.get_variable(config[CONF_DISPLAY_STATE]) + menu_display = await menu_display_to_code(config, display_buffer, display_state) menu_settings = await menu_settings_to_code(config[CONF_SETTINGS]) @@ -527,6 +351,11 @@ async def to_code(config): menu_screen = await menu_screen_to_code(conf) cg.add(menu.register_screen(menu_screen)) + # if CONF_APPS in config: + # for app in config[CONF_APPS]: + # new_app = await cg.get_variable(app) + # cg.add(menu.register_app(new_app)) + await battery_to_code(config, menu) await ids_to_code(config, menu, MENU_IDS) diff --git a/components/homeThing/homeThingMenuBase.cpp b/components/homeThing/homeThingMenuBase.cpp index 54af114a..15c63d91 100644 --- a/components/homeThing/homeThingMenuBase.cpp +++ b/components/homeThing/homeThingMenuBase.cpp @@ -7,6 +7,11 @@ namespace homething_menu_base { void HomeThingMenuBase::setup() { menu_display_->set_animation(animation_); + menu_display_->add_on_state_callback([this]() { + ESP_LOGI(TAG, "menu_display_->add_on_state_callback"); + this->update_display(); + }); + this->animation_->animationTick->add_on_state_callback( [this](float state) { this->displayUpdateDebounced(); }); @@ -27,8 +32,8 @@ void HomeThingMenuBase::setup() { } }); } - if (home_sceen_) { - home_sceen_->add_on_state_callback([this]() { + if (home_screen_) { + home_screen_->add_on_state_callback([this]() { switch (menuTree.back()) { case rootMenu: reload_menu_items_ = true; @@ -38,27 +43,6 @@ void HomeThingMenuBase::setup() { } }); } -#ifdef USE_MEDIA_PLAYER_GROUP - circle_menu_->set_bottom_menu(menu_display_->get_draw_now_playing_menu()); - if (this->media_player_group_) { - this->media_player_group_->add_on_state_callback([this](float state) { - switch (menuTree.back()) { - case bootMenu: - ESP_LOGI(TAG, "draw_menu_screen: update display boot"); - this->update_display(); - break; - case nowPlayingMenu: - case groupMenu: - ESP_LOGI(TAG, "draw_menu_screen: update display"); - reload_menu_items_ = true; - this->displayUpdateDebounced(); - break; - default: - break; - } - }); - } -#endif } void HomeThingMenuBase::draw_menu_screen() { @@ -71,7 +55,7 @@ void HomeThingMenuBase::draw_menu_screen() { if (menu_drawing_) { return; } - if (menuTree.front() == bootMenu && menu_display_->boot_->boot_complete()) { + if (menuTree.front() == bootMenu && menu_display_->boot_complete()) { finish_boot(); return; } @@ -79,8 +63,9 @@ void HomeThingMenuBase::draw_menu_screen() { auto title_name = menu_state_title(activeMenuState); if (reload_menu_items_ || (menu_titles.size() == 0 && activeMenuState != bootMenu)) { - ESP_LOGD(TAG, "draw_menu_screen: reload %d %s #%d", menuIndex, - title_name.c_str(), menu_titles.size()); + ESP_LOGI(TAG, "draw_menu_screen: reload %d index %d %s #%d", + reload_menu_items_, menuIndex, title_name.c_str(), + menu_titles.size()); for (auto title : menu_titles) { delete title; } @@ -90,14 +75,26 @@ void HomeThingMenuBase::draw_menu_screen() { } ESP_LOGD(TAG, "draw_menu_screen: draw %d %s #%d", menuIndex, title_name.c_str(), menu_titles.size()); -#ifdef USE_MEDIA_PLAYER_GROUP - if (menu_display_->draw_menu_screen(&activeMenuState, &menu_titles, menuIndex, - circle_menu_->get_active_menu(), - editing_menu_item)) { -#else + +#ifdef USE_HOMETHING_APP + if (active_app_ != nullptr) { + ESP_LOGI(TAG, "draw_menu_screen: draw header %d %s #%d", menuIndex, + title_name.c_str(), menu_titles.size()); + menu_display_->draw_menu_header(active_app_->get_header_source()); + } + if (active_app_ != nullptr && active_app_->should_draw_app()) { + active_app_->draw_app(menuIndex, &menu_titles); + this->animation_->animating = active_app_->is_animating(); + if (this->animation_->animating) { + this->animation_->tickAnimation(); + } + menu_drawing_ = false; + return; + } +#endif + if (menu_display_->draw_menu_screen(&activeMenuState, &menu_titles, menuIndex, nullptr, editing_menu_item)) { -#endif this->animation_->tickAnimation(); this->animation_->animating = true; } else { @@ -132,55 +129,10 @@ bool HomeThingMenuBase::selectMenu() { switch (menuTree.back()) { case rootMenu: return selectRootMenu(); - case nowPlayingMenu: -#ifdef USE_MEDIA_PLAYER_GROUP - menuTree.push_back(nowPlayingMenu); -#endif - break; - case sourcesMenu: { -#ifdef USE_MEDIA_PLAYER_GROUP - if (activeMenuTitle->titleType == SourceMenuTitleType) { - const auto sourceTitleState = - static_cast(activeMenuTitle); - auto source = sourceTitleState->media_source_; - const auto new_source = new media_player_source::MediaPlayerSourceItem( - source->get_name(), source->get_media_content_id(), - source->get_media_type()); - media_player_group_->playSource(new_source); - idleMenu(true); - circle_menu_->set_active_menu(playingNewSourceMenu, - media_player_group_->active_player_); - update_display(); - } else { - media_player_group_->set_active_player_source_index(menuIndex); - menuIndex = 0; - update_display(); - } -#endif - break; - } - case groupMenu: { -#ifdef USE_MEDIA_PLAYER_GROUP - auto playerTitleState = static_cast(activeMenuTitle); - media_player_group_->selectGroup(playerTitleState->media_player_, - menuIndex); -#endif - break; - } case lightsDetailMenu: ESP_LOGI(TAG, "selectMenu: began editing light detail"); editing_menu_item = true; break; - case mediaPlayersMenu: { -#ifdef USE_MEDIA_PLAYER_GROUP - auto media_player_title = static_cast(activeMenuTitle); - if (media_player_group_->selectMediaPlayers( - media_player_title->media_player_)) { - topMenu(); - } -#endif - break; - } case settingsMenu: if (active_menu_screen && active_menu_screen->select_menu(menuIndex)) { auto selected_entity = active_menu_screen->get_selected_entity(); @@ -192,8 +144,36 @@ bool HomeThingMenuBase::selectMenu() { update_display(); } break; + case appMenu: +#ifdef USE_HOMETHING_APP + ESP_LOGI(TAG, "selectMenu: select app menu %d", menuIndex); + if (active_app_) { + switch (active_app_->app_menu_select(menuIndex)) { + case homething_menu_app::NavigationCoordination:: + NavigationCoordinationNone: + return false; + case homething_menu_app::NavigationCoordination:: + NavigationCoordinationUpdate: + return true; + case homething_menu_app::NavigationCoordination:: + NavigationCoordinationPop: + menuTree.pop_back(); + menuIndex = 0; + if (menuTree.size() == 1) { + reset_menu(); + return true; + } + return true; + case homething_menu_app::NavigationCoordination:: + NavigationCoordinationRoot: + topMenu(); + return true; + } + } +#endif + return false; default: - ESP_LOGW(TAG, "menu state is bad but its an enum"); + ESP_LOGW(TAG, "selectMenu: menu state is bad but its an enum"); return false; } return true; @@ -202,11 +182,9 @@ bool HomeThingMenuBase::selectMenu() { bool HomeThingMenuBase::selectLightEntity( const std::tuple* menu_item) { MenuItemType menu_item_type = std::get<0>(*menu_item); - ESP_LOGW(TAG, "selectLightEntity: %d type: %d, static count: %d", menuIndex, - menu_item_type, static_menu_titles); + ESP_LOGW(TAG, "selectLightEntity: %d type: %d", menuIndex, menu_item_type); if (menu_item_type == MenuItemTypeLight) { - ESP_LOGW(TAG, "selectLightEntit2y: %d type: %d, static count: %d", - menuIndex, menu_item_type, static_menu_titles); + ESP_LOGW(TAG, "selectLightEntit2y: %d type: %d", menuIndex, menu_item_type); #ifdef USE_LIGHT auto light = static_cast(std::get<1>(*menu_item)); ESP_LOGW(TAG, "selectMenuHold: name %s", light->get_name().c_str()); @@ -226,14 +204,24 @@ bool HomeThingMenuBase::selectMenuHold() { ESP_LOGW(TAG, "selectMenuHold: %d", menuIndex); switch (menuTree.back()) { case rootMenu: { - if (home_sceen_) { - int index = menuIndex - static_menu_titles; - auto menu_item = home_sceen_->get_menu_item(index); - ESP_LOGW(TAG, "selectMenuHold: %d type: %d, name %s type %s", index, - std::get<0>(*menu_item), - home_sceen_->entity_name_at_index(index).c_str(), - nameForMenuItemType(std::get<0>(*menu_item)).c_str()); - return selectLightEntity(menu_item); + if (home_screen_) { + int offset = 0; +#ifdef USE_HOMETHING_APP + for (auto& menu_app : menu_apps_) { + offset = offset + menu_app->root_menu_size(); + } +#endif + int index = menuIndex - offset; + ESP_LOGW(TAG, "selectMenuHold: %d offset %d index %d", menuIndex, + offset, index); + if (menuIndex >= offset && index < home_screen_->get_entity_count()) { + auto menu_item = home_screen_->get_menu_item(index); + ESP_LOGW(TAG, "selectMenuHold: %d type: %d, name %s type %s", index, + std::get<0>(*menu_item), + home_screen_->entity_name_at_index(index).c_str(), + nameForMenuItemType(std::get<0>(*menu_item)).c_str()); + return selectLightEntity(menu_item); + } } break; } @@ -250,61 +238,41 @@ bool HomeThingMenuBase::selectMenuHold() { return false; } -std::vector HomeThingMenuBase::rootMenuTitles() { - std::vector out; -#ifdef USE_MEDIA_PLAYER_GROUP - if (media_player_group_) { - if (media_player_group_->totalPlayers() > 1) { - out.insert(out.end(), {nowPlayingMenu, sourcesMenu, mediaPlayersMenu}); - } else { - out.insert(out.end(), {nowPlayingMenu, sourcesMenu}); +bool HomeThingMenuBase::selectRootMenu() { + int offset = 0; +#ifdef USE_HOMETHING_APP + for (auto& menu_app : menu_apps_) { + int appMenuSize = menu_app->root_menu_size(); + if (menuIndex < (offset + appMenuSize)) { + ESP_LOGI(TAG, "selectRootMenu: app %d offset %d", menuIndex, offset); + menuTree.push_back(appMenu); + active_app_ = menu_app; + active_app_->set_app_menu_index(menuIndex - offset); + menuIndex = 0; + return true; } + offset += appMenuSize; } #endif - return out; -} - -bool HomeThingMenuBase::selectRootMenu() { - if (menuIndex < static_menu_titles) { - MenuStates currentMenu = rootMenuTitles()[menuIndex]; - ESP_LOGW(TAG, "select_root_menu: selecting menu %d %s of %d", menuIndex, - menu_state_title(menuTree.back()).c_str(), - rootMenuTitles().size()); - switch (currentMenu) { - case sourcesMenu: - menuTree.push_back(sourcesMenu); - break; - case nowPlayingMenu: - menuTree.push_back(nowPlayingMenu); - break; - case mediaPlayersMenu: - menuTree.push_back(mediaPlayersMenu); - break; - case entityMenu: - case settingsMenu: - case lightsDetailMenu: - case groupMenu: - case rootMenu: - case bootMenu: - ESP_LOGW(TAG, "select_root_menu: selecting menu is bad %d %s", - menuIndex, menu_state_title(menuTree.back()).c_str()); - menuIndex = 0; - return false; + int index = menuIndex - offset; + if (home_screen_ && index < home_screen_->get_entity_count()) { + ESP_LOGI(TAG, "selectRootMenu: home screen %d offset %d", menuIndex, + offset); + if (!home_screen_->select_menu(index)) { + // update_display(); + return false; } } else { - int index = menuIndex - static_menu_titles; - if (home_sceen_ && index < home_sceen_->get_entity_count()) { - if (home_sceen_->select_menu(index)) { - update_display(); - return false; - } - } else { - menuTree.push_back(settingsMenu); - int offset = home_sceen_ - ? home_sceen_->get_entity_count() + static_menu_titles - : static_menu_titles; - active_menu_screen = menu_screens_[menuIndex - offset]; - } + ESP_LOGI(TAG, "selectRootMenu: screen %d offset %d", menuIndex, offset); + menuTree.push_back(settingsMenu); + int home_screen_count = home_screen_ ? home_screen_->get_entity_count() : 0; + offset = home_screen_count + offset; + index = menuIndex - offset; + ESP_LOGI(TAG, + "selectRootMenu: 3 %d new offset %d menu screens %d index %d home " + "screen count %d", + menuIndex, offset, menu_screens_.size(), index, home_screen_count); + active_menu_screen = menu_screens_[index]; } menuIndex = 0; return true; @@ -313,53 +281,41 @@ bool HomeThingMenuBase::selectRootMenu() { MenuTitleBase* HomeThingMenuBase::menuTitleForType(MenuStates stringType, int index) { if (stringType == settingsMenu && menu_screens_.size() > 0) { - int offset = home_sceen_ - ? home_sceen_->get_entity_count() + static_menu_titles - : static_menu_titles; + int offset = home_screen_ ? home_screen_->get_entity_count() : 0; HomeThingMenuScreen* menu_screen = menu_screens_[index - offset]; std::string menu_name = menu_screen->get_name(); return new MenuTitleBase(menu_name, "", ArrowMenuTitleRightIcon); - } else if (stringType == entityMenu && home_sceen_) { - int offset = static_menu_titles; - std::string menu_name = home_sceen_->entity_name_at_index(index - offset); + } else if (stringType == entityMenu && home_screen_) { + std::string menu_name = home_screen_->entity_name_at_index(index); return new MenuTitleBase(menu_name, "", NoMenuTitleRightIcon); } return new MenuTitleBase(menu_state_title(stringType), "", menu_state_right_icon(stringType)); } -void HomeThingMenuBase::menuTypesToTitles( - std::vector menu, std::vector* menu_titles) { - for (int i = 0; i < menu.size(); i++) { - auto menuItem = menu[i]; - (*menu_titles).push_back(menuTitleForType(menuItem, i)); - } -} - void HomeThingMenuBase::finish_boot() { ESP_LOGI(TAG, "finish_boot: finished boot %d", menuTree.size()); menuTree.assign(1, rootMenu); idleTime = 0; topMenu(); + menu_display_->clearBoot(); } void HomeThingMenuBase::activeMenu(std::vector* menu_titles) { -#ifdef USE_MEDIA_PLAYER_GROUP - if (media_player_group_ && media_player_group_->playerSearchFinished && - menuTree.back() == bootMenu) { - finish_boot(); - } -#endif switch (menuTree.back()) { case rootMenu: { - menuTypesToTitles(rootMenuTitles(), menu_titles); - static_menu_titles = menu_titles->size(); - if (home_sceen_) { - // for (int i = 0; i < home_sceen_->get_entity_count(); i++) { +#ifdef USE_HOMETHING_APP + ESP_LOGD(TAG, "activeMenu: root menu apps %d", menu_apps_.size()); + for (auto& menu_app : menu_apps_) { + menu_app->rootMenuTitles(menu_titles); + } +#endif + if (home_screen_) { + // for (int i = 0; i < home_screen_->get_entity_count(); i++) { // out.push_back(entityMenu); // } - home_sceen_->menu_titles(menu_titles, false); - active_menu_screen = home_sceen_; + home_screen_->menu_titles(menu_titles, false); + active_menu_screen = home_screen_; } for (auto& menu_screen : menu_screens_) { std::string menu_name = menu_screen->get_name(); @@ -368,33 +324,6 @@ void HomeThingMenuBase::activeMenu(std::vector* menu_titles) { } return; } - case sourcesMenu: { -#ifdef USE_MEDIA_PLAYER_GROUP - const auto sources = media_player_group_->activePlayerSources(); - const auto index = media_player_group_->get_active_player_source_index(); - if (index == -1 && sources->size() > 1) { - activePlayerSourceTitles(sources, menu_titles); - return; - } else if (index == -1 && sources->size() == 1) { - auto playerSources = (*sources)[0]->get_sources(); - activePlayerSourceItemTitles(playerSources, menu_titles); - return; - } else if (sources->size() > 1) { - auto playerSources = (*sources)[index]->get_sources(); - activePlayerSourceItemTitles(playerSources, menu_titles); - return; - } -#endif - break; - } - case mediaPlayersMenu: { -#ifdef USE_MEDIA_PLAYER_GROUP - mediaPlayersTitleString(media_player_group_->get_media_players(), - menu_titles); - return; -#endif - break; - } case lightsDetailMenu: { #ifdef USE_LIGHT auto selectedEntity = active_menu_screen->get_selected_entity(); @@ -407,27 +336,6 @@ void HomeThingMenuBase::activeMenu(std::vector* menu_titles) { } else { return; } -#endif - break; - } - case nowPlayingMenu: -#ifdef USE_MEDIA_PLAYER_GROUP - speakerNowPlayingMenuStates(media_player_group_->active_player_, - menu_display_->get_draw_now_playing_menu(), - menu_titles); - return; -#endif - break; - case groupMenu: { -#ifdef USE_MEDIA_PLAYER_GROUP - if (media_player_group_->newSpeakerGroupParent != NULL) { - return groupTitleSwitches(media_player_group_->get_media_players(), - media_player_group_->newSpeakerGroupParent, - menu_titles); - return; - } - groupTitleString(media_player_group_->get_media_players(), menu_titles); - return; #endif break; } @@ -435,6 +343,14 @@ void HomeThingMenuBase::activeMenu(std::vector* menu_titles) { break; case settingsMenu: active_menu_screen->menu_titles(menu_titles, true); + break; + case appMenu: +#ifdef USE_HOMETHING_APP + if (active_app_) { + active_app_->app_menu_titles(menu_titles); + } +#endif + return; default: ESP_LOGW(TAG, "activeMenu: menu is bad %d, %s", menuIndex, menu_state_title(menuTree.back()).c_str()); @@ -442,6 +358,35 @@ void HomeThingMenuBase::activeMenu(std::vector* menu_titles) { } } +bool HomeThingMenuBase::skipBootPressed() { + switch (menuTree.back()) { + case bootMenu: { + switch (menu_display_->bootSequenceCanSkip(menuTree.back())) { + case BOOT_MENU_SKIP_STATE_SLEEP: + ESP_LOGI(TAG, "skipBootPressed: sleep"); +#ifdef USE_SWITCH + sleep_switch_->turn_on(); +#endif + return true; + case BOOT_MENU_SKIP_STATE_MENU: + ESP_LOGI(TAG, "skipBootPressed: menu"); + // #ifdef USE_MEDIA_PLAYER_GROUP + // media_player_group_->selectFirstActivePlayer(); + // #endif + finish_boot(); + return true; + case BOOT_MENU_SKIP_STATE_NONE: + ESP_LOGI(TAG, "skipBootPressed: none"); + break; + } + break; + } + default: + break; + } + return false; +} + bool HomeThingMenuBase::buttonPressWakeUpDisplay() { if (idleTime != -1) { idleTime = 0; @@ -466,95 +411,38 @@ bool HomeThingMenuBase::buttonPressWakeUpDisplay() { return false; } -#ifdef USE_MEDIA_PLAYER_GROUP -void HomeThingMenuBase::selectNowPlayingMenu() { - if (menu_titles.size() <= 0 && menuIndex < menu_titles.size()) { - ESP_LOGI(TAG, "selectNowPlayingMenu: select menu %d", menuIndex); - return; - } - auto features = media_player_group_->active_player_->get_option_menu_features( - menu_display_->get_draw_now_playing_menu()); - auto active_feature = (*features)[menuIndex]; - ESP_LOGI(TAG, "selectNowPlayingMenu: %d, %s", menuIndex, - active_feature->get_title().c_str()); - switch (active_feature->get_feature()) { - case homeassistant_media_player::MediaPlayerSupportedFeature::VOLUME_SET: - case homeassistant_media_player::MediaPlayerSupportedFeature::VOLUME_UP: - case homeassistant_media_player::MediaPlayerSupportedFeature::VOLUME_DOWN: - circle_menu_->set_active_menu(volumeOptionMenu, - media_player_group_->active_player_); - break; - case homeassistant_media_player::MediaPlayerSupportedFeature::GROUPING: - menuIndex = 0; - menuTree.push_back(groupMenu); - break; - default: - break; - } - select_media_player_feature(active_feature); - update_display(); -} - -bool HomeThingMenuBase::select_media_player_feature( - homeassistant_media_player::MediaPlayerFeatureCommand* command) { - auto feature = command->get_feature(); - switch (feature) { - case homeassistant_media_player::MediaPlayerSupportedFeature::MENU_HOME: - topMenu(); - return true; - case homeassistant_media_player::MediaPlayerSupportedFeature::GROUPING: - menuIndex = 0; - menuTree.push_back(groupMenu); - return true; - case homeassistant_media_player::MediaPlayerSupportedFeature:: - CUSTOM_COMMAND: { - auto feature_command = command->get_command(); - if (feature_command != nullptr) { - feature_command->on_command(); - return true; - } - } - - default: - media_player_group_->call_feature(feature); - break; - } - return false; -} - -bool HomeThingMenuBase::button_press_now_playing_option_continue( - CircleOptionMenuPosition position) { - if (circle_menu_->get_active_menu()) { - auto feature = circle_menu_->tap_option_menu( - position, media_player_group_->get_active_player()); - if (feature) { - ESP_LOGI( - TAG, - "button_press_now_playing_option_continue: option menu selected %d", - feature->get_feature()); - circle_menu_->clear_active_menu(); - if (!select_media_player_feature(feature)) { - return false; - } - reload_menu_items_ = true; - update_display(); - return false; - } - ESP_LOGW( - TAG, - "button_press_now_playing_option_continue: option menu NOT selected"); - return false; - } - return true; -} -#endif - void HomeThingMenuBase::buttonPressSelect() { if (!button_press_and_continue()) return; reload_menu_items_ = true; if (menu_settings_->get_mode() == MENU_MODE_ROTARY) { switch (menuTree.back()) { + case appMenu: +#ifdef USE_HOMETHING_APP + if (active_app_ && active_app_->should_draw_app()) { + switch (active_app_->buttonPressSelect(menuIndex)) { + case homething_menu_app::NavigationCoordination:: + NavigationCoordinationReturn: + return; + case homething_menu_app::NavigationCoordination:: + NavigationCoordinationNone: + break; + case homething_menu_app::NavigationCoordination:: + NavigationCoordinationUpdate: + update_display(); + return; + case homething_menu_app::NavigationCoordination:: + NavigationCoordinationPop: + upMenu(); + return; + case homething_menu_app::NavigationCoordination:: + NavigationCoordinationRoot: + topMenu(); + return; + } + } +#endif + break; case lightsDetailMenu: case settingsMenu: if (editing_menu_item) { @@ -565,26 +453,6 @@ void HomeThingMenuBase::buttonPressSelect() { return; } break; - case nowPlayingMenu: -#ifdef USE_MEDIA_PLAYER_GROUP - if (!button_press_now_playing_option_continue( - CircleOptionMenuPosition::CENTER)) - return; - - switch (media_player_group_->active_player_->get_player_type()) { - case homeassistant_media_player::RemotePlayerType::TVRemotePlayerType: - media_player_group_->sendActivePlayerRemoteCommand( - homeassistant_media_player::MediaPlayerTVRemoteCommand::SELECT); - break; - case homeassistant_media_player::RemotePlayerType:: - SpeakerRemotePlayerType: - break; - } - if (menu_display_->get_draw_now_playing_menu()) { - selectNowPlayingMenu(); - } -#endif - return; default: break; } @@ -602,11 +470,6 @@ void HomeThingMenuBase::buttonPressSelect() { } #endif break; - case nowPlayingMenu: -#ifdef USE_MEDIA_PLAYER_GROUP - selectNowPlayingMenu(); -#endif - return; default: break; } @@ -649,24 +512,20 @@ void HomeThingMenuBase::rotaryScrollCounterClockwise(int rotary) { if (!button_press_and_continue()) return; rotary_ = rotary; - if (menuIndex == 0 && menu_settings_->get_menu_rollback() && - menuTree.back() != nowPlayingMenu) { + if (menuIndex == 0 && menu_settings_->get_menu_rollback()) { + // && menuTree.back() != nowPlayingMenu) { upMenu(); return; } if (menu_settings_->get_mode() == MENU_MODE_ROTARY) { switch (menuTree.back()) { - case nowPlayingMenu: -#ifdef USE_MEDIA_PLAYER_GROUP - if (menu_display_->get_draw_now_playing_menu()) { - break; + case appMenu: +#ifdef USE_HOMETHING_APP + if (active_app_ && active_app_->should_draw_app()) { + active_app_->rotaryScrollCounterClockwise(rotary); } - media_player_group_->decreaseSpeakerVolume(); - circle_menu_->set_active_menu(volumeOptionMenu, - media_player_group_->active_player_); - debounceUpdateDisplay(); #endif - return; + break; case lightsDetailMenu: #ifdef USE_LIGHT if (HomeThingMenuControls::editingScrollBack( @@ -714,8 +573,8 @@ void HomeThingMenuBase::rotaryScrollCounterClockwise(int rotary) { if (menuIndex > 0) { menuIndex--; - } else if (menuTree.back() == nowPlayingMenu) { - menuIndex = menu_titles.size() - 1; + // } else if (menuTree.back() == nowPlayingMenu) { + // menuIndex = menu_titles.size() - 1; } } debounceUpdateDisplay(); @@ -729,17 +588,13 @@ void HomeThingMenuBase::rotaryScrollClockwise(int rotary) { rotary_ = rotary; if (menu_settings_->get_mode() == MENU_MODE_ROTARY) { switch (menuTree.back()) { - case nowPlayingMenu: -#ifdef USE_MEDIA_PLAYER_GROUP - if (menu_display_->get_draw_now_playing_menu()) { - break; + case appMenu: +#ifdef USE_HOMETHING_APP + if (active_app_ && active_app_->should_draw_app()) { + active_app_->rotaryScrollClockwise(rotary); } - media_player_group_->increaseSpeakerVolume(); - circle_menu_->set_active_menu(volumeOptionMenu, - media_player_group_->active_player_); - debounceUpdateDisplay(); #endif - return; + break; case lightsDetailMenu: #ifdef USE_LIGHT if (HomeThingMenuControls::editingScrollForward( @@ -800,35 +655,32 @@ void HomeThingMenuBase::buttonPressUp() { if (!button_press_and_continue()) return; switch (menuTree.back()) { - case nowPlayingMenu: -#ifdef USE_MEDIA_PLAYER_GROUP - if (!button_press_now_playing_option_continue( - CircleOptionMenuPosition::TOP)) - return; - - switch (media_player_group_->active_player_->get_player_type()) { - case homeassistant_media_player::RemotePlayerType::TVRemotePlayerType: - media_player_group_->sendActivePlayerRemoteCommand( - homeassistant_media_player::MediaPlayerTVRemoteCommand::UP); - return; - case homeassistant_media_player::RemotePlayerType:: - SpeakerRemotePlayerType: - break; + case appMenu: +#ifdef USE_HOMETHING_APP + if (active_app_ && active_app_->should_draw_app()) { + switch (active_app_->buttonPressUp()) { + case homething_menu_app::NavigationCoordination:: + NavigationCoordinationReturn: + return; + case homething_menu_app::NavigationCoordination:: + NavigationCoordinationNone: + break; + case homething_menu_app::NavigationCoordination:: + NavigationCoordinationUpdate: + update_display(); + return; + case homething_menu_app::NavigationCoordination:: + NavigationCoordinationPop: + upMenu(); + return; + case homething_menu_app::NavigationCoordination:: + NavigationCoordinationRoot: + topMenu(); + return; + } } #endif break; - case groupMenu: -#ifdef USE_MEDIA_PLAYER_GROUP - menuIndex = 0; - if (media_player_group_->newSpeakerGroupParent != NULL) { - media_player_group_->newSpeakerGroupParent = NULL; - } else { - circle_menu_->clear_active_menu(); - } - topMenu(); - update_display(); -#endif - return; case lightsDetailMenu: #ifdef USE_LIGHT if (editing_menu_item) { @@ -853,13 +705,6 @@ void HomeThingMenuBase::buttonPressUp() { } break; } - // if (option_menu_ == speakerOptionMenu) { - // media_player_group_->toggle_shuffle(); - // option_menu_ = noOptionMenu; - // update_display(); - // return; - // } - // option_menu_ = noOptionMenu; if (active_menu_screen) active_menu_screen->set_selected_entity(nullptr); topMenu(); @@ -870,21 +715,29 @@ void HomeThingMenuBase::buttonPressDown() { if (!button_press_and_continue()) return; switch (menuTree.back()) { - case nowPlayingMenu: -#ifdef USE_MEDIA_PLAYER_GROUP - // if (option_menu_ == tvOptionMenu) { - if (!button_press_now_playing_option_continue( - CircleOptionMenuPosition::BOTTOM)) - return; - - switch (media_player_group_->active_player_->get_player_type()) { - case homeassistant_media_player::RemotePlayerType::TVRemotePlayerType: - media_player_group_->sendActivePlayerRemoteCommand( - homeassistant_media_player::MediaPlayerTVRemoteCommand::DOWN); - return; - case homeassistant_media_player::RemotePlayerType:: - SpeakerRemotePlayerType: - media_player_group_->active_player_->playPause(); + case appMenu: +#ifdef USE_HOMETHING_APP + if (active_app_ && active_app_->should_draw_app()) { + switch (active_app_->buttonPressDown()) { + case homething_menu_app::NavigationCoordination:: + NavigationCoordinationReturn: + return; + case homething_menu_app::NavigationCoordination:: + NavigationCoordinationNone: + break; + case homething_menu_app::NavigationCoordination:: + NavigationCoordinationUpdate: + update_display(); + return; + case homething_menu_app::NavigationCoordination:: + NavigationCoordinationPop: + upMenu(); + return; + case homething_menu_app::NavigationCoordination:: + NavigationCoordinationRoot: + topMenu(); + return; + } } #endif break; @@ -897,27 +750,29 @@ void HomeThingMenuBase::buttonPressLeft() { if (!button_press_and_continue()) return; switch (menuTree.back()) { - case nowPlayingMenu: -#ifdef USE_MEDIA_PLAYER_GROUP - // if (option_menu_ == tvOptionMenu) { - if (!button_press_now_playing_option_continue( - CircleOptionMenuPosition::LEFT)) - return; - // option_menu_ = noOptionMenu; - // media_player_group_->sendActivePlayerRemoteCommand("back"); - // update_display(); - // return; - // } - - switch (media_player_group_->active_player_->get_player_type()) { - case homeassistant_media_player::RemotePlayerType::TVRemotePlayerType: - media_player_group_->sendActivePlayerRemoteCommand( - homeassistant_media_player::MediaPlayerTVRemoteCommand::LEFT); - return; - case homeassistant_media_player::RemotePlayerType:: - SpeakerRemotePlayerType: - circle_menu_->clear_active_menu(); - break; + case appMenu: +#ifdef USE_HOMETHING_APP + if (active_app_ && active_app_->should_draw_app()) { + switch (active_app_->buttonPressLeft()) { + case homething_menu_app::NavigationCoordination:: + NavigationCoordinationReturn: + return; + case homething_menu_app::NavigationCoordination:: + NavigationCoordinationNone: + break; + case homething_menu_app::NavigationCoordination:: + NavigationCoordinationUpdate: + update_display(); + return; + case homething_menu_app::NavigationCoordination:: + NavigationCoordinationPop: + upMenu(); + return; + case homething_menu_app::NavigationCoordination:: + NavigationCoordinationRoot: + topMenu(); + return; + } } #endif break; @@ -926,66 +781,35 @@ void HomeThingMenuBase::buttonPressLeft() { } } -bool HomeThingMenuBase::skipBootPressed() { - switch (menuTree.back()) { - case bootMenu: { - switch (menu_display_->boot_->bootSequenceCanSkip(menuTree.back())) { - case BOOT_MENU_SKIP_STATE_SLEEP: - ESP_LOGI(TAG, "skipBootPressed: sleep"); -#ifdef USE_SWITCH - sleep_switch_->turn_on(); -#endif - return true; - case BOOT_MENU_SKIP_STATE_MENU: - ESP_LOGI(TAG, "skipBootPressed: menu"); -#ifdef USE_MEDIA_PLAYER_GROUP - media_player_group_->selectFirstActivePlayer(); -#endif - finish_boot(); - return true; - case BOOT_MENU_SKIP_STATE_NONE: - ESP_LOGI(TAG, "skipBootPressed: none"); - break; - } - break; - } - default: - break; - } - return false; -} - void HomeThingMenuBase::buttonPressRight() { if (skipBootPressed()) return; if (!button_press_and_continue()) return; switch (menuTree.back()) { - case nowPlayingMenu: -#ifdef USE_MEDIA_PLAYER_GROUP - // if (option_menu_ == tvOptionMenu) { - if (!button_press_now_playing_option_continue( - CircleOptionMenuPosition::RIGHT)) - return; - // option_menu_ = noOptionMenu; - // media_player_group_->sendActivePlayerRemoteCommand("menu"); - // update_display(); - // return; - // } - switch (media_player_group_->active_player_->get_player_type()) { - case homeassistant_media_player::RemotePlayerType::TVRemotePlayerType: - media_player_group_->sendActivePlayerRemoteCommand( - homeassistant_media_player::MediaPlayerTVRemoteCommand::RIGHT); - return; - case homeassistant_media_player::RemotePlayerType:: - SpeakerRemotePlayerType: - // if (option_menu_ == speakerOptionMenu) { - // media_player_group_->toggle_mute(); - // update_display(); - // } else { - media_player_group_->active_player_->nextTrack(); - // } - break; + case appMenu: +#ifdef USE_HOMETHING_APP + if (active_app_ && active_app_->should_draw_app()) { + switch (active_app_->buttonPressRight()) { + case homething_menu_app::NavigationCoordination:: + NavigationCoordinationReturn: + return; + case homething_menu_app::NavigationCoordination:: + NavigationCoordinationNone: + break; + case homething_menu_app::NavigationCoordination:: + NavigationCoordinationUpdate: + update_display(); + return; + case homething_menu_app::NavigationCoordination:: + NavigationCoordinationPop: + upMenu(); + return; + case homething_menu_app::NavigationCoordination:: + NavigationCoordinationRoot: + topMenu(); + return; + } } #endif break; @@ -998,15 +822,29 @@ void HomeThingMenuBase::buttonReleaseScreenLeft() { if (!button_press_and_continue()) return; switch (menuTree.back()) { - case nowPlayingMenu: -#ifdef USE_MEDIA_PLAYER_GROUP - switch (media_player_group_->active_player_->get_player_type()) { - case homeassistant_media_player::RemotePlayerType::TVRemotePlayerType: - update_display(); - break; - case homeassistant_media_player::RemotePlayerType:: - SpeakerRemotePlayerType: - break; + case appMenu: +#ifdef USE_HOMETHING_APP + if (active_app_ && active_app_->should_draw_app()) { + switch (active_app_->buttonReleaseScreenLeft()) { + case homething_menu_app::NavigationCoordination:: + NavigationCoordinationReturn: + return; + case homething_menu_app::NavigationCoordination:: + NavigationCoordinationNone: + break; + case homething_menu_app::NavigationCoordination:: + NavigationCoordinationUpdate: + update_display(); + return; + case homething_menu_app::NavigationCoordination:: + NavigationCoordinationPop: + upMenu(); + return; + case homething_menu_app::NavigationCoordination:: + NavigationCoordinationRoot: + topMenu(); + return; + } } #endif break; @@ -1036,16 +874,28 @@ void HomeThingMenuBase::buttonPressScreenLeft() { return; } switch (menuTree.back()) { - case nowPlayingMenu: -#ifdef USE_MEDIA_PLAYER_GROUP - if (circle_menu_->get_active_menu()) { - circle_menu_->clear_active_menu(); - } else { - circle_menu_->set_active_menu(speakerOptionMenu, - media_player_group_->active_player_); + case appMenu: +#ifdef USE_HOMETHING_APP + if (active_app_ && active_app_->should_draw_app()) { + switch (active_app_->buttonPressScreenLeft()) { + case homething_menu_app::NavigationCoordination:: + NavigationCoordinationNone: + break; + case homething_menu_app::NavigationCoordination:: + NavigationCoordinationUpdate: + update_display(); + return; + case homething_menu_app::NavigationCoordination:: + NavigationCoordinationPop: + upMenu(); + return; + case homething_menu_app::NavigationCoordination:: + NavigationCoordinationRoot: + topMenu(); + return; + } } #endif - update_display(); break; default: break; @@ -1055,21 +905,32 @@ void HomeThingMenuBase::buttonPressScreenLeft() { void HomeThingMenuBase::buttonPressScreenRight() { if (!button_press_and_continue()) return; -#ifdef USE_MEDIA_PLAYER_GROUP - circle_menu_->clear_active_menu(); -#endif switch (menuTree.back()) { - case rootMenu: - case settingsMenu: - case nowPlayingMenu: -#ifdef USE_MEDIA_PLAYER_GROUP - media_player_group_->selectNextMediaPlayer(); + case appMenu: +#ifdef USE_HOMETHING_APP + if (active_app_ && active_app_->should_draw_app()) { + switch (active_app_->buttonPressScreenRight()) { + case homething_menu_app::NavigationCoordination:: + NavigationCoordinationNone: + break; + case homething_menu_app::NavigationCoordination:: + NavigationCoordinationUpdate: + update_display(); + return; + case homething_menu_app::NavigationCoordination:: + NavigationCoordinationPop: + upMenu(); + return; + case homething_menu_app::NavigationCoordination:: + NavigationCoordinationRoot: + topMenu(); + return; + } + } #endif - update_display(); break; - case sourcesMenu: - case groupMenu: - case mediaPlayersMenu: + case rootMenu: + case settingsMenu: case lightsDetailMenu: case bootMenu: break; @@ -1077,7 +938,14 @@ void HomeThingMenuBase::buttonPressScreenRight() { } void HomeThingMenuBase::displayUpdateDebounced() { - if (idleTime < 2 || animation_->animating || get_charging()) { + bool app_animating = false; +#ifdef USE_HOMETHING_APP + if (active_app_ != nullptr && active_app_->is_animating()) { + app_animating = true; + } +#endif + if (idleTime < 2 || animation_->animating || get_charging() || + app_animating) { update_display(); } } @@ -1111,7 +979,7 @@ bool HomeThingMenuBase::display_can_sleep() { int display_timeout_while_charging = menu_settings_->get_display_timeout_while_charging(); - ESP_LOGI(TAG, + ESP_LOGD(TAG, "screen timeout %d, charging %d, display_timeout_while_charging %d " "idle %d", idle_timeout, get_charging(), display_timeout_while_charging, @@ -1192,6 +1060,11 @@ void HomeThingMenuBase::idleTick() { idleTime++; return; } +#ifdef USE_HOMETHING_APP + for (auto app : menu_apps_) { + app->idleTick(idleTime, menu_settings_->get_display_timeout()); + } +#endif if (menu_settings_->get_lock_after() != 0 && idleTime >= menu_settings_->get_lock_after()) { lockDevice(); @@ -1199,28 +1072,10 @@ void HomeThingMenuBase::idleTick() { if (idleTime == 2) { unlock_presses_ = 0; } else if (idleTime == 3) { -#ifdef USE_MEDIA_PLAYER_GROUP - circle_menu_->clear_active_menu(); -#endif update_display(); } else if (display_can_fade_out()) { fade_out_display(); } else if (idleTime == menu_settings_->get_display_timeout()) { -#ifdef USE_MEDIA_PLAYER_GROUP - if (media_player_group_ != NULL && - media_player_group_->playerSearchFinished) { - if (get_charging() && menuTree.back() != bootMenu) { - idleTime++; - return; - } - ESP_LOGI(TAG, "idleTick: idle root menu %d", display_can_sleep()); - menuTree.assign(1, rootMenu); - animation_->resetAnimation(); - idleMenu(false); - menu_display_->updateDisplay(false); - } -#endif - ESP_LOGD(TAG, "idleTick: turning off display? %d", display_can_sleep()); if (display_can_sleep()) { ESP_LOGD(TAG, "idleTick: turning off display"); @@ -1242,45 +1097,15 @@ void HomeThingMenuBase::idleTick() { } #endif } -#ifdef USE_MEDIA_PLAYER_GROUP - if (media_player_group_ != NULL) { - bool updatedMediaPositions = media_player_group_->updateMediaPosition(); - if (updatedMediaPositions) { - switch (menuTree.back()) { - case nowPlayingMenu: { - ESP_LOGD(TAG, "idleTick: update media positions %d", - display_can_sleep()); - if (!display_can_sleep()) { - update_display(); - } else { - if (!get_charging()) - sleep_display(); - } - break; - } - default: - break; - } - } - } -#endif idleTime++; } void HomeThingMenuBase::goToScreenFromString(std::string screenName) { ESP_LOGI(TAG, "goToScreenFromString: %s", screenName.c_str()); - if (screenName == "nowPlaying") { - menuTree.push_back(nowPlayingMenu); - } else if (screenName == "sources") { - menuTree.push_back(sourcesMenu); - } else if (screenName == "mediaPlayers") { - menuTree.push_back(mediaPlayersMenu); - } else if (screenName == "lightDetail") { + if (screenName == "lightDetail") { menuTree.push_back(lightsDetailMenu); } else if (screenName == "home") { menuTree.assign(1, rootMenu); - } else if (screenName == "speakerGroup") { - menuTree.push_back(groupMenu); } else if (screenName == "boot") { menuTree.push_back(bootMenu); } @@ -1297,11 +1122,6 @@ void HomeThingMenuBase::idleMenu(bool force) { if (active_menu_screen) active_menu_screen->set_selected_entity(nullptr); reset_menu(); -#ifdef USE_MEDIA_PLAYER_GROUP - menuTree.push_back(nowPlayingMenu); - if (media_player_group_) - media_player_group_->newSpeakerGroupParent = NULL; -#endif if (force) { update_display(); } diff --git a/components/homeThing/homeThingMenuBase.h b/components/homeThing/homeThingMenuBase.h index b4c8323a..46ce44b9 100644 --- a/components/homeThing/homeThingMenuBase.h +++ b/components/homeThing/homeThingMenuBase.h @@ -9,17 +9,14 @@ #include "esphome/components/homeThing/homeThingMenuBoot.h" #include "esphome/components/homeThing/homeThingMenuControls.h" #include "esphome/components/homeThing/homeThingMenuDisplay.h" -#include "esphome/components/homeThing/homeThingMenuDisplayState.h" #include "esphome/components/homeThing/homeThingMenuHeader.h" #include "esphome/components/homeThing/homeThingMenuScreen.h" #include "esphome/components/homeThing/homeThingMenuSettings.h" #include "esphome/components/homeThing/homeThingMenuTitle.h" +#include "esphome/components/homeThingDisplayState/homeThingDisplayState.h" -#ifdef USE_MEDIA_PLAYER_GROUP -#include "esphome/components/homeThing/homeThingMenuNowPlaying.h" -#include "esphome/components/homeThing/homeThingMenuNowPlayingOptionMenu.h" -#include "esphome/components/homeThing/homeThingOptionMenu.h" -#include "esphome/components/homeassistant_media_player/HomeAssistantMediaPlayerGroup.h" +#ifdef USE_HOMETHING_APP +#include "esphome/components/homeThingApp/homeThingApp.h" #endif #include "esphome/core/automation.h" @@ -54,26 +51,20 @@ class HomeThingMenuBase : public PollingComponent { void set_backlight(light::LightState* backlight) { backlight_ = backlight; } #endif +#ifdef USE_HOMETHING_APP + void register_app(homething_menu_app::HomeThingApp* newApp) { + menu_apps_.push_back(newApp); + } +#endif + void register_screen(HomeThingMenuScreen* new_screen) { new_screen->set_index(menu_screens_.size()); menu_screens_.push_back(new_screen); } void register_home_screen(HomeThingMenuScreen* new_screen) { - home_sceen_ = new_screen; - } - -#ifdef USE_MEDIA_PLAYER_GROUP - homeassistant_media_player::HomeAssistantMediaPlayerGroup* - get_media_player_group() { - return media_player_group_; + home_screen_ = new_screen; } - void set_media_player_group( - homeassistant_media_player::HomeAssistantMediaPlayerGroup* - media_player_group) { - media_player_group_ = media_player_group; - } -#endif void draw_menu_screen(); void topMenu(); @@ -85,14 +76,6 @@ class HomeThingMenuBase : public PollingComponent { void idleTick(); bool buttonPressWakeUpDisplay(); void idleMenu(bool force); - - // controls -#ifdef USE_MEDIA_PLAYER_GROUP - bool select_media_player_feature( - homeassistant_media_player::MediaPlayerFeatureCommand* command); - bool button_press_now_playing_option_continue( - CircleOptionMenuPosition position); -#endif bool selectLightEntity( const std::tuple* menu_item); bool upMenu(); @@ -159,7 +142,6 @@ class HomeThingMenuBase : public PollingComponent { bool display_can_sleep(); int idleTime = -2; - int static_menu_titles = 0; std::vector menuTree = {bootMenu}; #ifdef USE_LIGHT light::LightState* backlight_{nullptr}; @@ -170,44 +152,35 @@ class HomeThingMenuBase : public PollingComponent { #endif HomeThingMenuSettings* menu_settings_{nullptr}; HomeThingMenuDisplay* menu_display_{nullptr}; - void menuTypesToTitles(std::vector menu, - std::vector* menu_titles); HomeThingMenuAnimation* animation_ = new HomeThingMenuAnimation(); std::vector menu_screens_; - HomeThingMenuScreen* home_sceen_{nullptr}; + HomeThingMenuScreen* home_screen_{nullptr}; HomeThingMenuScreen* active_menu_screen{nullptr}; -#ifdef USE_MEDIA_PLAYER_GROUP - homeassistant_media_player::HomeAssistantMediaPlayerGroup* - media_player_group_{nullptr}; - void selectNowPlayingMenu(); - HomeThingMenuNowPlayingOptionMenu* circle_menu_ = - new HomeThingMenuNowPlayingOptionMenu(); +#ifdef USE_HOMETHING_APP + std::vector menu_apps_; + homething_menu_app::HomeThingApp* active_app_{nullptr}; #endif void update_display() { this->on_redraw_callbacks_.call(); } void debounceUpdateDisplay(); void update(); void activeMenu(std::vector*); - std::vector rootMenuTitles(); void reset_menu() { menuIndex = 0; active_menu_screen = nullptr; reload_menu_items_ = true; editing_menu_item = false; -#ifdef USE_MEDIA_PLAYER_GROUP - circle_menu_->clear_active_menu(); -#endif if (menuTree.front() != bootMenu) { menuTree.assign(1, rootMenu); ESP_LOGD(TAG, "reset_menu: reset animation %d", menuTree.front()); animation_->resetAnimation(); } -#ifdef USE_MEDIA_PLAYER_GROUP - if (media_player_group_) { - media_player_group_->newSpeakerGroupParent = NULL; - media_player_group_->set_active_player_source_index(-1); +#ifdef USE_HOMETHING_APP + if (active_app_) { + active_app_->reset_menu(); } + active_app_ = nullptr; #endif } void turn_on_backlight(); diff --git a/components/homeThing/homeThingMenuBoot.cpp b/components/homeThing/homeThingMenuBoot.cpp index 37a9d74f..075ca6a4 100644 --- a/components/homeThing/homeThingMenuBoot.cpp +++ b/components/homeThing/homeThingMenuBoot.cpp @@ -6,6 +6,15 @@ namespace esphome { namespace homething_menu_base { +void HomeThingMenuBoot::set_media_player_group( + homeassistant_media_player::HomeAssistantMediaPlayerGroup* + media_player_group) { + media_player_group_ = media_player_group; + if (media_player_group_) { + media_player_group_->add_on_state_callback( + [this](float state) { this->callback_(); }); + } +} int HomeThingMenuBoot::drawBootSequenceTitleRainbow( int xPos, int yPos, const MenuStates activeMenuState) { std::string bootTitle = "homeThing"; @@ -209,10 +218,11 @@ int HomeThingMenuBoot::drawBootSequenceTitle(int xPos, int imageYPos, int maxAnimationDuration = 0; switch (get_boot_menu_state()) { case BOOT_MENU_STATE_API: - text_helpers_->drawTextWrapped( + display_state_->drawTextWrapped( xPos, yPos, display_state_->get_font_large_heavy(), display_state_->get_color_palette()->get_accent_primary(), - display::TextAlign::TOP_CENTER, "api connecting...", 4); + display::TextAlign::TOP_CENTER, "api connecting...", 4, + display_buffer_); break; case BOOT_MENU_STATE_PLAYERS: case BOOT_MENU_STATE_COMPLETE: { @@ -223,24 +233,27 @@ int HomeThingMenuBoot::drawBootSequenceTitle(int xPos, int imageYPos, auto playersLoadedString = to_string(loadedPlayers) + "/" + to_string(totalPlayers) + " media players loaded"; - text_helpers_->drawTextWrapped( + display_state_->drawTextWrapped( xPos, yPos, display_state_->get_font_large_heavy(), display_state_->get_color_palette()->get_accent_primary(), - display::TextAlign::TOP_CENTER, playersLoadedString, 5); + display::TextAlign::TOP_CENTER, playersLoadedString, 5, + display_buffer_); } else { - text_helpers_->drawTextWrapped( + display_state_->drawTextWrapped( xPos, yPos, display_state_->get_font_large_heavy(), display_state_->get_color_palette()->get_accent_primary(), - display::TextAlign::TOP_CENTER, "api connected!", 4); + display::TextAlign::TOP_CENTER, "api connected!", 4, + display_buffer_); } #endif break; } case BOOT_MENU_STATE_NETWORK: - text_helpers_->drawTextWrapped( + display_state_->drawTextWrapped( xPos, yPos, display_state_->get_font_large_heavy(), display_state_->get_color_palette()->get_accent_primary(), - display::TextAlign::TOP_CENTER, "wifi connecting...", 4); + display::TextAlign::TOP_CENTER, "wifi connecting...", 4, + display_buffer_); break; case BOOT_MENU_STATE_START: maxAnimationDuration = diff --git a/components/homeThing/homeThingMenuBoot.h b/components/homeThing/homeThingMenuBoot.h index dc001e9f..bc6121c5 100644 --- a/components/homeThing/homeThingMenuBoot.h +++ b/components/homeThing/homeThingMenuBoot.h @@ -5,9 +5,9 @@ #include #include "esphome/components/display/display_buffer.h" #include "esphome/components/homeThing/homeThingMenuAnimation.h" -#include "esphome/components/homeThing/homeThingMenuDisplayState.h" #include "esphome/components/homeThing/homeThingMenuHeader.h" -#include "esphome/components/homeThing/homeThingMenuTextHelpers.h" +#include "esphome/components/homeThingDisplayState/homeThingDisplayState.h" +#include "esphome/components/homeThingDisplayState/homeThingMenuTextHelpers.h" #ifdef USE_MEDIA_PLAYER_GROUP #include "esphome/components/homeassistant_media_player/HomeAssistantMediaPlayerGroup.h" #endif @@ -52,14 +52,13 @@ class HomeThingMenuBootAnimationConfig { class HomeThingMenuBoot { public: - HomeThingMenuBoot(display::DisplayBuffer* new_display_buffer, - HomeThingMenuDisplayState* new_display_state, - HomeThingMenuHeader* new_header, - HomeThingMenuTextHelpers* new_text_helpers) + HomeThingMenuBoot( + display::DisplayBuffer* new_display_buffer, + homething_display_state::HomeThingDisplayState* new_display_state, + HomeThingMenuHeader* new_header) : display_buffer_(new_display_buffer), display_state_(new_display_state), - header_(new_header), - text_helpers_(new_text_helpers) {} + header_(new_header) {} bool drawBootSequence(const MenuStates activeMenuState); BootMenuSkipState bootSequenceCanSkip(const MenuStates activeMenuState); void set_api_connected(binary_sensor::BinarySensor* api_connected) { @@ -74,11 +73,13 @@ class HomeThingMenuBoot { #ifdef USE_MEDIA_PLAYER_GROUP void set_media_player_group( homeassistant_media_player::HomeAssistantMediaPlayerGroup* - media_player_group) { - media_player_group_ = media_player_group; - } + media_player_group); #endif + void add_on_state_callback(std::function&& callback) { + this->callback_.add(std::move(callback)); + } + private: void drawBootSequenceLoadingBar(int yPosOffset, float progress); void drawBootSequenceSkipTitle(int xPos, int imageYPos, @@ -94,10 +95,9 @@ class HomeThingMenuBoot { BootMenuState get_boot_menu_state(); display::DisplayBuffer* display_buffer_{nullptr}; - HomeThingMenuDisplayState* display_state_{nullptr}; + homething_display_state::HomeThingDisplayState* display_state_{nullptr}; HomeThingMenuAnimation* animation_{nullptr}; HomeThingMenuHeader* header_{nullptr}; - HomeThingMenuTextHelpers* text_helpers_{nullptr}; #ifdef USE_MEDIA_PLAYER_GROUP homeassistant_media_player::HomeAssistantMediaPlayerGroup* media_player_group_{nullptr}; @@ -106,6 +106,7 @@ class HomeThingMenuBoot { const char* const TAG = "homething.boot"; HomeThingMenuBootAnimationConfig animation_config_ = HomeThingMenuBootAnimationConfig(); + CallbackManager callback_; bool boot_animation_complete_ = false; }; diff --git a/components/homeThing/homeThingMenuDisplay.cpp b/components/homeThing/homeThingMenuDisplay.cpp index c63b2006..ce51bed2 100644 --- a/components/homeThing/homeThingMenuDisplay.cpp +++ b/components/homeThing/homeThingMenuDisplay.cpp @@ -4,7 +4,15 @@ namespace esphome { namespace homething_menu_base { -void HomeThingMenuDisplay::setup() {} +void HomeThingMenuDisplay::setup() { + if (boot_ != nullptr) { + ESP_LOGW(TAG, "Boot setup"); + boot_->add_on_state_callback([this]() { + ESP_LOGW(TAG, "Boot update"); + this->callback_.call(); + }); + } +} bool HomeThingMenuDisplay::draw_menu_title(int menuState, int i, std::string title, int yPos, @@ -16,8 +24,9 @@ bool HomeThingMenuDisplay::draw_menu_title(int menuState, int i, int textYPos = yPos + (display_state_->get_margin_size() / 4); if (menuState == i) { int characterHeight = display_state_->get_font_medium()->get_baseline(); - int characterLimit = text_helpers_->getCharacterLimit( - xPos, characterHeight, display::TextAlign::TOP_LEFT); + int characterLimit = display_state_->getCharacterLimit( + xPos, characterHeight, display::TextAlign::TOP_LEFT, + display_buffer_->get_width()); ESP_LOGD(TAG, "characterLimit %d, title %d height %d", characterLimit, title.length(), characterHeight); @@ -38,15 +47,14 @@ bool HomeThingMenuDisplay::draw_menu_title(int menuState, int i, display_state_->get_font_medium()->get_baseline() + display_state_->get_margin_size(), display_state_->get_color_palette()->get_accent_primary()); - display_buffer_->printf( - xPos, textYPos, display_state_->get_font_medium(), - text_helpers_->secondaryTextColor(display_state_->get_dark_mode()), - display::TextAlign::TOP_LEFT, "%s", marqueeTitle.c_str()); + display_buffer_->printf(xPos, textYPos, display_state_->get_font_medium(), + display_state_->secondaryTextColor(), + display::TextAlign::TOP_LEFT, "%s", + marqueeTitle.c_str()); } else { - display_buffer_->printf( - xPos, textYPos, display_state_->get_font_medium(), - text_helpers_->primaryTextColor(display_state_->get_dark_mode()), - display::TextAlign::TOP_LEFT, "%s", title.c_str()); + display_buffer_->printf(xPos, textYPos, display_state_->get_font_medium(), + display_state_->primaryTextColor(), + display::TextAlign::TOP_LEFT, "%s", title.c_str()); } return animating; } @@ -60,8 +68,7 @@ void HomeThingMenuDisplay::draw_lock_screen(int unlock_presses) { auto number_font = display_state_->get_font_large_heavy(); auto background_color = display_state_->get_color_palette()->get_accent_primary(); - auto text_color = - text_helpers_->primaryTextColor(display_state_->get_dark_mode()); + auto text_color = display_state_->primaryTextColor(); display_buffer_->filled_rectangle(xPos - box_size_width / 2, yPos - box_size_height / 2, box_size_width, box_size_height, background_color); @@ -184,38 +191,33 @@ bool HomeThingMenuDisplay::draw_menu_titles( bool HomeThingMenuDisplay::draw_menu_screen( MenuStates* activeMenuState, const std::vector* active_menu, - const int menuIndex, HomeThingOptionMenu* option_menu, + const int menuIndex, + homething_menu_now_playing::HomeThingOptionMenu* option_menu, bool editing_menu_item) { - bool boot_complete = boot_->boot_complete(); if (!display_state_->get_dark_mode() && *activeMenuState != bootMenu) { display_buffer_->fill(display_state_->get_color_palette()->get_white()); } - if (!boot_complete && *activeMenuState == bootMenu) { + if (!boot_complete() && *activeMenuState == bootMenu) { return boot_->drawBootSequence(*activeMenuState); - } else if (boot_complete && *activeMenuState == bootMenu) { + } else if (boot_complete() && *activeMenuState == bootMenu) { ESP_LOGW(TAG, "finished boot"); *activeMenuState = rootMenu; return true; - } else if (!boot_complete && *activeMenuState != bootMenu) { + } else if (!boot_complete() && *activeMenuState != bootMenu) { ESP_LOGW(TAG, "boot not complete but we got to the menu %d state %d", - boot_complete, *activeMenuState); + boot_complete(), *activeMenuState); } - bool animating = false; - switch (*activeMenuState) { - case nowPlayingMenu: -#ifdef USE_MEDIA_PLAYER_GROUP - now_playing_->drawNowPlaying(menuIndex, option_menu, active_menu); -#endif - break; - default: - animating = draw_menu_titles(active_menu, menuIndex, editing_menu_item); - break; - } + bool animating = draw_menu_titles(active_menu, menuIndex, editing_menu_item); header_->drawHeader(0, *activeMenuState); return animating; } +void HomeThingMenuDisplay::draw_menu_header( + HomeThingMenuHeaderSource* header_source) { + header_->draw_menu_header(header_source); +} + void HomeThingMenuDisplay::drawScrollBar(int menuTitlesCount, int headerHeight, int menuIndex) { int scrollBarMargin = 1; @@ -325,10 +327,9 @@ void HomeThingMenuDisplay::drawTitleImage( (display_state_->get_font_medium()->get_baseline() * display_state_->get_font_size_width_ratio())) + 4; - auto color = - selected - ? text_helpers_->primaryTextColor(display_state_->get_dark_mode()) - : display_state_->get_color_palette()->get_accent_primary(); + auto color = selected + ? display_state_->primaryTextColor() + : display_state_->get_color_palette()->get_accent_primary(); switch (titleState) { case homeassistant_media_player::RemotePlayerState:: PlayingRemotePlayerState: @@ -358,5 +359,20 @@ void HomeThingMenuDisplay::drawTitleImage( void HomeThingMenuDisplay::updateDisplay(bool force) { // displayUpdate->updateDisplay(force); } + +bool HomeThingMenuDisplay::boot_complete() { + if (boot_ != nullptr) { + return boot_->boot_complete(); + } + return true; +} + +BootMenuSkipState HomeThingMenuDisplay::bootSequenceCanSkip( + const MenuStates activeMenuState) { + if (boot_ != nullptr) { + return boot_->bootSequenceCanSkip(activeMenuState); + } + return BootMenuSkipState::BOOT_MENU_SKIP_STATE_NONE; +} } // namespace homething_menu_base } // namespace esphome diff --git a/components/homeThing/homeThingMenuDisplay.h b/components/homeThing/homeThingMenuDisplay.h index 3a2fb1ea..2eb3d35f 100644 --- a/components/homeThing/homeThingMenuDisplay.h +++ b/components/homeThing/homeThingMenuDisplay.h @@ -6,19 +6,18 @@ #include "esphome/components/display/display_buffer.h" #include "esphome/components/homeThing/homeThingMenuAnimation.h" #include "esphome/components/homeThing/homeThingMenuBoot.h" -#include "esphome/components/homeThing/homeThingMenuDisplayState.h" #include "esphome/components/homeThing/homeThingMenuHeader.h" #include "esphome/components/homeThing/homeThingMenuRefactor.h" -#include "esphome/components/homeThing/homeThingMenuTextHelpers.h" #include "esphome/components/homeThing/homeThingMenuTitle.h" #include "esphome/components/homeThing/homeThingOptionMenu.h" +#include "esphome/components/homeThingDisplayState/homeThingDisplayState.h" +#include "esphome/components/homeThingDisplayState/homeThingMenuTextHelpers.h" #ifdef USE_LIGHT #include "esphome/components/homeThing/homeThingMenuTitleLight.h" #endif #ifdef USE_MEDIA_PLAYER_GROUP -#include "esphome/components/homeThing/homeThingMenuNowPlaying.h" #include "esphome/components/homeassistant_media_player/HomeAssistantMediaPlayerGroup.h" #endif @@ -34,24 +33,25 @@ namespace homething_menu_base { class HomeThingMenuDisplay { public: - HomeThingMenuDisplay(HomeThingMenuBoot* boot, - display::DisplayBuffer* display_buffer, - HomeThingMenuDisplayState* display_state, - HomeThingMenuTextHelpers* text_helpers, - HomeThingMenuRefactor* refactor, - HomeThingMenuHeader* header) + HomeThingMenuDisplay( + HomeThingMenuBoot* boot, display::DisplayBuffer* display_buffer, + homething_display_state::HomeThingDisplayState* display_state, + HomeThingMenuRefactor* refactor, HomeThingMenuHeader* header) : boot_(boot), display_buffer_(display_buffer), display_state_(display_state), - text_helpers_(text_helpers), refactor_(refactor), - header_(header) {} + header_(header) { + setup(); + } void setup(); void draw_lock_screen(int unlock_presses); - bool draw_menu_screen(MenuStates* activeMenuState, - const std::vector* active_menu, - const int menuIndex, HomeThingOptionMenu* option_menu, - bool editing_menu_item); + bool draw_menu_screen( + MenuStates* activeMenuState, + const std::vector* active_menu, const int menuIndex, + homething_menu_now_playing::HomeThingOptionMenu* option_menu, + bool editing_menu_item); + void draw_menu_header(HomeThingMenuHeaderSource* header_source); void updateDisplay(bool force); void set_animation(HomeThingMenuAnimation* animation) { @@ -65,23 +65,21 @@ class HomeThingMenuDisplay { return false; } -#ifdef USE_MEDIA_PLAYER_GROUP - void set_media_player_group( - homeassistant_media_player::HomeAssistantMediaPlayerGroup* - media_player_group) { - media_player_group_ = media_player_group; - } - void set_now_playing(HomeThingMenuNowPlaying* now_playing) { - now_playing_ = now_playing; - } -#endif - - HomeThingMenuBoot* boot_{nullptr}; void set_active_menu_screen(HomeThingMenuScreen** active_menu_screen) { header_->set_active_menu_screen(active_menu_screen); } + void clearBoot() { boot_ = nullptr; } + + bool boot_complete(); + BootMenuSkipState bootSequenceCanSkip(const MenuStates activeMenuState); + + void add_on_state_callback(std::function&& callback) { + this->callback_.add(std::move(callback)); + } + private: + HomeThingMenuBoot* boot_{nullptr}; int scrollTop = 0; bool draw_menu_titles(const std::vector* menuTitles, const int menuIndex, bool editing_menu_item); @@ -96,18 +94,17 @@ class HomeThingMenuDisplay { int i, int menuState, int yPos); display::DisplayBuffer* display_buffer_{nullptr}; - HomeThingMenuDisplayState* display_state_{nullptr}; - HomeThingMenuTextHelpers* text_helpers_{nullptr}; + homething_display_state::HomeThingDisplayState* display_state_{nullptr}; HomeThingMenuRefactor* refactor_{nullptr}; HomeThingMenuHeader* header_{nullptr}; HomeThingMenuAnimation* animation_{nullptr}; + CallbackManager callback_; #ifdef USE_MEDIA_PLAYER_GROUP void drawTitleImage( int characterCount, int yPos, const homeassistant_media_player::RemotePlayerState& titleState, bool selected); - HomeThingMenuNowPlaying* now_playing_{nullptr}; homeassistant_media_player::HomeAssistantMediaPlayerGroup* media_player_group_{nullptr}; #endif diff --git a/components/homeThing/homeThingMenuHeader.cpp b/components/homeThing/homeThingMenuHeader.cpp index 0f047cfd..50bc1162 100644 --- a/components/homeThing/homeThingMenuHeader.cpp +++ b/components/homeThing/homeThingMenuHeader.cpp @@ -15,10 +15,8 @@ int HomeThingMenuHeader::getHeaderTextYPos(int yPosOffset) { void HomeThingMenuHeader::drawHeaderTitleWithString(std::string title, int xPos, int yPosOffset) { int yPos = getHeaderTextYPos(yPosOffset); - display_buffer_->printf( - xPos, yPos, display_state_->get_font_small(), - text_helpers_->primaryTextColor(display_state_->get_dark_mode()), - title.c_str()); + display_buffer_->printf(xPos, yPos, display_state_->get_font_small(), + display_state_->primaryTextColor(), title.c_str()); } int HomeThingMenuHeader::drawHeaderIcon(std::string title, int xPos, @@ -36,28 +34,32 @@ void HomeThingMenuHeader::drawHeaderTitle(int yPosOffset, switch (activeMenuState) { case rootMenu: case settingsMenu: - case nowPlayingMenu: { -#ifdef USE_MEDIA_PLAYER_GROUP - if (media_player_group_ && media_player_group_->active_player_) { - auto headerMenuTitle = - headerMediaPlayerTitle(media_player_group_->active_player_); - xPos = drawPlayPauseIcon(xPos, headerMenuTitle); - drawHeaderTitleWithString((headerMenuTitle).get_name(), xPos); - } else { - drawHeaderTitleWithString("Remote", xPos); - } -#endif + drawHeaderTitleWithString("Remote", xPos); break; - } - case sourcesMenu: - drawHeaderTitleWithString("Sources", xPos); - break; - case groupMenu: - drawHeaderTitleWithString("Group Speakers", xPos); - break; - case mediaPlayersMenu: - drawHeaderTitleWithString("Media Players", xPos); + case appMenu: break; + // case nowPlayingMenu: { + // #ifdef USE_MEDIA_PLAYER_GROUP + // if (media_player_group_ && media_player_group_->active_player_) { + // auto headerMenuTitle = + // headerMediaPlayerTitle(media_player_group_->active_player_); + // xPos = drawPlayPauseIcon(xPos, headerMenuTitle); + // drawHeaderTitleWithString((headerMenuTitle).get_name(), xPos); + // } else { + // drawHeaderTitleWithString("Remote", xPos); + // } + // #endif + // break; + // } + // case sourcesMenu: + // drawHeaderTitleWithString("Sources", xPos); + // break; + // case groupMenu: + // drawHeaderTitleWithString("Group Speakers", xPos); + // break; + // case mediaPlayersMenu: + // drawHeaderTitleWithString("Media Players", xPos); + // break; case lightsDetailMenu: { #ifdef USE_LIGHT auto selectedEntity = (*active_menu_screen_)->get_selected_entity(); @@ -82,141 +84,27 @@ void HomeThingMenuHeader::drawHeaderTitle(int yPosOffset, } } -#ifdef USE_MEDIA_PLAYER_GROUP -int HomeThingMenuHeader::drawPlayPauseIcon(int oldXPos, - MenuTitlePlayer menuTitle) { - int yPos = getHeaderTextYPos(0); - int xPos = oldXPos; - switch (menuTitle.media_player_->playerState) { - case homeassistant_media_player::RemotePlayerState:: - PlayingRemotePlayerState: { - display_buffer_->printf( - xPos, yPos, display_state_->get_font_material_small(), - menuTitle.mediaSourceIconColor( - display_state_->get_color_palette()->get_accent_primary()), - menuTitle.mediaSourceIcon().c_str()); - break; - } - case homeassistant_media_player::RemotePlayerState::PausedRemotePlayerState: - display_buffer_->printf( - xPos, yPos, display_state_->get_font_material_small(), - display_state_->get_color_palette()->get_accent_primary(), "󰏤"); - break; - case homeassistant_media_player::RemotePlayerState:: - StoppedRemotePlayerState: - display_buffer_->printf( - xPos, yPos, display_state_->get_font_material_small(), - display_state_->get_color_palette()->get_accent_primary(), "󰓛"); - break; - case homeassistant_media_player::RemotePlayerState:: - PowerOffRemotePlayerState: - display_buffer_->printf( - xPos, yPos, display_state_->get_font_material_small(), - display_state_->get_color_palette()->get_accent_primary(), "󰽥"); - break; - default: - return oldXPos; - } - return xPos + display_state_->get_icon_size() + - display_state_->get_margin_size() / 2; -} - -int HomeThingMenuHeader::drawShuffle(int oldXPos, int yPosOffset) { - if (!media_player_group_ || media_player_group_->active_player_ == NULL || - display_state_->get_draw_shuffle() == DisplayIconEnabledState::OFF) { - return oldXPos; - } - auto active_player = media_player_group_->active_player_; - if (active_player->get_player_type() == - homeassistant_media_player::RemotePlayerType::TVRemotePlayerType || - !active_player->supports(homeassistant_media_player:: - MediaPlayerSupportedFeature::SHUFFLE_SET)) { - return oldXPos; - } - if (active_player->playerState != - homeassistant_media_player::RemotePlayerState::StoppedRemotePlayerState) { - int xPos = oldXPos - display_state_->get_icon_size() + - display_state_->get_margin_size() / 2; - int yPos = getHeaderTextYPos(yPosOffset); - if (media_player_group_->mediaShuffling()) { - display_buffer_->printf( - xPos, yPos, display_state_->get_font_material_small(), - display_state_->get_color_palette()->get_accent_primary(), "󰒝"); - } else if (display_state_->get_draw_shuffle() == - DisplayIconEnabledState::ALWAYS) { - display_buffer_->printf( - xPos, yPos, display_state_->get_font_material_small(), - display_state_->get_color_palette()->get_accent_primary(), "󰒞"); - } else { - return oldXPos; - } - return xPos - display_state_->get_margin_size() / 2; - } - return oldXPos; -} - -int HomeThingMenuHeader::drawRepeat(int oldXPos, int yPosOffset) { - if (display_state_->get_draw_repeat() == DisplayIconEnabledState::OFF || - !media_player_group_ || media_player_group_->active_player_ == NULL) { - return oldXPos; - } - auto active_player = media_player_group_->active_player_; - if (active_player->get_player_type() == - homeassistant_media_player::RemotePlayerType::TVRemotePlayerType || - !active_player->supports(homeassistant_media_player:: - MediaPlayerSupportedFeature::REPEAT_SET) || - active_player->playerState == - homeassistant_media_player::RemotePlayerState:: - StoppedRemotePlayerState) { - return oldXPos; - } - int xPos = oldXPos - display_state_->get_icon_size() + - display_state_->get_margin_size() / 2; - int yPos = getHeaderTextYPos(yPosOffset); - switch (media_player_group_->get_repeat_mode()) { - case homeassistant_media_player::MediaPlayerRepeatMode::ALL: - display_buffer_->printf( - xPos, yPos, display_state_->get_font_material_small(), - display_state_->get_color_palette()->get_accent_primary(), "󰑖"); - break; - case homeassistant_media_player::MediaPlayerRepeatMode::ONE: - display_buffer_->printf( - xPos, yPos, display_state_->get_font_material_small(), - display_state_->get_color_palette()->get_accent_primary(), "󰑘"); - break; - case homeassistant_media_player::MediaPlayerRepeatMode::OFF: - if (display_state_->get_draw_repeat() != - DisplayIconEnabledState::ALWAYS) { - return oldXPos; - } - display_buffer_->printf( - xPos, yPos, display_state_->get_font_material_small(), - display_state_->get_color_palette()->get_accent_primary(), "󰑗"); - break; - default: - return oldXPos; - } - return xPos - display_state_->get_margin_size() / 2; -} - -int HomeThingMenuHeader::drawHeaderVolumeLevel(int oldXPos, int yPosOffset) { - if (media_player_group_ == nullptr || - media_player_group_->active_player_ == nullptr) { - return oldXPos; +void HomeThingMenuHeader::draw_menu_header( + HomeThingMenuHeaderSource* header_source) { + int yPosOffset = 0; + display_buffer_->rectangle( + 0, display_state_->get_header_height() - yPosOffset, + display_buffer_->get_width(), 1, + display_state_->get_color_palette()->get_accent_primary()); + int xPos = 2; + if (header_source != nullptr) { + drawHeaderTitleWithString(header_source->get_header_title(), xPos); + } else { + drawHeaderTitleWithString("AppSource!", xPos); } - if (!display_state_->get_draw_volume_level()) { - return oldXPos; + xPos = display_buffer_->get_width() - display_state_->get_margin_size() / 2; + xPos = drawBattery(xPos, yPosOffset); + xPos = drawHeaderTime(xPos, yPosOffset); + if (header_source != nullptr) { + xPos = header_source->draw_header_details(xPos, getHeaderTextYPos(0), + display_buffer_, display_state_); } - int xPos = oldXPos - display_state_->get_margin_size() / 2; - int yPos = getHeaderTextYPos(yPosOffset); - display_buffer_->printf( - xPos, yPos, display_state_->get_font_small(), - text_helpers_->primaryTextColor(display_state_->get_dark_mode()), - display::TextAlign::TOP_RIGHT, "%.0f%%", - media_player_group_->getVolumeLevel()); - return xPos; } -#endif int HomeThingMenuHeader::drawHeaderTime(int oldXPos, int yPosOffset) { if (esp_time_ == nullptr) { @@ -231,13 +119,12 @@ int HomeThingMenuHeader::drawHeaderTime(int oldXPos, int yPosOffset) { if (timeString.length() > 0 && timeString[0] == '0') { timeString.erase(0, 1); } - int xPos = oldXPos - text_helpers_->getTextWidth( + int xPos = oldXPos - display_state_->getTextWidth( display_state_->get_font_small()->get_baseline(), timeString.length()); - display_buffer_->printf( - xPos, yPos, display_state_->get_font_small(), - text_helpers_->primaryTextColor(display_state_->get_dark_mode()), - timeString.c_str()); + display_buffer_->printf(xPos, yPos, display_state_->get_font_small(), + display_state_->primaryTextColor(), + timeString.c_str()); return xPos - display_state_->get_margin_size() / 2; } @@ -281,14 +168,10 @@ void HomeThingMenuHeader::drawHeader(int yPosOffset, int xPos = display_buffer_->get_width() - display_state_->get_margin_size() / 2; xPos = drawBattery(xPos, yPosOffset); -#ifdef USE_MEDIA_PLAYER_GROUP - xPos = drawRepeat(xPos, yPosOffset); - xPos = drawShuffle(xPos, yPosOffset); -#endif xPos = drawHeaderTime(xPos, yPosOffset); -#ifdef USE_MEDIA_PLAYER_GROUP - xPos = drawHeaderVolumeLevel(xPos, yPosOffset); -#endif + // #ifdef USE_MEDIA_PLAYER_GROUP + // xPos = drawHeaderVolumeLevel(xPos, yPosOffset); + // #endif } } // namespace homething_menu_base } // namespace esphome diff --git a/components/homeThing/homeThingMenuHeader.h b/components/homeThing/homeThingMenuHeader.h index f54131ab..79f7dc51 100644 --- a/components/homeThing/homeThingMenuHeader.h +++ b/components/homeThing/homeThingMenuHeader.h @@ -1,10 +1,9 @@ #pragma once #include -#include "esphome/components/homeThing/homeThingMenuDisplayState.h" #include "esphome/components/homeThing/homeThingMenuScreen.h" -#include "esphome/components/homeThing/homeThingMenuTextHelpers.h" #include "esphome/components/homeThing/homeThingMenuTitle.h" +#include "esphome/components/homeThingDisplayState/homeThingDisplayState.h" #ifdef USE_MEDIA_PLAYER_GROUP #include "esphome/components/homeThing/homeThingOptionMenu.h" @@ -19,15 +18,25 @@ namespace esphome { namespace homething_menu_base { +class HomeThingMenuHeaderSource { + public: + virtual std::string get_header_title() { return "xx"; } + virtual int draw_header_details( + int xPos, int yPosOffset, display::DisplayBuffer* display_buffer, + homething_display_state::HomeThingDisplayState* display_state) { + return 0; + } +}; + class HomeThingMenuHeader { public: - HomeThingMenuHeader(display::DisplayBuffer* new_display_buffer, - HomeThingMenuDisplayState* new_display_state, - HomeThingMenuTextHelpers* new_text_helpers) + HomeThingMenuHeader( + display::DisplayBuffer* new_display_buffer, + homething_display_state::HomeThingDisplayState* new_display_state) : display_buffer_(new_display_buffer), - display_state_(new_display_state), - text_helpers_(new_text_helpers) {} + display_state_(new_display_state) {} void drawHeader(int yPosOffset, const MenuStates activeMenuState); + void draw_menu_header(HomeThingMenuHeaderSource* header_source); void set_battery_percent(sensor::Sensor* battery_percent) { battery_percent_ = battery_percent; } @@ -39,14 +48,6 @@ class HomeThingMenuHeader { } void set_time_id(time::RealTimeClock* time_id) { this->esp_time_ = time_id; } -#ifdef USE_MEDIA_PLAYER_GROUP - void set_media_player_group( - homeassistant_media_player::HomeAssistantMediaPlayerGroup* - media_player_group) { - media_player_group_ = media_player_group; - } -#endif - private: float get_battery_percent() { if (battery_percent_ != nullptr && battery_percent_->has_state()) { @@ -70,21 +71,8 @@ class HomeThingMenuHeader { int drawHeaderIcon(std::string title, int xPos, Color iconColor); int drawHeaderTime(int oldXPos, int yPosOffset); -#ifdef USE_MEDIA_PLAYER_GROUP - int drawPlayPauseIcon(int oldXPos, MenuTitlePlayer menuTitle); - int drawShuffle(int oldXPos, int yPosOffset); - int drawRepeat(int oldXPos, int yPosOffset); - int drawHeaderVolumeLevel(int oldXPos, int yPosOffset); -#endif - -#ifdef USE_MEDIA_PLAYER_GROUP - homeassistant_media_player::HomeAssistantMediaPlayerGroup* - media_player_group_{nullptr}; -#endif - display::DisplayBuffer* display_buffer_{nullptr}; - HomeThingMenuDisplayState* display_state_{nullptr}; - HomeThingMenuTextHelpers* text_helpers_{nullptr}; + homething_display_state::HomeThingDisplayState* display_state_{nullptr}; sensor::Sensor* battery_percent_{nullptr}; binary_sensor::BinarySensor* charging_{nullptr}; time::RealTimeClock* esp_time_{nullptr}; diff --git a/components/homeThing/homeThingMenuRefactor.cpp b/components/homeThing/homeThingMenuRefactor.cpp index ad44d992..1ab14cf7 100644 --- a/components/homeThing/homeThingMenuRefactor.cpp +++ b/components/homeThing/homeThingMenuRefactor.cpp @@ -11,9 +11,8 @@ void HomeThingMenuRefactor::drawGroupedBar(int yPos, bool extend) { : (display_state_->get_font_medium()->get_baseline() + display_state_->get_margin_size()) / 2; - display_buffer_->line( - xPos, yPos, xPos, yPos + lineHeight, - text_helpers_->primaryTextColor(display_state_->get_dark_mode())); + display_buffer_->line(xPos, yPos, xPos, yPos + lineHeight, + display_state_->primaryTextColor()); display_buffer_->line( xPos, yPos + (display_state_->get_font_medium()->get_baseline() + @@ -23,7 +22,7 @@ void HomeThingMenuRefactor::drawGroupedBar(int yPos, bool extend) { yPos + (display_state_->get_font_medium()->get_baseline() + display_state_->get_margin_size()) / 2, - text_helpers_->primaryTextColor(display_state_->get_dark_mode())); + display_state_->primaryTextColor()); } void HomeThingMenuRefactor::drawLightSliderRGBBar(int xPos, int yPos, @@ -186,13 +185,11 @@ void HomeThingMenuRefactor::drawSwitch(bool switchState, int yPos) { int centerYPos = yPos + (display_state_->get_font_medium()->get_baseline() + display_state_->get_margin_size()) / 2; - display_buffer_->circle( - xPos, centerYPos, circleSize, - text_helpers_->primaryTextColor(display_state_->get_dark_mode())); + display_buffer_->circle(xPos, centerYPos, circleSize, + display_state_->primaryTextColor()); if (switchState) { - display_buffer_->filled_circle( - xPos, centerYPos, circleSize - 2, - text_helpers_->primaryTextColor(display_state_->get_dark_mode())); + display_buffer_->filled_circle(xPos, centerYPos, circleSize - 2, + display_state_->primaryTextColor()); } } @@ -230,7 +227,7 @@ void HomeThingMenuRefactor::drawArrow(int yPos, int menuTitlesCount, yPos + (display_state_->get_font_medium()->get_baseline() + display_state_->get_margin_size()) / 2, - text_helpers_->primaryTextColor(display_state_->get_dark_mode())); + display_state_->primaryTextColor()); display_buffer_->line( xPos, yPos + @@ -241,7 +238,7 @@ void HomeThingMenuRefactor::drawArrow(int yPos, int menuTitlesCount, yPos + (display_state_->get_font_medium()->get_baseline() + display_state_->get_margin_size()) / 2, - text_helpers_->primaryTextColor(display_state_->get_dark_mode())); + display_state_->primaryTextColor()); } } // namespace homething_menu_base } // namespace esphome diff --git a/components/homeThing/homeThingMenuRefactor.h b/components/homeThing/homeThingMenuRefactor.h index b6f3adbf..3e8b2d16 100644 --- a/components/homeThing/homeThingMenuRefactor.h +++ b/components/homeThing/homeThingMenuRefactor.h @@ -1,9 +1,9 @@ #pragma once #include "esphome/components/display/display_buffer.h" -#include "esphome/components/homeThing/homeThingMenuDisplayState.h" -#include "esphome/components/homeThing/homeThingMenuTextHelpers.h" #include "esphome/components/homeThing/homeThingMenuTitle.h" +#include "esphome/components/homeThingDisplayState/homeThingDisplayState.h" +#include "esphome/components/homeThingDisplayState/homeThingMenuTextHelpers.h" #ifdef USE_MEDIA_PLAYER_GROUP #include "esphome/components/homeassistant_media_player/HomeAssistantMediaPlayerGroup.h" @@ -14,12 +14,11 @@ namespace homething_menu_base { class HomeThingMenuRefactor { public: - HomeThingMenuRefactor(display::DisplayBuffer* new_display_buffer, - HomeThingMenuDisplayState* new_display_state, - HomeThingMenuTextHelpers* new_text_helpers) + HomeThingMenuRefactor( + display::DisplayBuffer* new_display_buffer, + homething_display_state::HomeThingDisplayState* new_display_state) : display_buffer_(new_display_buffer), - display_state_(new_display_state), - text_helpers_(new_text_helpers) {} + display_state_(new_display_state) {} // move to menu items void drawGroupedBar(int yPos, bool extend); void drawLightSliderBar(int xPos, int yPos, int sliderHeight, @@ -42,8 +41,7 @@ class HomeThingMenuRefactor { private: display::DisplayBuffer* display_buffer_{nullptr}; - HomeThingMenuDisplayState* display_state_{nullptr}; - HomeThingMenuTextHelpers* text_helpers_{nullptr}; + homething_display_state::HomeThingDisplayState* display_state_{nullptr}; const char* const TAG = "homething.menu.refactor"; }; } // namespace homething_menu_base diff --git a/components/homeThing/homeThingMenuScreen.cpp b/components/homeThing/homeThingMenuScreen.cpp index fc41b92e..dc981100 100644 --- a/components/homeThing/homeThingMenuScreen.cpp +++ b/components/homeThing/homeThingMenuScreen.cpp @@ -62,8 +62,9 @@ std::string HomeThingMenuScreen::entity_name_at_index(int index) { void HomeThingMenuScreen::menu_titles(std::vector* menu_titles, bool show_name) { if (show_name) { + ESP_LOGI(TAG, "menu_titles name %s", this->get_name().c_str()); menu_titles->push_back( - new MenuTitleBase(this->get_name(), "", NoMenuTitleRightIcon)); + new MenuTitleBase(this->get_name().c_str(), "", NoMenuTitleRightIcon)); show_name_ = true; } #ifdef SHOW_VERSION diff --git a/components/homeThing/homeThingMenuTextHelpers.h b/components/homeThing/homeThingMenuTextHelpers.h deleted file mode 100644 index 6bfb9d99..00000000 --- a/components/homeThing/homeThingMenuTextHelpers.h +++ /dev/null @@ -1,51 +0,0 @@ - -#pragma once - -#include -#include -#include "esphome/components/display/display_buffer.h" -#include "esphome/components/homeThing/homeThingMenuDisplayState.h" -#include "esphome/core/color.h" - -namespace esphome { -namespace homething_menu_base { - -class HomeThingMenuTextHelpers { - public: - // HomeThingMenuTextHelpers(display::DisplayBuffer* new_display_buffer, - // HomeThingMenuDisplayState* new_display_state) - // : display_buffer_(new_display_buffer), - // display_state_(new_display_state) {} - Color primaryTextColor(bool dark_mode); - Color secondaryTextColor(bool dark_mode); - int getCharacterLimit(int xPos, int fontSize, display::TextAlign alignment); - int getTextWidth(int fontSize, int characterCount); - std::string textWrap(std::string text, unsigned per_line); - void set_display_state(HomeThingMenuDisplayState* new_display_state) { - display_state_ = new_display_state; - } - void set_display_buffer(display::DisplayBuffer* new_display_buffer) { - display_buffer_ = new_display_buffer; - } - int drawTextWrapped(int xPos, int yPos, font::Font* font, Color color, - display::TextAlign alignment, std::string text, - int maxLines); - - private: - display::DisplayBuffer* display_buffer_{nullptr}; - HomeThingMenuDisplayState* display_state_{nullptr}; - const char* const TAG = "homething.menu.text_helpers"; - - void tokenize(std::string const& str, std::string delim, - std::vector* out) { - size_t start; - size_t end = 0; - - while ((start = str.find_first_not_of(delim, end)) != std::string::npos) { - end = str.find(delim, start); - out->push_back(str.substr(start, end - start)); - } - } -}; -} // namespace homething_menu_base -} // namespace esphome diff --git a/components/homeThing/homeThingMenuTitle.h b/components/homeThing/homeThingMenuTitle.h index 84e2c987..bb4fbdcc 100644 --- a/components/homeThing/homeThingMenuTitle.h +++ b/components/homeThing/homeThingMenuTitle.h @@ -18,11 +18,12 @@ static const char* const MENU_TITLE_TAG = "homething.menutitle"; enum MenuStates { bootMenu, rootMenu, - sourcesMenu, - groupMenu, - mediaPlayersMenu, + appMenu, + // sourcesMenu, + // groupMenu, + // mediaPlayersMenu, lightsDetailMenu, - nowPlayingMenu, + // nowPlayingMenu, settingsMenu, entityMenu }; @@ -38,18 +39,20 @@ enum MenuTitleRightIcon { NoMenuTitleRightIcon, ArrowMenuTitleRightIcon }; static std::string menu_state_title(MenuStates menu_state) { switch (menu_state) { - case nowPlayingMenu: - return "Now Playing"; - case sourcesMenu: - return "Sources"; - case mediaPlayersMenu: - return "Media Players"; + case appMenu: + return "App"; + // case nowPlayingMenu: + // return "Now Playing"; + // case sourcesMenu: + // return "Sources"; + // case mediaPlayersMenu: + // return "Media Players"; + // case groupMenu: + // return "Speaker Group"; case lightsDetailMenu: return "Light Detail"; case rootMenu: return "Home"; - case groupMenu: - return "Speaker Group"; case bootMenu: return "Boot"; case settingsMenu: @@ -62,18 +65,20 @@ static std::string menu_state_title(MenuStates menu_state) { static MenuTitleRightIcon menu_state_right_icon(MenuStates menu_state) { switch (menu_state) { - case nowPlayingMenu: - return ArrowMenuTitleRightIcon; - case sourcesMenu: - return ArrowMenuTitleRightIcon; - case mediaPlayersMenu: + case appMenu: return ArrowMenuTitleRightIcon; + // case nowPlayingMenu: + // return ArrowMenuTitleRightIcon; + // case sourcesMenu: + // return ArrowMenuTitleRightIcon; + // case mediaPlayersMenu: + // return ArrowMenuTitleRightIcon; + // case groupMenu: + // return ArrowMenuTitleRightIcon; case lightsDetailMenu: return ArrowMenuTitleRightIcon; case rootMenu: return NoMenuTitleRightIcon; - case groupMenu: - return ArrowMenuTitleRightIcon; case bootMenu: return NoMenuTitleRightIcon; case settingsMenu: @@ -257,95 +262,6 @@ class MenuTitleSource : public MenuTitleBase { std::string sourceTypeString() { return media_source_->sourceTypeString(); } }; -static void mediaPlayersTitleString( - const std::vector< - homeassistant_media_player::HomeAssistantBaseMediaPlayer*>* - media_players, - std::vector* menu_titles) { - - std::map< - homeassistant_media_player::HomeAssistantBaseMediaPlayer*, - std::vector> - tree; - - for (const auto media_player : (*media_players)) { - auto parent = media_player->get_parent_media_player(); - auto groupMembers = media_player->get_group_members(); - ESP_LOGD( - MENU_TITLE_TAG, - "mediaPlayersTitleString: player %s parent set %d group members %d", - media_player->get_entity_id().c_str(), parent != NULL, - groupMembers->size()); - if (parent != NULL) { - // ignore parent if its a soundbar because the tv is the root parent - if (parent->mediaSource == - homeassistant_media_player::RemotePlayerMediaSource:: - TVRemotePlayerMediaSource && - parent->get_parent_media_player() != NULL) { - auto grand_parent = parent->get_parent_media_player(); - // grand parent is tv, parent is soundbar, mediaplayer is grouped speaker - if (tree.find(grand_parent) == tree.end()) { - ESP_LOGD(MENU_TITLE_TAG, - "mediaPlayersTitleString: adding grandparent1 %s player %s", - grand_parent->get_entity_id().c_str(), - media_player->get_entity_id().c_str()); - tree[grand_parent] = {media_player}; - } else { - ESP_LOGD(MENU_TITLE_TAG, - "mediaPlayersTitleString: adding grandparent2 %s player %s", - grand_parent->get_entity_id().c_str(), - media_player->get_entity_id().c_str()); - tree[grand_parent].push_back(media_player); - } - } else if (tree.find(parent) == tree.end()) { - // dont add soundbar to tv if it's not playing - if (parent->get_player_type() == - homeassistant_media_player::RemotePlayerType:: - TVRemotePlayerType && - media_player->mediaSource != - homeassistant_media_player::RemotePlayerMediaSource:: - TVRemotePlayerMediaSource) { - ESP_LOGD(MENU_TITLE_TAG, - "mediaPlayersTitleString: adding player %s no parent", - parent->get_entity_id().c_str(), - media_player->get_entity_id().c_str()); - tree[media_player] = {}; - } else { - ESP_LOGD(MENU_TITLE_TAG, - "mediaPlayersTitleString: adding parent2 %s player %s", - parent->get_entity_id().c_str(), - media_player->get_entity_id().c_str()); - tree[parent] = {media_player}; - } - } else { - ESP_LOGD(MENU_TITLE_TAG, - "mediaPlayersTitleString: adding parent3 %s player %s", - parent->get_entity_id().c_str(), - media_player->get_entity_id().c_str()); - tree[parent].push_back(media_player); - } - } else { - if (tree.find(media_player) == tree.end()) { - ESP_LOGD(MENU_TITLE_TAG, "mediaPlayersTitleString: player set %s", - media_player->get_entity_id().c_str()); - tree[media_player] = {}; - } - } - } - ESP_LOGD(MENU_TITLE_TAG, "mediaPlayersTitleString: ------"); - for (auto tree_item : tree) { - auto parent = tree_item.first; - menu_titles->push_back( - new MenuTitlePlayer(parent->get_name(), parent->get_entity_id(), - NoMenuTitleLeftIcon, NoMenuTitleRightIcon, parent)); - for (const auto media_player : tree_item.second) { - menu_titles->push_back(new MenuTitlePlayer( - media_player->get_name(), media_player->get_entity_id(), - GroupedMenuTitleLeftIcon, NoMenuTitleRightIcon, media_player)); - } - } -} - static void activePlayerSourceTitles( std::vector* sources, std::vector* menu_titles) { diff --git a/components/homeThing/homeThingOptionMenu.h b/components/homeThing/homeThingOptionMenu.h index a2821ecc..6e9b3df1 100644 --- a/components/homeThing/homeThingOptionMenu.h +++ b/components/homeThing/homeThingOptionMenu.h @@ -3,7 +3,7 @@ #include namespace esphome { -namespace homething_menu_base { +namespace homething_menu_now_playing { struct PositionCoordinate { double x; @@ -40,5 +40,5 @@ struct HomeThingOptionMenu { circle_options = std::vector(); } }; -} // namespace homething_menu_base +} // namespace homething_menu_now_playing } // namespace esphome diff --git a/components/homeThing/version.h b/components/homeThing/version.h index 4449021d..e1ce87d4 100644 --- a/components/homeThing/version.h +++ b/components/homeThing/version.h @@ -4,8 +4,8 @@ namespace esphome { namespace homething_menu_base { -static const std::string COMPONENTS_HOMETHING_VERSION = "sept-update/2023-09-11"; +static const std::string COMPONENTS_HOMETHING_VERSION = + "lando/refactor-now-playing/2023-09-25"; } } // namespace esphome #endif // COMPONENTS_HOMETHING_VERSION_H_ - diff --git a/components/homeThingApp/__init__.py b/components/homeThingApp/__init__.py new file mode 100644 index 00000000..7e325a51 --- /dev/null +++ b/components/homeThingApp/__init__.py @@ -0,0 +1,28 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.const import CONF_ENTITY_ID, CONF_ID, CONF_NAME +from esphome.components import display +from esphome.components.homeThingDisplayState import homething_display_state_ns + +homething_app_ns = cg.esphome_ns.namespace("homething_menu_app") + +CONF_DISPLAY_STATE = "display_state" +CONF_DISPLAY = "display" + +HomeThingApp = homething_app_ns.class_("HomeThingApp") + +BASE_SCHEMA = cv.Schema( + { + cv.Required(CONF_DISPLAY_STATE): cv.use_id(homething_display_state_ns.HomeThingDisplayState), + cv.Required(CONF_DISPLAY): cv.use_id(display.DisplayBuffer), + } +).extend(cv.COMPONENT_SCHEMA) + +async def new_app_base(config): + cg.add_build_flag("-DUSE_HOMETHING_APP") + var = cg.new_Pvariable(config[CONF_ID]) + display_buffer = await cg.get_variable(config[CONF_DISPLAY]) + cg.add(var.set_display_buffer(display_buffer)) + display_state = await cg.get_variable(config[CONF_DISPLAY_STATE]) + cg.add(var.set_display_state(display_state)) + return var \ No newline at end of file diff --git a/components/homeThingApp/homeThingApp.h b/components/homeThingApp/homeThingApp.h new file mode 100644 index 00000000..1b68c7e7 --- /dev/null +++ b/components/homeThingApp/homeThingApp.h @@ -0,0 +1,102 @@ +#pragma once + +#include "esphome/components/homeThing/homeThingMenuHeader.h" +#include "esphome/components/homeThing/homeThingMenuTitle.h" +#include "esphome/core/component.h" + +#include "esphome/components/homeThing/homeThingMenuScreen.h" +#include "esphome/components/homeThingDisplayState/homeThingDisplayState.h" +#include "esphome/components/homeThingDisplayState/homeThingMenuTextHelpers.h" + +namespace esphome { +namespace homething_menu_app { + +enum NavigationCoordination { + NavigationCoordinationNone, + NavigationCoordinationPop, + NavigationCoordinationRoot, + NavigationCoordinationUpdate, + NavigationCoordinationReturn +}; + +class HomeThingApp : public homething_menu_base::HomeThingMenuHeaderSource, + public Component { + public: + // menu titles + virtual void rootMenuTitles( + std::vector* menu_titles) {} + virtual void app_menu_titles( + std::vector* menu_titles) {} + + // menu screens + virtual NavigationCoordination app_menu_select(int index) { + return NavigationCoordination::NavigationCoordinationNone; + } + virtual bool should_draw_app() { return false; } + virtual void draw_app( + int menuIndex, + const std::vector* active_menu); + virtual void idleTick(int idleTime, int display_timeout) {} + virtual int root_menu_size() { return 0; } + virtual void reset_menu() {} + virtual void set_app_menu_index(int app_menu_index) {} + + // buttons + virtual void rotaryScrollClockwise(int rotary) {} + virtual void rotaryScrollCounterClockwise(int rotary) {} + virtual NavigationCoordination buttonPressUp() { + return NavigationCoordination::NavigationCoordinationNone; + } + virtual NavigationCoordination buttonPressDown() { + return NavigationCoordination::NavigationCoordinationNone; + } + virtual NavigationCoordination buttonPressLeft() { + return NavigationCoordination::NavigationCoordinationNone; + } + virtual NavigationCoordination buttonPressRight() { + return NavigationCoordination::NavigationCoordinationNone; + } + virtual NavigationCoordination buttonPressSelect(int menuIndex) { + return NavigationCoordination::NavigationCoordinationNone; + } + virtual NavigationCoordination buttonPressSelectHold() { + return NavigationCoordination::NavigationCoordinationNone; + } + virtual NavigationCoordination buttonPressScreenLeft() { + return NavigationCoordination::NavigationCoordinationNone; + } + virtual NavigationCoordination buttonReleaseScreenLeft() { + return NavigationCoordination::NavigationCoordinationNone; + } + virtual NavigationCoordination buttonPressScreenRight() { + return NavigationCoordination::NavigationCoordinationNone; + } + + // header + virtual homething_menu_base::HomeThingMenuHeaderSource* get_header_source() { + return header_source_; + } + + // display + + virtual bool is_animating() { return false; } + + void set_display_buffer(display::DisplayBuffer* display_buffer) { + display_buffer_ = display_buffer; + } + + void set_display_state( + homething_display_state::HomeThingDisplayState* display_state) { + display_state_ = display_state; + } + + protected: + homething_menu_base::HomeThingMenuHeaderSource* header_source_{nullptr}; + display::DisplayBuffer* display_buffer_{nullptr}; + homething_display_state::HomeThingDisplayState* display_state_{nullptr}; + + private: + const char* const TAG = "homething.menu.app"; +}; +} // namespace homething_menu_app +} // namespace esphome \ No newline at end of file diff --git a/components/homeThingAppCatToy/__init__.py b/components/homeThingAppCatToy/__init__.py new file mode 100644 index 00000000..54b9a37a --- /dev/null +++ b/components/homeThingAppCatToy/__init__.py @@ -0,0 +1,24 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.const import CONF_ID +from esphome.components import homeThingApp, remote_transmitter + +CONF_MEDIA_PLAYERS = "media_player_group" +CONF_REMOTE_TRANSMITTER = "remote_transmitter" +AUTO_LOAD = ["homeThingApp"] +homething_cattoy_app_ns = cg.esphome_ns.namespace("homething_cattoy_app") + +HomeThingCatToyApp = homething_cattoy_app_ns.class_("HomeThingCatToyApp", cg.Component) + +CONFIG_SCHEMA = homeThingApp.BASE_SCHEMA.extend( + { + cv.GenerateID(CONF_ID): cv.declare_id(HomeThingCatToyApp), + cv.Required(CONF_REMOTE_TRANSMITTER): cv.use_id(remote_transmitter.RemoteTransmitterComponent) + } +) + +async def to_code(config): + var = await homeThingApp.new_app_base(config) + remote_transmitter = await cg.get_variable(config[CONF_REMOTE_TRANSMITTER]) + cg.add(var.set_remote_transmitter(remote_transmitter)) + await cg.register_component(var, config) \ No newline at end of file diff --git a/components/homeThingAppCatToy/homeThingCatToyApp.cpp b/components/homeThingAppCatToy/homeThingCatToyApp.cpp new file mode 100644 index 00000000..6bb16781 --- /dev/null +++ b/components/homeThingAppCatToy/homeThingCatToyApp.cpp @@ -0,0 +1,143 @@ +#include "homeThingCatToyApp.h" + +namespace esphome { +namespace homething_cattoy_app { + +void HomeThingCatToyApp::rootMenuTitles( + std::vector* menu_titles) { + menu_titles->push_back(new homething_menu_base::MenuTitleBase( + "Cat toy", "", homething_menu_base::ArrowMenuTitleRightIcon)); +} +void HomeThingCatToyApp::app_menu_titles( + std::vector* menu_titles) {} + +// menu screens +homething_menu_app::NavigationCoordination HomeThingCatToyApp::app_menu_select( + int index) { + return homething_menu_app::NavigationCoordination::NavigationCoordinationNone; +} +bool HomeThingCatToyApp::should_draw_app() { + return true; +} +void HomeThingCatToyApp::draw_app( + int menuIndex, + const std::vector* active_menu) { + if (display_buffer_ == nullptr) { + return; + } + auto largeFont = display_state_->get_font_large(); + auto primaryTextColor = display_state_->primaryTextColor(); + + auto color = Color(128, 0, 128); + int yPos = display_buffer_->get_height() * 0.1; + display_buffer_->printf(display_buffer_->get_width() * 0.5, yPos, largeFont, + color, display::TextAlign::TOP_CENTER, "Cat Toy!"); + + color = Color(255, 50, 100); + display_buffer_->printf((display_buffer_->get_width() * 0.5) + 1, yPos + 1, + largeFont, color, display::TextAlign::TOP_CENTER, + "Cat Toy!"); + + yPos = display_buffer_->get_height() * 0.3; + display_buffer_->printf(display_buffer_->get_width() * 0.5, yPos, largeFont, + primaryTextColor, display::TextAlign::TOP_CENTER, + "Scroll Right"); + + yPos = display_buffer_->get_height() * 0.4; + display_buffer_->printf(display_buffer_->get_width() * 0.5, yPos, largeFont, + primaryTextColor, display::TextAlign::TOP_CENTER, + "Drive"); + + yPos = display_buffer_->get_height() * 0.6; + display_buffer_->printf(display_buffer_->get_width() * 0.5, yPos, largeFont, + primaryTextColor, display::TextAlign::TOP_CENTER, + "Scroll Left"); + + yPos = display_buffer_->get_height() * 0.7; + display_buffer_->printf(display_buffer_->get_width() * 0.5, yPos, largeFont, + primaryTextColor, display::TextAlign::TOP_CENTER, + "Reverse"); +} + +void HomeThingCatToyApp::idleTick(int idleTime, int display_timeout) {} +int HomeThingCatToyApp::root_menu_size() { + return 1; +} +void HomeThingCatToyApp::reset_menu() {} +void HomeThingCatToyApp::set_app_menu_index(int app_menu_index) {} + +// buttons +void HomeThingCatToyApp::rotaryScrollClockwise(int rotary) { + auto call = remote_transmitter_->transmit(); + esphome::remote_base::ProntoData data = { + "0000 006D 0022 0000 0143 00A0 0015 0014 0015 0014 0015 0014 0015 0014 " + "0015 0014 0015 0014 0015 0014 0015 0014 0015 003A 0015 003A 0015 003A " + "0015 003A 0015 003A 0015 003A 0015 003A 0015 003A 0015 0014 0015 0014 " + "0015 0014 0015 0014 0015 0014 0015 0014 0015 0014 0015 0014 0015 003A " + "0015 003A 0015 003A 0015 003A 0015 003A 0015 003A 0015 003A 0015 003A " + "0015 06C3"}; + esphome::remote_base::ProntoProtocol().encode(call.get_data(), data); + call.set_send_times(1); + call.perform(); +} + +void HomeThingCatToyApp::rotaryScrollCounterClockwise(int rotary) { + auto call = remote_transmitter_->transmit(); + esphome::remote_base::ProntoData data = { + "0000 006D 0022 0000 0145 009D 0017 0011 0018 0011 0018 0011 0018 0011 " + "0017 0011 0018 0011 0018 0011 0018 0011 0017 0037 0018 0037 0017 0037 " + "0017 0037 0017 0037 0017 0037 0017 0037 0017 0037 0017 0011 0018 0011 " + "0017 0011 0017 0011 0017 0037 0017 0037 0017 0011 0017 0011 0017 0037 " + "0017 0037 0017 0037 0017 0037 0017 0011 0018 0011 0017 0037 0018 0036 " + "0019 06C3"}; + esphome::remote_base::ProntoProtocol().encode(call.get_data(), data); + call.set_send_times(1); + call.perform(); +} + +homething_menu_app::NavigationCoordination HomeThingCatToyApp::buttonPressUp() { + return homething_menu_app::NavigationCoordination::NavigationCoordinationPop; +} + +homething_menu_app::NavigationCoordination +HomeThingCatToyApp::buttonPressDown() { + return homething_menu_app::NavigationCoordination::NavigationCoordinationNone; +} + +homething_menu_app::NavigationCoordination +HomeThingCatToyApp::buttonPressLeft() { + return homething_menu_app::NavigationCoordination::NavigationCoordinationNone; +} + +homething_menu_app::NavigationCoordination +HomeThingCatToyApp::buttonPressRight() { + return homething_menu_app::NavigationCoordination::NavigationCoordinationNone; +} + +homething_menu_app::NavigationCoordination +HomeThingCatToyApp::buttonPressSelect(int menuIndex) { + return homething_menu_app::NavigationCoordination::NavigationCoordinationNone; +} + +homething_menu_app::NavigationCoordination +HomeThingCatToyApp::buttonPressSelectHold() { + return homething_menu_app::NavigationCoordination::NavigationCoordinationNone; +} + +homething_menu_app::NavigationCoordination +HomeThingCatToyApp::buttonPressScreenLeft() { + return homething_menu_app::NavigationCoordination::NavigationCoordinationNone; +} + +homething_menu_app::NavigationCoordination +HomeThingCatToyApp::buttonReleaseScreenLeft() { + return homething_menu_app::NavigationCoordination::NavigationCoordinationNone; +} + +homething_menu_app::NavigationCoordination +HomeThingCatToyApp::buttonPressScreenRight() { + return homething_menu_app::NavigationCoordination::NavigationCoordinationNone; +} + +} // namespace homething_cattoy_app +} // namespace esphome \ No newline at end of file diff --git a/components/homeThingAppCatToy/homeThingCatToyApp.h b/components/homeThingAppCatToy/homeThingCatToyApp.h new file mode 100644 index 00000000..7bfb98e9 --- /dev/null +++ b/components/homeThingAppCatToy/homeThingCatToyApp.h @@ -0,0 +1,87 @@ +#pragma once + +#include "esphome/components/homeThing/homeThingMenuHeader.h" +#include "esphome/components/homeThingApp/homeThingApp.h" +#include "esphome/components/remote_base/pronto_protocol.h" +#include "esphome/components/remote_transmitter/remote_transmitter.h" +namespace esphome { +namespace homething_cattoy_app { + +class HomeThingCatToyAppHeader + : public homething_menu_base::HomeThingMenuHeaderSource { + public: + // header + std::string get_header_title() { return "Cat Toy"; } + + int draw_header_details( + int xPos, int yPos, display::DisplayBuffer* display_buffer, + homething_display_state::HomeThingDisplayState* display_state, + homething_display_state::HomeThingMenuTextHelpers* text_helpers) { + return 0; + } + + protected: + private: + const char* const TAG = "homething.cattoy.header"; +}; + +class HomeThingCatToyApp : public homething_menu_app::HomeThingApp { + public: + // menu titles + void rootMenuTitles( + std::vector* menu_titles); + void app_menu_titles( + std::vector* menu_titles); + + // menu screens + homething_menu_app::NavigationCoordination app_menu_select(int index); + bool should_draw_app(); + void draw_app( + int menuIndex, + const std::vector* active_menu); + void idleTick(int idleTime, int display_timeout); + void active_tick(); + int root_menu_size(); + void reset_menu(); + void set_app_menu_index(int app_menu_index); + + // buttons + void rotaryScrollClockwise(int rotary); + void rotaryScrollCounterClockwise(int rotary); + homething_menu_app::NavigationCoordination buttonPressUp(); + homething_menu_app::NavigationCoordination buttonPressDown(); + homething_menu_app::NavigationCoordination buttonPressLeft(); + homething_menu_app::NavigationCoordination buttonPressRight(); + homething_menu_app::NavigationCoordination buttonPressSelect(int menuIndex); + homething_menu_app::NavigationCoordination buttonPressSelectHold(); + homething_menu_app::NavigationCoordination buttonPressScreenLeft(); + homething_menu_app::NavigationCoordination buttonReleaseScreenLeft(); + homething_menu_app::NavigationCoordination buttonPressScreenRight(); + + homething_menu_base::HomeThingMenuHeaderSource* get_header_source() { + return header_source_; + } + HomeThingMenuHeaderSource* header_source_ = new HomeThingCatToyAppHeader(); + + void set_remote_transmitter( + remote_transmitter::RemoteTransmitterComponent* remote_transmitter) { + remote_transmitter_ = remote_transmitter; + } + + bool is_animating() { return false; } + + protected: + private: + const char* const TAG = "homething.app.cattoy"; + + // menu titles + + void sourceMenuTitles( + std::vector* menu_titles); + void media_player_menu_titles( + std::vector* menu_titles); + + remote_transmitter::RemoteTransmitterComponent* remote_transmitter_; +}; +} // namespace homething_cattoy_app +} // namespace esphome \ No newline at end of file diff --git a/components/homeThingAppNowPlaying/HomeThingNowPlayingHeader.cpp b/components/homeThingAppNowPlaying/HomeThingNowPlayingHeader.cpp new file mode 100644 index 00000000..ce519753 --- /dev/null +++ b/components/homeThingAppNowPlaying/HomeThingNowPlayingHeader.cpp @@ -0,0 +1,195 @@ +#include "esphome/components/homeThingAppNowPlaying/HomeThingNowPlayingHeader.h" + +namespace esphome { +namespace homething_menu_now_playing { + +std::string HomeThingMenuNowPlayingHeader::get_header_title() { + switch (*app_menu_index_) { + case 0: { + if (media_player_group_ == nullptr) { + return "Now Playing"; + } + if (media_player_group_->active_player_ == nullptr) { + return "Loading..."; + } + return media_player_group_->active_player_->get_name(); + break; + } + case 1: + return "Sources"; + break; + case 2: + return "Media Players"; + break; + default: + break; + } + return "xx2"; +} + +int HomeThingMenuNowPlayingHeader::draw_header_details( + int xPos, int yPos, display::DisplayBuffer* display_buffer, + homething_display_state::HomeThingDisplayState* display_state) { + switch (*app_menu_index_) { + case 0: + break; + default: + return 0; + } + xPos = xPos - drawPlayPauseIcon(xPos, yPos, display_buffer, display_state); + xPos = xPos - drawRepeat(xPos, yPos, display_buffer, display_state); + xPos = xPos - drawShuffle(xPos, yPos, display_buffer, display_state); + return xPos; +} + +int HomeThingMenuNowPlayingHeader::drawPlayPauseIcon( + int oldXPos, int yPos, display::DisplayBuffer* display_buffer, + homething_display_state::HomeThingDisplayState* display_state) { + int iconWidth = + display_state->get_icon_size() + (display_state->get_margin_size() / 2); + int xPos = oldXPos - iconWidth + (display_state->get_margin_size() / 2); + auto active_player = media_player_group_->active_player_; + if (active_player == NULL) { + return 0; + } + auto menuTitle = homething_menu_base::headerMediaPlayerTitle(active_player); + switch (active_player->playerState) { + case homeassistant_media_player::RemotePlayerState:: + PlayingRemotePlayerState: { + display_buffer->printf( + xPos, yPos, display_state->get_font_material_small(), + menuTitle.mediaSourceIconColor( + display_state->get_color_palette()->get_accent_primary()), + menuTitle.mediaSourceIcon().c_str()); + break; + } + case homeassistant_media_player::RemotePlayerState::PausedRemotePlayerState: + display_buffer->printf( + xPos, yPos, display_state->get_font_material_small(), + display_state->get_color_palette()->get_accent_primary(), "󰏤"); + break; + case homeassistant_media_player::RemotePlayerState:: + StoppedRemotePlayerState: + display_buffer->printf( + xPos, yPos, display_state->get_font_material_small(), + display_state->get_color_palette()->get_accent_primary(), "󰓛"); + break; + case homeassistant_media_player::RemotePlayerState:: + PowerOffRemotePlayerState: + display_buffer->printf( + xPos, yPos, display_state->get_font_material_small(), + display_state->get_color_palette()->get_accent_primary(), "󰽥"); + break; + default: + return 0; + } + return iconWidth; +} + +int HomeThingMenuNowPlayingHeader::drawShuffle( + int oldXPos, int yPos, display::DisplayBuffer* display_buffer, + homething_display_state::HomeThingDisplayState* display_state) { + if (!media_player_group_ || media_player_group_->active_player_ == NULL || + display_state->get_draw_shuffle() == + homething_display_state::DisplayIconEnabledState::OFF) { + ESP_LOGI(TAG, "drawShuffle return 0"); + return 0; + } + auto active_player = media_player_group_->active_player_; + if (active_player->get_player_type() == + homeassistant_media_player::RemotePlayerType::TVRemotePlayerType || + !active_player->supports(homeassistant_media_player:: + MediaPlayerSupportedFeature::SHUFFLE_SET)) { + ESP_LOGI(TAG, "drawShuffle return 0 not set"); + return 0; + } + if (active_player->playerState != + homeassistant_media_player::RemotePlayerState::StoppedRemotePlayerState) { + int iconWidth = + display_state->get_icon_size() + (display_state->get_margin_size() / 2); + int xPos = oldXPos - iconWidth + (display_state->get_margin_size() / 2); + if (media_player_group_->mediaShuffling()) { + display_buffer->printf( + xPos, yPos, display_state->get_font_material_small(), + display_state->get_color_palette()->get_accent_primary(), "󰒝"); + } else if (display_state->get_draw_shuffle() == + homething_display_state::DisplayIconEnabledState::ALWAYS) { + display_buffer->printf( + xPos, yPos, display_state->get_font_material_small(), + display_state->get_color_palette()->get_accent_primary(), "󰒞"); + } else { + ESP_LOGI(TAG, "drawShuffle uhh %d", display_state->get_draw_shuffle()); + return 0; + } + return iconWidth; + } + ESP_LOGI(TAG, "drawShuffle fail"); + return 0; +} + +int HomeThingMenuNowPlayingHeader::drawRepeat( + int oldXPos, int yPos, display::DisplayBuffer* display_buffer, + homething_display_state::HomeThingDisplayState* display_state) { + if (display_state->get_draw_repeat() == + homething_display_state::DisplayIconEnabledState::OFF || + !media_player_group_ || media_player_group_->active_player_ == NULL) { + return 0; + } + auto active_player = media_player_group_->active_player_; + if (active_player->get_player_type() == + homeassistant_media_player::RemotePlayerType::TVRemotePlayerType || + !active_player->supports(homeassistant_media_player:: + MediaPlayerSupportedFeature::REPEAT_SET) || + active_player->playerState == + homeassistant_media_player::RemotePlayerState:: + StoppedRemotePlayerState) { + return 0; + } + int iconWidth = + display_state->get_icon_size() + (display_state->get_margin_size() / 2); + int xPos = oldXPos - iconWidth + (display_state->get_margin_size() / 2); + switch (media_player_group_->get_repeat_mode()) { + case homeassistant_media_player::MediaPlayerRepeatMode::ALL: + display_buffer->printf( + xPos, yPos, display_state->get_font_material_small(), + display_state->get_color_palette()->get_accent_primary(), "󰑖"); + break; + case homeassistant_media_player::MediaPlayerRepeatMode::ONE: + display_buffer->printf( + xPos, yPos, display_state->get_font_material_small(), + display_state->get_color_palette()->get_accent_primary(), "󰑘"); + break; + case homeassistant_media_player::MediaPlayerRepeatMode::OFF: + if (display_state->get_draw_repeat() != + homething_display_state::DisplayIconEnabledState::ALWAYS) { + return 0; + } + display_buffer->printf( + xPos, yPos, display_state->get_font_material_small(), + display_state->get_color_palette()->get_accent_primary(), "󰑗"); + break; + default: + return 0; + } + return iconWidth; +} + +int HomeThingMenuNowPlayingHeader::drawHeaderVolumeLevel( + int oldXPos, int yPos, display::DisplayBuffer* display_buffer, + homething_display_state::HomeThingDisplayState* display_state) { + if (media_player_group_ == nullptr || + media_player_group_->active_player_ == nullptr) { + return 0; + } + if (!display_state->get_draw_volume_level()) { + return 0; + } + int xPos = oldXPos - display_state->get_margin_size() / 2; + display_buffer->printf(xPos, yPos, display_state->get_font_small(), + display_state->primaryTextColor(), + display::TextAlign::TOP_RIGHT, "%.0f%%", + media_player_group_->getVolumeLevel()); + return 24; +} +} // namespace homething_menu_now_playing +} // namespace esphome \ No newline at end of file diff --git a/components/homeThingAppNowPlaying/HomeThingNowPlayingHeader.h b/components/homeThingAppNowPlaying/HomeThingNowPlayingHeader.h new file mode 100644 index 00000000..98660f92 --- /dev/null +++ b/components/homeThingAppNowPlaying/HomeThingNowPlayingHeader.h @@ -0,0 +1,48 @@ +#pragma once + +#include "esphome/components/homeThing/homeThingMenuHeader.h" +#include "esphome/components/homeThing/homeThingMenuScreen.h" +#include "esphome/components/homeThingDisplayState/homeThingDisplayState.h" +#include "esphome/components/homeThingDisplayState/homeThingMenuTextHelpers.h" +#include "esphome/components/homeassistant_media_player/HomeAssistantMediaPlayerGroup.h" + +namespace esphome { +namespace homething_menu_now_playing { + +class HomeThingMenuNowPlayingHeader + : public homething_menu_base::HomeThingMenuHeaderSource { + public: + HomeThingMenuNowPlayingHeader( + homeassistant_media_player::HomeAssistantMediaPlayerGroup* + media_player_group, + int* app_menu_index) + : media_player_group_(media_player_group), + app_menu_index_(app_menu_index) {} + // header + std::string get_header_title(); + + int draw_header_details( + int xPos, int yPos, display::DisplayBuffer* display_buffer, + homething_display_state::HomeThingDisplayState* display_state); + + protected: + homeassistant_media_player::HomeAssistantMediaPlayerGroup* + media_player_group_{nullptr}; + + private: + int drawPlayPauseIcon( + int oldXPos, int yPos, display::DisplayBuffer* display_buffer, + homething_display_state::HomeThingDisplayState* display_state); + int drawShuffle( + int oldXPos, int yPos, display::DisplayBuffer* display_buffer, + homething_display_state::HomeThingDisplayState* display_state); + int drawRepeat(int oldXPos, int yPos, display::DisplayBuffer* display_buffer, + homething_display_state::HomeThingDisplayState* display_state); + int drawHeaderVolumeLevel( + int oldXPos, int yPos, display::DisplayBuffer* display_buffer, + homething_display_state::HomeThingDisplayState* display_state); + const char* const TAG = "homething.nowplaying.control.header"; + int* app_menu_index_; +}; +} // namespace homething_menu_now_playing +} // namespace esphome \ No newline at end of file diff --git a/components/homeThingAppNowPlaying/__init__.py b/components/homeThingAppNowPlaying/__init__.py new file mode 100644 index 00000000..7b14cae3 --- /dev/null +++ b/components/homeThingAppNowPlaying/__init__.py @@ -0,0 +1,32 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.const import CONF_ID +from esphome.components import homeThingApp +from esphome.components.homeassistant_media_player import homeassistant_media_player_ns +CONF_MEDIA_PLAYERS = "media_player_group" +CONF_DISPLAY = "display" +CONF_DISPLAY_STATE = "display_state" +AUTO_LOAD = ["homeThingApp"] +DEPENDENCIES = ["homeThingApp"] + +homething_menu_now_playing_ns = cg.esphome_ns.namespace("homething_menu_now_playing") + +HomeThingMenuNowPlayingControl = homething_menu_now_playing_ns.class_("HomeThingMenuNowPlayingControl", cg.Component) + +CONF_REMOTE_TRANSMITTER = "remote_transmitter" +CONFIG_SCHEMA = homeThingApp.BASE_SCHEMA.extend( + { + cv.GenerateID(CONF_ID): cv.declare_id(HomeThingMenuNowPlayingControl), + cv.Required(CONF_MEDIA_PLAYERS): cv.use_id(homeassistant_media_player_ns.HomeAssistantMediaPlayerGroup) + } +) + +async def to_code(config): + var = await homeThingApp.new_app_base(config) + media_players = await cg.get_variable(config[CONF_MEDIA_PLAYERS]) + cg.add(var.set_media_player_group(media_players)) + + display_buffer = await cg.get_variable(config[CONF_DISPLAY]) + display_state = await cg.get_variable(config[CONF_DISPLAY_STATE]) + cg.add(var.set_now_playing_display(display_buffer, display_state, media_players)) + await cg.register_component(var, config) \ No newline at end of file diff --git a/components/homeThingAppNowPlaying/homeThingNowPlayingControl.cpp b/components/homeThingAppNowPlaying/homeThingNowPlayingControl.cpp new file mode 100644 index 00000000..b1cdef82 --- /dev/null +++ b/components/homeThingAppNowPlaying/homeThingNowPlayingControl.cpp @@ -0,0 +1,607 @@ +#include "homeThingNowPlayingControl.h" + +namespace esphome { +namespace homething_menu_now_playing { + +homeassistant_media_player::HomeAssistantMediaPlayerGroup* +HomeThingMenuNowPlayingControl::get_media_player_group() { + ESP_LOGI(TAG, "get_media_player_group null %d", + media_player_group_ == nullptr); + return media_player_group_; +} + +void HomeThingMenuNowPlayingControl::set_media_player_group( + homeassistant_media_player::HomeAssistantMediaPlayerGroup* + media_player_group) { + ESP_LOGI(TAG, "set_media_player_group null %d", + media_player_group_ == nullptr); + media_player_group_ = media_player_group; + header_source_ = + new HomeThingMenuNowPlayingHeader(media_player_group, &app_menu_index_); +} + +void HomeThingMenuNowPlayingControl::rootMenuTitles( + std::vector* menu_titles) { + ESP_LOGI(TAG, "rootMenuTitles null %d", media_player_group_ == nullptr); + if (media_player_group_ != nullptr) { + std::string title = "Now Playing"; + if (media_player_group_->active_player_ != nullptr) { + title = media_player_group_->active_player_->get_name(); + } + menu_titles->push_back(new homething_menu_base::MenuTitleBase( + title, "", homething_menu_base::NoMenuTitleRightIcon)); + menu_titles->push_back(new homething_menu_base::MenuTitleBase( + "Sources", "", homething_menu_base::NoMenuTitleRightIcon)); + if (media_player_group_->totalPlayers() > 1) { + menu_titles->push_back(new homething_menu_base::MenuTitleBase( + "Media Players", "", homething_menu_base::NoMenuTitleRightIcon)); + } + } +} + +void HomeThingMenuNowPlayingControl::app_menu_titles( + std::vector* menu_titles) { + ESP_LOGI(TAG, "menu_titles null %d app menu index %d", + media_player_group_ == nullptr, app_menu_index_); + if (media_player_group_ != nullptr) { + if (app_menu_index_ == 0) { + return; + } else if (app_menu_index_ == 1) { + sourceMenuTitles(menu_titles); + } else if (app_menu_index_ == 2) { + media_player_menu_titles(menu_titles); + } + } +} + +void HomeThingMenuNowPlayingControl::select_source_menu(int index) { + // const auto sourceTitleState = static_cast(activeMenuTitle); + // auto source = sourceTitleState->media_source_; + auto player_source_index = + media_player_group_->get_active_player_source_index(); + if (player_source_index == -1) { + ESP_LOGI(TAG, "select_source_menu: set player source index %d", index); + media_player_group_->set_active_player_source_index(index); + return; + } + + const auto sources = media_player_group_->activePlayerSources(); + if (sources->size() == 0) { + return; + } + int active_player_source_index = + sources->size() == 1 ? 0 : player_source_index; + auto playerSources = (*sources)[active_player_source_index]->get_sources(); + media_player_source::MediaPlayerSourceItem* source = (*playerSources)[index]; + media_player_group_->playSource(source); + ESP_LOGI(TAG, "select_source_menu: set player source index %d", + active_player_source_index); + // const auto new_source = new media_player_source::MediaPlayerSourceItem( + // source->get_name(), source->get_media_content_id(), + // source->get_media_type()); + // media_player_group_->playSource(new_source); + // idleMenu(true); + circle_menu_->set_active_menu(playingNewSourceMenu, + media_player_group_->active_player_); + app_menu_index_ = 0; +} + +homething_menu_app::NavigationCoordination +HomeThingMenuNowPlayingControl::app_menu_select(int index) { + ESP_LOGI(TAG, "app_menu_select null %d app menu index %d", + media_player_group_ == nullptr, app_menu_index_); + switch (app_menu_index_) { + case 0: + break; + case 1: + select_source_menu(index); + return homething_menu_app::NavigationCoordination:: + NavigationCoordinationUpdate; + case 2: { + auto media_players = media_player_group_->get_media_players(); + if (media_players->size() == 0 || media_players->size() <= index) { + return homething_menu_app::NavigationCoordination:: + NavigationCoordinationNone; + } + media_player_group_->selectMediaPlayers((*media_players)[index]); + return homething_menu_app::NavigationCoordination:: + NavigationCoordinationPop; + } + } + return homething_menu_app::NavigationCoordination::NavigationCoordinationNone; +} + +void HomeThingMenuNowPlayingControl::sourceMenuTitles( + std::vector* menu_titles) { + if (media_player_group_ == nullptr) { + return; + } + if (media_player_group_->active_player_ == nullptr) { + media_player_group_->selectNextMediaPlayer(); + if (media_player_group_->active_player_ == nullptr) { + return; + } + } + const auto sources = media_player_group_->activePlayerSources(); + const auto index = media_player_group_->get_active_player_source_index(); + if (index == -1 && sources->size() > 1) { + activePlayerSourceTitles(sources, menu_titles); + return; + } else if (index == -1 && sources->size() == 1) { + auto playerSources = (*sources)[0]->get_sources(); + activePlayerSourceItemTitles(playerSources, menu_titles); + return; + } else if (sources->size() > 1) { + auto playerSources = (*sources)[index]->get_sources(); + activePlayerSourceItemTitles(playerSources, menu_titles); + return; + } +} + +void HomeThingMenuNowPlayingControl::media_player_menu_titles( + std::vector* menu_titles) { + + std::map< + homeassistant_media_player::HomeAssistantBaseMediaPlayer*, + std::vector> + tree; + + for (const auto media_player : (*media_player_group_->get_media_players())) { + auto parent = media_player->get_parent_media_player(); + auto groupMembers = media_player->get_group_members(); + ESP_LOGD( + TAG, + "mediaPlayersTitleString: player %s parent set %d group members %d", + media_player->get_entity_id().c_str(), parent != NULL, + groupMembers->size()); + if (parent != NULL) { + // ignore parent if its a soundbar because the tv is the root parent + if (parent->mediaSource == + homeassistant_media_player::RemotePlayerMediaSource:: + TVRemotePlayerMediaSource && + parent->get_parent_media_player() != NULL) { + auto grand_parent = parent->get_parent_media_player(); + // grand parent is tv, parent is soundbar, mediaplayer is grouped speaker + if (tree.find(grand_parent) == tree.end()) { + ESP_LOGD(TAG, + "mediaPlayersTitleString: adding grandparent1 %s player %s", + grand_parent->get_entity_id().c_str(), + media_player->get_entity_id().c_str()); + tree[grand_parent] = {media_player}; + } else { + ESP_LOGD(TAG, + "mediaPlayersTitleString: adding grandparent2 %s player %s", + grand_parent->get_entity_id().c_str(), + media_player->get_entity_id().c_str()); + tree[grand_parent].push_back(media_player); + } + } else if (tree.find(parent) == tree.end()) { + // dont add soundbar to tv if it's not playing + if (parent->get_player_type() == + homeassistant_media_player::RemotePlayerType:: + TVRemotePlayerType && + media_player->mediaSource != + homeassistant_media_player::RemotePlayerMediaSource:: + TVRemotePlayerMediaSource) { + ESP_LOGD(TAG, "mediaPlayersTitleString: adding player %s no parent", + parent->get_entity_id().c_str(), + media_player->get_entity_id().c_str()); + tree[media_player] = {}; + } else { + ESP_LOGD(TAG, "mediaPlayersTitleString: adding parent2 %s player %s", + parent->get_entity_id().c_str(), + media_player->get_entity_id().c_str()); + tree[parent] = {media_player}; + } + } else { + ESP_LOGD(TAG, "mediaPlayersTitleString: adding parent3 %s player %s", + parent->get_entity_id().c_str(), + media_player->get_entity_id().c_str()); + tree[parent].push_back(media_player); + } + } else { + if (tree.find(media_player) == tree.end()) { + ESP_LOGD(TAG, "mediaPlayersTitleString: player set %s", + media_player->get_entity_id().c_str()); + tree[media_player] = {}; + } + } + } + ESP_LOGD(TAG, "mediaPlayersTitleString: ------"); + for (auto tree_item : tree) { + auto parent = tree_item.first; + menu_titles->push_back(new homething_menu_base::MenuTitlePlayer( + parent->get_name(), parent->get_entity_id(), + homething_menu_base::NoMenuTitleLeftIcon, + homething_menu_base::NoMenuTitleRightIcon, parent)); + for (const auto media_player : tree_item.second) { + menu_titles->push_back(new homething_menu_base::MenuTitlePlayer( + media_player->get_name(), media_player->get_entity_id(), + homething_menu_base::GroupedMenuTitleLeftIcon, + homething_menu_base::NoMenuTitleRightIcon, media_player)); + } + } +} + +int HomeThingMenuNowPlayingControl::root_menu_size() { + if (media_player_group_ != nullptr) { + if (media_player_group_->totalPlayers() > 1) { + return 3; + } + return 2; + } + return 0; +} + +void HomeThingMenuNowPlayingControl::set_app_menu_index(int app_menu_index) { + if (app_menu_index_ >= root_menu_size()) { + return; + } + app_menu_index_ = app_menu_index; +} + +bool HomeThingMenuNowPlayingControl::should_draw_app() { + if (app_menu_index_ == 0) { + return true; + } + return false; +} + +void HomeThingMenuNowPlayingControl::draw_app( + int menuIndex, + const std::vector* active_menu) { + switch (app_menu_index_) { + case 0: + now_playing_display_->drawNowPlaying( + menuIndex, circle_menu_->get_active_menu(), active_menu); + break; + default: + break; + } +} + +void HomeThingMenuNowPlayingControl::idleTick(int idleTime, + int display_timeout) { + ESP_LOGI(TAG, "idleTick: idle %d", idleTime); + if (media_player_group_ != nullptr) { + media_player_group_->findActivePlayer(); + } + if (idleTime == 3) { + circle_menu_->clear_active_menu(); + } else if (idleTime == display_timeout) { + if (media_player_group_ != NULL && + media_player_group_->playerSearchFinished) { + // if (get_charging() && menuTree.back() != bootMenu) { + // idleTime++; + // return; + // } + // ESP_LOGI(TAG, "idleTick: idle root menu %d", display_can_sleep()); + // menuTree.assign(1, rootMenu); + // animation_->resetAnimation(); + // idleMenu(false); + // menu_display_->updateDisplay(false); + } + return; + } + if (media_player_group_ != NULL) { + bool updatedMediaPositions = media_player_group_->updateMediaPosition(); + if (updatedMediaPositions) { + // switch (menuTree.back()) { + // case nowPlayingMenu: { + // ESP_LOGD(TAG, "idleTick: update media positions %d", + // display_can_sleep()); + // if (!display_can_sleep()) { + // update_display(); + // } else { + // if (!get_charging()) + // sleep_display(); + // } + // break; + // } + // default: + // break; + // } + } + } +} + +void HomeThingMenuNowPlayingControl::reset_menu() { + if (media_player_group_) { + media_player_group_->newSpeakerGroupParent = NULL; + media_player_group_->set_active_player_source_index(-1); + } + app_menu_index_ = -1; +} + +// void HomeThingMenuNowPlayingControl::activeMenu(std::vector* menu_titles) { +// switch (menuTree.back()) { +// case nowPlayingMenu: +// #ifdef USE_MEDIA_PLAYER_GROUP +// speakerNowPlayingMenuStates(media_player_group_->active_player_, +// menu_display_->get_draw_now_playing_menu(), +// menu_titles); +// return; +// #endif +// break; +// case groupMenu: { +// #ifdef USE_MEDIA_PLAYER_GROUP +// if (media_player_group_->newSpeakerGroupParent != NULL) { +// return groupTitleSwitches(media_player_group_->get_media_players(), +// media_player_group_->newSpeakerGroupParent, +// menu_titles); +// return; +// } +// groupTitleString(media_player_group_->get_media_players(), menu_titles); +// return; +// #endif +// break; +// } +// } +// } + +bool HomeThingMenuNowPlayingControl::select_media_player_feature( + homeassistant_media_player::MediaPlayerFeatureCommand* command) { + auto feature = command->get_feature(); + switch (feature) { + case homeassistant_media_player::MediaPlayerSupportedFeature::MENU_HOME: + // topMenu(); + return true; + case homeassistant_media_player::MediaPlayerSupportedFeature::GROUPING: + // menuIndex = 0; + // menuTree.push_back(groupMenu); + return true; + case homeassistant_media_player::MediaPlayerSupportedFeature:: + CUSTOM_COMMAND: { + auto feature_command = command->get_command(); + if (feature_command != nullptr) { + feature_command->on_command(); + return true; + } + } + + default: + media_player_group_->call_feature(feature); + break; + } + return false; +} + +homething_menu_app::NavigationCoordination +HomeThingMenuNowPlayingControl::button_press_now_playing_option( + CircleOptionMenuPosition position) { + if (circle_menu_->get_active_menu()) { + auto feature = circle_menu_->tap_option_menu( + position, media_player_group_->get_active_player()); + if (feature) { + ESP_LOGI(TAG, "button_press_now_playing_option: option menu selected %d", + feature->get_feature()); + circle_menu_->clear_active_menu(); + if (select_media_player_feature(feature)) { + return homething_menu_app::NavigationCoordination:: + NavigationCoordinationPop; + } + return homething_menu_app::NavigationCoordination:: + NavigationCoordinationUpdate; + } + ESP_LOGW(TAG, "button_press_now_playing_option: option menu NOT selected"); + return homething_menu_app::NavigationCoordination:: + NavigationCoordinationNone; + } + return homething_menu_app::NavigationCoordination::NavigationCoordinationNone; +} + +// MARK: Buttons + +void HomeThingMenuNowPlayingControl::rotaryScrollClockwise(int rotary) { + // if (menu_display_->get_draw_now_playing_menu()) { + // break; + // } + media_player_group_->increaseSpeakerVolume(); + circle_menu_->set_active_menu(volumeOptionMenu, + media_player_group_->active_player_); +} +void HomeThingMenuNowPlayingControl::rotaryScrollCounterClockwise(int rotary) { + // if (menu_display_->get_draw_now_playing_menu()) { + // break; + // } + media_player_group_->decreaseSpeakerVolume(); + circle_menu_->set_active_menu(volumeOptionMenu, + media_player_group_->active_player_); +} + +homething_menu_app::NavigationCoordination +HomeThingMenuNowPlayingControl::buttonPressUp() { + switch (button_press_now_playing_option(CircleOptionMenuPosition::TOP)) { + case homething_menu_app::NavigationCoordination:: + NavigationCoordinationUpdate: + return homething_menu_app::NavigationCoordination:: + NavigationCoordinationUpdate; + case homething_menu_app::NavigationCoordination::NavigationCoordinationPop: + return homething_menu_app::NavigationCoordination:: + NavigationCoordinationPop; + default: + break; + } + + if (media_player_group_ == nullptr) { + return homething_menu_app::NavigationCoordination:: + NavigationCoordinationPop; + } + + switch (media_player_group_->active_player_->get_player_type()) { + case homeassistant_media_player::RemotePlayerType::TVRemotePlayerType: + media_player_group_->sendActivePlayerRemoteCommand( + homeassistant_media_player::MediaPlayerTVRemoteCommand::UP); + return homething_menu_app::NavigationCoordination:: + NavigationCoordinationReturn; + case homeassistant_media_player::RemotePlayerType::SpeakerRemotePlayerType: + break; + } + return homething_menu_app::NavigationCoordination::NavigationCoordinationPop; +} + +homething_menu_app::NavigationCoordination +HomeThingMenuNowPlayingControl::buttonPressDown() { + switch (button_press_now_playing_option(CircleOptionMenuPosition::BOTTOM)) { + case homething_menu_app::NavigationCoordination:: + NavigationCoordinationUpdate: + return homething_menu_app::NavigationCoordination:: + NavigationCoordinationUpdate; + case homething_menu_app::NavigationCoordination::NavigationCoordinationPop: + return homething_menu_app::NavigationCoordination:: + NavigationCoordinationPop; + default: + break; + } + + switch (media_player_group_->active_player_->get_player_type()) { + case homeassistant_media_player::RemotePlayerType::TVRemotePlayerType: + media_player_group_->sendActivePlayerRemoteCommand( + homeassistant_media_player::MediaPlayerTVRemoteCommand::DOWN); + return homething_menu_app::NavigationCoordination:: + NavigationCoordinationReturn; + case homeassistant_media_player::RemotePlayerType::SpeakerRemotePlayerType: + media_player_group_->active_player_->playPause(); + break; + } + return homething_menu_app::NavigationCoordination::NavigationCoordinationNone; +} + +homething_menu_app::NavigationCoordination +HomeThingMenuNowPlayingControl::buttonPressLeft() { + switch (button_press_now_playing_option(CircleOptionMenuPosition::LEFT)) { + case homething_menu_app::NavigationCoordination:: + NavigationCoordinationUpdate: + return homething_menu_app::NavigationCoordination:: + NavigationCoordinationUpdate; + case homething_menu_app::NavigationCoordination::NavigationCoordinationPop: + return homething_menu_app::NavigationCoordination:: + NavigationCoordinationPop; + default: + break; + } + + switch (media_player_group_->active_player_->get_player_type()) { + case homeassistant_media_player::RemotePlayerType::TVRemotePlayerType: + media_player_group_->sendActivePlayerRemoteCommand( + homeassistant_media_player::MediaPlayerTVRemoteCommand::LEFT); + return homething_menu_app::NavigationCoordination:: + NavigationCoordinationReturn; + case homeassistant_media_player::RemotePlayerType::SpeakerRemotePlayerType: + circle_menu_->clear_active_menu(); + break; + } + return homething_menu_app::NavigationCoordination::NavigationCoordinationNone; +} + +homething_menu_app::NavigationCoordination +HomeThingMenuNowPlayingControl::buttonPressRight() { + switch (button_press_now_playing_option(CircleOptionMenuPosition::RIGHT)) { + case homething_menu_app::NavigationCoordination:: + NavigationCoordinationUpdate: + return homething_menu_app::NavigationCoordination:: + NavigationCoordinationUpdate; + case homething_menu_app::NavigationCoordination::NavigationCoordinationPop: + return homething_menu_app::NavigationCoordination:: + NavigationCoordinationPop; + default: + break; + } + + switch (media_player_group_->active_player_->get_player_type()) { + case homeassistant_media_player::RemotePlayerType::TVRemotePlayerType: + media_player_group_->sendActivePlayerRemoteCommand( + homeassistant_media_player::MediaPlayerTVRemoteCommand::RIGHT); + return homething_menu_app::NavigationCoordination:: + NavigationCoordinationReturn; + case homeassistant_media_player::RemotePlayerType::SpeakerRemotePlayerType: + media_player_group_->active_player_->nextTrack(); + break; + } + return homething_menu_app::NavigationCoordination::NavigationCoordinationNone; +} + +homething_menu_app::NavigationCoordination +HomeThingMenuNowPlayingControl::buttonPressSelect(int menuIndex) { + switch (button_press_now_playing_option(CircleOptionMenuPosition::CENTER)) { + case homething_menu_app::NavigationCoordination:: + NavigationCoordinationUpdate: + return homething_menu_app::NavigationCoordination:: + NavigationCoordinationUpdate; + case homething_menu_app::NavigationCoordination::NavigationCoordinationPop: + return homething_menu_app::NavigationCoordination:: + NavigationCoordinationPop; + default: + break; + } + switch (media_player_group_->active_player_->get_player_type()) { + case homeassistant_media_player::RemotePlayerType::TVRemotePlayerType: + media_player_group_->sendActivePlayerRemoteCommand( + homeassistant_media_player::MediaPlayerTVRemoteCommand::SELECT); + return homething_menu_app::NavigationCoordination:: + NavigationCoordinationReturn; + case homeassistant_media_player::RemotePlayerType::SpeakerRemotePlayerType: + break; + } + // auto features = + // media_player_group_->active_player_->get_option_menu_features(true); + // auto active_feature = (*features)[menuIndex]; + // ESP_LOGI(TAG, "selectNowPlayingMenu: %d, %s", menuIndex, + // active_feature->get_title().c_str()); + // switch (active_feature->get_feature()) { + // case homeassistant_media_player::MediaPlayerSupportedFeature::VOLUME_SET: + // case homeassistant_media_player::MediaPlayerSupportedFeature::VOLUME_UP: + // case homeassistant_media_player::MediaPlayerSupportedFeature::VOLUME_DOWN: + // circle_menu_->set_active_menu(volumeOptionMenu, + // media_player_group_->active_player_); + // break; + // case homeassistant_media_player::MediaPlayerSupportedFeature::GROUPING: + // menuIndex = 0; + // // menuTree.push_back(groupMenu); + // break; + // default: + // break; + // } + // select_media_player_feature(active_feature); + return homething_menu_app::NavigationCoordination:: + NavigationCoordinationUpdate; +} + +homething_menu_app::NavigationCoordination +HomeThingMenuNowPlayingControl::buttonPressSelectHold() { + return homething_menu_app::NavigationCoordination::NavigationCoordinationNone; +} + +homething_menu_app::NavigationCoordination +HomeThingMenuNowPlayingControl::buttonPressScreenLeft() { + if (circle_menu_->get_active_menu()) { + circle_menu_->clear_active_menu(); + } else { + circle_menu_->set_active_menu(speakerOptionMenu, + media_player_group_->active_player_); + } + return homething_menu_app::NavigationCoordination:: + NavigationCoordinationUpdate; +} + +homething_menu_app::NavigationCoordination +HomeThingMenuNowPlayingControl::buttonReleaseScreenLeft() { + switch (media_player_group_->active_player_->get_player_type()) { + case homeassistant_media_player::RemotePlayerType::TVRemotePlayerType: + // update_display(); + break; + case homeassistant_media_player::RemotePlayerType::SpeakerRemotePlayerType: + break; + } + return homething_menu_app::NavigationCoordination::NavigationCoordinationNone; +} + +homething_menu_app::NavigationCoordination +HomeThingMenuNowPlayingControl::buttonPressScreenRight() { + media_player_group_->selectNextMediaPlayer(); + return homething_menu_app::NavigationCoordination:: + NavigationCoordinationUpdate; +} + +} // namespace homething_menu_now_playing +} // namespace esphome \ No newline at end of file diff --git a/components/homeThingAppNowPlaying/homeThingNowPlayingControl.h b/components/homeThingAppNowPlaying/homeThingNowPlayingControl.h new file mode 100644 index 00000000..fc58d7c8 --- /dev/null +++ b/components/homeThingAppNowPlaying/homeThingNowPlayingControl.h @@ -0,0 +1,100 @@ +#pragma once + +#include "esphome/components/homeThing/homeThingMenuTitle.h" +#include "esphome/components/homeThing/homeThingOptionMenu.h" +#include "esphome/components/homeThingApp/homeThingApp.h" +#include "esphome/components/homeThingAppNowPlaying/homeThingNowPlayingDisplay.h" +#include "esphome/components/homeThingAppNowPlaying/homeThingNowPlayingOptionMenu.h" +#include "esphome/components/homeassistant_media_player/HomeAssistantMediaPlayerGroup.h" + +#include "esphome/components/homeThing/homeThingMenuScreen.h" +#include "esphome/components/homeThingAppNowPlaying/HomeThingNowPlayingHeader.h" +#include "esphome/components/homeThingDisplayState/homeThingDisplayState.h" +#include "esphome/components/homeThingDisplayState/homeThingMenuTextHelpers.h" + +namespace esphome { +namespace homething_menu_now_playing { + +class HomeThingMenuNowPlayingControl : public homething_menu_app::HomeThingApp { + public: + homeassistant_media_player::HomeAssistantMediaPlayerGroup* + get_media_player_group(); + void set_media_player_group( + homeassistant_media_player::HomeAssistantMediaPlayerGroup* + media_player_group); + + // menu titles + void rootMenuTitles( + std::vector* menu_titles); + void app_menu_titles( + std::vector* menu_titles); + + // menu screens + homething_menu_app::NavigationCoordination app_menu_select(int index); + bool should_draw_app(); + void draw_app( + int menuIndex, + const std::vector* active_menu); + void idleTick(int idleTime, int display_timeout); + int root_menu_size(); + // void selectNowPlayingMenu(); + void reset_menu(); + void set_app_menu_index(int app_menu_index); + + // buttons + void rotaryScrollClockwise(int rotary); + void rotaryScrollCounterClockwise(int rotary); + homething_menu_app::NavigationCoordination buttonPressUp(); + homething_menu_app::NavigationCoordination buttonPressDown(); + homething_menu_app::NavigationCoordination buttonPressLeft(); + homething_menu_app::NavigationCoordination buttonPressRight(); + homething_menu_app::NavigationCoordination buttonPressSelect(int menuIndex); + homething_menu_app::NavigationCoordination buttonPressSelectHold(); + homething_menu_app::NavigationCoordination buttonPressScreenLeft(); + homething_menu_app::NavigationCoordination buttonReleaseScreenLeft(); + homething_menu_app::NavigationCoordination buttonPressScreenRight(); + + // controls + bool select_media_player_feature( + homeassistant_media_player::MediaPlayerFeatureCommand* command); + homething_menu_app::NavigationCoordination button_press_now_playing_option( + CircleOptionMenuPosition position); + + // display + void set_now_playing_display( + display::DisplayBuffer* new_display_buffer, + homething_display_state::HomeThingDisplayState* new_display_state, + homeassistant_media_player::HomeAssistantMediaPlayerGroup* + new_media_player_group) { + now_playing_display_ = new HomeThingMenuNowPlaying( + new_display_buffer, new_display_state, new_media_player_group); + } + + homething_menu_base::HomeThingMenuHeaderSource* get_header_source() { + return header_source_; + } + HomeThingMenuHeaderSource* header_source_{nullptr}; + + bool is_animating() { return false; } + + protected: + homeassistant_media_player::HomeAssistantMediaPlayerGroup* + media_player_group_{nullptr}; + HomeThingMenuNowPlayingOptionMenu* circle_menu_ = + new HomeThingMenuNowPlayingOptionMenu(); + HomeThingMenuNowPlaying* now_playing_display_{nullptr}; + void select_source_menu(int index); + int app_menu_index_ = 0; + + private: + const char* const TAG = "homething.nowplaying.control"; + + // menu titles + + void sourceMenuTitles( + std::vector* menu_titles); + void media_player_menu_titles( + std::vector* menu_titles); +}; +} // namespace homething_menu_now_playing +} // namespace esphome \ No newline at end of file diff --git a/components/homeThing/homeThingMenuNowPlaying.cpp b/components/homeThingAppNowPlaying/homeThingNowPlayingDisplay.cpp similarity index 73% rename from components/homeThing/homeThingMenuNowPlaying.cpp rename to components/homeThingAppNowPlaying/homeThingNowPlayingDisplay.cpp index 0e5e0a34..2d3b2434 100644 --- a/components/homeThing/homeThingMenuNowPlaying.cpp +++ b/components/homeThingAppNowPlaying/homeThingNowPlayingDisplay.cpp @@ -1,12 +1,12 @@ #ifdef USE_MEDIA_PLAYER_GROUP -#include "homeThingMenuNowPlaying.h" -#include "esphome/components/homeThing/homeThingMenuDisplayState.h" -#include "esphome/components/homeThing/homeThingMenuTextHelpers.h" +#include "homeThingNowPlayingDisplay.h" #include "esphome/components/homeThing/homeThingOptionMenu.h" +#include "esphome/components/homeThingDisplayState/homeThingDisplayState.h" +#include "esphome/components/homeThingDisplayState/homeThingMenuTextHelpers.h" #include "esphome/core/log.h" namespace esphome { -namespace homething_menu_base { +namespace homething_menu_now_playing { PositionCoordinate HomeThingMenuNowPlaying::get_coordinate(double radius, double angle) { @@ -79,52 +79,47 @@ void HomeThingMenuNowPlaying::drawCircleOptionMenu( coordinate.x, coordinate.y); display_buffer_->printf( (display_buffer_->get_width() / 2) + coordinate.x, y_pos + coordinate.y, - display_state_->get_font_small(), - text_helpers_->primaryTextColor(display_state_->get_dark_mode()), + display_state_->get_font_small(), display_state_->primaryTextColor(), text_alignment, title.c_str()); } } void HomeThingMenuNowPlaying::drawNowPlayingSelectMenu( - const std::vector* menu_titles, int menu_index) { + const std::vector* menu_titles, + int menu_index) { int yPos = display_buffer_->get_height() - display_state_->get_margin_size() - display_state_->get_font_large()->get_baseline(); auto menuTitlesSize = menu_titles->size(); if (menuTitlesSize < 1 || menu_index >= menuTitlesSize) { return; } - display_buffer_->printf( - display_buffer_->get_width() * 0.5, yPos, - display_state_->get_font_large(), - text_helpers_->primaryTextColor(display_state_->get_dark_mode()), - display::TextAlign::TOP_CENTER, - (*menu_titles)[menu_index]->get_name().c_str()); + display_buffer_->printf(display_buffer_->get_width() * 0.5, yPos, + display_state_->get_font_large(), + display_state_->primaryTextColor(), + display::TextAlign::TOP_CENTER, + (*menu_titles)[menu_index]->get_name().c_str()); if (menu_index + 1 < menuTitlesSize) { - display_buffer_->printf( - display_buffer_->get_width() * 0.85, yPos, - display_state_->get_font_small(), - text_helpers_->primaryTextColor(display_state_->get_dark_mode()), - display::TextAlign::TOP_CENTER, - (*menu_titles)[menu_index + 1]->get_name().c_str()); + display_buffer_->printf(display_buffer_->get_width() * 0.85, yPos, + display_state_->get_font_small(), + display_state_->primaryTextColor(), + display::TextAlign::TOP_CENTER, + (*menu_titles)[menu_index + 1]->get_name().c_str()); } else { display_buffer_->printf( display_buffer_->get_width() * 0.85, yPos, - display_state_->get_font_small(), - text_helpers_->primaryTextColor(display_state_->get_dark_mode()), + display_state_->get_font_small(), display_state_->primaryTextColor(), display::TextAlign::TOP_CENTER, (*menu_titles)[0]->get_name().c_str()); } if (menu_index - 1 >= 0) { - display_buffer_->printf( - display_buffer_->get_width() * 0.15, yPos, - display_state_->get_font_small(), - text_helpers_->primaryTextColor(display_state_->get_dark_mode()), - display::TextAlign::TOP_CENTER, - (*menu_titles)[menu_index - 1]->get_name().c_str()); + display_buffer_->printf(display_buffer_->get_width() * 0.15, yPos, + display_state_->get_font_small(), + display_state_->primaryTextColor(), + display::TextAlign::TOP_CENTER, + (*menu_titles)[menu_index - 1]->get_name().c_str()); } else { display_buffer_->printf( display_buffer_->get_width() * 0.15, yPos, - display_state_->get_font_small(), - text_helpers_->primaryTextColor(display_state_->get_dark_mode()), + display_state_->get_font_small(), display_state_->primaryTextColor(), display::TextAlign::TOP_CENTER, (*menu_titles)[menuTitlesSize - 1]->get_name().c_str()); } @@ -132,9 +127,13 @@ void HomeThingMenuNowPlaying::drawNowPlayingSelectMenu( void HomeThingMenuNowPlaying::drawNowPlaying( int menuIndex, HomeThingOptionMenu* option_menu, - const std::vector* active_menu) { - if ((option_menu && drawOptionMenuAndStop(option_menu)) || - display_state_ == nullptr) { + const std::vector* active_menu) { + if (drawOptionMenuAndStop(option_menu)) { + ESP_LOGI(TAG, "drawNowPlaying: drawOptionMenuAndStop"); + return; + } + if (display_state_ == nullptr) { + ESP_LOGI(TAG, "drawNowPlaying: display state null"); return; } if (active_menu && active_menu->size() > 0 && @@ -146,11 +145,10 @@ void HomeThingMenuNowPlaying::drawNowPlaying( if (media_player_group_->active_player_->playerState == homeassistant_media_player::RemotePlayerState:: PowerOffRemotePlayerState) { - display_buffer_->printf( - display_buffer_->get_width() / 2, yPos, - display_state_->get_font_large(), - text_helpers_->primaryTextColor(display_state_->get_dark_mode()), - display::TextAlign::TOP_CENTER, "Power Off"); + display_buffer_->printf(display_buffer_->get_width() / 2, yPos, + display_state_->get_font_large(), + display_state_->primaryTextColor(), + display::TextAlign::TOP_CENTER, "Power Off"); return; } std::string nowPlayingText = "Now Playing,"; @@ -196,17 +194,15 @@ void HomeThingMenuNowPlaying::drawNowPlaying( yPos = drawTextWrapped( display_state_->get_margin_size(), yPos, display_state_->get_font_medium()->get_baseline(), - display_state_->get_font_medium(), - text_helpers_->primaryTextColor(display_state_->get_dark_mode()), + display_state_->get_font_medium(), display_state_->primaryTextColor(), display::TextAlign::TOP_LEFT, *nowPlayingWrappedText, maxLines); delete nowPlayingWrappedText; if (mediaArtistWrappedText->size() == 0 && mediaTitleWrappedText->size() == 0) { - display_buffer_->printf( - display_buffer_->get_width() / 2, yPos, - display_state_->get_font_large(), - text_helpers_->primaryTextColor(display_state_->get_dark_mode()), - display::TextAlign::TOP_CENTER, "Nothing!"); + display_buffer_->printf(display_buffer_->get_width() / 2, yPos, + display_state_->get_font_large(), + display_state_->primaryTextColor(), + display::TextAlign::TOP_CENTER, "Nothing!"); delete mediaArtistWrappedText; delete mediaTitleWrappedText; return; @@ -220,8 +216,7 @@ void HomeThingMenuNowPlaying::drawNowPlaying( if (mediaArtistWrappedText->size() > 0) { yPos = drawTextWrapped( xPos, yPos, display_state_->get_font_large()->get_baseline(), - display_state_->get_font_large(), - text_helpers_->primaryTextColor(display_state_->get_dark_mode()), + display_state_->get_font_large(), display_state_->primaryTextColor(), display::TextAlign::TOP_CENTER, *mediaArtistWrappedText, maxLines); } delete mediaArtistWrappedText; @@ -232,8 +227,7 @@ void HomeThingMenuNowPlaying::drawNowPlaying( drawTextWrapped( display_buffer_->get_width() / 2, yPos, display_state_->get_font_medium()->get_baseline(), - display_state_->get_font_medium(), - text_helpers_->primaryTextColor(display_state_->get_dark_mode()), + display_state_->get_font_medium(), display_state_->primaryTextColor(), display::TextAlign::TOP_CENTER, *mediaTitleWrappedText, maxLines); } delete mediaTitleWrappedText; @@ -270,29 +264,25 @@ void HomeThingMenuNowPlaying::drawMediaDuration() { int yPos = display_state_->getBottomBarYPosition( true, display_buffer_->get_height()); - display_buffer_->rectangle( - textWidth, yPos, totalBarWidth, barHeight, - text_helpers_->primaryTextColor(display_state_->get_dark_mode())); + display_buffer_->rectangle(textWidth, yPos, totalBarWidth, barHeight, + display_state_->primaryTextColor()); display_buffer_->filled_rectangle( textWidth + barMargin * 2, yPos + barMargin * 2, barWidth, - barHeight - 2 - barMargin * 2, - text_helpers_->primaryTextColor(display_state_->get_dark_mode())); + barHeight - 2 - barMargin * 2, display_state_->primaryTextColor()); int textYPos = yPos - display_state_->get_font_small()->get_baseline() * 0.1; std::string mediaDurationSeconds = secondsToString(mediaDuration); std::string mediaPositionSeconds = secondsToString(mediaPosition); - display_buffer_->printf( - display_state_->get_margin_size(), textYPos, - display_state_->get_font_small(), - text_helpers_->primaryTextColor(display_state_->get_dark_mode()), - display::TextAlign::TOP_LEFT, "%d:%s", mediaPosition / 60, - mediaPositionSeconds.c_str()); + display_buffer_->printf(display_state_->get_margin_size(), textYPos, + display_state_->get_font_small(), + display_state_->primaryTextColor(), + display::TextAlign::TOP_LEFT, "%d:%s", + mediaPosition / 60, mediaPositionSeconds.c_str()); display_buffer_->printf( display_buffer_->get_width() - display_state_->get_margin_size(), textYPos, display_state_->get_font_small(), - text_helpers_->primaryTextColor(display_state_->get_dark_mode()), - display::TextAlign::TOP_RIGHT, "%d:%s", mediaDuration / 60, - mediaDurationSeconds.c_str()); + display_state_->primaryTextColor(), display::TextAlign::TOP_RIGHT, + "%d:%s", mediaDuration / 60, mediaDurationSeconds.c_str()); } void HomeThingMenuNowPlaying::drawVolumeOptionMenu() { @@ -343,26 +333,25 @@ bool HomeThingMenuNowPlaying::drawOptionMenuAndStop( case noOptionMenu: return false; case playingNewSourceMenu: - display_buffer_->printf( - display_buffer_->get_width() / 2, - display_state_->get_header_height() + - display_state_->get_margin_size(), - display_state_->get_font_medium(), - text_helpers_->primaryTextColor(display_state_->get_dark_mode()), - display::TextAlign::TOP_CENTER, "Playing..."); + display_buffer_->printf(display_buffer_->get_width() / 2, + display_state_->get_header_height() + + display_state_->get_margin_size(), + display_state_->get_font_medium(), + display_state_->primaryTextColor(), + display::TextAlign::TOP_CENTER, "Playing..."); auto playingNewSourceWrappedText = getWrappedTitles(display_buffer_->get_width() / 2, display_state_->get_font_large()->get_baseline(), display::TextAlign::TOP_CENTER, media_player_group_->get_new_source_name()); - drawTextWrapped( - display_buffer_->get_width() / 2, - display_state_->get_header_height() + - display_state_->get_margin_size() * 2 + - display_state_->get_font_medium()->get_baseline(), - 24, display_state_->get_font_large(), - text_helpers_->primaryTextColor(display_state_->get_dark_mode()), - display::TextAlign::TOP_CENTER, *playingNewSourceWrappedText, 0); + drawTextWrapped(display_buffer_->get_width() / 2, + display_state_->get_header_height() + + display_state_->get_margin_size() * 2 + + display_state_->get_font_medium()->get_baseline(), + 24, display_state_->get_font_large(), + display_state_->primaryTextColor(), + display::TextAlign::TOP_CENTER, + *playingNewSourceWrappedText, 0); delete playingNewSourceWrappedText; return true; } @@ -384,8 +373,9 @@ std::vector* HomeThingMenuNowPlaying::getWrappedTitles( if (text.size() == 0) { return output; } - std::string wrappedTitles = text_helpers_->textWrap( - text, text_helpers_->getCharacterLimit(xPos, fontSize, alignment)); + std::string wrappedTitles = display_state_->get_text_helpers()->textWrap( + text, display_state_->getCharacterLimit(xPos, fontSize, alignment, + display_buffer_->get_width())); tokenize(wrappedTitles, "\n", output); return output; } @@ -394,8 +384,8 @@ int HomeThingMenuNowPlaying::drawTextWrapped( int xPos, int yPos, int fontSize, font::Font* font, Color color, display::TextAlign alignment, std::vector wrappedTitles, int maxLines) { - int characterLimit = - text_helpers_->getCharacterLimit(xPos, fontSize, alignment); + int characterLimit = display_state_->getCharacterLimit( + xPos, fontSize, alignment, display_buffer_->get_width()); int max = maxLines != 0 && maxLines < wrappedTitles.size() ? maxLines : wrappedTitles.size(); @@ -416,6 +406,6 @@ int HomeThingMenuNowPlaying::drawTextWrapped( } return yPos + (max * fontSize); } -} // namespace homething_menu_base +} // namespace homething_menu_now_playing } // namespace esphome #endif diff --git a/components/homeThing/homeThingMenuNowPlaying.h b/components/homeThingAppNowPlaying/homeThingNowPlayingDisplay.h similarity index 68% rename from components/homeThing/homeThingMenuNowPlaying.h rename to components/homeThingAppNowPlaying/homeThingNowPlayingDisplay.h index cfdd8a77..537f5228 100644 --- a/components/homeThing/homeThingMenuNowPlaying.h +++ b/components/homeThingAppNowPlaying/homeThingNowPlayingDisplay.h @@ -7,35 +7,31 @@ #include #include #include "esphome/components/display/display_buffer.h" -#include "esphome/components/homeThing/homeThingMenuDisplayState.h" -#include "esphome/components/homeThing/homeThingMenuTextHelpers.h" #include "esphome/components/homeThing/homeThingMenuTitle.h" #include "esphome/components/homeThing/homeThingOptionMenu.h" +#include "esphome/components/homeThingDisplayState/homeThingDisplayState.h" +#include "esphome/components/homeThingDisplayState/homeThingMenuTextHelpers.h" #include "esphome/components/homeassistant_media_player/HomeAssistantMediaPlayerGroup.h" namespace esphome { -namespace homething_menu_base { +namespace homething_menu_now_playing { class HomeThingMenuNowPlaying { public: - HomeThingMenuNowPlaying(display::DisplayBuffer* new_display_buffer, - HomeThingMenuDisplayState* new_display_state, - HomeThingMenuTextHelpers* new_text_helpers) + HomeThingMenuNowPlaying( + display::DisplayBuffer* new_display_buffer, + homething_display_state::HomeThingDisplayState* new_display_state, + homeassistant_media_player::HomeAssistantMediaPlayerGroup* + new_media_player_group) : display_buffer_(new_display_buffer), display_state_(new_display_state), - text_helpers_(new_text_helpers) {} + media_player_group_(new_media_player_group) {} PositionCoordinate get_coordinate(double radius, double angle); - void drawNowPlaying(int menuIndex, HomeThingOptionMenu* option_menu, - const std::vector* active_menu); - - void set_media_player_group( - homeassistant_media_player::HomeAssistantMediaPlayerGroup* - media_player_group) { - media_player_group_ = media_player_group; - } + void drawNowPlaying( + int menuIndex, HomeThingOptionMenu* option_menu, + const std::vector* active_menu); private: display::DisplayBuffer* display_buffer_{nullptr}; - HomeThingMenuDisplayState* display_state_{nullptr}; - HomeThingMenuTextHelpers* text_helpers_{nullptr}; + homething_display_state::HomeThingDisplayState* display_state_{nullptr}; homeassistant_media_player::HomeAssistantMediaPlayerGroup* media_player_group_{nullptr}; void drawCircleOptionMenu( @@ -44,8 +40,9 @@ class HomeThingMenuNowPlaying { std::string secondsToString(int seconds); void drawMediaDuration(); bool drawOptionMenuAndStop(const HomeThingOptionMenu* option_menu); - void drawNowPlayingSelectMenu(const std::vector* menu_titles, - int menu_index); + void drawNowPlayingSelectMenu( + const std::vector* menu_titles, + int menu_index); std::vector* getWrappedTitles(int xPos, int fontSize, display::TextAlign alignment, std::string text); @@ -67,6 +64,6 @@ class HomeThingMenuNowPlaying { const char* const TAG = "homething.menu.now_playing"; }; -} // namespace homething_menu_base +} // namespace homething_menu_now_playing } // namespace esphome #endif \ No newline at end of file diff --git a/components/homeThing/homeThingMenuNowPlayingOptionMenu.cpp b/components/homeThingAppNowPlaying/homeThingNowPlayingOptionMenu.cpp similarity index 95% rename from components/homeThing/homeThingMenuNowPlayingOptionMenu.cpp rename to components/homeThingAppNowPlaying/homeThingNowPlayingOptionMenu.cpp index 89c86b20..4df96dd7 100644 --- a/components/homeThing/homeThingMenuNowPlayingOptionMenu.cpp +++ b/components/homeThingAppNowPlaying/homeThingNowPlayingOptionMenu.cpp @@ -1,8 +1,8 @@ #ifdef USE_MEDIA_PLAYER_GROUP -#include "homeThingMenuNowPlayingOptionMenu.h" +#include "homeThingNowPlayingOptionMenu.h" namespace esphome { -namespace homething_menu_base { +namespace homething_menu_now_playing { void HomeThingMenuNowPlayingOptionMenu::set_active_menu( const HomeThingOptionMenuType type, @@ -67,7 +67,7 @@ HomeThingMenuNowPlayingOptionMenu::tap_option_menu( } return nullptr; } -} // namespace homething_menu_base +} // namespace homething_menu_now_playing } // namespace esphome #endif \ No newline at end of file diff --git a/components/homeThing/homeThingMenuNowPlayingOptionMenu.h b/components/homeThingAppNowPlaying/homeThingNowPlayingOptionMenu.h similarity index 84% rename from components/homeThing/homeThingMenuNowPlayingOptionMenu.h rename to components/homeThingAppNowPlaying/homeThingNowPlayingOptionMenu.h index 47a736f8..25518c18 100644 --- a/components/homeThing/homeThingMenuNowPlayingOptionMenu.h +++ b/components/homeThingAppNowPlaying/homeThingNowPlayingOptionMenu.h @@ -6,14 +6,14 @@ #include #include #include "esphome/components/display/display_buffer.h" -#include "esphome/components/homeThing/homeThingMenuDisplayState.h" -#include "esphome/components/homeThing/homeThingMenuTextHelpers.h" #include "esphome/components/homeThing/homeThingMenuTitle.h" #include "esphome/components/homeThing/homeThingOptionMenu.h" +#include "esphome/components/homeThingDisplayState/homeThingDisplayState.h" +#include "esphome/components/homeThingDisplayState/homeThingMenuTextHelpers.h" #include "esphome/components/homeassistant_media_player/HomeAssistantMediaPlayerGroup.h" namespace esphome { -namespace homething_menu_base { +namespace homething_menu_now_playing { class HomeThingMenuNowPlayingOptionMenu { public: @@ -35,7 +35,7 @@ class HomeThingMenuNowPlayingOptionMenu { const char* const TAG = "homething.menu.option"; bool bottomMenu_ = false; }; -} // namespace homething_menu_base +} // namespace homething_menu_now_playing } // namespace esphome #endif diff --git a/components/homeThingAppSnake/__init__.py b/components/homeThingAppSnake/__init__.py new file mode 100644 index 00000000..b08f97f4 --- /dev/null +++ b/components/homeThingAppSnake/__init__.py @@ -0,0 +1,19 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.const import CONF_ID +from esphome.components import homeThingApp + +AUTO_LOAD = ["homeThingApp"] +homething_app_snake_ns = cg.esphome_ns.namespace("homething_app_snake") + +HomeThingAppSnake = homething_app_snake_ns.class_("HomeThingAppSnake", cg.Component) + +CONFIG_SCHEMA = homeThingApp.BASE_SCHEMA.extend( + { + cv.GenerateID(CONF_ID): cv.declare_id(HomeThingAppSnake) + } +) + +async def to_code(config): + var = await homeThingApp.new_app_base(config) + await cg.register_component(var, config) \ No newline at end of file diff --git a/components/homeThingAppSnake/homeThingAppSnake.cpp b/components/homeThingAppSnake/homeThingAppSnake.cpp new file mode 100644 index 00000000..f0186f4f --- /dev/null +++ b/components/homeThingAppSnake/homeThingAppSnake.cpp @@ -0,0 +1,184 @@ +#include "homeThingAppSnake.h" +#include "esphome/core/log.h" + +namespace esphome { +namespace homething_app_snake { + +void HomeThingAppSnake::reset() { + ESP_LOGI(TAG, "Resetting snake"); + const auto bounds = get_display_bounds(); + const auto newFruitPosition = get_random_coordinate(); + const auto newSnakePosition = get_random_coordinate(); + fruit_position_.x = newFruitPosition.x; + fruit_position_.y = newFruitPosition.y; + snake.clear(); + snake.push_back(newSnakePosition); +} + +Coordinate HomeThingAppSnake::get_random_coordinate() { + const auto bounds = get_display_bounds(); + return Coordinate((rand() % (bounds.x)), (rand() % (bounds.y))); +} + +Coordinate HomeThingAppSnake::get_display_bounds() { + int widthBounds = + (display_buffer_->get_width() - (margin * 2)) / displayScale; + int heightBounds = (display_buffer_->get_height() - + ((margin * 2) + display_state_->get_header_height())) / + displayScale; + return Coordinate(widthBounds, heightBounds); +} + +void HomeThingAppSnake::rootMenuTitles( + std::vector* menu_titles) { + menu_titles->push_back(new homething_menu_base::MenuTitleBase( + "Snake", "", homething_menu_base::ArrowMenuTitleRightIcon)); +} + +void HomeThingAppSnake::app_menu_titles( + std::vector* menu_titles) {} + +// menu screens +homething_menu_app::NavigationCoordination HomeThingAppSnake::app_menu_select( + int index) { + return homething_menu_app::NavigationCoordination::NavigationCoordinationNone; +} + +bool HomeThingAppSnake::should_draw_app() { + return true; +} + +void HomeThingAppSnake::draw_resized_pixel(int coordinateX, int coordinateY, + Color color) { + int x = coordinateX * displayScale; + int y = coordinateY * displayScale; + for (int i = 0; i < displayScale; ++i) { + for (int j = 0; j < displayScale; ++j) { + display_buffer_->draw_pixel_at( + x + i + margin, y + j + margin + display_state_->get_header_height(), + color); + } + } +} + +void HomeThingAppSnake::draw_app( + int menuIndex, + const std::vector* active_menu) { + active_tick(); + for (auto segment : snake) { + draw_resized_pixel(segment.x, segment.y, Color(255, 255, 255)); + } + draw_resized_pixel(fruit_position_.x, fruit_position_.y, Color(255, 0, 0)); + display_buffer_->rectangle( + margin, margin + display_state_->get_header_height(), + get_display_bounds().x * displayScale, + get_display_bounds().y * displayScale, Color(255, 255, 255)); +} + +void HomeThingAppSnake::idleTick(int idleTime, int display_timeout) {} + +void HomeThingAppSnake::active_tick() { + if (fruit_position_.x == -1) { + reset(); + } + int newHeadY = snake[0].y + snake_direction_.x; + int newHeadX = snake[0].x + snake_direction_.y; + const auto bounds = get_display_bounds(); + int widthBounds = bounds.x; + int heightBounds = bounds.y; + if (newHeadX == fruit_position_.x && newHeadY == fruit_position_.y) { + // Snake ate the fruit + snake.push_back(Coordinate(fruit_position_.x, fruit_position_.y)); + auto newFruitPosition = get_random_coordinate(); + fruit_position_.x = newFruitPosition.x; + fruit_position_.y = newFruitPosition.y; + ESP_LOGW(TAG, "Snake ate the fruit %d %d, %d %d", newHeadX, newHeadY, + widthBounds, heightBounds); + return; + } else { + // Move the snake + for (int i = snake.size() - 1; i > 0; --i) { + snake[i].x = snake[i - 1].x; + snake[i].y = snake[i - 1].y; + } + snake[0].x = newHeadX; + snake[0].y = newHeadY; + } + + // Check for collisions with the snake's body + for (int i = 1; i < snake.size(); ++i) { + if (snake[i].x == newHeadX && snake[i].y == newHeadY) { + ESP_LOGW(TAG, "Snake hit itself %d %d, %d %d", newHeadX, newHeadY, + widthBounds, heightBounds); + reset(); + } + } + // Check for collisions with the window boundaries + if (newHeadX < 0 || newHeadX >= bounds.x || newHeadY < 0 || + newHeadY >= bounds.y) { + ESP_LOGW(TAG, "Snake hit the wall %d %d, %d %d", newHeadX, newHeadY, + bounds.x, bounds.y); + reset(); + } +} + +int HomeThingAppSnake::root_menu_size() { + return 1; +} +void HomeThingAppSnake::reset_menu() {} +void HomeThingAppSnake::set_app_menu_index(int app_menu_index) {} + +// buttons +void HomeThingAppSnake::rotaryScrollClockwise(int rotary) {} +void HomeThingAppSnake::rotaryScrollCounterClockwise(int rotary) {} +homething_menu_app::NavigationCoordination HomeThingAppSnake::buttonPressUp() { + snake_direction_ = Coordinate(-1, 0); + return homething_menu_app::NavigationCoordination:: + NavigationCoordinationReturn; +} +homething_menu_app::NavigationCoordination +HomeThingAppSnake::buttonPressDown() { + snake_direction_ = Coordinate(1, 0); + return homething_menu_app::NavigationCoordination:: + NavigationCoordinationReturn; +} // namespace homething_app_snake +homething_menu_app::NavigationCoordination +HomeThingAppSnake::buttonPressLeft() { + snake_direction_ = Coordinate(0, -1); + return homething_menu_app::NavigationCoordination:: + NavigationCoordinationReturn; +} +homething_menu_app::NavigationCoordination +HomeThingAppSnake::buttonPressRight() { + snake_direction_ = Coordinate(0, 1); + return homething_menu_app::NavigationCoordination::NavigationCoordinationNone; +} +homething_menu_app::NavigationCoordination HomeThingAppSnake::buttonPressSelect( + int menuIndex) { + reset(); + if (displayScale < 20) { + displayScale = displayScale + 2; + } else { + displayScale = 2; + } + return homething_menu_app::NavigationCoordination::NavigationCoordinationNone; +} +homething_menu_app::NavigationCoordination +HomeThingAppSnake::buttonPressSelectHold() { + return homething_menu_app::NavigationCoordination::NavigationCoordinationNone; +} +homething_menu_app::NavigationCoordination +HomeThingAppSnake::buttonPressScreenLeft() { + return homething_menu_app::NavigationCoordination::NavigationCoordinationNone; +} +homething_menu_app::NavigationCoordination +HomeThingAppSnake::buttonReleaseScreenLeft() { + return homething_menu_app::NavigationCoordination::NavigationCoordinationNone; +} +homething_menu_app::NavigationCoordination +HomeThingAppSnake::buttonPressScreenRight() { + return homething_menu_app::NavigationCoordination::NavigationCoordinationNone; +} + +} // namespace homething_app_snake +} // namespace esphome \ No newline at end of file diff --git a/components/homeThingAppSnake/homeThingAppSnake.h b/components/homeThingAppSnake/homeThingAppSnake.h new file mode 100644 index 00000000..7f406c53 --- /dev/null +++ b/components/homeThingAppSnake/homeThingAppSnake.h @@ -0,0 +1,111 @@ +#pragma once + +#include "esphome/components/homeThing/homeThingMenuHeader.h" +#include "esphome/components/homeThingApp/homeThingApp.h" + +namespace esphome { +namespace homething_app_snake { + +class HomeThingAppSnakeHeader + : public homething_menu_base::HomeThingMenuHeaderSource { + public: + // header + std::string get_header_title() { return "Snake"; } + + int draw_header_details( + int xPos, int yPos, display::DisplayBuffer* display_buffer, + homething_display_state::HomeThingDisplayState* display_state, + homething_display_state::HomeThingMenuTextHelpers* text_helpers) { + return 0; + } + + protected: + private: + const char* const TAG = "homething.app.snake.header"; +}; + +struct Coordinate { + int x, y; + Coordinate(int newX, int newY) : x(newX), y(newY) {} +}; + +class HomeThingAppSnake : public homething_menu_app::HomeThingApp { + public: + void reset(); + // menu titles + void rootMenuTitles( + std::vector* menu_titles); + + void app_menu_titles( + std::vector* menu_titles); + + // menu screens + homething_menu_app::NavigationCoordination app_menu_select(int index); + bool should_draw_app(); + void draw_app( + int menuIndex, + const std::vector* active_menu); + + void idleTick(int idleTime, int display_timeout); + void active_tick(); + + int root_menu_size(); + void reset_menu(); + void set_app_menu_index(int app_menu_index); + + // buttons + void rotaryScrollClockwise(int rotary); + void rotaryScrollCounterClockwise(int rotary); + homething_menu_app::NavigationCoordination buttonPressUp(); + homething_menu_app::NavigationCoordination buttonPressDown(); + homething_menu_app::NavigationCoordination buttonPressLeft(); + homething_menu_app::NavigationCoordination buttonPressRight(); + homething_menu_app::NavigationCoordination buttonPressSelect(int menuIndex); + homething_menu_app::NavigationCoordination buttonPressSelectHold(); + homething_menu_app::NavigationCoordination buttonPressScreenLeft(); + homething_menu_app::NavigationCoordination buttonReleaseScreenLeft(); + homething_menu_app::NavigationCoordination buttonPressScreenRight(); + + homething_menu_base::HomeThingMenuHeaderSource* get_header_source() { + return header_source_; + } + HomeThingMenuHeaderSource* header_source_ = new HomeThingAppSnakeHeader(); + + void set_display_buffer(display::DisplayBuffer* display_buffer) { + display_buffer_ = display_buffer; + } + + void set_display_state( + homething_display_state::HomeThingDisplayState* display_state) { + display_state_ = display_state; + } + + bool is_animating() { return true; } + + protected: + private: + const char* const TAG = "homething.app.snake"; + + // display + display::DisplayBuffer* display_buffer_{nullptr}; + homething_display_state::HomeThingDisplayState* display_state_{nullptr}; + + // menu titles + + void sourceMenuTitles( + std::vector* menu_titles); + void media_player_menu_titles( + std::vector* menu_titles); + + void draw_resized_pixel(int coordinateX, int coordinateY, Color color); + Coordinate get_display_bounds(); + void create_new_fruit(); + Coordinate get_random_coordinate(); + Coordinate fruit_position_ = Coordinate(-1, -1); + Coordinate snake_direction_ = Coordinate(1, 0); + std::vector snake = {Coordinate(30, 30)}; + double displayScale = 16; + int margin = 4; +}; +} // namespace homething_app_snake +} // namespace esphome \ No newline at end of file diff --git a/components/homeThingDisplayState/__init__.py b/components/homeThingDisplayState/__init__.py new file mode 100644 index 00000000..44916054 --- /dev/null +++ b/components/homeThingDisplayState/__init__.py @@ -0,0 +1,172 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import font, color, image +from esphome.const import CONF_ID, CONF_RED, CONF_BLUE, CONF_GREEN + +homething_display_state_ns = cg.esphome_ns.namespace("homething_display_state") +HomeThingDisplayState = homething_display_state_ns.class_("HomeThingDisplayState") +HomeThingColorPalette = homething_display_state_ns.class_("HomeThingColorPalette") +DisplayIconEnabledState = homething_display_state_ns.enum("DisplayIconEnabledState") + +CONF_DISPLAY_STATE = "display_state" + +# display state +CONF_OFF = "off" +CONF_ON = "on" +CONF_ALWAYS = "always" +CONF_FONT_SMALL = "font_small" +CONF_FONT_MEDIUM = "font_medium" +CONF_FONT_LARGE = "font_large" +CONF_FONT_LARGE_HEAVY = "font_large_heavy" +CONF_FONT_MATERIAL_LARGE = "font_material_large" +CONF_FONT_MATERIAL_SMALL = "font_material_small" +CONF_LAUNCH_IMAGE = "launch_image" +CONF_DRAW_NOW_PLAYING_BOTTOM_MENU = "draw_now_playing_bottom_menu" +CONF_HEADER_HEIGHT = "header_height" +CONF_MARGIN_SIZE = "margin_size" +CONF_BOTTOM_BAR_MARGIN = "bottom_bar_margin" +CONF_SLIDER_MARGIN_SIZE = "slider_margin_size" +CONF_ICON_SIZE = "icon_size" +CONF_SCROLL_BAR_WIDTH = "scroll_bar_width" +CONF_BOOT_LOGO_SIZE = "boot_logo_size" +CONF_NOW_PLAYING_MAX_LINES = "now_playing_max_lines" +CONF_FONT_SIZE_WIDTH_RATIO = "font_size_width_ratio" +CONF_DRAW_SHUFFLE = "draw_shuffle" +CONF_DRAW_REPEAT = "draw_repeat" +CONF_DRAW_HEADER_TIME = "draw_header_time" +CONF_DRAW_BATTERY_LEVEL = "draw_battery_level" +CONF_DARK_MODE = "dark_mode" +CONF_DRAW_VOLUME_LEVEL = "draw_volume_level" +CONF_BOOT_DEVICE_NAME = "boot_device_name" + +# colors +CONF_COLORS = "colors" +CONF_GRAY_DARK = "gray_dark" +CONF_GRAY_DARK_2 = "gray_dark_2" +CONF_GRAY = "gray" +CONF_ACCENT_PRIMARY = "accent_primary" +CONF_BLACK = "black" +CONF_WHITE = "white" +CONF_PINK = "pink" +CONF_YELLOW = "yellow" + +COLOR_PALETTE_IDS = [ + CONF_GRAY_DARK, + CONF_GRAY_DARK_2, + CONF_GRAY, + CONF_ACCENT_PRIMARY, + CONF_BLUE, + CONF_GREEN, + CONF_BLACK, + CONF_WHITE, + CONF_PINK, + CONF_RED, + CONF_YELLOW +] + +COLOR_SCHEMA = cv.Schema( + { + cv.GenerateID(): cv.declare_id(HomeThingColorPalette), + cv.Optional(CONF_GRAY_DARK): cv.use_id(color.ColorStruct), + cv.Optional(CONF_GRAY_DARK_2): cv.use_id(color.ColorStruct), + cv.Optional(CONF_GRAY): cv.use_id(color.ColorStruct), + cv.Optional(CONF_ACCENT_PRIMARY): cv.use_id(color.ColorStruct), + cv.Optional(CONF_BLUE): cv.use_id(color.ColorStruct), + cv.Optional(CONF_GREEN): cv.use_id(color.ColorStruct), + cv.Optional(CONF_BLACK): cv.use_id(color.ColorStruct), + cv.Optional(CONF_WHITE): cv.use_id(color.ColorStruct), + cv.Optional(CONF_PINK): cv.use_id(color.ColorStruct), + cv.Optional(CONF_RED): cv.use_id(color.ColorStruct), + cv.Optional(CONF_YELLOW): cv.use_id(color.ColorStruct), + }, + cv.has_at_least_one_key() +) + +DISPLAY_ICON_MODES = { + CONF_OFF: DisplayIconEnabledState.OFF, + CONF_ON: DisplayIconEnabledState.ON, + CONF_ALWAYS: DisplayIconEnabledState.ALWAYS, +} + +CONFIG_SCHEMA = cv.Schema( + { + cv.GenerateID(): cv.declare_id(HomeThingDisplayState), + cv.Required(CONF_FONT_SMALL): cv.use_id(font.Font), + cv.Required(CONF_FONT_MEDIUM): cv.use_id(font.Font), + cv.Required(CONF_FONT_LARGE): cv.use_id(font.Font), + cv.Required(CONF_FONT_LARGE_HEAVY): cv.use_id(font.Font), + cv.Required(CONF_FONT_MATERIAL_LARGE): cv.use_id(font.Font), + cv.Required(CONF_FONT_MATERIAL_SMALL): cv.use_id(font.Font), + cv.Optional(CONF_LAUNCH_IMAGE, default={}): cv.use_id(image.Image_), + cv.Optional(CONF_HEADER_HEIGHT, default=16): cv.int_, + cv.Optional(CONF_MARGIN_SIZE, default=4): cv.int_, + cv.Optional(CONF_BOTTOM_BAR_MARGIN, default=1): cv.int_, + cv.Optional(CONF_SLIDER_MARGIN_SIZE, default=8): cv.int_, + cv.Optional(CONF_ICON_SIZE, default=18): cv.int_, + cv.Optional(CONF_SCROLL_BAR_WIDTH, default=6): cv.int_, + cv.Optional(CONF_BOOT_LOGO_SIZE, default=48): cv.int_, + cv.Optional(CONF_NOW_PLAYING_MAX_LINES, default=5): cv.int_, + cv.Optional(CONF_FONT_SIZE_WIDTH_RATIO, default=0.6): cv.float_, + cv.Optional(CONF_DRAW_SHUFFLE, default=CONF_ON): cv.enum(DISPLAY_ICON_MODES), + cv.Optional(CONF_DRAW_REPEAT, default=CONF_ON): cv.enum(DISPLAY_ICON_MODES), + cv.Optional(CONF_DRAW_HEADER_TIME, default=True): cv.boolean, + cv.Optional(CONF_DRAW_BATTERY_LEVEL, default=False): cv.boolean, + cv.Optional(CONF_DARK_MODE, default=True): cv.boolean, + cv.Optional(CONF_DRAW_VOLUME_LEVEL, default=False): cv.boolean, + cv.Optional(CONF_DRAW_NOW_PLAYING_BOTTOM_MENU, default=False): cv.boolean, + cv.Optional(CONF_BOOT_DEVICE_NAME, default="homeThing"): cv.string, + cv.Optional(CONF_COLORS, default={}): COLOR_SCHEMA, + } +) + +async def ids_to_code(config, var, types): + for key in types: + if key in config: + conf = await cg.get_variable(config[key]) + cg.add(getattr(var, f"set_{key}")(conf)) + +def keys_to_code(config, var, types): + for key in types: + if key in config: + conf = config[key] + cg.add(getattr(var, f"set_{key}")(conf)) + +DISPLAY_STATE_IDS = [ + CONF_FONT_SMALL, + CONF_FONT_MEDIUM, + CONF_FONT_LARGE, + CONF_FONT_LARGE_HEAVY, + CONF_FONT_MATERIAL_LARGE, + CONF_FONT_MATERIAL_SMALL, + CONF_LAUNCH_IMAGE +] + +DISPLAY_STATE_TYPES = [ + CONF_DRAW_NOW_PLAYING_BOTTOM_MENU, + CONF_HEADER_HEIGHT, + CONF_MARGIN_SIZE, + CONF_BOTTOM_BAR_MARGIN, + CONF_SLIDER_MARGIN_SIZE, + CONF_ICON_SIZE, + CONF_SCROLL_BAR_WIDTH, + CONF_BOOT_LOGO_SIZE, + CONF_NOW_PLAYING_MAX_LINES, + CONF_FONT_SIZE_WIDTH_RATIO, + CONF_DRAW_SHUFFLE, + CONF_DRAW_REPEAT, + CONF_DRAW_HEADER_TIME, + CONF_DRAW_BATTERY_LEVEL, + CONF_DARK_MODE, + CONF_DRAW_VOLUME_LEVEL, + CONF_BOOT_DEVICE_NAME +] + +async def to_code(config): + display_state = cg.new_Pvariable(config[CONF_ID]) + keys_to_code(config, display_state, DISPLAY_STATE_TYPES) + await ids_to_code(config, display_state, DISPLAY_STATE_IDS) + + if CONF_COLORS in config: + color_palette = cg.new_Pvariable(config[CONF_COLORS][CONF_ID]) + await ids_to_code(config[CONF_COLORS], color_palette, COLOR_PALETTE_IDS) + cg.add(display_state.set_color_palette(color_palette)) diff --git a/components/homeThing/homeThingColorPalette.h b/components/homeThingDisplayState/homeThingColorPalette.h similarity index 95% rename from components/homeThing/homeThingColorPalette.h rename to components/homeThingDisplayState/homeThingColorPalette.h index 8350ac53..405f7d13 100644 --- a/components/homeThing/homeThingColorPalette.h +++ b/components/homeThingDisplayState/homeThingColorPalette.h @@ -3,7 +3,7 @@ #include "esphome/core/color.h" namespace esphome { -namespace homething_menu_base { +namespace homething_display_state { class HomeThingColorPalette { public: @@ -46,5 +46,5 @@ class HomeThingColorPalette { Color red_ = Color(255, 0, 0); Color yellow_ = Color(255, 191, 25); }; -} // namespace homething_menu_base +} // namespace homething_display_state } // namespace esphome diff --git a/components/homeThing/homeThingMenuDisplayState.h b/components/homeThingDisplayState/homeThingDisplayState.h similarity index 75% rename from components/homeThing/homeThingMenuDisplayState.h rename to components/homeThingDisplayState/homeThingDisplayState.h index a99c4ce8..71911cc7 100644 --- a/components/homeThing/homeThingMenuDisplayState.h +++ b/components/homeThingDisplayState/homeThingDisplayState.h @@ -3,15 +3,16 @@ #include #include "esphome/components/display/display_buffer.h" #include "esphome/components/font/font.h" +#include "esphome/components/homeThingDisplayState/homeThingColorPalette.h" #include "esphome/components/image/image.h" -#include "homeThingColorPalette.h" +#include "homeThingMenuTextHelpers.h" namespace esphome { -namespace homething_menu_base { +namespace homething_display_state { enum DisplayIconEnabledState { OFF = 1, ON = 2, ALWAYS = 3 }; -class HomeThingMenuDisplayState { +class HomeThingDisplayState { public: font::Font* get_font_small() { return font_small_; } void set_font_small(font::Font* font_small) { font_small_ = font_small; } @@ -119,7 +120,39 @@ class HomeThingMenuDisplayState { color_palette_ = color_palette; } + HomeThingMenuTextHelpers* get_text_helpers() { return text_helpers_; } + + Color primaryTextColor() { + return text_helpers_->primaryTextColor(dark_mode_, + get_color_palette()->get_white(), + get_color_palette()->get_black()); + } + Color secondaryTextColor() { + return text_helpers_->primaryTextColor(dark_mode_, + get_color_palette()->get_white(), + get_color_palette()->get_white()); + } + + int getCharacterLimit(int xPos, int fontSize, display::TextAlign alignment, + int displayWidth) { + return text_helpers_->getCharacterLimit( + xPos, fontSize, alignment, displayWidth, get_font_size_width_ratio()); + } + int getTextWidth(int fontSize, int characterCount) { + return text_helpers_->getTextWidth(fontSize, characterCount, + get_font_size_width_ratio()); + } + + int drawTextWrapped(int xPos, int yPos, font::Font* font, Color color, + display::TextAlign alignment, std::string text, + int maxLines, display::DisplayBuffer* display_buffer) { + return text_helpers_->drawTextWrapped(xPos, yPos, font, color, alignment, + text, maxLines, display_buffer, + get_font_size_width_ratio()); + } + private: + HomeThingMenuTextHelpers* text_helpers_ = new HomeThingMenuTextHelpers(); HomeThingColorPalette* color_palette_; font::Font* font_small_{nullptr}; font::Font* font_medium_{nullptr}; @@ -146,5 +179,5 @@ class HomeThingMenuDisplayState { bool draw_now_playing_menu_; std::string boot_device_name_ = "homeThing"; }; -} // namespace homething_menu_base +} // namespace homething_display_state } // namespace esphome diff --git a/components/homeThing/homeThingMenuTextHelpers.cpp b/components/homeThingDisplayState/homeThingMenuTextHelpers.cpp similarity index 52% rename from components/homeThing/homeThingMenuTextHelpers.cpp rename to components/homeThingDisplayState/homeThingMenuTextHelpers.cpp index 692c76a9..c70d5720 100644 --- a/components/homeThing/homeThingMenuTextHelpers.cpp +++ b/components/homeThingDisplayState/homeThingMenuTextHelpers.cpp @@ -2,42 +2,42 @@ #include "esphome/core/log.h" namespace esphome { -namespace homething_menu_base { -Color HomeThingMenuTextHelpers::primaryTextColor(bool dark_mode) { +namespace homething_display_state { + +Color HomeThingMenuTextHelpers::primaryTextColor(bool dark_mode, + Color lightColor, + Color darkColor) { if (dark_mode) { - return display_state_->get_color_palette()->get_white(); + return lightColor; } else { - return display_state_->get_color_palette()->get_black(); + return darkColor; } } -Color HomeThingMenuTextHelpers::secondaryTextColor(bool dark_mode) { +Color HomeThingMenuTextHelpers::secondaryTextColor(bool dark_mode, + Color lightColor, + Color darkColor) { if (dark_mode) { - return display_state_->get_color_palette()->get_white(); + return lightColor; } else { - return display_state_->get_color_palette()->get_white(); + return darkColor; } } int HomeThingMenuTextHelpers::getCharacterLimit(int xPos, int fontSize, - display::TextAlign alignment) { - int characterLimit = - (display_buffer_->get_width() - xPos) / - (fontSize * display_state_->get_font_size_width_ratio()) - - 1; - if (xPos == display_buffer_->get_width() / 2 && - alignment == display::TextAlign::TOP_CENTER) { - characterLimit = - display_buffer_->get_width() / - (fontSize * display_state_->get_font_size_width_ratio()) - - 1; + display::TextAlign alignment, + int displayWidth, + float widthRatio) { + int characterLimit = (displayWidth - xPos) / (fontSize * widthRatio) - 1; + if (xPos == displayWidth / 2 && alignment == display::TextAlign::TOP_CENTER) { + characterLimit = displayWidth / (fontSize * widthRatio) - 1; } return characterLimit; } -int HomeThingMenuTextHelpers::getTextWidth(int fontSize, int characterCount) { - return (fontSize * display_state_->get_font_size_width_ratio() * - characterCount); +int HomeThingMenuTextHelpers::getTextWidth(int fontSize, int characterCount, + float widthRatio) { + return (fontSize * widthRatio * characterCount); } std::string HomeThingMenuTextHelpers::textWrap(std::string text, @@ -72,16 +72,18 @@ std::string HomeThingMenuTextHelpers::textWrap(std::string text, return text; } -int HomeThingMenuTextHelpers::drawTextWrapped(int xPos, int yPos, - font::Font* font, Color color, - display::TextAlign alignment, - std::string text, int maxLines) { +int HomeThingMenuTextHelpers::drawTextWrapped( + int xPos, int yPos, font::Font* font, Color color, + display::TextAlign alignment, std::string text, int maxLines, + display::DisplayBuffer* display_buffer, float widthRatio) { int fontSize = font->get_baseline(); auto wrappedTitles = new std::vector(); - auto wrappedString = - textWrap(text, getCharacterLimit(xPos, fontSize, alignment)); + auto wrappedString = textWrap( + text, getCharacterLimit(xPos, fontSize, alignment, + display_buffer->get_width(), widthRatio)); tokenize(wrappedString, "\n", wrappedTitles); - int characterLimit = getCharacterLimit(xPos, fontSize, alignment); + int characterLimit = getCharacterLimit( + xPos, fontSize, alignment, display_buffer->get_width(), widthRatio); int max = maxLines != 0 && maxLines < wrappedTitles->size() ? maxLines : wrappedTitles->size(); @@ -92,15 +94,15 @@ int HomeThingMenuTextHelpers::drawTextWrapped(int xPos, int yPos, title.erase(title.length() - 3); } title = title + "..."; - display_buffer_->printf(xPos, yPos + (i * fontSize), font, color, - alignment, title.c_str()); + display_buffer->printf(xPos, yPos + (i * fontSize), font, color, + alignment, title.c_str()); break; } else { - display_buffer_->printf(xPos, yPos + (i * fontSize), font, color, - alignment, (*wrappedTitles)[i].c_str()); + display_buffer->printf(xPos, yPos + (i * fontSize), font, color, + alignment, (*wrappedTitles)[i].c_str()); } } return yPos + (max * fontSize); } -} // namespace homething_menu_base +} // namespace homething_display_state } // namespace esphome diff --git a/components/homeThingDisplayState/homeThingMenuTextHelpers.h b/components/homeThingDisplayState/homeThingMenuTextHelpers.h new file mode 100644 index 00000000..f2bdbf4d --- /dev/null +++ b/components/homeThingDisplayState/homeThingMenuTextHelpers.h @@ -0,0 +1,41 @@ +#pragma once + +#include +#include +#include "esphome/components/display/display_buffer.h" +#include "esphome/components/font/font.h" +#include "esphome/core/color.h" + +namespace esphome { +namespace homething_display_state { + +class HomeThingMenuTextHelpers { + public: + Color primaryTextColor(bool dark_mode, Color lightColor, Color darkColor); + Color secondaryTextColor(bool dark_mode, Color lightColor, Color darkColor); + int getCharacterLimit(int xPos, int fontSize, display::TextAlign alignment, + int displayWidth, float widthRatio); + int getTextWidth(int fontSize, int characterCount, float widthRatio); + std::string textWrap(std::string text, unsigned per_line); + int drawTextWrapped(int xPos, int yPos, font::Font* font, Color color, + display::TextAlign alignment, std::string text, + int maxLines, display::DisplayBuffer* display_buffer, + float widthRatio); + + private: + const char* const TAG = "homething.menu.text_helpers"; + + void tokenize(std::string const& str, std::string delim, + std::vector* out) { + size_t start; + size_t end = 0; + + while ((start = str.find_first_not_of(delim, end)) != std::string::npos) { + end = str.find(delim, start); + out->push_back(str.substr(start, end - start)); + } + } +}; + +} // namespace homething_display_state +} // namespace esphome diff --git a/m5stack-fire.yaml b/m5stack-fire.yaml index 08343779..917946b2 100644 --- a/m5stack-fire.yaml +++ b/m5stack-fire.yaml @@ -31,8 +31,14 @@ external_components: type: git url: https://github.com/landonr/homeThing ref: main + # type: local + # path: components refresh: 0s - components: [homeThing] + components: [homeThingDisplayState, homeThing, homeThingApp, homeThingAppNowPlaying] + - source: github://pr#5214 # used to load images on compile + components: [ image ] + - source: github://pr#5254 # used to load fonts on compile + components: [ font, external_files ] - source: type: git url: https://github.com/landonr/esphome-components @@ -46,10 +52,6 @@ external_components: media_player_source_spotify, media_player_source_custom ] - - source: github://pr#5214 # used to load images on compile - components: [ image ] - - source: github://pr#5254 # used to load fonts on compile - components: [ font, external_files ] packages: # maybe modify: include default ipod controls remote_package: @@ -65,7 +67,7 @@ packages: # maybe modify: include default ipod controls common/m5stack-fire/binary_sensor.yaml, # buttons common/m5stack-fire/backlight.yaml, # backlight common/m5stack-fire/sidelight.yaml, # sidelight - common/images.yaml # boot screen image + common/images.yaml, # boot screen image ] refresh: 0s @@ -138,26 +140,36 @@ cover: # home assistant cover name: "Megadesk" id: cover_megadesk +homeThingAppNowPlaying: + id: now_playing + media_player_group: media_group_component + display: my_display + display_state: display_state_id + +homeThingDisplayState: + id: display_state_id + colors: + accent_primary: my_primary_accent + draw_battery_level: true + font_small: small_font + font_medium: medium_font + font_large: large_font + font_large_heavy: large_heavy_font + font_material_large: material_font_large + font_material_small: material_font_small + launch_image: launch_image + homeThing: id: homeThingMenu settings: sleep_after: 14400 - media_player_group: media_group_component display: my_display on_redraw: then: component.update: my_display - display_state: - colors: - accent_primary: my_primary_accent - draw_battery_level: true - font_small: small_font - font_medium: medium_font - font_large: large_font - font_large_heavy: large_heavy_font - font_material_large: material_font_large - font_material_small: material_font_small - launch_image: launch_image + display_state: display_state_id + apps: + - now_playing screens: - name: Desk Screen entities: diff --git a/m5stack-stickc.yaml b/m5stack-stickc.yaml index 58457e6a..7b00c5cb 100644 --- a/m5stack-stickc.yaml +++ b/m5stack-stickc.yaml @@ -24,23 +24,18 @@ wifi: # setup wifi, make sure secrets.yaml exists! power_save_mode: HIGH external_components: #include homething, and esphome-components - # - source: - # type: git - # url: https://gitlab.com/geiseri/esphome_extras.git - # refresh: 0s - # components: [axp192] - - source: - type: git - url: https://github.com/landonr/esphome-axp192 - ref: "lando/add-charging-indicator" - components: [axp192] - refresh: 0s - source: type: git url: https://github.com/landonr/homeThing ref: main + # type: local + # path: components refresh: 0s - components: [homeThing] + components: [homeThingDisplayState, homeThing, homeThingApp, homeThingAppNowPlaying] + - source: github://pr#5214 # used to load images on compile + components: [ image ] + - source: github://pr#5254 # used to load fonts on compile + components: [ font, external_files ] - source: type: git url: https://github.com/landonr/esphome-components @@ -54,10 +49,17 @@ external_components: #include homething, and esphome-components media_player_source_spotify, media_player_source_custom ] - - source: github://pr#5214 # used to load images on compile - components: [ image ] - - source: github://pr#5254 # used to load fonts on compile - components: [ font, external_files ] + # - source: + # type: git + # url: https://gitlab.com/geiseri/esphome_extras.git + # refresh: 0s + # components: [axp192] + - source: + type: git + url: https://github.com/landonr/esphome-axp192 + ref: "lando/add-charging-indicator" + components: [axp192] + refresh: 0s packages: # maybe modify: include default ipod controls # axp192: !include ../homeThing/common/m5stack-stickc/axp192-marty.yaml # power management and screen backlight @@ -72,7 +74,7 @@ packages: # maybe modify: include default ipod controls common/m5stack-stickc/axp192-marty.yaml, # power management and screen backlight common/m5stack-stickc/sleep.yaml, # deep sleep common/m5stack-stickc/binary_sensor.yaml, # power management and screen backlight - common/images.yaml # boot screen image + common/images.yaml, # boot screen image ] refresh: 0s @@ -138,12 +140,30 @@ cover: # home assistant cover name: "Megadesk" id: cover_megadesk +homeThingAppNowPlaying: + id: now_playing + media_player_group: media_group_component + display: my_display + display_state: display_state_id + +homeThingDisplayState: + id: display_state_id + colors: + accent_primary: my_primary_accent + draw_battery_level: true + font_small: small_font + font_medium: medium_font + font_large: large_font + font_large_heavy: large_heavy_font + font_material_large: material_font_large + font_material_small: material_font_small + launch_image: launch_image + homeThing: id: homeThingMenu settings: sleep_after: 14400 display_timeout_while_charging: 30 - media_player_group: media_group_component display: my_display backlight: backlight battery: @@ -152,17 +172,9 @@ homeThing: on_redraw: then: component.update: my_display - display_state: - colors: - accent_primary: my_primary_accent - draw_battery_level: true - font_small: small_font - font_medium: medium_font - font_large: large_font - font_large_heavy: large_heavy_font - font_material_large: material_font_large - font_material_small: material_font_small - launch_image: launch_image + display_state: display_state_id + apps: + - now_playing screens: - name: Desk Screen entities: diff --git a/m5stack-stickcplus-rotary.yaml b/m5stack-stickcplus-rotary.yaml index d02f9c29..d174c93d 100755 --- a/m5stack-stickcplus-rotary.yaml +++ b/m5stack-stickcplus-rotary.yaml @@ -24,6 +24,31 @@ wifi: # setup wifi, make sure secrets.yaml exists! power_save_mode: HIGH external_components: #include homething, and esphome-components + - source: + type: git + url: https://github.com/landonr/homeThing + ref: main + # type: local + # path: components + refresh: 0s + components: [homeThingDisplayState, homeThing, homeThingApp, homeThingAppNowPlaying] + - source: github://pr#5214 # used to load images on compile + components: [ image ] + - source: github://pr#5254 # used to load fonts on compile + components: [ font, external_files ] + - source: + type: git + url: https://github.com/landonr/esphome-components + ref: main + refresh: 0s + components: [ + homeassistant_component, + homeassistant_media_player, + media_player_source, + media_player_source_sonos, + media_player_source_spotify, + media_player_source_custom + ] # - source: # type: git # url: https://gitlab.com/geiseri/esphome_extras.git @@ -35,30 +60,14 @@ external_components: #include homething, and esphome-components ref: "lando/add-charging-indicator" components: [axp192] refresh: 0s - - source: - type: git - url: https://github.com/landonr/homeThing - ref: main - refresh: 0s - components: [homeThing] - source: type: git url: https://github.com/landonr/esphome-components ref: main refresh: 0s components: [ - homeassistant_component, - homeassistant_media_player, - media_player_source, - media_player_source_sonos, - media_player_source_spotify, - media_player_source_custom, MiniEncoderC ] - - source: github://pr#5214 # used to load images on compile - components: [ image ] - - source: github://pr#5254 # used to load fonts on compile - components: [ font, external_files ] packages: # maybe modify: include default ipod controls remote_package: @@ -73,7 +82,7 @@ packages: # maybe modify: include default ipod controls common/m5stack-stickc/sleep.yaml, # deep sleep common/m5stack-stickc/binary_sensor.yaml, # buttons common/m5stack-stickc/MiniEncoderC.yaml, # rotary encoder and built in led - common/images.yaml # boot screen image + common/images.yaml, # boot screen image ] refresh: 0s @@ -139,12 +148,30 @@ cover: # home assistant cover name: "Megadesk" id: cover_megadesk +homeThingAppNowPlaying: + id: now_playing + media_player_group: media_group_component + display: my_display + display_state: display_state_id + +homeThingDisplayState: + id: display_state_id + colors: + accent_primary: my_primary_accent + draw_battery_level: true + font_small: small_font + font_medium: medium_font + font_large: large_font + font_large_heavy: large_heavy_font + font_material_large: material_font_large + font_material_small: material_font_small + launch_image: launch_image + homeThing: id: homeThingMenu settings: sleep_after: 14400 display_timeout_while_charging: 30 - media_player_group: media_group_component display: my_display backlight: backlight battery: @@ -153,17 +180,9 @@ homeThing: on_redraw: then: component.update: my_display - display_state: - colors: - accent_primary: my_primary_accent - draw_battery_level: true - font_small: small_font - font_medium: medium_font - font_large: large_font - font_large_heavy: large_heavy_font - font_material_large: material_font_large - font_material_small: material_font_small - launch_image: launch_image + display_state: display_state_id + apps: + - now_playing screens: - name: Desk Screen entities: diff --git a/tdisplay-ipod.yaml b/tdisplay-ipod.yaml index b779edd5..d8df9626 100644 --- a/tdisplay-ipod.yaml +++ b/tdisplay-ipod.yaml @@ -21,13 +21,19 @@ wifi: # setup wifi, make sure secrets.yaml exists! id: wifi_id power_save_mode: HIGH -external_components: #include homething, and esphome-components +external_components: - source: type: git url: https://github.com/landonr/homeThing ref: main + # type: local + # path: components refresh: 0s - components: [homeThing] + components: [homeThingDisplayState, homeThing, homeThingApp, homeThingAppNowPlaying] + - source: github://pr#5214 # used to load images on compile + components: [ image ] + - source: github://pr#5254 # used to load fonts on compile + components: [ font, external_files ] - source: type: git url: https://github.com/landonr/esphome-components @@ -41,11 +47,6 @@ external_components: #include homething, and esphome-components media_player_source_spotify, media_player_source_custom ] - - source: github://pr#5214 # used to load images on compile - components: [ image ] - - source: github://pr#5254 # used to load fonts on compile - components: [ font, external_files ] - packages: # maybe modify: include default ipod controls remote_package: @@ -61,7 +62,7 @@ packages: # maybe modify: include default ipod controls common/fonts.yaml, # default font common/icon_fonts.yaml, # material icons common/settings.yaml, # settings screen - common/images.yaml # boot screen image + common/images.yaml, # boot screen image ] refresh: 0s @@ -131,6 +132,23 @@ cover: # home assistant cover name: "Megadesk" id: cover_megadesk +homeThingAppNowPlaying: + id: now_playing + media_player_group: media_group_component + display: my_display + display_state: display_state_id + +homeThingDisplayState: + id: display_state_id + draw_battery_level: true + font_small: small_font + font_medium: medium_font + font_large: large_font + font_large_heavy: large_font + font_material_large: material_font_large + font_material_small: material_font_small + launch_image: launch_image + homeThing: id: homeThingMenu settings: @@ -140,23 +158,13 @@ homeThing: battery: battery_percent: battery_percent charging: charging - media_player_group: media_group_component display: my_display + display_state: display_state_id + apps: + - now_playing on_redraw: then: component.update: my_display - display_state: - colors: - accent_primary: my_primary_accent - draw_battery_level: true - font_small: small_font - font_medium: medium_font - font_large: large_font - font_large_heavy: large_heavy_font - font_material_large: material_font_large - font_material_small: material_font_small - launch_image: launch_image - boot_device_name: "cool remote" screens: - name: Desk Screen entities: diff --git a/tdisplay-megadesk.yaml b/tdisplay-megadesk.yaml index 2b04e809..bb6ed626 100644 --- a/tdisplay-megadesk.yaml +++ b/tdisplay-megadesk.yaml @@ -26,14 +26,20 @@ wifi: substitutions: friendly_name: "mega homething" log_level: "WARN" - + external_components: - source: type: git url: https://github.com/landonr/homeThing ref: main + # type: local + # path: components refresh: 0s - components: [homeThing] + components: [homeThingDisplayState, homeThing, homeThingApp, homeThingAppNowPlaying] + - source: github://pr#5214 # used to load images on compile + components: [ image ] + - source: github://pr#5254 # used to load fonts on compile + components: [ font, external_files ] - source: type: git url: https://github.com/landonr/esphome-components @@ -47,11 +53,7 @@ external_components: media_player_source_spotify, media_player_source_custom ] - - source: github://pr#5214 # used to load images on compile - components: [ image ] - - source: github://pr#5254 # used to load fonts on compile - components: [ font, external_files ] - + packages: # maybe modify: include default ipod controls remote_package: url: https://github.com/landonr/homeThing @@ -63,7 +65,7 @@ packages: # maybe modify: include default ipod controls common/fonts.yaml, # default font common/icon_fonts.yaml, # material icons common/settings.yaml, # settings screen - common/images.yaml # boot screen image + common/images.yaml, # boot screen image ] refresh: 0s @@ -103,6 +105,25 @@ homeassistant_media_player: - id: media_player_beam type: speaker +homeThingAppNowPlaying: + id: now_playing + media_player_group: media_group_component + display: my_display + display_state: display_state_id + +homeThingDisplayState: + id: display_state_id + colors: + accent_primary: my_primary_accent + draw_now_playing_bottom_menu: true + font_small: small_font + font_medium: medium_font + font_large: large_font + font_large_heavy: large_font + font_material_large: material_font_large + font_material_small: material_font_small + launch_image: launch_image + homeThing: id: homeThingMenu settings: @@ -111,24 +132,15 @@ homeThing: menu_rollback: true menu_rollover: true backlight: backlight - media_player_group: media_group_component display: my_display header: time_id: esptime on_redraw: then: component.update: my_display - display_state: - colors: - accent_primary: my_primary_accent - draw_now_playing_bottom_menu: true - font_small: small_font - font_medium: medium_font - font_large: large_font - font_large_heavy: large_font - font_material_large: material_font_large - font_material_small: material_font_small - launch_image: launch_image + display_state: display_state_id + apps: + - now_playing screens: - name: Desk Screen entities: diff --git a/tdisplay-s3.yaml b/tdisplay-s3.yaml index f3f5c342..35873bb9 100644 --- a/tdisplay-s3.yaml +++ b/tdisplay-s3.yaml @@ -30,12 +30,21 @@ wifi: password: "zQ9tuPKIfFMu" external_components: + - source: github://landonr/lilygo-tdisplays3-esphome + components: [tdisplays3] + refresh: 0s - source: type: git url: https://github.com/landonr/homeThing ref: main + # type: local + # path: components refresh: 0s - components: [homeThing] + components: [homeThingDisplayState, homeThing, homeThingApp, homeThingAppNowPlaying] + - source: github://pr#5214 # used to load images on compile + components: [ image ] + - source: github://pr#5254 # used to load fonts on compile + components: [ font, external_files ] - source: type: git url: https://github.com/landonr/esphome-components @@ -49,13 +58,6 @@ external_components: media_player_source_spotify, media_player_source_custom ] - - source: github://landonr/lilygo-tdisplays3-esphome - components: [tdisplays3] - refresh: 0s - - source: github://pr#5214 # used to load images on compile - components: [ image ] - - source: github://pr#5254 # used to load fonts on compile - components: [ font, external_files ] packages: # maybe modify: include default ipod controls remote_package: @@ -71,7 +73,7 @@ packages: # maybe modify: include default ipod controls common/fonts.yaml, # default font common/icon_fonts.yaml, # material icons common/settings.yaml, # settings screen - common/images.yaml # boot screen image + common/images.yaml, # boot screen image ] refresh: 0s @@ -147,6 +149,25 @@ cover: # home assistant cover name: "Megadesk" id: cover_megadesk +homeThingAppNowPlaying: + id: now_playing + media_player_group: media_group_component + display: my_display + display_state: display_state_id + +homeThingDisplayState: + id: display_state_id + colors: + accent_primary: my_primary_accent + draw_battery_level: true + font_small: small_font + font_medium: medium_font + font_large: large_font + font_large_heavy: large_heavy_font + font_material_large: material_font_large + font_material_small: material_font_small + launch_image: launch_image + homeThing: id: homeThingMenu settings: @@ -156,22 +177,13 @@ homeThing: battery: battery_percent: battery_percent charging: charging - media_player_group: media_group_component display: my_display on_redraw: then: component.update: my_display - display_state: - colors: - accent_primary: my_primary_accent - draw_battery_level: true - font_small: small_font - font_medium: medium_font - font_large: large_font - font_large_heavy: large_heavy_font - font_material_large: material_font_large - font_material_small: material_font_small - launch_image: launch_image + display_state: display_state_id + apps: + - now_playing screens: - name: Desk Screen entities: diff --git a/tdisplay-t4.yaml b/tdisplay-t4.yaml index b57c18bf..85649446 100644 --- a/tdisplay-t4.yaml +++ b/tdisplay-t4.yaml @@ -15,13 +15,19 @@ wifi: ssid: "${friendly_name} Fallback" password: !secret wifi_fallback_password -external_components: #include homething, and esphome-components +external_components: - source: type: git url: https://github.com/landonr/homeThing ref: main + # type: local + # path: components refresh: 0s - components: [homeThing] + components: [homeThingDisplayState, homeThing, homeThingApp, homeThingAppNowPlaying] + - source: github://pr#5214 # used to load images on compile + components: [ image ] + - source: github://pr#5254 # used to load fonts on compile + components: [ font, external_files ] - source: type: git url: https://github.com/landonr/esphome-components @@ -35,11 +41,6 @@ external_components: #include homething, and esphome-components media_player_source_spotify, media_player_source_custom ] - - source: github://pr#5214 # used to load images on compile - components: [ image ] - - source: github://pr#5254 # used to load fonts on compile - components: [ font, external_files ] - packages: # maybe modify: include default ipod controls remote_package: @@ -50,7 +51,7 @@ packages: # maybe modify: include default ipod controls common/fonts.yaml, # default font common/icon_fonts.yaml, # material icons common/settings.yaml, # settings screen - common/images.yaml # boot screen image + common/images.yaml, # boot screen image ] refresh: 0s @@ -222,26 +223,36 @@ cover: # home assistant cover name: "Megadesk" id: cover_megadesk +homeThingAppNowPlaying: + id: now_playing + media_player_group: media_group_component + display: my_display + display_state: display_state_id + +homeThingDisplayState: + id: display_state_id + colors: + accent_primary: my_primary_accent + draw_battery_level: true + font_small: small_font + font_medium: medium_font + font_large: large_font + font_large_heavy: large_heavy_font + font_material_large: material_font_large + font_material_small: material_font_small + launch_image: launch_image + homeThing: id: homeThingMenu settings: sleep_after: 14400 - media_player_group: media_group_component display: my_display on_redraw: then: component.update: my_display - display_state: - colors: - accent_primary: my_primary_accent - draw_battery_level: true - font_small: small_font - font_medium: medium_font - font_large: large_font - font_large_heavy: large_heavy_font - font_material_large: material_font_large - font_material_small: material_font_small - launch_image: launch_image + display_state: display_state_id + apps: + - now_playing screens: - name: Desk Screen entities: