First Run
This section guides you through starting the EnerOS API server, verifying service availability, and executing your first power flow calculation. It also covers runtime management operations such as Dashboard, logging, health checks, and stopping/restarting.
Start the API Server
After building, you can start the API server via the eneros-api binary.
Startup Options
# Start with default configuration
./target/release/eneros-api
# Specify a configuration file
./target/release/eneros-api --config eneros.toml
# Specify listen address and port
./target/release/eneros-api --host 0.0.0.0 --port 9090
# Enable Dashboard
./target/release/eneros-api --with-dashboard
# Specify log level
./target/release/eneros-api --log-level debug
# Run in background (Linux / macOS)
nohup ./target/release/eneros-api > eneros.log 2>&1 &
# View process
ps aux | grep eneros-api
Complete Command-Line Arguments
| Argument | Shortcut | Default | Description |
|---|---|---|---|
--config | -c | eneros.toml | Configuration file path |
--host | -H | 0.0.0.0 | Listen address |
--port | -p | 8080 | Listen port |
--log-level | -l | info | Log level (trace/debug/info/warn/error) |
--with-dashboard | - | false | Enable Web Dashboard |
--data-dir | -d | ./data | Data directory |
--pid-file | - | none | PID file path |
--daemon | - | false | Run as a daemon |
--version | -V | - | Print version and exit |
--help | -h | - | Print help information |
After startup, the API server listens on http://localhost:8080 by default.
Configuration File Load Order
EnerOS looks up configuration files in the following order; the first one found takes precedence:
- Explicitly specified via
--configcommand-line argument eneros.tomlin the current directory~/.eneros/eneros.toml(user-level)/etc/eneros/eneros.toml(system-level)- Built-in defaults
If no configuration file is found, built-in defaults are used and a warning is printed in the logs.
Log Levels
EnerOS uses the tracing library to output structured logs. You can control it via --log-level or environment variables:
# Command-line argument
./target/release/eneros-api --log-level debug
# Environment variable
export ENEROS_LOG=debug
./target/release/eneros-api
| Level | Purpose |
|---|---|
trace | Very detailed, includes all internal state changes |
debug | Debug information, including request/response details |
info | Key business events (default) |
warn | Warnings, system can continue running |
error | Errors, require attention |
off | Disable logging |
Startup Log Example
2026-07-06T10:00:00.123Z INFO eneros_api::server | EnerOS API Server v0.47.0
2026-07-06T10:00:00.124Z INFO eneros_api::server | Loading config from eneros.toml
2026-07-06T10:00:00.130Z INFO eneros_api::server | Listening on 0.0.0.0:8080
2026-07-06T10:00:00.131Z INFO eneros_api::server | Workers: 4
2026-07-06T10:00:00.132Z INFO eneros_topology::store | Topology cache initialized
2026-07-06T10:00:00.133Z INFO eneros_powerflow::solver | PowerFlow solver ready (newton-raphson)
2026-07-06T10:00:00.134Z INFO eneros_api::server | Dashboard enabled at /dashboard
2026-07-06T10:00:00.135Z INFO eneros_api::server | Ready to accept connections
Verify the Service
Health Check
curl http://localhost:8080/api/v1/health
Expected response:
{
"status": "ok",
"version": "0.47.0",
"uptime_seconds": 42,
"components": {
"database": "ok",
"topology": "ok",
"powerflow": "ok",
"agent_runtime": "ok",
"timeseries": "ok"
}
}
Health Check Response Field Description
| Field | Type | Description |
|---|---|---|
status | string | Overall status, ok / degraded / down |
version | string | EnerOS version number |
uptime_seconds | number | Service uptime (seconds) |
components | object | Health status of each component |
components.database | string | Database status |
components.topology | string | Topology service status |
components.powerflow | string | Power flow calculation service status |
components.agent_runtime | string | Agent runtime status |
components.timeseries | string | Time-series storage status |
Readiness Check
# Unlike the health check: the readiness check waits for dependencies to initialize
curl http://localhost:8080/api/v1/ready
# {"ready": true}
Metrics Endpoint
# Prometheus format metrics
curl http://localhost:8080/api/v1/metrics
Run Power Flow Calculation
Via REST API (cURL)
Step 1: Create a Grid Network
# Create an IEEE 14-bus test network
curl -X POST http://localhost:8080/api/v1/networks \
-H "Content-Type: application/json" \
-d '{
"name": "IEEE-14",
"source": "ieee14",
"description": "IEEE 14-bus standard test system"
}'
Response:
{
"network_id": "net_a1b2c3d4",
"name": "IEEE-14",
"bus_count": 14,
"branch_count": 20,
"generator_count": 5,
"created_at": "2026-07-06T10:00:00Z"
}
Step 2: Run Power Flow Calculation
# Run Newton-Raphson power flow calculation
curl -X POST http://localhost:8080/api/v1/networks/net_a1b2c3d4/powerflow \
-H "Content-Type: application/json" \
-d '{
"method": "newton-raphson",
"tolerance": 1e-8,
"max_iterations": 20,
"flat_start": false
}'
Response:
{
"result_id": "pf_x1y2z3",
"network_id": "net_a1b2c3d4",
"method": "newton-raphson",
"converged": true,
"iterations": 4,
"duration_ms": 11.8,
"buses": [
{"id": 1, "voltage": 1.060, "angle": 0.00, "type": "slack"},
{"id": 2, "voltage": 1.045, "angle": -4.98, "type": "PV"},
{"id": 3, "voltage": 1.010, "angle": -12.72, "type": "PV"},
{"id": 4, "voltage": 1.019, "angle": -10.31, "type": "PQ"}
],
"branches": [
{"from": 1, "to": 2, "power_mw": 156.9, "loss_mw": 0.42}
],
"total_loss_mw": 13.79,
"timestamp": "2026-07-06T10:00:01Z"
}
Power Flow Calculation Parameter Details
| Parameter | Type | Default | Description |
|---|---|---|---|
method | string | newton-raphson | Solver method (newton-raphson / fast-decoupled / dc / gauss-seidel) |
tolerance | number | 1e-8 | Convergence precision (per unit) |
max_iterations | number | 20 | Maximum iterations |
flat_start | boolean | false | Whether to use flat start (voltage initial values all 1.0) |
q_limit_check | boolean | true | Whether to perform reactive power limit check |
tap_adjust | boolean | true | Whether to adjust transformer tap ratio |
Via Rust Code
use eneros_powerflow::PowerFlowSolver;
use eneros_topology::NetworkGraph;
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Load IEEE 14-bus network
let network = NetworkGraph::load_ieee14()?;
// Create power flow solver
let solver = PowerFlowSolver::new()
.method(eneros_powerflow::Method::NewtonRaphson)
.tolerance(1e-8)
.max_iterations(20)
.flat_start(false);
// Run power flow calculation
let result = solver.solve(&network)?;
// Output results
println!("Converged: {}", result.converged);
println!("Iterations: {}", result.iterations);
println!("Duration: {:.2} ms", result.duration_ms);
for bus in &result.buses {
println!(
"Bus {:>3}: V={:.4} pu, angle={:.2}°, P={:.2} MW, Q={:.2} MVAr",
bus.id,
bus.voltage,
bus.angle.to_degrees(),
bus.power_mw,
bus.reactive_mvar
);
}
println!("Total loss: {:.4} MW", result.total_loss_mw);
Ok(())
}
Add the above code to examples/powerflow_demo.rs, then run:
cargo run --release --example powerflow_demo
Expected output:
Converged: true
Iterations: 4
Duration: 11.80 ms
Bus 1: V=1.0600 pu, angle=0.00°, P=0.00 MW, Q=0.00 MVAr
Bus 2: V=1.0450 pu, angle=-4.98°, P=18.30 MW, Q=0.00 MVAr
Bus 3: V=1.0100 pu, angle=-12.72°, P=-94.20 MW, Q=0.00 MVAr
Bus 4: V=1.0186 pu, angle=-10.31°, P=-47.80 MW, Q=-3.90 MVAr
...
Total loss: 13.7934 MW
Via Python Client
import requests
BASE_URL = "http://localhost:8080/api/v1"
# Create network
resp = requests.post(
f"{BASE_URL}/networks",
json={
"name": "IEEE-14",
"source": "ieee14",
"description": "IEEE 14-bus standard test system"
}
)
network = resp.json()
network_id = network["network_id"]
print(f"Network created: {network_id}")
# Run power flow calculation
resp = requests.post(
f"{BASE_URL}/networks/{network_id}/powerflow",
json={
"method": "newton-raphson",
"tolerance": 1e-8,
"max_iterations": 20,
"flat_start": False
}
)
result = resp.json()
print(f"Converged: {result['converged']}")
print(f"Iterations: {result['iterations']}")
print(f"Duration: {result['duration_ms']} ms")
print(f"Total loss: {result['total_loss_mw']} MW")
for bus in result["buses"]:
print(f"Bus {bus['id']:>3}: V={bus['voltage']:.4f} pu, "
f"angle={bus['angle']:.2f}°")
Run:
python powerflow_demo.py
Access the Dashboard
If started with --with-dashboard, visit http://localhost:8080/dashboard to use the built-in Web Dashboard.
Dashboard Features
| Feature Module | Path | Description |
|---|---|---|
| Overview | /dashboard | System overview, key metrics |
| Topology Visualization | /dashboard/topology | Graphical grid topology display |
| Power Flow Results | /dashboard/powerflow | Power flow calculation result visualization |
| Agent Monitoring | /dashboard/agents | Agent running status and logs |
| Time-Series Data | /dashboard/timeseries | Time-series data charts |
| Alerts | /dashboard/alerts | Real-time alert list |
| Settings | /dashboard/settings | System settings |
Dashboard Operation Examples
- View Topology: Visit
/dashboard/topology, drag nodes to layout, click a node to view device details - Trigger Power Flow: Click the “Run PowerFlow” button on the topology page
- View Agents: Visit
/dashboard/agentsto view the list of running Agents - View Real-Time Curves: Visit
/dashboard/timeseries, select measurement points to draw curves
Error Handling
Common Error Responses
EnerOS API uses a unified error response format:
{
"error": {
"code": "POWERFLOW_NOT_CONVERGED",
"message": "Power flow calculation did not converge within 20 iterations",
"details": {
"iterations": 20,
"final_mismatch": 0.0123,
"network_id": "net_a1b2c3d4"
}
}
}
Error Code Table
| HTTP | code | Description |
|---|---|---|
| 400 | INVALID_REQUEST | Invalid request parameters |
| 401 | UNAUTHORIZED | Not authenticated |
| 403 | FORBIDDEN | No permission |
| 404 | NETWORK_NOT_FOUND | Network does not exist |
| 404 | BUS_NOT_FOUND | Bus does not exist |
| 409 | NETWORK_EXISTS | Network already exists |
| 422 | POWERFLOW_NOT_CONVERGED | Power flow did not converge |
| 422 | CONSTRAINT_VIOLATION | Security constraint violated |
| 500 | INTERNAL_ERROR | Internal error |
| 503 | SERVICE_UNAVAILABLE | Service unavailable |
Handling Power Flow Non-Convergence
# When POWERFLOW_NOT_CONVERGED is returned, try the following:
# 1. Increase iterations
curl -X POST http://localhost:8080/api/v1/networks/net_a1b2c3d4/powerflow \
-H "Content-Type: application/json" \
-d '{"method":"newton-raphson","max_iterations":50,"tolerance":1e-6}'
# 2. Use flat start
curl -X POST http://localhost:8080/api/v1/networks/net_a1b2c3d4/powerflow \
-H "Content-Type: application/json" \
-d '{"method":"newton-raphson","flat_start":true,"max_iterations":50}'
# 3. Switch to fast decoupled method
curl -X POST http://localhost:8080/api/v1/networks/net_a1b2c3d4/powerflow \
-H "Content-Type: application/json" \
-d '{"method":"fast-decoupled","max_iterations":50}'
# 4. DC power flow (approximate solution)
curl -X POST http://localhost:8080/api/v1/networks/net_a1b2c3d4/powerflow \
-H "Content-Type: application/json" \
-d '{"method":"dc"}'
Stop and Restart
Graceful Stop
# Send SIGTERM
kill $(cat eneros.pid)
# Or use enerosctl
./target/release/enerosctl server stop
# Force kill after 30 seconds if not exited
kill -9 $(cat eneros.pid)
Restart
# Use enerosctl
./target/release/enerosctl server restart
# Manual restart
./target/release/enerosctl server stop
./target/release/eneros-api --config eneros.toml
systemd Service (Linux)
# /etc/systemd/system/eneros.service
[Unit]
Description=EnerOS API Server
After=network.target
[Service]
Type=simple
User=eneros
ExecStart=/opt/eneros/bin/eneros-api --config /etc/eneros/eneros.toml
ExecStop=/opt/eneros/bin/enerosctl server stop
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable eneros
sudo systemctl start eneros
sudo systemctl status eneros
Common Runtime Issues
Problem 1: Port Already in Use
Error: Address already in use (os error 98)
Solution:
# Find the occupying process
lsof -i :8080 # Linux / macOS
netstat -ano | findstr :8080 # Windows
# Terminate the occupying process
kill -9 <PID>
# Or start on a different port
./target/release/eneros-api --port 9090
Problem 2: Database File Locked
Error: database is locked
Solution: Another process holds the database. Check if there is another eneros-api instance:
ps aux | grep eneros-api
Problem 3: Insufficient Permissions
Error: Permission denied (os error 13)
Solution:
# Check data directory permissions
ls -la ./data/
# Change owner
sudo chown -R $USER:$USER ./data/
Problem 4: Empty Power Flow Result
Cause: Wrong network ID, or network not loaded.
Solution:
# List all networks
curl http://localhost:8080/api/v1/networks
# Confirm network_id and retry
Next Steps
- First Agent - Create and run your first EnerOS Agent