Skip to content

Commit e1590a6

Browse files
authored
Add example for advanced variable types
1 parent 38c66cd commit e1590a6

File tree

3 files changed

+202
-3
lines changed

3 files changed

+202
-3
lines changed
Loading
Loading

content/arduino-cloud/01.guides/04.micropython/content.md

+202-3
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ libraries:
1313

1414
## Introduction
1515

16-
This tutorial guides you on how to use the MicroPython library to connect your Arduino device to the Arduino Cloud.
16+
This tutorial guides you on how to use the MicroPython library to connect your Arduino device to the Arduino Cloud. As a minimal example we will toggle the on-board LED using an Arduino Cloud dashboard widget.
1717

1818
It requires your board to have a version of MicroPython installed, which is covered in [this article](/micropython/basics/board-installation).
1919

@@ -134,7 +134,7 @@ For more options on how to install libraries on your board, check out our [Insta
134134

135135
## Programming the Board
136136

137-
Here is the example code to copy and paste into your sketch. It connects your device
137+
Here is the example code to copy and paste into your program. It connects your device to Arduino IoT Cloud over WiFi.
138138

139139
```python
140140
from machine import Pin
@@ -148,7 +148,7 @@ from secrets import WIFI_PASSWORD
148148
from secrets import DEVICE_ID
149149
from secrets import CLOUD_PASSWORD
150150

151-
led = Pin("LEDB", Pin.OUT) # Configure the desired LED pin as an output.
151+
led = Pin("LED_BUILTIN", Pin.OUT) # Configure the desired LED pin as an output.
152152

153153
def on_switch_changed(client, value):
154154
# Toggles the hardware LED on or off.
@@ -214,6 +214,205 @@ if __name__ == "__main__":
214214

215215
Open Arduino Lab for MicroPython and connect to your board. Pasting the above code and run the script. Then open your Arduino Cloud dashboard. You should see the registered "ledSwitch" and "led" widgets. Toggle the "ledSwitch", and the LED on your Arduino board should light up accordingly. The state of the "led" variable should also change, mirroring the state of the physical LED.
216216

217+
## Using Advanced Cloud Variables
218+
219+
To use variables in Arduino IoT Cloud that are not of a basic type, you can set them up like you would do with any other variable. For example, to control a colored light such as the on-board RGB led on some Arduino boards, you can create a variable of type `CloudColoredLight`. ![Variable creation in Arduino Cloud](./assets/colored-light-variable.png)
220+
221+
222+
On the programming side, you need to import the corresponding class in MicroPython. For the colored light example, you need to import the `ColoredLight` class:
223+
224+
```py
225+
from arduino_iot_cloud import ColoredLight
226+
```
227+
228+
The cloud variable needs then to be registered with the client using that type and the name that you gave it ("light" in our example):
229+
230+
```py
231+
client.register(ColoredLight("light", swi=True, on_write=on_colored_light_changed))
232+
```
233+
234+
In the callback function for this variable ("on_colored_light_changed") you will receive an object of the same type with populated properties. Those properties depend on the type. For example the `ColoredLight` class has the following properties:
235+
236+
- swi: The on-value of the light switch (True/False)
237+
- hue: The hue value of the color
238+
- sat: The saturation of the color
239+
- bri: The brightness of the color
240+
241+
Once you receive these values from the Cloud you will need to convert them to RGB so you can set the RGB LEDs accordingly. For reasons of brevity we won't go into the code for the color conversion, it is provided however in the full example code further down. Also we need to make all three RGB LEDs available in the code so their value can be set:
242+
243+
```py
244+
led_red = Pin("LEDR", Pin.OUT)
245+
led_green = Pin("LEDG", Pin.OUT)
246+
led_blue = Pin("LEDB", Pin.OUT)
247+
```
248+
249+
Then each of the three LEDs' brightness needs to be set so that the resulting color is as desired. This is done using a technique called [PWM](/learn/microcontrollers/analog-output/):
250+
251+
```py
252+
def set_led_brightness(led, brightness):
253+
"""
254+
Sets the brightness (0 - 255) of an LED using PWM.
255+
"""
256+
pwm = PWM(led)
257+
max_brightness = 255
258+
259+
# Ensure brightness is between 0 and max_brightness.
260+
brightness = max(0, min(max_brightness, brightness))
261+
262+
# Map input brightness from 0-max_brightness to 0-65535.
263+
duty_cycle = int(brightness * 65535 / max_brightness)
264+
pwm.duty_u16(duty_cycle)
265+
```
266+
267+
With that defined we can set the corresponding values of the RGBs:
268+
269+
```py
270+
def set_leds_from_rgb(rgb, common_cathode=True):
271+
# For common cathode RGB LEDs, invert the RGB values
272+
# since the LED is on when the pin is low.
273+
if common_cathode:
274+
rgb = (255 - rgb[0], 255 - rgb[1], 255 - rgb[2])
275+
set_led_brightness(led_red, rgb[0])
276+
set_led_brightness(led_green, rgb[1])
277+
set_led_brightness(led_blue, rgb[2])
278+
```
279+
280+
The missing piece is the callback handler for when the cloud variable changes that was defined when registering the variable:
281+
282+
```py
283+
def on_colored_light_changed(client, light):
284+
# Do nothing if the hue, saturation or brightness is None.
285+
if light.hue is None or light.sat is None or light.bri is None:
286+
return
287+
288+
light_enabled = light.swi
289+
290+
if light_enabled:
291+
rgb_value = convert_hs_to_rgb(light.hue, light.sat, light.bri)
292+
set_leds_from_rgb(rgb_value)
293+
else:
294+
set_leds_from_rgb((0, 0, 0)) # Turn LEDs off
295+
```
296+
297+
Here is the complete code to try it out:
298+
299+
```py
300+
# This file is part of the Python Arduino IoT Cloud.
301+
# Any copyright is dedicated to the Public Domain.
302+
# https://creativecommons.org/publicdomain/zero/1.0/
303+
from machine import Pin, PWM
304+
import time
305+
import network
306+
import logging
307+
from arduino_iot_cloud import ArduinoCloudClient
308+
from arduino_iot_cloud import ColoredLight
309+
310+
from secrets import *
311+
312+
led_red = Pin("LEDR", Pin.OUT)
313+
led_green = Pin("LEDG", Pin.OUT)
314+
led_blue = Pin("LEDB", Pin.OUT)
315+
316+
def set_led_brightness(led, brightness):
317+
"""
318+
Sets the brightness (0 - 255) of an LED using PWM.
319+
"""
320+
pwm = PWM(led)
321+
max_brightness = 255
322+
323+
# Ensure brightness is between 0 and max_brightness.
324+
brightness = max(0, min(max_brightness, brightness))
325+
326+
# Map input brightness from 0-max_brightness to 0-65535.
327+
duty_cycle = int(brightness * 65535 / max_brightness)
328+
pwm.duty_u16(duty_cycle)
329+
330+
def convert_hs_to_rgb(hue, sat, bri):
331+
# Convert hue, saturation and brightness to RGB.
332+
# This function is based on the algorithm described at
333+
# https://www.developers.meethue.com/documentation/color-conversions-rgb-xy
334+
# and https://gist.github.com/mjackson/5311256
335+
h = hue / 360
336+
s = sat / 100
337+
v = bri / 100
338+
if s == 0.0:
339+
return (int(v * 255), int(v * 255), int(v * 255))
340+
i = int(h * 6)
341+
f = (h * 6) - i
342+
p = v * (1 - s)
343+
q = v * (1 - s * f)
344+
t = v * (1 - s * (1 - f))
345+
if i % 6 == 0:
346+
return (int(v * 255), int(t * 255), int(p * 255))
347+
if i % 6 == 1:
348+
return (int(q * 255), int(v * 255), int(p * 255))
349+
if i % 6 == 2:
350+
return (int(p * 255), int(v * 255), int(t * 255))
351+
if i % 6 == 3:
352+
return (int(p * 255), int(q * 255), int(v * 255))
353+
if i % 6 == 4:
354+
return (int(t * 255), int(p * 255), int(v * 255))
355+
if i % 6 == 5:
356+
return (int(v * 255), int(p * 255), int(q * 255))
357+
358+
def set_leds_from_rgb(rgb, common_cathode=True):
359+
# For common cathode RGB LEDs, invert the RGB values
360+
# since the LED is on when the pin is low.
361+
if common_cathode:
362+
rgb = (255 - rgb[0], 255 - rgb[1], 255 - rgb[2])
363+
set_led_brightness(led_red, rgb[0])
364+
set_led_brightness(led_green, rgb[1])
365+
set_led_brightness(led_blue, rgb[2])
366+
367+
368+
def on_colored_light_changed(client, light):
369+
# Do nothing if the hue, saturation or brightness is None.
370+
if light.hue is None or light.sat is None or light.bri is None:
371+
return
372+
373+
light_enabled = light.swi
374+
375+
if light_enabled:
376+
rgb_value = convert_hs_to_rgb(light.hue, light.sat, light.bri)
377+
set_leds_from_rgb(rgb_value)
378+
else:
379+
set_leds_from_rgb((0, 0, 0))
380+
381+
def wifi_connect():
382+
if not WIFI_SSID or not WIFI_PASSWORD:
383+
raise (Exception("Network is not configured. Set SSID and passwords in secrets.py"))
384+
wlan = network.WLAN(network.STA_IF)
385+
wlan.active(True)
386+
wlan.connect(WIFI_SSID, WIFI_PASSWORD)
387+
while not wlan.isconnected():
388+
logging.info("Trying to connect. Note this may take a while...")
389+
time.sleep_ms(500)
390+
logging.info(f"WiFi Connected {wlan.ifconfig()}")
391+
392+
if __name__ == "__main__":
393+
# Configure the logger.
394+
# All message equal or higher to the logger level are printed.
395+
# To see more debugging messages, set level=logging.DEBUG.
396+
logging.basicConfig(
397+
datefmt="%H:%M:%S",
398+
format="%(asctime)s.%(msecs)03d %(message)s",
399+
level=logging.INFO,
400+
)
401+
402+
# NOTE: Add networking code here or in boot.py
403+
wifi_connect()
404+
405+
# Create a client object to connect to the Arduino IoT cloud.
406+
# For MicroPython, the key and cert files must be stored in DER format on the filesystem.
407+
# Alternatively, a username and password can be used to authenticate:
408+
client = ArduinoCloudClient(device_id=DEVICE_ID, username=DEVICE_ID, password=CLOUD_PASSWORD)
409+
client.register(ColoredLight("light", swi=True, on_write=on_colored_light_changed))
410+
client.register("led", value=None)
411+
412+
# Start the Arduino IoT cloud client.
413+
client.start()
414+
```
415+
217416
## Troubleshoot
218417

219418
If the code is not working, there are some common issues we can troubleshoot:

0 commit comments

Comments
 (0)