Skip to main content

Running OpenEMS Edge on a Raspberry PI

Release 2025.11.0

This guide walks through running OpenEMS Edge on a Raspberry Pi and connecting it to an OpenEMS UI running as a Docker container on a separate machine over a local network.

The goal is a simple, reproducible local Edge + local UI setup suitable for development, simulation, and early deployments.


Architecture Overview

This setup consists of two main components connected over the internet:

  • Edge (Raspberry Pi)
    Runs OpenEMS Edge as a systemd service and connects to the internet via Wi‑Fi.

  • Client (Laptop / Desktop)
    Runs the OpenEMS UI inside a Docker container. The UI may run on a different network (home, office, cloud VM).

Communication:

  • The UI communicates with the Edge via a WebSocket connection (default port 8085) over the public internet.

This means the Edge must be reachable via a public IP, port forwarding, or a secure tunnel.


Assumptions & Prerequisites

Before starting, ensure:

  • Raspberry Pi has working Wi‑Fi internet access

  • You have one of the following for remote access to the Pi:

    • Public IPv4 address with port forwarding, or

    • A static public IP, or

    • A secure tunnel (e.g. WireGuard, Tailscale, Cloudflare Tunnel)

  • Ports 80, 443, and 8085 are reachable from the Client

  • You have sudo access on the Raspberry Pi

  • Raspberry Pi OS is 64‑bit (ARM64)

Strong recommendation: For production or long‑running setups, use a VPN or tunnel instead of exposing ports directly.


Requirements

Hardware

  • Raspberry Pi–based Edge device
    (e.g. SL-RP4 with embedded Raspberry Pi 4B)

  • 2 GB RAM (minimum)

  • 16 GB micro-SD card + reader

Software / Dependencies

  • SSH

  • Rsync or WinSCP (Windows)

  • Raspberry Pi Imager

  • Docker Desktop

  • OpenEMS source code (release 2025.11.0)

  • Adoptium OpenJDK Temurin 21 (ARM64)


Fresh Device Deployment

This guide uses headless setup only. No monitor or keyboard is required for the Raspberry Pi.

Format SD Card (Client)

Install and launch Raspberry Pi Imager, then select:

  • Device: Raspberry Pi 4

  • Operating System: Raspberry Pi OS Lite (64-bit)
    (Debian Trixie – 2025-10-01)

  • Storage: Target SD card

Click Next → Edit Settings.

These settings are written to the SD card and applied on the first boot.

OS Customisation — General

Mandatory:

  • Hostname

  • Username and password

  • Enable SSH

Required for this setup:

  • Configure Wi‑Fi SSID, password, and country

Also configure:

  • Timezone

  • Keyboard layout

OS Customisation — Services

Enable the following:

  • Enable SSH (key-based auth recommended)

  • Enable Raspberry Pi Connect

Raspberry Pi Connect allows secure remote access to the Pi over the internet, even behind NAT, without port forwarding.

Proceed to format the SD card.


Raspberry Pi Connect (Remote Access)

Raspberry Pi Connect provides a secure, browser-based and SSH-like remote access method for headless Raspberry Pi devices without exposing ports or requiring a VPN.

Why Use Raspberry Pi Connect

  • No monitor or keyboard required

  • Works behind NAT and firewalls

  • Secure, encrypted connection

  • Accessible from anywhere via a browser

Requirements

  • Raspberry Pi OS (64-bit)

  • Internet access via Wi-Fi

  • Raspberry Pi ID account

First Login via Raspberry Pi Connect

  1. During first boot, ensure the Pi is connected to Wi-Fi

  2. Sign in to Raspberry Pi Connect from another device:

https://connect.raspberrypi.com
  1. Log in with your Raspberry Pi ID

  2. Select your Pi from the device list

  3. Open a remote shell or desktop session (if enabled)

Once Raspberry Pi Connect is active, SSH is optional but still recommended for automation.


While Formatting… (Client)

Clone the OpenEMS source code:

git clone -b 2025.11.0 https://github.com/OpenEMS/openems piDeployDemo
cd piDeployDemo

Build the UI-only Docker image:

docker build . -t openems_ui -f tools/docker/ui/Dockerfile.edge

Setting Up the Raspberry Pi (Edge)

  1. Insert the SD card into the Raspberry Pi

  2. Connect networking and power

  3. Once the device boots, SSH into it:

ssh user@host-name.local

Create a working directory:

mkdir downloads
cd downloads

Checkpoint:

  • hostname returns the configured hostname

  • ip a shows a LAN IP address


Installing Java & OpenEMS Edge (Edge)

Download OpenEMS Edge

wget https://github.com/OpenEMS/openems/releases/download/2025.11.0/openems-edge.jar
sudo chmod +x openems-edge.jar

Install Java (Temurin 21)

OpenEMS 2025.11.0 requires Java 21. Use Adoptium Temurin for ARM64 compatibility.

sudo -s
apt install -y wget apt-transport-https gpg
wget -qO - https://packages.adoptium.net/artifactory/api/gpg/key/public \
 | gpg --dearmor | tee /etc/apt/trusted.gpg.d/adoptium.gpg > /dev/null
echo "deb https://packages.adoptium.net/artifactory/deb \
$(awk -F= '/^VERSION_CODENAME/{print $2}' /etc/os-release) main" \
 | tee /etc/apt/sources.list.d/adoptium.list
exit

sudo apt update
sudo apt install temurin-21-jdk

Checkpoint:

java -version

Should report Java 21.


Set Up OpenEMS as a System Service (Edge)

Create directories:

sudo mkdir /usr/lib/openems
sudo mv openems-edge.jar /usr/lib/openems
sudo mkdir /etc/openems.d

Create the service definition:

sudo nano /etc/systemd/system/openems.service

Paste the following:

[Unit]
Description=OpenEMS Edge
After=network.target

[Service]
User=root
Group=root
Type=notify
WorkingDirectory=/usr/lib/openems
ExecStart=/usr/bin/java -Dfelix.cm.dir=/etc/openems.d/ \
  -jar /usr/lib/openems/openems-edge.jar
SuccessExitStatus=143
Restart=always
RestartSec=10
WatchdogSec=60

[Install]
WantedBy=multi-user.target

Why this configuration:

  • felix.cm.dir externalizes configuration for persistence

  • Restart=always improves resilience

  • systemd ensures Edge starts on boot

Reload and start the service:

sudo systemctl daemon-reload
sudo systemctl enable openems
sudo systemctl restart openems --no-block
journalctl -lfu openems

Checkpoint:

systemctl status openems

⚠️ WebSocket Configuration (Critical)

The UI will load even if the Edge is unreachable. You must explicitly enable and configure the WebSocket on the Edge.

Below is a minimal, explicit configuration to get the UI ↔ Edge connection working.

1. Create the WebSocket configuration (Edge)

On the Raspberry Pi:

sudo nano /etc/openems.d/io.openems.edge.websocket.cfg

Paste the following example configuration:

# Enable WebSocket API for UI connection
websocket.enabled=true

# WebSocket port (default)
websocket.port=8085

# Allow remote UI connections
websocket.allowedOrigins=*

Save and exit.

For production, restrict allowedOrigins instead of using *.


2. (Optional but Recommended) Verify Edge is listening

sudo ss -lntp | grep 8085

You should see Java listening on port 8085.


3. Restart OpenEMS Edge

sudo systemctl restart openems

Check logs:

journalctl -lfu openems

You should see messages indicating the WebSocket service started.


4. Connectivity Options (Internet Access)

Choose one of the following so the UI can reach the Pi:

  1. Port Forwarding (Basic / Not Recommended for Production)

    • Forward external port 8085 → Pi internal port 8085

    • Use your public IP or DNS name as WEBSOCKET_HOST

  2. VPN or Tunnel (Recommended)

    • WireGuard / Tailscale / ZeroTier / Cloudflare Tunnel

    • Keeps the Edge private while allowing secure access

For detailed simulation setup, see OpenEMS Getting Started, Section 5 (Steps 1–8):
https://openems.github.io/openems.io/openems/latest/gettingstarted.html#starting-a-simulation


OpenEMS UI Login (Client)

Start the UI by accessing:

http://localhost/login

Default password: admin

  • Change language via:
    Top-left menu → Admin icon → “Sprache wählen”

  • Refresh or use the back arrow to return to the overview


Create & Launch the UI Docker Container (Client)

Set WEBSOCKET_HOST to one of the following:

  • Public IP address of the Raspberry Pi

  • Public DNS name (recommended)

  • VPN / tunnel IP or hostname

Example using a public hostname:

docker container run \
  -e WEBSOCKET_HOST=edge.example.com \
  -p 443:443 -p 80:80 \
  --restart unless-stopped \
  --name openems_ui_container \
  openems_ui

Why UI is Containerized but Edge Runs as a Service

In this guide, the OpenEMS UI runs in Docker while OpenEMS Edge runs as a native systemd service on the Raspberry Pi.

Why containerize the UI

  • The UI behaves like a web application: it’s comparatively portable and easier to run consistently across machines.

  • Docker makes it simple to package dependencies, run upgrades/rollbacks, and expose the UI via standard ports.

  • The UI typically needs only a small set of runtime settings (e.g., WEBSOCKET_HOST).

Why run Edge as a system service

OpenEMS Edge is closer to an appliance / gateway and is often more reliable when managed directly by the host OS:

  • Boot reliability: systemd starts Edge on boot and restarts it if it crashes.

  • Hardware & networking access: Edge may need stable access to devices and networking (serial/USB/Modbus/etc.). Running directly on the OS avoids Docker-specific device mapping and networking edge cases.

  • Persistent configuration: Externalized configs in /etc/openems.d are straightforward to manage and back up.

  • Simpler troubleshooting: Standard Linux tooling works immediately (systemctl status, journalctl).

When running Edge in Docker can make sense

  • You are running simulation only (no direct hardware I/O)

  • You already use container fleet management (e.g., docker-compose, k3s, balena)

  • You can standardize volumes, device mappings, and networking mode


Troubleshooting

  • UI loads but no Edge connection
    → Check public reachability of port 8085

  • Works on LAN but not remotely
    → Router port forwarding or firewall missing

  • Public IP keeps changing
    → Use Dynamic DNS or a tunnel

  • Connection drops frequently
    → Use VPN/tunnel instead of raw port forwarding


Security Notes (Important)

When exposing OpenEMS Edge over the internet:

  • Avoid running long‑term setups with raw port forwarding

  • Prefer WireGuard, Tailscale, or Cloudflare Tunnel

  • Consider TLS termination and authentication

  • Restrict SSH access (key‑based auth only)

This setup is suitable for remote development, pilots, and managed deployments.