Go Beyond the Basics
Table of Contents
- Authenticate users: Use Anvil’s built in user authentication to control access to your Pico W code.
- Async code: Use
uasynciowith Uplink functions.
- HTTP endpoints: Serve HTTP requests from your Pico W.
- Run code on connection: Run code after your device connects to your Anvil app, or each time it reconnects.
- Work Around Micropython’s Limitations: Use Anvil’s Server Modules, with their full Python environments, from your Pico W code.
Anvil has built in user authentication supporting email/password, Google, Facebook, and even enterprise SAML authentication. You can use this authentication to restrict calls on your Pico W to only permit authorised users.
To do this, add the Users Service to your app, then add
require_user=True to any
@anvil.pico.callable definition. For example:
@anvil.pico.callable(require_user=True) def toggle_led(): # This call will only run if invoked by logged-in user led.toggle()
For an example of this, see the Morse code transmitter tutorial.
Require a specific user
You can also require that only a specific user may be logged in to call your function - calls from other users will be rejected. For example:
@anvil.pico.callable(require_user="firstname.lastname@example.org") def toggle_led(): # This call will only run if invoked by email@example.com. led.toggle()
Get the logged-in user
You can get the email address of the currently logged-in user by calling
await anvil.pico.get_user_email(). This function returns
None if nobody is logged in.
If you want to use async code (
uasyncio) in your function, then use
@anvil.pico.callable_async instead of
import uasyncio as a @anvil.pico.callable_async async def blink_led(): for i in range(20): led.toggle() await a.sleep_ms(50)
For example, here’s an HTTP endpoint that calls
toggle_led() from the Pico W:
# In a Server Module: @anvil.server.http_endpoint("/blink") def http_blink(**params): anvil.server.call("toggle_led")
And here is how the function is defined on your Pico W code:
# On your Pico W: @anvil.pico.callable def toggle_led(): led.toggle()
Run code at startup
If you want to run code as soon as the Pico W connects to Anvil, then pass a task as an argument to
anvil.pico.connect(). For example:
# Define a task to run after the Anvil Uplink has connected async def flash_led_for(seconds): for i in range(seconds): led.toggle() await a.sleep_ms(100) led.toggle() await a.sleep(1) # Connect the Anvil Uplink. In Micropython, this call will block forever. anvil.pico.connect(UPLINK_KEY, flash_led_for(30))
Run code on every connection
If you want to run code each time the Pico reconnects to Anvil – rather than just once – specify
on_every_connect= instead. This is useful if, for example, you’re using the Client Uplink and want to authenticate when your device connects.
Example: Authenticating a device at login
USERNAME="firstname.lastname@example.org" PASSWORD="1234" async def do_login(): await anvil.pico.call("authenticate_device", USERNAME, PASSWORD) anvil.pico.connect(UPLINK_KEY, on_every_connect=do_login())
And then in a Server Module in your Anvil app:
import anvil.users @anvil.server.callable def authenticate_device(username, password): # Called each time a device connects anvil.users.login_with_email(username, password)
Work Around Micropython’s Limitations
Micropython on the Pico W is quite a limited environment, with few libraries and only a few kilobytes of RAM. Consequently, your Pico W code can’t directly access Anvil’s Data Tables, the Email Service, use Portable Classes, or define HTTP endpoints.
However, Anvil’s Server Modules can do all of those things, because they run in a proper Python environment! So when you want to do something that doesn’t fit on the Pico, define a Server Function to do it, then use
anvil.pico.call() to invoke it from your Pico.
For example, you could write a Server Function that adds a row to a Data Table called “Visitors”, with “name” (string) and “when” (date/time) columns:
from datetime import datetime @anvil.server.callable def record_visitor(name): app_tables.visitors.add_row(name=name, when=datetime.now())
And you can call it from your Pico W:
async def register_visitor(name): await anvil.pico.call("record_visitor", name)