EVCS Core
Implementing an Electric Vehicle Charging Station
These are a couple of steps that should be helpful in your implementation of a new evcs component. Note that some parts may still be missing.
-
Gather all the important information about your Electric Vehicle Charging Station (EVCS)
-
Communication Protocol
-
Possible Read/Write values (Important for used Natures and their values)
-
IP address, URL, Modbus Unit ID, or any other relevant parameters required for the communication
-
-
Select Natures depending on the Read/Write values provided by the evcs (In many cases more than one)
-
Evcs (Basic reading functionality)
-
ManagedEvcs (Additional Channels and functions for writing charge power limits)
-
SocEvcs (Additional Channels for the State of Charge information)
-
-
Use already existing Bridge (e.g. Hypercharger using AbstractOpenemsModbusComponent) or create a new bridge (Not every protocol is/can be generalized in a separate bundle)
-
Note that AbstractManagedEvcsComponent cannot be used if the component is a modbus component (Some functions must be called manually)
-
-
Create Component based on the evcs related natures. Example HyperchargerImpl:
@Designate(ocd = Config.class, factory = true) @Component(// name = "Evcs.AlpitronicHypercharger", // immediate = true, // configurationPolicy = ConfigurationPolicy.REQUIRE // ) @EventTopics({ // EdgeEventConstants.TOPIC_CYCLE_BEFORE_PROCESS_IMAGE, // EdgeEventConstants.TOPIC_CYCLE_EXECUTE_WRITE // }) public class HyperchargerImpl extends AbstractOpenemsModbusComponent implements Evcs, ManagedEvcs, OpenemsComponent, ModbusComponent, EventHandler, Hypercharger, TimedataProvider {-
@Designate: Standard
-
@Component: Standard
-
@EventTopics: Handle this events in the handleEvent method
-
AbstractOpenemsModbusComponent: Ease the communication with a modbus device
-
Evcs: See above
-
ManagedEvcs: See above
-
OpenemsComponent: Identifies an OpenemsComponent
-
ModbusComponent: Specific for modbus component
-
EventHandler: Used to act in a specific Event in an Openems Cycle
-
Hypercharger: Individual "Nature" for additional Channels besides the evcs natures
-
TimedataProvider: Needed for this evcs to calculate the total energy charged
-
-
Create Properties needed. Most important for components not using AbstractManagedEvcsComponent:
/** * Handles charge states. */ private final ChargeStateHandler chargeStateHandler = new ChargeStateHandler(this); /** * Processes the controller's writes to this evcs component. */ private final WriteHandler writeHandler = new WriteHandler(this); -
Constructor using ChannelIds of implementing Natures:
public HyperchargerImpl() { super(// OpenemsComponent.ChannelId.values(), // ModbusComponent.ChannelId.values(), // Evcs.ChannelId.values(), // ManagedEvcs.ChannelId.values(), // Hypercharger.ChannelId.values()); }If it is not listed here, the component is not aware of the channels in that nature.
-
Add Activate, Deactivate & Modified
@Activate private void activate(ComponentContext context, Config config) throws OpenemsNamedException { this.config = config; if (super.activate(context, config.id(), config.alias(), config.enabled(), config.modbusUnitId(), this.cm, "Modbus", config.modbus_id())) { return; } /* * Calculates the maximum and minimum hardware power dynamically by listening on * the fixed hardware limit and the phases used for charging */ Evcs.addCalculatePowerLimitListeners(this); this.applyConfig(config); } @Modified private void modified(ComponentContext context, Config config) throws OpenemsNamedException { if (super.modified(context, config.id(), config.alias(), config.enabled(), config.modbusUnitId(), this.cm, "Modbus", config.modbus_id())) { return; } this.applyConfig(config); } private void applyConfig(Config config) { this.config = config; this.calculateTotalEnergy = new CalculateEnergyFromPower(this, Evcs.ChannelId.ACTIVE_CONSUMPTION_ENERGY); this._setFixedMinimumHardwarePower(config.minHwPower()); this._setFixedMaximumHardwarePower(config.maxHwPower()); this._setPowerPrecision(1); this._setPhases(3); } @Override @Deactivate protected void deactivate() { super.deactivate(); }The Channel values set in the applyConfig are given by the config or by default.
The Fixed Minimum/Maximum HardwarePower and the Phases Channel are used to calculate the minimum and maximum power for the user interface. (Automatically handled by calling Evcs.addCalculatePowerLimitListeners(this) or the AbstractManagedEvcsComponent)
Maximum Charge power selected: 17000 W
4140 W -----------------------x------------ 22080 W (charging 6 - 32 amps on 3 phases)
Maximum Charge power selected: 1600 W
1380 W --x--------------------------------- 7360 W (charging 6 - 32 amps on 1 phase)
-
Modbus specific methods
-
Reference to the modbus bridge
@Override @Reference(policy = ReferencePolicy.STATIC, policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.MANDATORY) protected void setModbus(BridgeModbus modbus) { super.setModbus(modbus); } -
Modbus-Register mapping
@Override protected ModbusProtocol defineModbusProtocol() throws OpenemsException { var modbusProtocol = new ModbusProtocol(this, new FC3ReadRegistersTask(this.offset.apply(0), Priority.LOW, m(Hypercharger.ChannelId.RAW_CHARGE_POWER_SET, new UnsignedDoublewordElement(this.offset.apply(0)))), new FC16WriteRegistersTask(this.offset.apply(0), m(Hypercharger.ChannelId.APPLY_CHARGE_POWER_LIMIT, new UnsignedDoublewordElement(this.offset.apply(0))), m(Hypercharger.ChannelId.SETPOINT_REACTIVE_POWER, new UnsignedDoublewordElement(this.offset.apply(2)))), ...Most mistakes: - Wrong function code, offset, or any other information provided by the Modbus protocol or manual - Wrong AbstractModbusRegisterElement for a register - Missing register (Unimportant register could be skipped with new DummyRegisterElement(xxx),) - Important tasks with Priority HIGH are blocked by other unimportant tasks with Priority HIGH - Read/Write register must be read and write in different tasks with different function codes - Scale factor overlooked. The scale factor can be easily adjusted using, for example, SCALE_FACTOR_MINUS_2
-
-
Check if every Channel is set correctly
To do this, you could add the component in the controller 'DebugDetailedLog', or download the information of a component using the 'Excel Export' feature in the system profile."