#pragma once #include #include #include #include #include #include "spore/Service.h" #include "spore/core/TaskManager.h" #include "spore/core/NodeContext.h" class ApiServer; class AsyncWebServerRequest; class MultiMatrixService : public Service { public: MultiMatrixService(NodeContext& ctx, TaskManager& taskManager, uint8_t rxPin, uint8_t txPin, uint8_t potentiometerPin); void registerEndpoints(ApiServer& api) override; const char* getName() const override { return "MultiMatrixAudio"; } bool isReady() const; uint8_t getVolume() const; bool isLoopEnabled() const; void play(); void stop(); void pause(); void resume(); void next(); void previous(); void setVolume(uint8_t volume); void setLoop(bool enabled); private: static constexpr uint16_t POTENTIOMETER_SAMPLE_INTERVAL_MS = 200; static constexpr uint8_t MAX_VOLUME = 30; static constexpr uint8_t POT_VOLUME_EPSILON = 2; void registerTasks(); void pollPotentiometer(); void handleStatusRequest(AsyncWebServerRequest* request); void handleControlRequest(AsyncWebServerRequest* request); uint8_t calculateVolumeFromPotentiometer(uint16_t rawValue) const; void applyVolume(uint8_t targetVolume); void publishEvent(const char* action); NodeContext& m_ctx; TaskManager& m_taskManager; std::unique_ptr m_serial; DFRobotDFPlayerMini m_player; uint8_t m_potentiometerPin; uint8_t m_volume; bool m_playerReady; bool m_loopEnabled; };