Skip to content

Commit 3aea282

Browse files
me-sosaOrangeTux
authored andcommitted
Add examples OCPP 2.0 examples
1 parent 44742f7 commit 3aea282

File tree

8 files changed

+164
-30
lines changed

8 files changed

+164
-30
lines changed

MANIFEST.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ recursive-exclude tests *
22
exclude requirements_dev.txt
33
include requirements.txt
44
recursive-include ocpp/v16/schemas *.json
5+
recursive-include ocpp/v20/schemas *.json

README.rst

Lines changed: 23 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@
1010
OCPP
1111
----
1212

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

1616
You can find the documentation on `rtd`_.
1717

@@ -33,7 +33,8 @@ Or clone the project and install it manually using:
3333
Quick start
3434
-----------
3535

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

3839
.. note::
3940

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

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

5254

5355
.. code-block:: python
@@ -57,26 +59,18 @@ calls. You can find a detailed explaination of the code in the `Central System d
5759
from datetime import datetime
5860
5961
from ocpp.routing import on
60-
from ocpp.v16 import ChargePoint as cp
61-
from ocpp.v16.enums import Action, RegistrationStatus
62-
from ocpp.v16 import call_result
63-
62+
from ocpp.v20 import ChargePoint as cp
63+
from ocpp.v20 import call_result
6464
6565
class ChargePoint(cp):
66-
@on(Action.BootNotification)
67-
def on_boot_notification(self, charge_point_vendor, charge_point_model, **kwargs):
66+
@on('BootNotification')
67+
def on_boot_notitication(self, charging_station, reason, **kwargs):
6868
return call_result.BootNotificationPayload(
6969
current_time=datetime.utcnow().isoformat(),
7070
interval=10,
71-
status=RegistrationStatus.accepted
71+
status='Accepted'
7272
)
7373
74-
@after(Action.BootNotification)
75-
def after_boot_notification(self, charge_point_vendor, charge_point_model, **kwargs):
76-
print("ChargePoint Vendor is: %s", charge_point_vendor)
77-
print("ChargePoint Model is: %s",charge_point_model)
78-
79-
8074
async def on_connect(websocket, path):
8175
""" For every new charge point that connects, create a ChargePoint instance
8276
and start listening for messages.
@@ -93,7 +87,7 @@ calls. You can find a detailed explaination of the code in the `Central System d
9387
on_connect,
9488
'0.0.0.0',
9589
9000,
96-
subprotocols=['ocpp1.6']
90+
subprotocols=['ocpp2.0']
9791
)
9892
9993
await server.wait_closed()
@@ -110,27 +104,30 @@ Charge point
110104
import asyncio
111105
import websockets
112106
113-
from ocpp.v16 import call, ChargePoint as cp
114-
from ocpp.v16.enums import RegistrationStatus
107+
from ocpp.v20 import call
108+
from ocpp.v20 import ChargePoint as cp
115109
116110
117111
class ChargePoint(cp):
112+
118113
async def send_boot_notification(self):
119114
request = call.BootNotificationPayload(
120-
charge_point_model="Optimus",
121-
charge_point_vendor="The Mobility House"
115+
charging_station={
116+
'model': 'Wallbox XYZ',
117+
'vendor_name': 'anewone'
118+
},
119+
reason="PowerUp"
122120
)
123-
124121
response = await self.call(request)
125122
126-
if response.status == RegistrationStatus.accepted:
123+
if response.status == 'Accepted':
127124
print("Connected to central system.")
128125
129126
130127
async def main():
131128
async with websockets.connect(
132129
'ws://localhost:9000/CP_1',
133-
subprotocols=['ocpp1.6']
130+
subprotocols=['ocpp2.0']
134131
) as ws:
135132
136133
cp = ChargePoint('CP_1', ws)

docs/source/central_system.rst

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,13 @@ After you've started the server you can connect a client to it by using the `web
7575
OCPP compliant handler
7676
----------------------
7777

78+
.. note::
79+
80+
This document describes how to create an central system that supports OCPP
81+
1.6. The ocpp Python package has support for OCPP 2.0 as well. This
82+
documentation will be updated soon to reflect that. In the mean time please
83+
consult the `examples/`_ to learn how to create an OCPP 2.0 central system.
84+
7885
The websocket server created above is not very useful and only sends a non-OCPP compliant message.
7986

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

134141
.. note::
135142

136-
OCPP uses a camelCase naming scheme for the keys in the payload. Python, on the other hand, uses
137-
snake_case.
143+
OCPP uses a camelCase naming scheme for the keys in the payload. Python, on
144+
the other hand, uses snake_case.
138145

139146
Therefore this ocpp package converts all keys in messages from camelCase to
140147
snake_case and vice versa to make sure you can write Pythonic code.
@@ -162,7 +169,7 @@ You can find the source code of the central system created in this document in t
162169
directory.
163170
164171
.. _client: https://websockets.readthedocs.io/en/stable/intro.html#one-more-thing
165-
.. _examples/: https://github.com/mobilityhouse/ocpp/blob/master/examples/central_system.py
172+
.. _examples/: https://github.com/mobilityhouse/ocpp/blob/master/examples
166173
.. _ocpp.v16.call_result.BootNotificationPayload: https://github.com/mobilityhouse/ocpp/blob/3b92c2c53453dd6511a202e1dc1b9aa1a236389e/ocpp/v16/call_result.py#L28
167174
.. _ocpp.v16.ChargePoint: https://github.com/mobilityhouse/ocpp/blob/master/ocpp/v16/charge_point.py#L80
168175
.. _start(): https://github.com/mobilityhouse/ocpp/blob/3b92c2c53453dd6511a202e1dc1b9aa1a236389e/ocpp/v16/charge_point.py#L125

docs/source/conf.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
import os
1414
import sys
1515
sys.path.insert(0, os.path.abspath('../../'))
16-
print(os.path.abspath('../../ocpp'))
1716

1817

1918
# -- Project information -----------------------------------------------------
File renamed without changes.
File renamed without changes.

examples/v20/central_system.py

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import asyncio
2+
from datetime import datetime
3+
4+
try:
5+
import websockets
6+
except ModuleNotFoundError:
7+
print("This example relies on the 'websockets' package.")
8+
print("Please install it by running: ")
9+
print()
10+
print(" $ pip install websockets")
11+
import sys
12+
sys.exit(1)
13+
14+
from ocpp.routing import on
15+
from ocpp.v20 import ChargePoint as cp
16+
from ocpp.v20 import call_result
17+
18+
19+
class ChargePoint(cp):
20+
@on('BootNotification')
21+
def on_boot_notitication(self, charging_station, reason, **kwargs):
22+
return call_result.BootNotificationPayload(
23+
current_time=datetime.utcnow().isoformat(),
24+
interval=10,
25+
status='Accepted'
26+
)
27+
28+
@on('Heartbeat')
29+
def on_heartbeat(self):
30+
print('Got a Heartbeat!')
31+
return call_result.HeartbeatPayload(
32+
current_time=datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%S') + "Z"
33+
)
34+
35+
36+
async def on_connect(websocket, path):
37+
""" For every new charge point that connects, create a ChargePoint instance
38+
and start listening for messages.
39+
40+
"""
41+
charge_point_id = path.strip('/')
42+
cp = ChargePoint(charge_point_id, websocket)
43+
44+
await cp.start()
45+
46+
47+
async def main():
48+
server = await websockets.serve(
49+
on_connect,
50+
'0.0.0.0',
51+
9000,
52+
subprotocols=['ocpp1.6']
53+
)
54+
55+
await server.wait_closed()
56+
57+
58+
if __name__ == '__main__':
59+
try:
60+
# asyncio.run() is used when running this example with Python 3.7 and
61+
# higher.
62+
asyncio.run(main())
63+
except AttributeError:
64+
# For Python 3.6 a bit more code is required to run the main() task on
65+
# an event loop.
66+
loop = asyncio.get_event_loop()
67+
loop.run_until_complete(main())
68+
loop.close()

examples/v20/charge_point.py

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import asyncio
2+
3+
try:
4+
import websockets
5+
except ModuleNotFoundError:
6+
print("This example relies on the 'websockets' package.")
7+
print("Please install it by running: ")
8+
print()
9+
print(" $ pip install websockets")
10+
import sys
11+
sys.exit(1)
12+
13+
14+
from ocpp.v20 import call
15+
from ocpp.v20 import ChargePoint as cp
16+
17+
18+
class ChargePoint(cp):
19+
20+
async def send_heartbeat(self, interval):
21+
request = call.HeartbeatPayload()
22+
while True:
23+
await self.call(request)
24+
await asyncio.sleep(interval)
25+
26+
async def send_boot_notification(self):
27+
request = call.BootNotificationPayload(
28+
charging_station={
29+
'model': 'Wallbox XYZ',
30+
'vendor_name': 'anewone'
31+
},
32+
reason="PowerUp"
33+
)
34+
response = await self.call(request)
35+
36+
if response.status == 'Accepted':
37+
print("Connected to central system.")
38+
await self.send_heartbeat(response.interval)
39+
40+
41+
async def main():
42+
async with websockets.connect(
43+
'ws://localhost:9000/CP_1',
44+
subprotocols=['ocpp2.0']
45+
) as ws:
46+
47+
cp = ChargePoint('CP_1', ws)
48+
49+
await asyncio.gather(cp.start(), cp.send_boot_notification())
50+
51+
52+
if __name__ == '__main__':
53+
try:
54+
# asyncio.run() is used when running this example with Python 3.7 and
55+
# higher.
56+
asyncio.run(main())
57+
except AttributeError:
58+
# For Python 3.6 a bit more code is required to run the main() task on
59+
# an event loop.
60+
loop = asyncio.get_event_loop()
61+
loop.run_until_complete(main())
62+
loop.close()

0 commit comments

Comments
 (0)