OCPP J 1.5 Add on - motown-io/motown GitHub Wiki

Responsibility

The OCPP J 1.5 Add-on implements OCPP v1.5 over websockets according to the OCPPJ implementation guide, which is (to be) published at http://www.ocppforum.net/project/index.

Calls initiated by the Charging Station: Authorize, Boot Notification, Data Transfer, Diagnostics Status Notification, Firmware Status Notification, Heartbeat, Meter Values, Start Transaction, Status Notification and Stop Transaction.

Calls initiated by Motown: Cancel Reservation, Change Availability, Change Configuration, Clear Cache, Data Transfer, Get Configuration, Get Diagnostics, Get Local List Version, Remote Start Transaction, Remote Stop Transaction, Reserve Now, Reset, Send Local List, Unlock Connector and Update Firmware.

The Charging Station communication will get 'linked' to this specific add-on upon receipt of the Charging Station's BootNotification. Allowing Motown to support different versions of the OCPP protocol in parallel.

Technology

This add on exposes a restful JSON service over websockets.

For the messages to and from the Charging Station the Web Application Messaging Protocol (WAMP v1) is being used.

The Websocket part is implemented using Atmosphere.

Configuring the add-on

All configuration samples below are Spring based. Spring is not required but it makes configuration a lot easier.

JPA

Make sure a JPA entity manager factory is running.

The JPA entities reside in package:

  • io.motown.ocpp.viewmodel.persistence.entities

The repositories reside in package:

  • io.motown.ocpp.viewmodel.persistence.repositories

Sample JPA configuration:

    <jdbc:embedded-database id="ocppWebservicesDataSource" type="HSQL"/>

    <bean id="entityManagerFactoryOcppWebServices"
              class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="dataSource" ref="ocppWebservicesDataSource"/>
        <property name="packagesToScan" value="io.motown.ocpp.viewmodel.persistence.entities"/>
        <property name="jpaVendorAdapter">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
                <property name="database" value="HSQL"/>
                <property name="generateDdl" value="true"/>
            </bean>
        </property>
    </bean>

    <bean id="chargingStationRepositoryOcppWebServices"
                class="io.motown.ocpp.viewmodel.persistence.repositories.ChargingStationRepository">
          <property name="entityManagerFactory" ref="entityManagerFactoryOcppWebServices"/>
    </bean>

    <bean id="reservationIdentifierRepositoryOcppWebServices"
                class="io.motown.ocpp.viewmodel.persistence.repositories.ReservationIdentifierRepository">
          <property name="entityManagerFactory" ref="entityManagerFactoryOcppWebServices"/>
    </bean>

    <bean id="transactionRepositoryOcppWebServices"
                class="io.motown.ocpp.viewmodel.persistence.repositories.TransactionRepository">
          <property name="entityManagerFactory" ref="entityManagerFactoryOcppWebServices"/>
    </bean>

    <bean id="ocppWebServicesTransactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
          <property name="entityManagerFactory" ref="entityManagerFactoryOcppWebServices"/>
    </bean>

Domain service

The domain service (io.motown.ocpp.viewmodel.domain.DomainService) contains the logic for accessing the repositories, and sending commands to the Motown Core.

Sample configuration:

    <bean id="ocppDomainService" class="io.motown.ocpp.viewmodel.domain.DomainService">
        <property name="chargingStationRepository" ref="chargingStationRepositoryOcppWebServices"/>
        <property name="commandGateway" ref="domainCommandGateway"/>
        <property name="eventWaitingGateway" ref="eventWaitingGateway"/>
        <property name="entityManagerFactory" ref="entityManagerFactoryOcppWebServices"/>
        <property name="heartbeatInterval" value="900"/>
        <property name="reservationIdentifierRepository" ref="reservationIdentifierRepositoryOcppWebServices"/>
        <property name="transactionRepository" ref="transactionRepositoryOcppWebServices"/>
        <property name="userIdentitiesWithAllPermissions" ref="userIdentitiesWithAllPermissions"/>
    </bean>

    <bean id="domainCommandGateway" class="org.axonframework.commandhandling.gateway.CommandGatewayFactoryBean">
        <property name="commandBus" ref="commandBus"/>
        <property name="gatewayInterface" value="io.motown.ocpp.viewmodel.domain.DomainCommandGateway"/>
    </bean>

    <bean id="configurationCommandGateway" class="org.axonframework.commandhandling.gateway.CommandGatewayFactoryBean">
        <property name="commandBus" ref="commandBus"/>
        <property name="gatewayInterface" value="io.motown.ocpp.viewmodel.configuration.ConfigurationCommandGateway"/>
    </bean>

    <bean id="eventWaitingGateway" class="io.motown.domain.utils.axon.EventWaitingGateway">
        <property name="commandBus" ref="commandBus"/>
        <property name="eventBus" ref="eventBus"/>
    </bean>

OCPP Central System service

The OCPP Central System service is the service the Charging Stations will be using to communicate with the backoffice.

Sample configuration:

    <bean id="ocppJsonService" class="io.motown.ocpp.websocketjson.OcppJsonService">
        <property name="domainService" ref="ocppDomainService" />
        <property name="schemaValidator">
            <bean class="io.motown.ocpp.websocketjson.schema.SchemaValidator" />
        </property>
        <property name="wampMessageParser">
            <bean class="io.motown.ocpp.websocketjson.wamp.WampMessageParser"/>
        </property>
        <property name="gson" ref="gson" />
        <property name="addOnId" value="1" />
    </bean>

    <bean id="gson" class="io.motown.ocpp.websocketjson.gson.GsonFactoryBean">
        <property name="dateFormat" value="yyyy-MM-dd'T'HH:mm:ss'Z'"/>
        <property name="typeAdapterSerializers">
            <set>
                <bean class="io.motown.ocpp.websocketjson.gson.serializer.AuthorizationListIdTagStatusTypeAdapterSerializer"/>
                <bean class="io.motown.ocpp.websocketjson.gson.serializer.BootnotificationResponseStatusTypeAdapterSerializer"/>
                <bean class="io.motown.ocpp.websocketjson.gson.serializer.ChangeAvailabilityTypeAdapterSerializer"/>
                <bean class="io.motown.ocpp.websocketjson.gson.serializer.DataTransferResponseStatusTypeAdapterSerializer"/>
                <bean class="io.motown.ocpp.websocketjson.gson.serializer.ResetTypeAdapterSerializer"/>
                <bean class="io.motown.ocpp.websocketjson.gson.serializer.SendLocalListRequestUpdateTypeAdapterSerializer"/>
                <bean class="io.motown.ocpp.websocketjson.gson.serializer.StartTransactionIdTagStatusTypeAdapterSerializer"/>
                <bean class="io.motown.ocpp.websocketjson.gson.serializer.MessageProcUriAdapterSerializer"/>
            </set>
        </property>
        <property name="typeAdapterDeserializers">
            <set>
                <bean class="io.motown.ocpp.websocketjson.gson.deserializer.AuthorizationIdTagStatusAdapterDeserializer"/>
                <bean class="io.motown.ocpp.websocketjson.gson.deserializer.CancelReservationResponseStatusTypeAdapterDeserializer"/>
                <bean class="io.motown.ocpp.websocketjson.gson.deserializer.ChangeAvailabilityTypeAdapterDeserializer"/>
                <bean class="io.motown.ocpp.websocketjson.gson.deserializer.ChangeConfigurationResponseStatusTypeAdapterDeserializer"/>
                <bean class="io.motown.ocpp.websocketjson.gson.deserializer.ChargePointErrorCodeTypeAdapterDeserializer"/>
                <bean class="io.motown.ocpp.websocketjson.gson.deserializer.ChargePointStatusTypeAdapterDeserializer"/>
                <bean class="io.motown.ocpp.websocketjson.gson.deserializer.ClearCacheResponseStatusTypeAdapterDeserializer"/>
                <bean class="io.motown.ocpp.websocketjson.gson.deserializer.DataTransferResponseStatusTypeAdapterDeserializer"/>
                <bean class="io.motown.ocpp.websocketjson.gson.deserializer.DiagnosticsStatusTypeAdapterDeserializer"/>
                <bean class="io.motown.ocpp.websocketjson.gson.deserializer.FirmwareStatusTypeAdapterDeserializer"/>
                <bean class="io.motown.ocpp.websocketjson.gson.deserializer.MessageProcUriAdapterDeserializer"/>
                <bean class="io.motown.ocpp.websocketjson.gson.deserializer.RemoteStartTransactionResponseTypeAdapterDeserializer"/>
                <bean class="io.motown.ocpp.websocketjson.gson.deserializer.RemoteStopTransactionResponseTypeAdapterDeserializer"/>
                <bean class="io.motown.ocpp.websocketjson.gson.deserializer.ReserveNowResponseStatusTypeAdapterDeserializer"/>
                <bean class="io.motown.ocpp.websocketjson.gson.deserializer.ResetResponseStatusAdapterDeserializer"/>
                <bean class="io.motown.ocpp.websocketjson.gson.deserializer.SendLocalListResponseStatusTypeAdapterDeserializer"/>
                <bean class="io.motown.ocpp.websocketjson.gson.deserializer.StopTransactionIdTagStatusAdapterDeserializer"/>
                <bean class="io.motown.ocpp.websocketjson.gson.deserializer.UnlockConnectorResponseStatusTypeAdapterDeserializer"/>
            </set>
        </property>
    </bean>

Webservice exposure

In order to expose the service interface through websockets, the Atmosphere servlet should be configured in your web.xml.

Sample web.xml configuration

    <filter>
        <filter-name>SecWebSocketVersionInterceptor</filter-name>
        <filter-class>io.motown.ocpp.websocketjson.servlet.SecWebSocketVersionInterceptor</filter-class>
        <init-param>
            <param-name>compressionThreshold</param-name>
            <param-value>10</param-value>
        </init-param>
        <init-param>
            <param-name>supportedProtocols</param-name>
            <param-value>ocpp1.5</param-value>
        </init-param>
    </filter>

    <filter-mapping>
        <filter-name>SecWebSocketVersionInterceptor</filter-name>
        <servlet-name>AtmosphereServlet</servlet-name>
    </filter-mapping>

    <servlet>
        <description>AtmosphereServlet</description>
        <servlet-name>AtmosphereServlet</servlet-name>
        <servlet-class>org.atmosphere.cpr.AtmosphereServlet</servlet-class>
        <init-param>
            <param-name>org.atmosphere.cpr.packages</param-name>
            <param-value>io.motown.ocpp.websocketjson</param-value>
        </init-param>
        <init-param>
            <param-name>org.atmosphere.interceptor.HeartbeatInterceptor.heartbeatFrequencyInSeconds</param-name>
            <param-value>900</param-value>
        </init-param>
        <load-on-startup>0</load-on-startup>
        <async-supported>true</async-supported>
    </servlet>

    <servlet-mapping>
        <servlet-name>AtmosphereServlet</servlet-name>
        <url-pattern>/socket/*</url-pattern>
    </servlet-mapping>

According to the mapping and configuration above, the Charging Station's specific endpoint of the service will be ws://<server>/socket/<ChargingStationId>.

⚠️ **GitHub.com Fallback** ⚠️