Documentation

1. Concept

The OpenEMS Documentation is built with Antora .

OpenEMS Files and Documentation are separated on two different repositories.

The UI was slightly modified to fit our needs.

For more Information regarding AsciiDoc and Antora see their Docs.

2. Edit a page

If you want to edit a Docs - Page just click on 'Edit this Page' in the upper right corner to edit the page you are currently visiting.

Edit the Page according to your ideas and commit your changes.

You will see the changes you have made after our frequent Docs - Update.

3. Add a page

To add a page, clone the OpenEMS Repository (preferably Source Tree) and open it with a Code Editor (preferably Visual Studio Code).

  1. Go to doc/modules/ROOT/pages and create a .adoc file with the desired name.

  2. Go to doc/modules/ROOT/nav.adoc and add your page with the correct filename to the nav file.

4. Build Docs

To build the docs, clone the OpenEMS Repository (preferably Source Tree) and open it with a Code Editor (preferably Visual Studio Code).

NodeJS has to be installed

Build the documents:

Open the integrated terminal, change to the root directory and type

gradlew buildAntoraDocs

Docs should be building.. the finished HTML Folder can be found in your local 'build' folder (inside your repository build folder )

If you want to build your own docs with Antora see this guide

5. Dynamic Documentation Generation

Some parts of the OpenEMS documentation are generated dynamically during the build process.

In the repository you can find pages like nature.adoc with some text and then

Unresolved include directive in modules/ROOT/pages/development/documentation.adoc - include::nature.adoc.d/_include.adoc[]

where the corresponding folder nature.adoc.d is basically empty. (It only contains a .gitignore file to keep it that way in version control.) This is, where the dynamic generation happens.

5.1. The Process

(shown at the example of Natures documentation)

  1. Build-Time Generation (in doc/build.gradle lines 320-405)

The copyBundleReadmes Gradle task runs during the documentation build process and:

  1. Creates an empty _include.adoc file in doc/modules/ROOT/pages/edge/nature.adoc.d/

  2. Scans all bundles in the project looking for readme.adoc files

  3. Identifies .api bundles - When it finds a bundle ending with .api, it:

    • Copies that bundle’s readme.adoc to nature.adoc.d/{bundle-name}.adoc

    • Appends an include statement to _include.adoc:

Unresolved directive in documentation.adoc - include::{bundle-name}.adoc[leveloffset=+1]
  1. The Result

The generated nature.adoc.d/_include.adoc file contains something like:

Unresolved include directive in modules/ROOT/pages/development/documentation.adoc - include::io.openems.edge.battery.api.adoc[]
Unresolved include directive in modules/ROOT/pages/development/documentation.adoc - include::io.openems.edge.batteryinverter.api.adoc[]
Unresolved include directive in modules/ROOT/pages/development/documentation.adoc - include::io.openems.edge.ess.api.adoc[]
Unresolved include directive in modules/ROOT/pages/development/documentation.adoc - include::io.openems.edge.meter.api.adoc[]
...
  1. AsciiDoc Processing

When Antora builds the documentation, it processes nature.adoc which includes the line: Unresolved include directive in modules/ROOT/pages/development/documentation.adoc - include::nature.adoc.d/_include.adoc[]

This cascades to include all the individual bundle readme files, creating the complete list of natures.

5.2. Why This Pattern?

  • Automatic: New .api bundles with readme.adoc files automatically appear in the documentation

  • Maintainable: Each bundle documents itself in its own readme.adoc

  • DRY: No need to manually maintain a central list

  • Build artifact: The _include.adoc is git-ignored (hence the .gitignore in the directory) and regenerated on each build

You can see this in action by running:

./gradlew copyBundleReadmes

This will not only populate doc/modules/ROOT/pages/edge/nature.adoc.d/ with all the individual nature documentation files! It will do it for all dynamically generated documentation parts in the OpenEMS docs that follow this pattern.