Feature-based architecture for miners — multiple controllers per miner#80
Open
Feature-based architecture for miners — multiple controllers per miner#80
Conversation
…toring and control ports in domain layer
…nd updating adapter service methods into application layer
…r enhanced functionality
…onality and refining schemas for features
…inking after creation and update
…roved service configuration
…er association handling
… use get_env_temp
…nced miner monitoring
…d miner device information retrieval
…tures in database
…d PyASICMinerController
…value objects in MinerStateSnapshot
…nd requirements.txt
…found and system uptime
…s in ConfigurationService
This was
linked to
issues
Apr 12, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Replaces the single
Miner.controller_iddesign with a feature-based architecture where each miner aggregates multipleMinerFeaturevalue objects, each provided by a different controller.This PR closes #79 #56 #54
Architecture
Before
After
The system resolves the best provider for each capability at runtime: filter by type → filter enabled → sort by priority (descending) → take first.
Design principles applied
MinerControlPort(6 methods) is split into 16 granular ports, one per feature type. Adapters implement only the ports they support.Minerbecomes a proper aggregate root managing theMinerFeaturecollection with invariant enforcement (uniqueness per type+controller, priority range 1–100).feature_type: ClassVar[MinerFeatureType]. When a controller is associated with a miner, the system walks the adapter class's MRO to discover which features it supports — no static maps needed.set_miner_controller(controller_id, miner_id)automatically createsMinerFeatureentries for every feature the controller's adapter supports.Changes
Domain layer
domain/miner/common.pyMinerFeatureTypeenum (16 values across monitoring and control categories)domain/miner/value_objects.pyMinerFeaturefrozen dataclass (feature_type, controller_id, priority, enabled). AddedTemperature,FanSpeed,Voltage,FrequencyVOs. EnrichedMinerStateSnapshotwith 8 new optional fieldsdomain/miner/ports.pyMinerControlPortwithMinerFeaturePortbase + 16 concrete feature ports (HashrateMonitorPort,PowerMonitorPort,MiningControlPort, etc.)domain/miner/aggregate_roots.pyMinermoved here, now derives fromAggregateRoot. Manages features collection with 11 methods (add/remove/enable/disable/set_priority/get_active_feature/etc.)domain/miner/entities.pyMinerremoved. OnlyMinerControllerremainsAdapter layer
adapters/.../pyasic.pyadapters/.../generic_socket_home_assistant_api.pyadapters/.../dummy.pyPersistence layer
adapters/.../tables.pyminer_featurestable (id, miner_id, controller_id, feature_type, priority, enabled). Removedcontroller_idfromminerstable. Helper functions for loading/saving features outside ORM (frozen VO cannot be imperatively mapped)adapters/.../repositories.pyget_by_controller_idnow queries via features. CRUD methods load/save features alongside mineralembic/versions/a1b2c3d4e5f6_...miner_featurestable, dropscontroller_idfromminersApplication layer
application/interfaces.pyAdapterServiceInterface: newget_miner_feature_port(miner, feature_type)andget_miner_controller_adapter(miner, controller_id).ConfigurationServiceInterface: removedcontroller_idfromadd_miner/update_miner, addedunlink_controller_from_minerapplication/services/adapter_service.pyget_miner_feature_port()resolves active feature → controller → adapter → verifies support via MROapplication/services/configuration_service.pyset_miner_controllerauto-creates features via MRO discovery. Newunlink_controller_from_miner. Injectedadapter_servicedependencyapplication/services/optimization_service.pyapplication/services/miner_action_service.pyMINING_CONTROLwithPOWER_CONTROLfallback. Each metric queried via its own feature portAPI layer
adapters/.../schemas.pyMinerFeatureSchema.MinerSchemaexposesfeatureslist and computedcontroller_idsinstead ofcontroller_id. Removedcontroller_idfrom create/update schemasadapters/.../router.pyset-controllerendpoint. NewPOST /miners/{id}/unlink-controllerendpointadapters/.../cli/commands.pyminer.controller_idreferences replaced with feature-based equivalentsBreaking changes
Miner.controller_idfield removed. Replaced byMiner.features: List[MinerFeature].MinerControlPortinterface removed. Replaced by 16 granular feature ports.add_minerandupdate_minerno longer acceptcontroller_id. Useset_miner_controllerto associate controllers.controller_idfield replaced byfeaturesarray andcontroller_idsarray.miner_featurestable,controller_idcolumn dropped fromminers).Testing
All 259 existing tests pass. The migration has been validated against the Alembic test suite (9 tests).