OpenEVSE OCPP Emulator (Python)

OCPP enable EV charger emulator screenshot

OpenEVSE OCPP Emulator (Python)

Introduction

OpenEVSE supplies open-source charging station hardware and software solutions to manufacturers and individuals.  OpenEVSE controllers allow manufacturers to bring their products to market sooner at a lower cost than designing from scratch. Ibeyonde is striving to IoT enable the OpneEVSE system by making OpenEVSE Charge Point OCPP compliant. In densely populated areas, you will need such self-service and multi-tenant devices. This technology will allow smart sharing. SteVe is the server-side implementation of the OCPP protocol that is used to do end to end testing. Here we will talk about an OpenEVSE OCPP emulator.

 

 IoT and OpenEVSE

OpenEVSE Serial Connections

Figure: OpenEVSE Serial Connections: Yellow(Rx), Green(Tx)

 

OpenEVSE comes with a standalone solution that is IP based HTTP, MQTT access to it, implemented on Huzzah hardware module. We are taking it further by making it an IoT product so that thousands of such standalone units can become part of larger multi-tenant and self-service network. The IoT module is with Raspberry Pi and connects to its serial ports that speak RAPI.

 

To make the OCPP server solution easy to test, we have designed an OpenEVSE OCPP emulator.

 

 

 

Serial communication with OpenEVSE

 

You can open a console to connect the COMM port of OpenEVSE to the USB-TTL adapter with a baud rate of 115200. From the console, you can interact with the OpenEVSE using RAPI protocol.  The Remote API is potent for querying and controlling OpenEVSE. It is useful for information, configuration, and external applications.

 

 

Here are some interesting RAPI Get commands:

  • $GG – Get real-time charging current. Returns $OK current-voltage(future hardware)
  • $GP – Get real-time Temperature values from RTC chip, MCP9808, and TMP007 IR sensors. Returns $OK RTC, MCP9808, TMP007 – 0 is returned if sensor is not found.
  • $GS – Set EVSE State. Returns the current state $OK State – 1 Not Connected – 2 Connected – 3 Charging – 4 Error – 5 Error.
  • $GU – Get usage statistics. Returns $OK Energy used last session and lifetime
  • We took a headless raspberry pi zero w with its serial ports connected to OpenEVSE.

 

Using PySerial, we were able to talk RAPI with OpenEVSE. The PYserial module connects OpenEVSE with the client-side OCPP implementation.

 

 

OpenEVSE OCPP Emulator (Python)

For any proper testing of the OpenEVSE system, you either need a working OpenEVSE, or you can use the serial port emulator. This article is mainly about implementing a serial port OpenEVSE emulator in python.

To simplify end to end testing without the need for carrying around OpenEVSE hardware, we overrode the PySerial class with our custom implementation that is capable of emulating the OpenEVSE hardware. The overridden functions are: write( ), read(), close(), isOpen() and readline().

Also, it provided the implementation of all standard OpenEVSE RAPI commands:

def get_response(self, request):
    request = request.decode("utf-8")
..
    request_for = request[0:3]
..
    if request_for == '$FF':
       response = "$OK 20"
    elif request_for == '$FB':
       response = "$OK 2" # set backlight color
       print("Backlight color is " + p1)
       lcd_color = int(p1)
   elif request_for == '$FD':
       response = "$OK 2" #disable EVSE
       status = _status_functions['FD']
   elif request_for == '$FE':
       response = "$OK 2" #enable EVSE
       status = _status_functions['FE']
   elif request_for == '$FS':
...

To emulate – connect, start charging, stop charging and disconnect it uses shared memory to pass on these actions to the emulator. This asynchronous mechanism of communication can be used by either a command-line tool or a web interface.

 

def processSerialCommands(self, serialCmd):
  while True:
    try:
      cmdv = serialCmd.read()  # Read command from share memory channel
      time.sleep(1)
      if cmdv is not None:
        if cmdv[0] == 'Connect':
        print("Received start transaction on serial shm")
        self.update_status("$ST 2\r")  # send the status update via serial channel
        state=2

.....

 

To use the emulator, you need to make sure that the python picks up the emulated library instead of the PySerial.

capability = os.popen('cat ../system.properties | grep capability | cut -d"=" -f 2').read()

if ("OPENEVSE_EMULATOR" in capability):
import emulator_serial as serial # use emulated class if emulator mode is enabled
else:
import serial

*A capability file specifies functionality available on the Raspberry pi HAT.

Following code creates a serial channel to connect to OpenEVSE Emulator.

self.s = serial.Serial(port='/dev/ttyAMA0', baudrate=115200, timeout=STANDARD_SERIAL_TIMEOUT)
...
while True:
  c = self.s.read()  # read from serial port
  if c == b'':
    raise EvseTimeoutError
    line += c.decode('ascii')
  if c == b'\r':
    break
return line

 

OpenEVSE and Steve

Steve OCPP 1.5J

Steve OCPP 1.5J Compliant Server

 

Further, the following code connects to the cloud server implementing of OCPP 1.5J based on SteVe. SteVe was developed at the RWTH Aachen University and currently implement OCPP 1.5 and 1.6. The OpenEVSE State changes (or statuses) are communicated to the OCPP 1.5J compliant cloud server. The SteVe server manages ChargePoints users, devices and charging sessions.

 

 

websocket.enableTrace(True)
ws = websocket.WebSocketApp("ws://" + SIP + ":880/steve/websocket/CentralSystemService/" + uuid,
            on_message=on_message,
            on_error=on_error,
            on_close=on_close,
           header=[ "Sec-WebSocket-Protocol: ocpp1.5"])
ws.on_open = on_open
ws.run_forever()

.....
logging.info("created= openevse.SerialOpenEVSE()")
openevse_serial = openevse.SerialOpenEVSE()
while True:
   try:
      status = openevse_serial.get_status_change()
      if status == "not connected":
        logging.info("Status=%s" % status)
        sm.disconnect()
        ocpp_resp.write("Disconnect", "Success")
      elif status == "connected":
        logging.info("Status=%s" % status)
        if sm.isCharging():
          sendRequest(ws, client_cmd.getStopTransaction(sm.getUsername(), sm.getTransactionId(), 20))
          sm.stopCharging()
...

The full demo is available here for further inquiry contact info@ibeyonde.com.

Share this post

Leave a Reply

Your email address will not be published. Required fields are marked *


You've just added this product to the cart: