Skip to main content

First Run

Quick Start

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

ArgumentShortcutDefaultDescription
--config-ceneros.tomlConfiguration file path
--host-H0.0.0.0Listen address
--port-p8080Listen port
--log-level-linfoLog level (trace/debug/info/warn/error)
--with-dashboard-falseEnable Web Dashboard
--data-dir-d./dataData directory
--pid-file-nonePID file path
--daemon-falseRun 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:

  1. Explicitly specified via --config command-line argument
  2. eneros.toml in the current directory
  3. ~/.eneros/eneros.toml (user-level)
  4. /etc/eneros/eneros.toml (system-level)
  5. 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
LevelPurpose
traceVery detailed, includes all internal state changes
debugDebug information, including request/response details
infoKey business events (default)
warnWarnings, system can continue running
errorErrors, require attention
offDisable 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

FieldTypeDescription
statusstringOverall status, ok / degraded / down
versionstringEnerOS version number
uptime_secondsnumberService uptime (seconds)
componentsobjectHealth status of each component
components.databasestringDatabase status
components.topologystringTopology service status
components.powerflowstringPower flow calculation service status
components.agent_runtimestringAgent runtime status
components.timeseriesstringTime-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

ParameterTypeDefaultDescription
methodstringnewton-raphsonSolver method (newton-raphson / fast-decoupled / dc / gauss-seidel)
tolerancenumber1e-8Convergence precision (per unit)
max_iterationsnumber20Maximum iterations
flat_startbooleanfalseWhether to use flat start (voltage initial values all 1.0)
q_limit_checkbooleantrueWhether to perform reactive power limit check
tap_adjustbooleantrueWhether 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 ModulePathDescription
Overview/dashboardSystem overview, key metrics
Topology Visualization/dashboard/topologyGraphical grid topology display
Power Flow Results/dashboard/powerflowPower flow calculation result visualization
Agent Monitoring/dashboard/agentsAgent running status and logs
Time-Series Data/dashboard/timeseriesTime-series data charts
Alerts/dashboard/alertsReal-time alert list
Settings/dashboard/settingsSystem settings

Dashboard Operation Examples

  1. View Topology: Visit /dashboard/topology, drag nodes to layout, click a node to view device details
  2. Trigger Power Flow: Click the “Run PowerFlow” button on the topology page
  3. View Agents: Visit /dashboard/agents to view the list of running Agents
  4. 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

HTTPcodeDescription
400INVALID_REQUESTInvalid request parameters
401UNAUTHORIZEDNot authenticated
403FORBIDDENNo permission
404NETWORK_NOT_FOUNDNetwork does not exist
404BUS_NOT_FOUNDBus does not exist
409NETWORK_EXISTSNetwork already exists
422POWERFLOW_NOT_CONVERGEDPower flow did not converge
422CONSTRAINT_VIOLATIONSecurity constraint violated
500INTERNAL_ERRORInternal error
503SERVICE_UNAVAILABLEService 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