OpenEVSE 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. Such self-service and multi-tenant devices will be required in more crowded places where there is very less density of such devices. This technology will enable smart sharing. SteVe is the server side implementation of OCPP protocol that is used to do end to end testing.

 

OpenEVSE Serial Connections

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 make 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 being built on top of a raspberry pi that connects to its serial ports that speak RAPI .

 

OpenEvse equipment can be accessed thru its serial port. It supports Serial TTL Devices at 5v on the 6 pin header.

 

 

 

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 very powerful 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 Emulator (Python)

For any relevant 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().

In addition, 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 is our way of specifying what all is included 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