Skip to content

Commit efc6593

Browse files
authored
Merge pull request #13 from bcmi-labs/examples
examples: Add separate example for MicroPython.
2 parents 87b75b0 + 1fee2af commit efc6593

File tree

4 files changed

+188
-139
lines changed

4 files changed

+188
-139
lines changed

README.md

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -43,34 +43,27 @@ softhsm2-util --delete-token --token "arduino"
4343
```
4444

4545
### Run the example script
46-
* Set `KEY_URI`, `CERT_URI`, `DEVICE_ID`, `THING_ID` in `example.py`.
46+
* Set `KEY_PATH`, `CERT_PATH`, `DEVICE_ID`, `THING_ID` in `example.py`.
4747
* Provide a CA certificate in a `ca-root.pem` file or set `CA_PATH` to `None` if it's not used.
4848
* Override the default `pin` and provide `ENGINE_PATH` and `MODULE_PATH` in `ssl_params` if needed.
4949
* Clone this repository and run the following:
5050
```bash
51-
python example.py
51+
python examples/example.py
5252
```
5353

5454
## Testing on MicroPython
55-
The following changes to the example code are required, because MicroPython does Not support secure elements yet:
55+
MicroPython currently does Not support secure elements, the key and cert files must be stored in DER format on the filesystem.
56+
Convert the key and certificate to DER, using the following commands, and copy to the filesystem storage.
5657

5758
#### Convert key and certificate to `.DER`
5859
```bash
5960
openssl ec -in key.pem -out key.der -outform DER
6061
openssl x509 -in cert.pem -out cert.der -outform DER
6162
```
6263

63-
#### Load key and certificate from filesystem storage
64-
```python
65-
KEY_PATH = "key.der"
66-
CERT_PATH = "cert.der"
67-
....
68-
69-
async def main():
70-
with open(KEY_PATH, "rb") as fin: key = fin.read()
71-
with open(CERT_PATH, "rb") as fin: cert = fin.read()
72-
client = AIOTClient(device_id=DEVICE_ID, keepalive=10, ssl_params = {"key":key, "cert":cert})
73-
....
64+
### Run the MicroPython example script
65+
* Set `KEY_PATH`, `CERT_PATH`, to key and certificate DER paths respectively.
66+
* run `examples/micropython.py`
7467
```
7568
7669
## Useful links

example.py

Lines changed: 0 additions & 125 deletions
This file was deleted.

examples/example.py

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
# This file is part of the Python Arduino IoT Cloud.
2+
# The MIT License (MIT)
3+
# Copyright (c) 2022 Arduino SA
4+
import time
5+
import asyncio
6+
import logging
7+
from time import strftime
8+
from arduino_iot_cloud import AIOTClient
9+
from arduino_iot_cloud import Location
10+
from arduino_iot_cloud import Schedule
11+
from arduino_iot_cloud import ColoredLight
12+
from random import randint
13+
import argparse
14+
15+
KEY_PATH = "pkcs11:token=arduino"
16+
CERT_PATH = "pkcs11:token=arduino"
17+
CA_PATH = "ca-root.pem"
18+
DEVICE_ID = b"25deeda1-3fda-4d06-9c3c-dd31be382cd2"
19+
20+
21+
async def user_main(client):
22+
# Add your code here. Note to allow other tasks to run, this function
23+
# must yield execution periodically by calling asyncio.sleep(seconds).
24+
while True:
25+
# The composite cloud object's fields can be assigned to individually:
26+
client["clight"].hue = randint(0, 100)
27+
client["clight"].bri = randint(0, 100)
28+
await asyncio.sleep(1.0)
29+
30+
31+
def on_switch_changed(client, value):
32+
# This is a write callback for the switch that toggles the LED variable. The LED
33+
# variable can be accessed via the client object passed in the first argument.
34+
client["led"] = value
35+
36+
37+
def on_clight_changed(client, clight):
38+
logging.info(f"ColoredLight changed. Swi: {clight.swi} Bri: {clight.bri} Sat: {clight.sat} Hue: {clight.hue}")
39+
40+
41+
async def main():
42+
# Create a client to connect to the Arduino IoT cloud. To use a secure element, set the token "pin"
43+
# and URI in "keyfile" and "certfile, and CA certificate (if used), in ssl_params. Alternatively,
44+
# a username and a password can be used for authentication, for example:
45+
# client = AIOTClient(device_id, username="username", password="password")
46+
client = AIOTClient(
47+
device_id=DEVICE_ID,
48+
ssl_params={"pin": "1234", "keyfile": KEY_PATH, "certfile": CERT_PATH, "ca_certs": CA_PATH},
49+
)
50+
51+
# Register cloud objects. Note these objects must be created first in the dashboard.
52+
# This cloud object is initialized with its last known value from the cloud. When this object is updated
53+
# from the dashboard, the on_switch_changed function is called with the client object and the new value.
54+
client.register("sw1", value=None, on_write=on_switch_changed, interval=0.250)
55+
56+
# This cloud object is updated manually in the switch's on_write_change callback.
57+
client.register("led", value=None)
58+
59+
# This is a periodic cloud object that gets updated at fixed intervals (in this case 1 seconed) with the
60+
# value returned from its on_read function (a formatted string of the current time). Note this object's
61+
# initial value is None, it will be initialized by calling the on_read function.
62+
client.register("clk", value=None, on_read=lambda x: strftime("%H:%M:%S", time.localtime()), interval=1.0)
63+
64+
# This is an example of a composite cloud object (a cloud object with multiple variables). In this case
65+
# a colored light with switch, hue, saturation and brightness attributes. Once initialized, the object's
66+
# attributes can be accessed using dot notation. For example: client["clight"].swi = False.
67+
client.register(ColoredLight("clight", swi=True, on_write=on_clight_changed))
68+
69+
# This is another example of a composite cloud object, a map location with lat and long attributes.
70+
client.register(Location("treasureisland", lat=31.264694, lon=29.979987))
71+
72+
# This object allows scheduling recurring events from the cloud UI. On activation of the event, if the
73+
# on_active callback is provided, it gets called with the client object and the schedule object value.
74+
# Note: The activation status of the object can also be polled using client["schedule"].active.
75+
client.register(Schedule("schedule", on_active=lambda client, value: logging.info(f"Schedule activated {value}!")))
76+
77+
# Start the Arduino IoT cloud client. Note a co-routine can be passed to client.run(coro), in this case it will
78+
# scheduled to run along with the other cloud objects.
79+
await client.run(user_main)
80+
81+
82+
if __name__ == "__main__":
83+
# Parse command line args.
84+
parser = argparse.ArgumentParser(description="arduino_iot_cloud.py")
85+
parser.add_argument("-d", "--debug", action="store_true", help="Enable debugging messages")
86+
args = parser.parse_args()
87+
88+
# Assume the host has an active Internet connection.
89+
90+
# Configure the logger.
91+
# All message equal or higher to the logger level are printed.
92+
# To see more debugging messages, pass --debug on the command line.
93+
logging.basicConfig(
94+
datefmt="%H:%M:%S",
95+
format="%(asctime)s.%(msecs)03d %(message)s",
96+
level=logging.DEBUG if args.debug else logging.INFO,
97+
)
98+
asyncio.run(main())

examples/micropython.py

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
# This file is part of the Python Arduino IoT Cloud.
2+
# The MIT License (MIT)
3+
# Copyright (c) 2022 Arduino SA
4+
import time
5+
import uasyncio as asyncio
6+
import ulogging as logging
7+
from ulogging.ustrftime import strftime
8+
from arduino_iot_cloud import AIOTClient, Location, Schedule, ColoredLight
9+
from random import randint
10+
11+
KEY_PATH = "key.der"
12+
CERT_PATH = "cert.der"
13+
DEVICE_ID = b"25deeda1-3fda-4d06-9c3c-dd31be382cd2"
14+
15+
16+
async def user_main(client):
17+
# Add your code here. Note to allow other tasks to run, this function
18+
# must yield execution periodically by calling asyncio.sleep(seconds).
19+
while True:
20+
# The composite cloud object's fields can be assigned to individually:
21+
client["clight"].hue = randint(0, 100)
22+
client["clight"].bri = randint(0, 100)
23+
await asyncio.sleep(1.0)
24+
25+
26+
def on_switch_changed(client, value):
27+
# This is a write callback for the switch that toggles the LED variable. The LED
28+
# variable can be accessed via the client object passed in the first argument.
29+
client["led"] = value
30+
31+
32+
def on_clight_changed(client, clight):
33+
logging.info(f"ColoredLight changed. Swi: {clight.swi} Bri: {clight.bri} Sat: {clight.sat} Hue: {clight.hue}")
34+
35+
36+
async def main():
37+
# Create a client to connect to the Arduino IoT cloud. For MicroPython, the key and cert files must be stored
38+
# in DER format on the filesystem. Alternatively, a username and a password can be used for authentication:
39+
# client = AIOTClient(device_id, username="username", password="password")
40+
client = AIOTClient(device_id=DEVICE_ID, ssl_params={"keyfile": KEY_PATH, "certfile": CERT_PATH})
41+
42+
# Register cloud objects. Note these objects must be created first in the dashboard.
43+
# This cloud object is initialized with its last known value from the cloud. When this object is updated
44+
# from the dashboard, the on_switch_changed function is called with the client object and the new value.
45+
client.register("sw1", value=None, on_write=on_switch_changed, interval=0.250)
46+
47+
# This cloud object is updated manually in the switch's on_write_change callback.
48+
client.register("led", value=None)
49+
50+
# This is a periodic cloud object that gets updated at fixed intervals (in this case 1 seconed) with the
51+
# value returned from its on_read function (a formatted string of the current time). Note this object's
52+
# initial value is None, it will be initialized by calling the on_read function.
53+
client.register("clk", value=None, on_read=lambda x: strftime("%H:%M:%S", time.localtime()), interval=1.0)
54+
55+
# This is an example of a composite cloud object (a cloud object with multiple variables). In this case
56+
# a colored light with switch, hue, saturation and brightness attributes. Once initialized, the object's
57+
# attributes can be accessed using dot notation. For example: client["clight"].swi = False.
58+
client.register(ColoredLight("clight", swi=True, on_write=on_clight_changed))
59+
60+
# This is another example of a composite cloud object, a map location with lat and long attributes.
61+
client.register(Location("treasureisland", lat=31.264694, lon=29.979987))
62+
63+
# This object allows scheduling recurring events from the cloud UI. On activation of the event, if the
64+
# on_active callback is provided, it gets called with the client object and the schedule object value.
65+
# Note: The activation status of the object can also be polled using client["schedule"].active.
66+
client.register(Schedule("schedule", on_active=lambda client, value: logging.info(f"Schedule activated {value}!")))
67+
68+
# Start the Arduino IoT cloud client. Note a co-routine can be passed to client.run(coro), in this case it will
69+
# scheduled to run along with the other cloud objects.
70+
await client.run(user_main)
71+
72+
73+
if __name__ == "__main__":
74+
# Configure the logger.
75+
# All message equal or higher to the logger level are printed.
76+
# To see more debugging messages, set level=logging.DEBUG.
77+
logging.basicConfig(
78+
datefmt="%H:%M:%S",
79+
format="%(asctime)s.%(msecs)03d %(message)s",
80+
level=logging.INFO,
81+
)
82+
# NOTE: Add networking code here or in boot.py
83+
asyncio.run(main())

0 commit comments

Comments
 (0)