A worker service for managing Bitdeer D40 cooling containers with oil and water cooling systems for MiningOS. This service provides comprehensive monitoring and control capabilities for multiple miner models via MQTT protocol.
- Overview
- Object Model
- Worker Types
- Requirements
- Installation
- Configuration
- Running the Worker
- API Documentation
- Alert System
- Controll Operations
- Mock Server
- Testing
- Development
- Troubleshooting
The Bitdeer D40 container worker provides a unified interface for managing cooling containers with dual oil and water cooling systems. It supports real-time monitoring, temperature control, power management, and sophisticated operational tactics for optimizing mining operations.
The following is a fragment of MiningOS object model that contains the concrete class representing Bitdeer Container workers (highlighted in blue). The rounded nodes reprsent abstract classes and the square nodes represents a concrete classes:
---
title: Object Model of MiningOS
---
flowchart RL
bfx-wrk-base@{ shape: stadium, label: "*bfx-wrk-base*" }
tether-wrk-base@{ shape: stadium, label: "*tether-wrk-base*" }
tether-wrk-base--->bfx-wrk-base
miningos-tlp-wrk-thing@{ shape: stadium, label: "*miningos-tlp-wrk-thing*" }
miningos-tlp-wrk-thing--->tether-wrk-base
miningos-tpl-wrk-container@{ shape: stadium, label: "*miningos-tpl-wrk-container*" }
miningos-tpl-wrk-container--->miningos-tlp-wrk-thing
miningos-wrk-container-bitdeer-base["miningos-wrk-container-bitdeer-base"]
miningos-wrk-container-bitdeer-base--->miningos-tpl-wrk-container
miningos-wrk-container-bitdeer-D40M30["miningos-wrk-container-bitdeer-D40M30"]
miningos-wrk-container-bitdeer-D40M30--->miningos-wrk-container-bitdeer-base
miningos-wrk-container-bitdeer-D40M56["miningos-wrk-container-bitdeer-D40M56"]
miningos-wrk-container-bitdeer-D40M56--->miningos-wrk-container-bitdeer-base
miningos-wrk-container-bitdeer-D40S19XP["miningos-wrk-container-bitdeer-D40S19XP"]
miningos-wrk-container-bitdeer-D40S19XP--->miningos-wrk-container-bitdeer-base
miningos-wrk-container-bitdeer-D40A1346["miningos-wrk-container-bitdeer-D40A1346"]
miningos-wrk-container-bitdeer-D40A1346--->miningos-wrk-container-bitdeer-base
style miningos-wrk-container-bitdeer-base fill:#005,stroke-width:4px,color:white
style miningos-wrk-container-bitdeer-D40M30 fill:#005,stroke-width:4px,color:white
style miningos-wrk-container-bitdeer-D40M56 fill:#005,stroke-width:4px,color:white
style miningos-wrk-container-bitdeer-D40A1346 fill:#005,stroke-width:4px,color:white
style miningos-wrk-container-bitdeer-D40S19XP fill:#005,stroke-width:4px,color:white
Check out miningos-tpl-wrk-container for more information about parent classes.
- Dual Cooling System: Separate oil and water circulation systems with independent pump control
- PDU Management: Control and monitor individual power distribution unit sockets
- Dry Cooler Control: Manage multiple dry cooler units with fan arrays
- Temperature Monitoring: Comprehensive temperature tracking for hot/cold oil and water
- Operational Tactics: Start/stop policies based on electricity prices or coin prices
- UPS Integration: Monitor uninterruptible power supply status
- Alert System: Configurable alerts for pumps, temperature, and system faults
- MQTT Communication: Real-time communication with containers via MQTT protocol
The system supports four miner models, each with its own worker type:
- wrk-container-rack-d40-m56 For M56 miners
- wrk-container-rack-d40-m30 For M30 miners
- wrk-container-rack-d40-a1346 For A1346 miners
- wrk-container-rack-d40-s19xp For S19XP miners
*All worker types share the same alert definitions and core functionality.
- Node.js >= 20.0
- MQTT broker* accessible to both worker and containers
- Network connectivity to container control systems
- Proper configuration files in place
*Users don't need to install Mosquitto or another MQTT broker.
- Clone the repository:
git clone https://github.com/tetherto/miningos-wrk-container-bitdeer.git
cd miningos-wrk-container-bitdeer- Install dependencies:
npm install- Set up configuration files:
./setup-config.shconfig/
├── base.thing.json # Container monitoring and alert configuration
├── common.json # Common settings (logging, debug)
└── facs/ # Facility-specific configurations
├── miningos-net.config.json
├── net.config.json
└── store.config.json
collectSnapTimeoutMs: Timeout for collecting snapshots (default: 120000ms)collectSnapsItvMs: Interval for collecting snapshots (default: 60000ms)logRotateMaxLength: Maximum log file length before rotation (default: 10000)logKeepCount: Number of log files to keep (default: 3)thingRtdConcurrency: Concurrent real-time data operations (default: 500)container.delay: Delay between operations (default: 100ms)container.timeout: Operation timeout (default: 30000ms)alerts: Miner-specific alert definitions with severity levels
dir_log: Directory for log files (default: "logs")debug: Debug level (0 = off, 1 = on)
All miner models share the same alert types with configurable parameters:
"oil_min_inlet_temp_warn": {
"description": "Oil tank inlet temperature is too low.",
"severity": "medium",
"params": {
"temp": 20 // Configurable threshold
}
}For M56 miners:
node worker.js --wtype wrk-container-rack-d40-m56 --env development --rack 1For other miner types, replace the worker type accordingly:
- M30:
--wtype wrk-container-rack-d40-m30 - A1346:
--wtype wrk-container-rack-d40-a1346 - S19XP:
--wtype wrk-container-rack-d40-s19xp
After starting the worker, register a container:
hp-rpc-cli -s wrk-d40 -m registerThing -d '{"info":{"container":"bitdeer-9a"},"opts":{"containerId": "bitdeer-9a"}}'Parameters:
info.container: Container identifier for displayopts.containerId: MQTT topic prefix for the container
See docs/bitdeer.md for complete API documentation.
getDeviceInformation()- Get pump and dry cooler statusgetPDUSocketInformation()- Get PDU socket status and power datagetContainerPowerInformation()- Get total and per-phase power metricsgetTemperatureInformation()- Get all temperature readingsgetUPSInformation()- Get UPS status and battery levelgetTactics()- Get current operational tacticsgetAlarmTemperatures()- Get temperature alarm thresholdsgetSetTemperatures()- Get temperature setpointsgetTankStatus()- Get tank enable/disable statusgetExhaustFanStatus()- Get exhaust fan status
setPumpState(pumpType, index, status)- Control oil/water pumpssetPDUSocketState(PDUIndex, socketIndex, status)- Control PDU socketssetDryCoolerState(dryCoolerIndex, fanIndex, status)- Control dry cooler fanssetStopTactic(tacticType, stopPrice, currentPrice)- Set stop tacticssetStartTactic(tacticType, startPrice, currentPrice)- Set start tacticssetHotOilAlarmTemperature(temperature)- Set hot oil alarm thresholdsetHotWaterAlarmTemperature(temperature)- Set hot water alarm thresholdsetColdOilAlarmTemperature(temperature)- Set cold oil alarm thresholdsetColdWaterAlarmTemperature(temperature)- Set cold water alarm thresholdsetColdOilTemperature(temperature)- Set cold oil target temperaturesetExhaustFanTemperature(fanTemperature)- Set exhaust fan trigger temperaturesetTankEnabled(tankIndex, status)- Enable/disable tankssetAirExhaustEnabled(status)- Enable/disable exhaust systemresetAlarm()- Reset active alarmssetAutoRun(state)- Set automatic operation mode
The Bitdeer container worker exposes RPC (Remote Procedure Call) methods that allow external systems to interact with containers. These methods are accessed through the RPC server and provide both management and control capabilities.
Registers a new container with the worker system. This method creates a new container instance and establishes MQTT communication.
Parameters:
req.id(optional): Unique identifier for the container. If not provided, a UUID will be generated automaticallyreq.info: Container metadata objectreq.info.container: Display name for the container
req.opts: Container options objectreq.opts.containerId: MQTT topic prefix for container communication
req.tags(optional): Array of custom tags for categorization
Example:
{
"info": {
"container": "bitdeer-9a"
},
"opts": {
"containerId": "bitdeer-9a"
},
"tags": ["production", "zone-a"]
}Returns: 1 on successful registration
Updates an existing container's configuration or metadata. This method allows modification of container properties without requiring re-registration.
Parameters:
req.id(required): Container ID to updatereq.info(optional): New or updated metadatareq.opts(optional): New or updated optionsreq.tags(optional): New tag array (replaces existing tags)req.forceOverwrite(optional): When true, completely replaces info instead of merging
Returns: 1 on successful update
Removes one or more containers from the system. This disconnects MQTT communication and removes all stored data.
Parameters:
req.query: MongoDB-style query to select containersreq.query.id.$in: Array of container IDs to remove
req.all: When true, removes all containers (use with caution)
Example:
// Remove specific containers
{ "query": { "id": { "$in": ["container-1", "container-2"] } } }
// Remove all containers
{ "all": true }Returns: 1 on successful removal
Lists all registered containers with their current status and configuration.
Parameters:
req.query(optional): MongoDB-style query for filteringreq.fields(optional): Field projection for returned datareq.sort(optional): Sort criteriareq.offset(optional): Number of items to skip (default: 0)req.limit(optional): Maximum items to return (default: 100)req.status(optional): When true, includes last snapshot and alert status
Returns: Array of container objects with metadata and status
Executes a method on a specific container's control interface. This provides direct access to container operations.
Parameters:
req.id(required): Container IDreq.method(required): Method name to executereq.params(optional): Array of parameters for the method
Example:
// Query container power information
{
"id": "bitdeer-9a",
"method": "getContainerPowerInformation",
"params": []
}Returns: Method-specific response data
Retrieves information about the current rack (worker instance).
Returns:
id: Rack identifierrpcPubKey: RPC server public key for authentication
Applies operations to multiple containers simultaneously. This method enables batch operations and coordinated control.
Parameters:
req.method(required): Operation to applyreq.params(optional): Parameters for the operationreq.query(optional): MongoDB-style query to select target containers
Supported Operations for Bitdeer:
switchContainer: Enable/disable containersswitchSocket: Control PDU socketsswitchCoolingSystem: Control cooling systemssetTankEnabled: Enable/disable oil/water tankssetAirExhaustEnabled: Control exhaust fan systemresetAlarm: Clear active alarmssetTemperatureSettings: Configure temperature thresholds
Example:
// Turn off all containers in zone-a
{
"method": "switchContainer",
"params": [false],
"query": { "tags": "zone-a" }
}
// Set temperature settings for specific container
{
"method": "setTemperatureSettings",
"params": [{
"coldOil": 25,
"hotOil": 55,
"exhaustFan": 40
}],
"query": { "id": { "$in": ["bitdeer-9a"] } }
}Returns: Count of successfully processed containers
Retrieves historical log data for containers. This method provides access to time-series data for analysis and troubleshooting.
Parameters:
req.key(required): Container ID or log identifierreq.tag(required): Log type (e.g., "5m" for 5-minute logs)req.offset(optional): Log offset for paginationreq.limit(optional): Maximum entries to returnreq.start(optional): Start timestamp (milliseconds)req.end(optional): End timestamp (milliseconds)req.reverse(optional): When true, returns newest entries firstreq.fields(optional): Field projection for returned data
Example:
// Get last 10 snapshots for a container
{
"key": "thing",
"tag": "5m-bitdeer-9a",
"limit": 10,
"reverse": true
}Returns: Array of log entries with timestamps and snapshot data
RPC methods are typically called using the hp-rpc-cli tool or programmatically through the RPC client library:
# Register a container using CLI
hp-rpc-cli -s wrk-d40 -m registerThing -d '{"info":{"container":"bitdeer-9a"},"opts":{"containerId":"bitdeer-9a"}}'
# Query container status
hp-rpc-cli -s wrk-d40 -m queryThing -d '{"id":"bitdeer-9a","method":"getSnap"}'
# Apply batch operation
hp-rpc-cli -s wrk-d40 -m applyThings -d '{"method":"switchCoolingSystem","params":[true],"query":{}}'When an RPC method is called, the following sequence occurs:
- Request Reception: The RPC server receives and validates the request
- Authentication: Request is authenticated using RPC keys if configured
- Thing Selection: For operations on containers, the query selects target containers
- Method Execution: The requested method is executed on selected containers
- Response Collection: Results are aggregated and formatted
- Response Return: Final response is sent back to the caller
For container-specific operations, the worker maintains MQTT connections to each registered container, allowing real-time command execution and data collection.
The system monitors various fault conditions with three severity levels:
- critical: Immediate action required (pump failures, overheating)
- high: Significant issues requiring attention
- medium: Monitoring conditions (low inlet temperature)
- Pump Errors: Thermal relay actions requiring manual reset
- Temperature Warnings: Hot/cold oil and water temperature limits
- Pump Operation: Detection of pump control signal without pump running
- Inlet Temperature: Low oil inlet temperature warning (configurable)
// Start oil pump 1
setPumpState('oilPump', 1, true)
// Stop water pump 2
setPumpState('waterPump', 2, false)// Turn on PDU 0, socket 1
setPDUSocketState(0, 1, true)
// Turn off all sockets on all PDUs
setPDUSocketState(-1, -1, false)Set policies for automatic start/stop based on market conditions. Examples:
// Set stop policy based on electricity price
setStopTactic('electricityPolicy', 0.10, 0.08) // Can be used to stop when price > $0.10/kWh
// Set start policy based on coin price
setStartTactic('coinPricePolicy', 50000, 48000) // Can be used to start when BTC > $50,000For development and testing without real hardware:
# Basic usage
node mock/server.js --type D40_M56 --id bitdeer-9a
# With custom MQTT port
node mock/server.js --type D40_M56 --id bitdeer-9a -p 10883
# With error simulation
node mock/server.js --type D40_M56 --id bitdeer-9a --error--type: Container type (required) - D40_M56, D40_M30, D40_A1346, or D40_S19xp--id: Container ID for MQTT topics (default: C024_D40)-p, --port: MQTT server port (default: 10883)-h, --host: MQTT server host (default: 127.0.0.1)--error: Enable error response simulation--bulk: Load multiple containers from JSON file
Extended features can be enabled by appending capabilities to the type:
# Enable pressure monitoring simulation
node mock/server.js --type D40_M56+P --id bitdeer-9aAvailable capabilities:
P- Pressure monitoring updates
Run the complete test suite:
npm run testUsing npm scripts:
# Start mock MQTT server with M56 container
npm run mock
# Start worker for M56 miners
npm run workerThis starts:
- Mock MQTT server on port 4001 with debug logging
- Worker configured for development environment
workers/
├── lib/
│ ├── alerts.js # Alert processing
│ ├── container.js # Core container class
│ ├── stats.js # Statistics processing
│ ├── utils/
│ │ ├── constants.js # System constants
│ │ ├── optimize.js # Optimization algorithms
│ │ └── pduOps.js # PDU operations
│ └── worker-base.js # Base worker class
└── *.wrk.js # Miner-specific workers
-
MQTT Connection Failed
- Verify MQTT broker is running
- Check container ID matches between worker and container
- Ensure network connectivity to MQTT broker
-
Container Not Responding
- Check container is publishing to correct MQTT topics
- Verify container ID in registration matches actual container
- Monitor MQTT traffic for communication issues
-
Temperature Alarms
- Adjust alarm thresholds in runtime using API
- Check physical cooling system operation
- Verify temperature sensor readings
-
PDU Socket Control Issues
- Ensure manual/automatic switch is in "automatic" position
- Check PDU index and socket index are valid
- Verify power to PDU units
Enable comprehensive debug logging:
# Set debug in config
echo '{"dir_log": "logs", "debug": 1}' > config/common.json
# Or use DEBUG environment variable
DEBUG=* node worker.js --wtype wrk-container-rack-d40-m56 --env development --rack 1