Skip to content

Commit 6ddc8cb

Browse files
authored
Merge pull request #1838 from arduino/sebromero/upython-cloud-rgb
2 parents 2901846 + e275d52 commit 6ddc8cb

File tree

3 files changed

+211
-3
lines changed

3 files changed

+211
-3
lines changed
Loading
Loading

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

+211-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,8 @@ 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 Cloud over Wi-Fi®.
138+
138139

139140
```python
140141
from machine import Pin
@@ -148,7 +149,7 @@ from secrets import WIFI_PASSWORD
148149
from secrets import DEVICE_ID
149150
from secrets import CLOUD_PASSWORD
150151

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

153154
def on_switch_changed(client, value):
154155
# Toggles the hardware LED on or off.
@@ -214,6 +215,213 @@ if __name__ == "__main__":
214215

215216
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.
216217

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

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

0 commit comments

Comments
 (0)