Core concepts & terminology

This chapter describes some of the core concepts and commonly used terms in OpenEMS:

1. OSGi Bundle

OpenEMS Edge is using the OSGi platform to provide a completely modular and dynamic service oriented system.

Logical groups of source code are put into one OSGi Bundle. Every directory in the source code root directory starting with io.openems.*` is a bundle.

More bundle naming conventions are:

  • Bundle names ending with *.common are for common code that is shared by multiple components. Examples are:

    io.openems.common

    for common code between Edge and Backend, like helper utils, JSON-RPC definitions and Abstract Worker implementations

    io.openems.backend.common

    for common code within Backend.

    io.openems.edge.common

    for common code within Edge.

    io.openems.edge.controller.api.common

    for common code used by API Controllers

    …​
  • Bundle names ending with *.api are for Natures and APIs. Examples are:

    io.openems.edge.controller.api

    for Controllers

    io.openems.edge.scheduler.api

    for Schedulers

    …​
  • Bundle names ending with *.core are for shared and helper OSGi services. Examples are:

    io.openems.edge.core

    for central singleton services:

    ComponentManager

    handles access to OpenEMS Components and Channels

    Cycle

    is responsible for the process Cycle

    Host

    for accessing the host and operating system

    Meta

    for some Meta information like the version of the running OpenEMS Edge

    Sum

    for summing the values of the entire energy system, all meters, energy storage systems and so on.

    io.openems.edge.ess.core

    for the central EssPower service, that distributes power requirements to different energy storage systems

2. OpenEMS Component

An OpenEMS Component is the fundamental building block in OpenEMS. Within the used OSGi Java framework, an OpenEMS component represents a service with requirements and capabilities.

As an example, an OpenEMS Component can declare to have the capabilities of an Energy Storage System (ESS) and as such represents the digital twin of a real device. A specific control algorithm can be implemented as a separate OpenEMS Component that declares a requirement for an ESS. Using this metadata, these building blocks are wired together at runtime and form a very flexible system. OSGi provides the capability to enable, modify or disable an OpenEMS Component at any time, without requiring a restart of the software. Re-wiring of the building blocks happens transparently in the background by the framework.

Every OpenEMS Component is identified by a unique ID, the "Component-ID". In an ecosystem consisting of a couple of ESS, a power meter at the grid connection point, and a measured photovoltaic system, those Component-IDs can be represented as follows: * ess1 for the first ESS * ess2 for the second ESS * ess0 for a virtual ESS cluster Component that aggregates ess1 and ess2 * meter0 for the power meter at the grid connection point * meter1 for the measured photovoltaic system * …​

To declare an OpenEMS component, the Java class has to implement the OpenemsComponent interface .

3. Channel

Each OpenEMS component has a defined set of data points. These data points are called "Channels". Each represents a single piece of information about a component. By definition, each channel has a unique ID, the "Channel-ID", within its parent component. Channels are defined by metadata like descriptive text, access-mode (read-only, read-write, write-only), data type (string, integer, float, etc.), and unit of measure (Watt, Volt, Degree Celsius, etc.). It is up to the OpenEMS component to provide the input for its read-channels as well as triggering actions on write-channels.

Example: An OpenEMS Component that represents a device connected via the Modbus communication protocol continuously reads data, such as the current measured power and provides the data in its Channels. Other Components in the system can then use the channel data for their application, e.g. as input for a control algorithm, to analyse it, store it locally or publish it via an application programming interface (API).

An energy system architecture as depicted in the Introduction is complex: connected to multiple hardware devices - batteries, converters, meters, and others - and an operating system and other software components. All of these elements are possible sources of errors. Because of this, measures are implemented in OpenEMS to improve fault tolerance. The developer needs to be aware, that every Channel value, while it will never change within a cycle, it could always be undefined or null, e.g. because there is no communication (yet) with the external hardware device or service. Therefore, the programming API for accessing a channel value requires an explicit declaration of what should be done in that case. It provides the following methods to get the actual value:

  • public T getOrError() throws InvalidValueException;

  • public T orElse(T alternativeValue);

Each Channel implements the Channel interface .

4. Nature

Certain categories of devices and services provide the same kind of information (i.e. Channels). To group these similar devices and services, OpenEMS defines "Natures" as sets of characteristics and attributes which need to be provided by each component that implements them. That is, a Nature extends a normal Java interface with channels.

Examples of abstracting physical devices using Natures are: - "ElectricityMeter" for electricity meters - "SymmetricEss" for symmetric battery energy storage systems - "Evcs" for electric vehicle charging stations.

OpenEMS components can declare their service capabilities and requirements as Natures. In this way, a control algorithm can simply declare a requirement for a controllable energy storage system (“ManagedSymmetricEss”) and will at runtime be wired with a service that provides this capability. The control algorithm does not need to know anything about the ESS’s specific communication interface, protocol, or manufacturer.

Natures extend normal Java interfaces with 'Channels'. If a Component implements a Nature it also needs to provide the required Channels. For example the Energy Storage System (ESS) Simulator Simulator.EssSymmetric.Reacting implements the Ess interface and therefor needs to provide a Soc Channel that provides the current 'State of Charge' of the battery.

Controllers are written against Nature implementations. Example: A Controller can be used with any ESS, because it can be sure that it provides all the data the Controller requires for its algorithm.

5. Channel Address

By combining the unique Component-ID and Channel-ID each Channel in the system can be addressed by a distinct 'Channel Address' in the form Component-ID/Channel-ID.

Example: the state of charge ("Soc") of the first energy storage system ("ess0") has the channel address ess0/Soc.

6. Scheduler

The Scheduler handles the order, in which Controllers are executed. For details see Scheduler and Controller below.

7. Controller

The actual business logic or algorithms are wrapped as 'Controllers'. i.e. they implement the Controller interface . Each Controller holds one specific, encapsulated task.