Skip to content

Commit

Permalink
Add examples OCPP 2.0 examples
Browse files Browse the repository at this point in the history
  • Loading branch information
me-sosa authored and OrangeTux committed Oct 29, 2019
1 parent 44742f7 commit 3aea282
Show file tree
Hide file tree
Showing 8 changed files with 164 additions and 30 deletions.
1 change: 1 addition & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ recursive-exclude tests *
exclude requirements_dev.txt
include requirements.txt
recursive-include ocpp/v16/schemas *.json
recursive-include ocpp/v20/schemas *.json
49 changes: 23 additions & 26 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
OCPP
----

Python package implementing the JSON version of the Open Charge Point Protocol (OCPP). Currently
only OCPP 1.6 is supported.
Python package implementing the JSON version of the Open Charge Point Protocol
(OCPP). Currently OCPP 1.6 and OCPP 2.0 are supported.

You can find the documentation on `rtd`_.

Expand All @@ -33,7 +33,8 @@ Or clone the project and install it manually using:
Quick start
-----------

Below you can find examples on how to create a simple charge point as well as a charge point.
Below you can find examples on how to create a simple OCPP 2.0 centrl system as
well as an OCPP 2.0 charge point.

.. note::

Expand All @@ -46,8 +47,9 @@ Below you can find examples on how to create a simple charge point as well as a
Central system
~~~~~~~~~~~~~~

The code snippet below creates a simple central system which is able to handle BootNotification
calls. You can find a detailed explaination of the code in the `Central System documentation_`.
The code snippet below creates a simple OCPP 2.0 central system which is able
to handle BootNotification calls. You can find a detailed explanation of the
code in the `Central System documentation_`.


.. code-block:: python
Expand All @@ -57,26 +59,18 @@ calls. You can find a detailed explaination of the code in the `Central System d
from datetime import datetime
from ocpp.routing import on
from ocpp.v16 import ChargePoint as cp
from ocpp.v16.enums import Action, RegistrationStatus
from ocpp.v16 import call_result
from ocpp.v20 import ChargePoint as cp
from ocpp.v20 import call_result
class ChargePoint(cp):
@on(Action.BootNotification)
def on_boot_notification(self, charge_point_vendor, charge_point_model, **kwargs):
@on('BootNotification')
def on_boot_notitication(self, charging_station, reason, **kwargs):
return call_result.BootNotificationPayload(
current_time=datetime.utcnow().isoformat(),
interval=10,
status=RegistrationStatus.accepted
status='Accepted'
)
@after(Action.BootNotification)
def after_boot_notification(self, charge_point_vendor, charge_point_model, **kwargs):
print("ChargePoint Vendor is: %s", charge_point_vendor)
print("ChargePoint Model is: %s",charge_point_model)
async def on_connect(websocket, path):
""" For every new charge point that connects, create a ChargePoint instance
and start listening for messages.
Expand All @@ -93,7 +87,7 @@ calls. You can find a detailed explaination of the code in the `Central System d
on_connect,
'0.0.0.0',
9000,
subprotocols=['ocpp1.6']
subprotocols=['ocpp2.0']
)
await server.wait_closed()
Expand All @@ -110,27 +104,30 @@ Charge point
import asyncio
import websockets
from ocpp.v16 import call, ChargePoint as cp
from ocpp.v16.enums import RegistrationStatus
from ocpp.v20 import call
from ocpp.v20 import ChargePoint as cp
class ChargePoint(cp):
async def send_boot_notification(self):
request = call.BootNotificationPayload(
charge_point_model="Optimus",
charge_point_vendor="The Mobility House"
charging_station={
'model': 'Wallbox XYZ',
'vendor_name': 'anewone'
},
reason="PowerUp"
)
response = await self.call(request)
if response.status == RegistrationStatus.accepted:
if response.status == 'Accepted':
print("Connected to central system.")
async def main():
async with websockets.connect(
'ws://localhost:9000/CP_1',
subprotocols=['ocpp1.6']
subprotocols=['ocpp2.0']
) as ws:
cp = ChargePoint('CP_1', ws)
Expand Down
13 changes: 10 additions & 3 deletions docs/source/central_system.rst
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,13 @@ After you've started the server you can connect a client to it by using the `web
OCPP compliant handler
----------------------

.. note::

This document describes how to create an central system that supports OCPP
1.6. The ocpp Python package has support for OCPP 2.0 as well. This
documentation will be updated soon to reflect that. In the mean time please
consult the `examples/`_ to learn how to create an OCPP 2.0 central system.

The websocket server created above is not very useful and only sends a non-OCPP compliant message.

Remove the `on_connect()` handler from the code above and replace it by the following snippet.
Expand Down Expand Up @@ -133,8 +140,8 @@ is used to create a response that is send back to the client.

.. note::

OCPP uses a camelCase naming scheme for the keys in the payload. Python, on the other hand, uses
snake_case.
OCPP uses a camelCase naming scheme for the keys in the payload. Python, on
the other hand, uses snake_case.

Therefore this ocpp package converts all keys in messages from camelCase to
snake_case and vice versa to make sure you can write Pythonic code.
Expand Down Expand Up @@ -162,7 +169,7 @@ You can find the source code of the central system created in this document in t
directory.
.. _client: https://websockets.readthedocs.io/en/stable/intro.html#one-more-thing
.. _examples/: https://github.com/mobilityhouse/ocpp/blob/master/examples/central_system.py
.. _examples/: https://github.com/mobilityhouse/ocpp/blob/master/examples
.. _ocpp.v16.call_result.BootNotificationPayload: https://github.com/mobilityhouse/ocpp/blob/3b92c2c53453dd6511a202e1dc1b9aa1a236389e/ocpp/v16/call_result.py#L28
.. _ocpp.v16.ChargePoint: https://github.com/mobilityhouse/ocpp/blob/master/ocpp/v16/charge_point.py#L80
.. _start(): https://github.com/mobilityhouse/ocpp/blob/3b92c2c53453dd6511a202e1dc1b9aa1a236389e/ocpp/v16/charge_point.py#L125
Expand Down
1 change: 0 additions & 1 deletion docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
import os
import sys
sys.path.insert(0, os.path.abspath('../../'))
print(os.path.abspath('../../ocpp'))


# -- Project information -----------------------------------------------------
Expand Down
File renamed without changes.
File renamed without changes.
68 changes: 68 additions & 0 deletions examples/v20/central_system.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import asyncio
from datetime import datetime

try:
import websockets
except ModuleNotFoundError:
print("This example relies on the 'websockets' package.")
print("Please install it by running: ")
print()
print(" $ pip install websockets")
import sys
sys.exit(1)

from ocpp.routing import on
from ocpp.v20 import ChargePoint as cp
from ocpp.v20 import call_result


class ChargePoint(cp):
@on('BootNotification')
def on_boot_notitication(self, charging_station, reason, **kwargs):
return call_result.BootNotificationPayload(
current_time=datetime.utcnow().isoformat(),
interval=10,
status='Accepted'
)

@on('Heartbeat')
def on_heartbeat(self):
print('Got a Heartbeat!')
return call_result.HeartbeatPayload(
current_time=datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%S') + "Z"
)


async def on_connect(websocket, path):
""" For every new charge point that connects, create a ChargePoint instance
and start listening for messages.
"""
charge_point_id = path.strip('/')
cp = ChargePoint(charge_point_id, websocket)

await cp.start()


async def main():
server = await websockets.serve(
on_connect,
'0.0.0.0',
9000,
subprotocols=['ocpp1.6']
)

await server.wait_closed()


if __name__ == '__main__':
try:
# asyncio.run() is used when running this example with Python 3.7 and
# higher.
asyncio.run(main())
except AttributeError:
# For Python 3.6 a bit more code is required to run the main() task on
# an event loop.
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
loop.close()
62 changes: 62 additions & 0 deletions examples/v20/charge_point.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import asyncio

try:
import websockets
except ModuleNotFoundError:
print("This example relies on the 'websockets' package.")
print("Please install it by running: ")
print()
print(" $ pip install websockets")
import sys
sys.exit(1)


from ocpp.v20 import call
from ocpp.v20 import ChargePoint as cp


class ChargePoint(cp):

async def send_heartbeat(self, interval):
request = call.HeartbeatPayload()
while True:
await self.call(request)
await asyncio.sleep(interval)

async def send_boot_notification(self):
request = call.BootNotificationPayload(
charging_station={
'model': 'Wallbox XYZ',
'vendor_name': 'anewone'
},
reason="PowerUp"
)
response = await self.call(request)

if response.status == 'Accepted':
print("Connected to central system.")
await self.send_heartbeat(response.interval)


async def main():
async with websockets.connect(
'ws://localhost:9000/CP_1',
subprotocols=['ocpp2.0']
) as ws:

cp = ChargePoint('CP_1', ws)

await asyncio.gather(cp.start(), cp.send_boot_notification())


if __name__ == '__main__':
try:
# asyncio.run() is used when running this example with Python 3.7 and
# higher.
asyncio.run(main())
except AttributeError:
# For Python 3.6 a bit more code is required to run the main() task on
# an event loop.
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
loop.close()

0 comments on commit 3aea282

Please sign in to comment.