#pragma once #include "esphome/core/component.h" #include "esphome/core/log.h" #include "esphome/core/preferences.h" #include "msc_disk.h" #include #include #include #include #include namespace esphome { namespace grub_boot_switch { class GrubBootSwitch : public Component { public: void setup() override; void dump_config() override; float get_setup_priority() const override { return setup_priority::HARDWARE; } void set_volume_serial(uint32_t s) { disk_.set_volume_serial(s); } void set_volume_label(const std::string &l) { disk_.set_volume_label(l.c_str()); } void set_usb_ids(uint16_t vid, uint16_t pid) { usb_vid_ = vid; usb_pid_ = pid; } void set_usb_strings(const std::string &manuf, const std::string &product) { usb_manufacturer_ = manuf; usb_product_ = product; } void set_initial_target(uint8_t t) { current_target_ = t; } // Target table: digit (0-9) → human-readable label. Populated from YAML // before setup() runs. Order matters only for select-platform option lists. void add_target(uint8_t digit, const std::string &label) { targets_.emplace_back(digit, label); } const std::vector> &get_targets() const { return targets_; } // Look up the label for a digit. Returns empty string if no match. std::string label_for_digit(uint8_t digit) const; // Look up the digit for a label. Returns false on miss; *out unchanged. bool digit_for_label(const std::string &label, uint8_t *out) const; // Public API used by automations + sub-components. set_target() persists // to NVS and notifies registered callbacks. uint8_t get_target() const { return current_target_.load(); } void set_target(uint8_t t); // Registered by the select sub-platform so it can publish state changes // when set_target() is called from REST/automation/etc. void add_on_target_change(std::function &&cb) { callbacks_.emplace_back(std::move(cb)); } // Called by the TinyUSB MSC glue layer. int read_lba(uint32_t lba, uint8_t *out) { return disk_.read_lba(lba, out); } uint32_t sector_count() const { return disk_.sector_count(); } uint32_t sector_size() const { return disk_.sector_size(); } protected: void install_virtual_files_(); void start_usb_(); MscDisk disk_; std::atomic current_target_{0}; std::vector> targets_; std::vector> callbacks_; ESPPreferenceObject pref_; uint16_t usb_vid_ = 0x26BA; uint16_t usb_pid_ = 0x8003; std::string usb_manufacturer_; std::string usb_product_; }; } // namespace grub_boot_switch } // namespace esphome