This guide starts a normal Docker installation, creates or edits the config, runs diagnostics, and opens the dashboard.
The preview shows the Docker-first Analytics bootstrap — install commands,
installer output, a guided config init with example values, and the running
dashboard. It is also available as video: MP4 ·
WebM.
Home Assistant is optional. The advanced native Python path is documented separately in native-python.md.
You need:
- Docker with Docker Compose v2.24.0 or newer (
docker compose, not the legacydocker-compose). On macOS/Windows use Docker Desktop; Windows must use Linux containers. - network access from the EMS host to the grid meter
- network access from the EMS host to each Zendure device (or to the MQTT broker)
- the credentials or network identifiers for your chosen Zendure connection — a device IP address and serial for the Local API, or the broker profile / Zendure API key for Local MQTT / Zendure cloud MQTT
- grid meter type and endpoint settings
At least one supported Zendure connection — Local API, Local MQTT, or Zendure
cloud MQTT — must be available for EMS control; the Local API is recommended for
ZenSDK models because it is local and low-latency. Do not run Zendure HEMS, Home
Assistant automations, MQTT writers, or any other controller in parallel if they
write Zendure outputLimit. EMS assumes exclusive write control over
outputLimit while active.
If Docker is not installed yet, see install-docker.md. If you are unsure whether your hardware fits, see supported-setups.md.
Verify that both commands work:
docker --version
docker compose versionThe installer writes docker-compose.yml, creates config/ and data/, and
starts EMS. No repository clone is required. For EMS-only installs,
config/config.json is created on first container start; with Analytics the
installer creates it during setup because it runs config init --analytics.
Linux/macOS, EMS only:
mkdir -p ems-solarflow-api-control && cd ems-solarflow-api-control
curl -fsSLo install-docker.sh https://raw.githubusercontent.com/basecubedev/ems-solarflow-api-control/main/install-docker.sh
sh install-docker.shLinux/macOS, EMS + Analytics (bundled InfluxDB):
mkdir -p ems-solarflow-api-control && cd ems-solarflow-api-control
curl -fsSLo install-docker.sh https://raw.githubusercontent.com/basecubedev/ems-solarflow-api-control/main/install-docker.sh
sh install-docker.sh --analyticsWindows PowerShell (Docker Desktop with Linux containers), EMS only:
mkdir ems-solarflow-api-control
cd ems-solarflow-api-control
irm https://raw.githubusercontent.com/basecubedev/ems-solarflow-api-control/main/install-docker.ps1 -OutFile install-docker.ps1
powershell -ExecutionPolicy Bypass -File .\install-docker.ps1Add -Analytics for EMS + Analytics. chmod +x is not required on
Linux/macOS: run the script through sh install-docker.sh.
If you prefer to run each step yourself, see the manual path in
docker.md. It downloads docker-compose.yml, runs config init,
and starts the stack with the same commands the installer uses.
On first start, the container creates config/config.json from the built-in
template if the file does not exist yet. Existing config/config.json files
are not overwritten.
The generated Compose file uses service name ems, port mapping
8080:8080, and bind mounts ./config:/app/config and ./data:/app/data.
Check that the container started:
docker compose ps
docker compose logs -fStop following logs with Ctrl+C; the container keeps running.
docker compose exec ems python3 emsctl.py config initThe setup assistant is optional. It helps fill common settings and does not blindly replace an existing edited config. Choose your grid meter in the guided setup assistant. For Zendure SmartMeter D0, select "Zendure SmartMeter D0 via MQTT".
nano config/config.jsonSet at least:
grid_meter.typegrid_meter.ipfor HTTP meters, orgrid_meter.mqtt.hostandgrid_meter.mqtt.topicfor Zendure SmartMeter D0 / MQTT- each device
ip - each device
sn - installation-specific power and SOC limits
Template placeholder values force safe mode until replaced. In safe mode, EMS control is disabled, dry-run is enabled, and hardware writes are blocked.
docker compose restartdocker compose exec ems python3 emsctl.py diagnoseUse the hardware check only when you are ready to probe the configured local meter and devices. It is read-only.
docker compose exec ems python3 emsctl.py diagnose --hardwareOpen:
http://<host-ip>:8080
On the same machine, use:
http://127.0.0.1:8080
- Configuration details: configuration.md
- Copy/paste examples: configuration-examples.md
- Supported setups: supported-setups.md
- First-run checklist: first-run-checklist.md
- Common commands: common-commands.md
- Docker reference: docker.md
- Analytics (bundled InfluxDB): influxdb.md
- Troubleshooting: troubleshooting.md
- Backup and restore: backup-restore.md
- Backups are stored in
data/backups/by default. - FAQ: faq.md
Before pulling a new image, create backups. Password-protected backups are recommended, especially for config archives:
docker compose exec ems python3 emsctl.py backup create --type config --password
docker compose exec ems python3 emsctl.py backup create --type databases --password
docker compose pull
docker compose up -d
docker compose exec ems python3 emsctl.py config upgrade --dry-run
docker compose exec ems python3 emsctl.py config upgrade --yes --backup
docker compose exec ems python3 emsctl.py diagnoseBackups are stored under host path data/backups/. Without the password, an
encrypted backup cannot be restored. If you do not use bundled InfluxDB
analytics, you do not need an InfluxDB backup.
Native Python is still supported for developers and advanced/manual installs. Use native-python.md for venv, dependency installation, manual config creation, dry-run checks, service-manager notes, and native CLI commands.
