Digi Micropython: Programming Guide
Digi Micropython: Programming Guide
Programming Guide
Revision history
Revision history—90002219
Z August 2022 Added note to code storage topic that main code will not be run on
startup.
Disclaimers
Information in this document is subject to change without notice and does not represent a
commitment on the part of Digi International. Digi provides this document “as is,” without warranty of
any kind, expressed or implied, including, but not limited to, the implied warranties of fitness or
merchantability for a particular purpose. Digi may make improvements and/or changes in this manual
or in the product(s) and/or the program(s) described in this manual at any time.
Warranty
To view product warranty information, go to the following website:
www.digi.com/howtobuy/terms
Customer support
Gather support information: Before contacting Digi technical support for help, gather the following
information:
Product name and model
Product serial number (s)
Feedback
To provide feedback on this document, email your comments to
[email protected]
Include the document title and part number (Digi MicroPython Programming Guide, 90002219 Z) in
the subject line of your email.
Use MicroPython
Access the MicroPython environment 16
Enter MicroPython code 16
Direct entry 16
Exit MicroPython 16
Display tools 16
Coding tips 16
Recover an XBee device 17
MicroPython syntax
Colons 19
After conditional statements and loop statements 19
Indentations 19
FOR loop with one statement indented 19
FOR loop with two statements indented 20
Functions 20
Function with arguments 20
MicroPython modules
XBee-specific functions 72
Standard modules and functions 72
Discover available modules 73
Machine module
Reset-cause 75
Constants 75
Random numbers 75
Unique identifier 75
Class PWM (pulse width modulation) 75
Class ADC: analog to digital conversion 76
Constructors 76
Methods 77
Sample program 77
Class I2C: two-wire serial protocol 78
Constructors 79
General methods 79
Standard bus operations methods 79
Memory operations methods 79
Sample programs 80
Class Pin 83
Class UART 83
Test the UART interface 84
Use the UART class 84
Constructors 85
Methods 85
Constants 86
Class WDT: watchdog timer 86
Access the XBee device's I/O pins 86
Use the Pin() constructor 88
Use mode() to configure a pin 89
digi.ble module
Feature support 93
active() 93
config() 94
Query a value 94
Update configuration values 94
disconnect_code() 95
gap_connect() 95
<addr_type> 95
<address> 95
<timeout_ms> 96
<interval_us>, <window_us> 96
<onclose> 96
Return value 96
gap_connection methods 96
gattc_services() 96
gattc_characteristics() 97
gattc_descriptors() 98
gattc_read_characteristic() 98
gattc_configure() 98
gattc_read_descriptor() 99
gattc_write_characteristic() 99
gattc_write_descriptor() 100
addr() 100
close() 100
config() 100
isconnected() 102
secure() 102
io_callbacks() 102
delete_bondings() 103
passkey_enter() 103
passkey_confirm() 103
UUID() 103
<value> 103
Return value 103
gap_scan() 104
<duration_ms> 104
<interval_us>, <window_us> 104
<oldest> 104
Return value 104
gap_scan methods 104
get() 104
any() 105
stop() 105
stopped() 105
gap_scan advertisement format 105
XBee module
AT commands that do not work in MicroPython 117
class XBee on XBee Cellular Modem 117
Constructors 117
Methods 118
XBee MicroPython module on the XBee 3 RF Modules 118
Functions 118
atcmd() 118
discover() 119
receive() 120
receive_callback(rx_callback) 121
transmit() 121
modem_status 123
digi.cloud module
Create and upload data points 125
digi.gnss module
GNSS module methods 134
single_acquisition(callback, timeout=60) 134
raw_mode(callback) 134
GNSS examples 135
Terminal redirection
dupterm(stream_obj, index=0) 137
Socket examples
Sockets 156
Basic socket operations: sending and receiving data, and closing the network connection 156
Basic data exchange code sample 156
Response header lines 157
Specialized receiving: send received data to a specific memory location 158
DNS lookup 159
DNS lookup code output 160
Set the timeout value and blocking/non-blocking mode 160
Send an HTTP request and dump the response 162
Socket errors 163
ENOTCONN: Time out error 163
ENFILE: No sockets are available 163
ENXIO: No such device or address 163
Unsupported methods 163
SMS examples
Send an SMS message 173
Send an SMS message to a valid phone number 173
Check network connection and send an SMS message 173
Receive an SMS message 174
Sample code 174
Receive an SMS message using a callback 175
Reference material
MicroPython is an open-source programming language based on the Python 3 standard library.
MicroPython is optimized to run on a microcontroller, cellular modem, or embedded system.
Refer to the Get started with MicroPython section of the appropriate user guide for information on
how to enter the MicroPython environment and several simple examples to get you started:
n MicroPython: micropython.org
n MicroPython documentation: docs.micropython.org
n MicroPython Wiki: wiki.micropython.org
n Python: python.org
1Remote Manager features are only supported on XBee 3 Cellular devices, not XBee Cellular.
2Files can be deleted, but doing so does not reclaim their space on the file system.
3XBee 3 Global LTE-M/NB-IoT, XBee 3 Global LTE Cat 1, and XBee 3 North America LTE Cat 1 only.
Direct entry
From a serial terminal, you can type code at the MicroPython REPL prompt. When you press Enter,
the line of code runs and another MicroPython prompt appears. Manually typing in code is the
simplest method.
Example
1. Access the MicroPython environment.
2. At the MicroPython >>> prompt, type print("This is a simple line of code") and then press
Enter. The phrase in quotes prints in the terminal: This is a simple line of code
Exit MicroPython
When you are done coding, exit MicroPython by closing the MicroPython terminal. Any code that has
been executed will continue to run, even if the XBee device is set to Transparent or API mode.
For additional instructions, see the Exit MicroPython mode section in the appropriate user guide.
Display tools
MicroPython mode requires echo to be turned off in terminal emulation. Command mode does not
echo your input back to you. In order to see what you are typing, use the appropriate display tool:
n MicroPython mode: For MicroPython coding, use the XCTU MicroPython Terminal or configure
your terminal emulator for "echo off."
n Command mode: For device configuration that is done in Command mode (initiated by
sending +++ to the device), use the XCTU Serial Console or configure your terminal emulator
for "echo on."
Coding tips
For all XBee devices:
n Use the integer division operator (//) unless you need a floating point.
n MicroPython's struct_time does not include the tm_isdst element in the tuple.
For the XBee Cellular Modem:
n The XBee Cellular Modem supports the use of hostnames in socket.connect() calls, unlike
other MicroPython platforms that require an IP address obtained by doing a manual look-up
using socket.getaddrinfo().
For the XBee 3 Zigbee RF Module:
n The Micropython time.time() function returns the number of seconds since the epoch. The
XBee 3 Zigbee RF Module does not have a realtime clock, so it does not support time.time().
To track elapsed time, use time.ticks_ms().
For XBee3 radio modules:
n The counter for the Micropython ticks_us() function will fall behind ticks_ms() by about 1 ms
every 10 seconds.
n If you need a high level of accuracy over a long period of time, use ticks_ms().
Colons 19
Indentations 19
Functions 20
Colons
MicroPython requires a colon (:) after you entered the following statement types:
Defining a function
A function consists of the following:
n def keyword
n Function name
n Any arguments the function takes, inside a set of parentheses. The parentheses remain empty
if there are no passed arguments
n The function declaration must be followed by a colon
The code sample below is a basic function definition. Note that a colon is entered after the function
name. This colon defines the following indented lines as part of the function. Indentation is equally
important, and is discussed in Indentations.
def sample_function():
print("I am a sample function!")
>if True:
print("Condition is true!")
for x in range(10):
print("Current number: %d" % x)
Indentations
In MicroPython, an indentation tells the compiler which statements are members of a function,
conditional execution block, or a loop. If a line is not indented, that line is not considered a part of the
function, conditional execution block, or loop.
A function declaration, conditional execution block, or loop should be followed by a colon. All code
after the colon that is meant to be part of that block must be indented. For more information about
how colons are used in the code, see Colons.
When this code executes, it prints "In the FOR loop, iteration # <number>" 10 times, where
<number> is 0 in the first loop of the code, and 9 at the last loop. Line 3 of the code runs one time,
after the loop completes, printing the phrase "Current number: 9" one time.
for x in range(10):
print("In the FOR loop, iteration # %d" % x)
print("Current number: %d" % x)
for x in range(10):
print("In the FOR loop, iteration # %d" % x)
print("Current number: %d" % x)
Functions
A function is an operation that performs an action and may return a value. A function consists of the
following:
n def keyword. The def keyword is required, and is short for "define".
n Function name.
n Any arguments the function takes, defined by a set of parentheses. The parentheses remain
empty if there are no passed arguments.
n The function statement must be followed by a colon. For more information, see Colons.
The code sample below is a basic function definition. Note that the colon is entered after the function
name and parentheses. This colon defines that everything after that line that is indented is part of the
function. Indentation is equally important, and is discussed in the Indentations section.
def example_function():
print("I am a function!")
def addition_function(x,y):
sum_val = x + y
print("value of sum (x+y): %d" % sum_val)
return sum_val
global_sum = addition_function(3,4)
print("Value of global_sum: %d" % global_sum)
Note You can copy and paste code from the online version of the Digi MicroPython Programming
Guide. Use caution with the PDF version, as it may not maintain essential indentations.
Note Some exceptions have Error in their name and others have Exception.
Syntax error 23
Name error 23
OSError 24
Socket errors 24
Syntax error
A syntax error occurs when a MicroPython code statement has the wrong syntax.
Example
In this example, the syntax is incorrect. A colon is missing after the word "True".
When you press Enter to run the code it generates the following Exception describing the error
(SyntaxError) and the execution path that led to it (line 1 of the code you entered).
Name error
A name error is generated when a name of an item, such as a variable or function, cannot be found.
This can occur when:
def example_func():
print("Entering example function...")
local_variable = "I'm a variable inside this function"
print(local_variable)
example_func()
print(local_variable)
OSError
MicroPython returns an OSError when a function returns a system-related error.
For example, if you try to send a message on a Zigbee network:
import xbee
xbee.transmit(xbee.ADDR_COORDINATOR, 'Hello!')
This code assumes that the device is associated to a network and able to send and receive data.
If the device is not associated with a network, it produces an OS error:
OSError: [Errno 7107] ENOTCONN.
Socket errors
Note This section only applies to the XBee Cellular Modem. See Which features apply to my device?
for a list of the supported features.
n Close abandoned sockets: Initiate garbage collection (gc.collect()) to close any abandoned
MicroPython sockets. For example, an abandoned socket could occur if a socket was created in
a function but not returned. For information about the gc module, see the MicroPython
garbage collection documentation.
n Close all allocated sockets: Press Ctrl+D to perform a soft reset of the MicroPython REPL to
close all allocated sockets and return them to the socket pool.
Keyboard shortcuts 26
Select a previously typed statement 26
Keyboard shortcuts
XCTU version 6.3.6.2 and higher works when the REPL is enabled. The MicroPython Terminal tool
allows you to communicate with the MicroPython stack of your device through the serial interface.
The MicroPython Terminal tool in XCTU supports the following control characters:
Ctrl+A: Enter raw REPL mode. This is like a permanent paste mode, except that characters are not
echoed back.
Ctrl+B: Print the MicroPython banner. Leave raw mode and return to the regular REPL (also known as
friendly REPL). Reprints the MicroPython banner followed by a REPL prompt.
Ctrl+C: Regain control of the terminal. Interrupt the currently running program.
Ctrl+D: Reboot the MicroPython REPL. Soft-reset MicroPython, clears the heap.
Ctrl+E: Enter paste mode. Does not auto-indent and compiles pasted code all at once before
execution. Uses a REPL prompt of ===. Use Ctrl-D to compile uploaded code, or Ctrl-C to abort.
Ctrl+F: Upload code to flash. Uses a REPL prompt of ^^^. Use Ctrl-D to compile uploaded code, or
Ctrl-C to abort.
Ctrl+R: Run code in flash. Run code compiled in flash.
Note If PS is set to 1, code in flash automatically runs once at startup. Use Ctrl-R to re-run it.
Note This shortcut does not work: (1) while in paste mode (Ctrl-E) or on any code entered while in
paste mode and (2) while in flash upload mode.
Arrow keys work to scroll back through previous commands, and to edit the current command. Some
terminal emulators (like CoolTerm) might not work with scrollback.
5. At the MicroPython >>> prompt, press the UP arrow key on the keyboard. The most recently
typed statement displays at the prompt. In this example, the statement print("statement 3")
displays.
6. You can press the UP arrow key on the keyboard to display the next most recently type
statement, or press the DOWN arrow key on the keyboard to return the previously selected
statement. Continue this process until the statement you want to use displays at the
MicroPython >>> prompt. Use the Left and Right arrow keys and Backspace to make edits to
the previous statement if desired.
7. Press Enter to execute the displayed statement.
Memory management 28
Variable types 28
Syntax 28
Memory management
In C, memory has to be allocated by the user for a variable or object before it can be used.
For a variable in C, this is done by a declaration statement as shown in the code below. The first 2
lines create a floating-point (decimal-valued real number) type variable named salary and an integer
named x. The last 2 lines assign values to each of those variables.
float salary;
int x;
x = 9;
salary = 3.0 + x;
In MicroPython, a variable does not need to be declared before it can be used. For example, the
MicroPython code shown below does the same thing as the C code shown in the example above. Each
line does multiple things: creates the variable (the name), assigns it a type based on the assigned
value, determines the space it needs in memory and allocates that space, and then assigns the value
to it.
Note You can copy and paste code from the online version of the Digi MicroPython Programming
Guide. Use caution with the PDF version, as it may not maintain essential indentations.
x = 9
salary = x + 3.0
Variable types
In C, variables are "statically typed", meaning they are a certain type when they are created, and the
type does not change. This also means the variable can only hold data appropriate for the type.
In the C code sample shown below, an integer type variable named my_variable is created. An
integer type variable can only hold integer values and the amount of memory allocated to this
variable for storing its value is a fixed size- 4 bytes, limiting the range of values to -2,147,483,648 to
2,147,483,647 for a signed integer.
int my_variable;
my_variable = 32;
In MicroPython, variables are dynamically (or automatically) assigned a variable type when the user
assigns a value to the variable. In the code shown below, the variable big_number is assigned an
integer type, allocated the appropriate amount of memory, and the value stored after the user assigns
a value to the variable.
big_number = 99999999999999999999
If a user changes the value of the variable to a text string, MicroPython stores the string and
automatically changes the variable type to string.
Syntax
Syntax refers to rules that you must follow when programming. The following sections explain the
differences in syntax between MicroPython and other programming languages.
void action1(void) {
printf("Function action1\n");
}
void action2(void) {
printf("Function action2\n");
}
if condition {
action1();
}
else {
action2();
}
In MicroPython, only a colon is required. Any statements that are part of the function must be
indented. The C code sample shown above would be coded in MicroPython as shown below. After the
function definitions and conditionals, the code to be executed is indented to make it a part of that
block. Indentation is used in MicroPython to tell the compiler which lines are members of a certain
structure.
def action1():
print("Function action1")
def action2():
print("Function action2")
if condition:
action1()
else:
action2()
In C, all of the instructions to be executed for the function some_function() are contained within the
curly braces. Most programmers indent all the instructions within the function for readability, but this
is not required for the code to work.
void some_function(void) {
int x;
x = 7;
x = x + 1;
printf("Incremented x!\n");
x = x + 2;
printf("Incremented x by 2!\n");
}
In MicroPython, indentation is required to tell the compiler what lines of code are to be executed for
the function some_function(), as shown in the example below.
def some_function():
x = 7
x = x + 1
print("Incremented x!")
x = x + 2
print("Incremented x by 2!")
When nesting conditions and functions, C relies on curly braces, as shown in the example below. Each
level of code is indented to make it more readable, but it is not required for the code to run.
void some_other_function(void) {
if (condition) {
do_something();
}
}
In MicroPython, indentation is the only thing telling the compiler what instructions belong to what
function or condition. The nested C code example shown above is coded in MicroPython in the
example below:
def some_other_function():
if condition:
do_something()
Semicolons
Statements in C are followed by a semicolon, as shown in the example below.
int x;
x = 7 + 3;
action1();
In MicroPython, statements are ended by starting a new line. A special symbol or character is not
needed.
x = 7 + 3
action1()
Increment operator
C and Java have an "increment" operator, which lets the user increase the value of a variable by 1.
See the following excample:
int x;
x = 1;
x++; // x is now 2
x++; // x is now 3
MicroPython does not have an "increment" operator. To do the equivalent in MicroPython the
variable would have to have 1 explicitly added to it, or use the += operator.
The += operator states that a variable equals itself plus a value. So, in the MicroPython code block
below, line 3 is basically shorthand for line 2. They both do the same operation: set x equal to x plus
1.
x = 1
x = x + 1 # x is now 2
x += 1 # x is now 3
Logical operators
In C, the logical operators AND, OR, and NOT are represented by &&, ||, and ! respectively. The C code
block below shows the logical operators in use.
In MicroPython, the operators for AND, OR, and NOT are simply and, or, and not, which is much more
intuitive. The MicroPython code shown below has the same function as the C code shown above.
n Heap (32 kB of RAM): Area used for variables, objects and modules imported from .py
and .mpy files in the file system.
n Stack (4 kB of RAM): RAM used by the MicroPython interpreter/task running as part of the XBee
firmware. If your function has tail recursion, try to rewrite it as a loop to reduce stack use.
n File System: Storage area for .py and .mpy files, along with SSL/TLS certificates and other data
files. File system is managed using ATFS commands, the MicroPython os module, and XCTU.
n Frozen/bundled .mpy files (32 kB of device flash): Storage area for compiled modules that can
execute in place. Standard MicroPython builds for other hardware (like the pyboard) refer to
these as "frozen" .mpy files but only support embedding them into the firmware at compile-
time. The XBee device adds an os.bundle() method to freeze multiple .mpy files into the
device flash so they can execute in place with a minimal impact on heap.
Note On XBee 3 Cellular devices with firmware ending in *15 or newer, the MicroPython heap has
been increased to 64 kB and the MicroPython stack has been increased to 6 kB of RAM.
Code storage
The XBee device stores code in different formats.
Note Main code (bundled) in flash will not be run on startup or when CTRL-R is issued in the REPL.
See Run code at startup for more information.
As you can see above, it loaded from /flash/main.mpy the first time, but the second time it re-ran the
same code.
n The gc module
n The micropython module
The gc module
You can import gc for tools to initiate garbage collection (deletion of objects on the heap no longer in
use) and measure heap usage. Use gc.mem_free() and gc.mem_alloc() for counts of available and
used memory. The two values should always add up to the same number. Due to the overhead
required by heap management, the 32 kB heap (32,768 bytes) only has 32,000 bytes available for
allocation.
Use gc.collect() to force garbage collection of unreferenced objects in the heap. You should always do
this before calling gc.mem_free() or gc.mem_alloc() in order to get an accurate value, or between
successive calls to see how much space was released.
>>> import gc
>>> gc.mem_free()
31232
>>> gc.mem_alloc()
896
>>> gc.mem_free() + gc.mem_alloc()
32000
>>> gc.collect()
>>> gc.mem_free()
31472
micropython.mem_info()
Calling mem_info() without any parameters prints a summary of heap usage. Calling it with a
parameter—for example, micropython.mem_info(1)—adds a detailed report of memory usage on the
heap. Each line of the report starts with a memory offset into the heap, and then 64 characters
representing 16-byte blocks with the following meanings:
Character Description
. unused (available) block
h start (head) of an allocation (unknown content)
= continuation of allocation
A start of array or bytearray
B start of function/bytecode
D start of dict
F start of float
L start of list
M start of module
S start of string or bytes
T start of tuple
The example below shows heap usage before and after importing a module (urequests) stored as
an mpy file on the XBee device.
micropython.qstr_info()
MicroPython stores identifiers (the names of things in your code – variables, methods, classes, and so
forth) in pools as "QSTR" objects. In doing so, it can reference the full QSTR in bytecode by using a 16-
bit index into the pool. The XBee firmware has a static QSTR pool embedded in it with names of built-
in modules and their identifiers. Any Python code that runs on the XBee device can reference those
existing names in its compiled bytecode. New identifiers go into dynamic QSTR pools allocated in
MicroPython's heap.
You can use the qstr_info() method to report on the contents of those allocated pools. Without a
parameter, you will just see summary usage information. With a parameter, it prints the contents of
each QSTR stored in the pool.
At the beginning of the following example, MicroPython has not allocated any QSTR pools. In
importing a module (urequests) stored as an mpy file on the XBee device, MicroPython allocated two
pools, totaling 50 strings of 464 bytes and using a total of 736 bytes of the heap.
)
Q(k)
Q(: )
# [...30 deleted QSTR entries...]
Q(method)
Q(url)
Q(data)
Q(headers)
Q(stream)
Q(verify)
Q(cert)
Q(scheme)
Q(host)
Q(http:)
Efficient coding
Follow recommendations from the MicroPython documentation on Maximising MicroPython Speed.
Feel free to use docstrings (string literals used to document code) in your programs, as the parser will
ignore them and they are not included in compiled code or the .mpy file generated from the .py
source.
Application evolution
As you work on your MicroPython application, you will likely take portions of it though a series of
versions as it evolves from incomplete code (undergoing active development and debugging) to
feature-complete, debugged modules that rarely change. The following topics provide some
techniques you will use along the way to creating a production-ready application. If you are not
already familiar with the Python concept of modules, you can learn about them at
https://docs.python.org/3/tutorial/modules.html.
import os
os.format()
Note When uploading code through flash upload mode, /flash/main.mpy will be deleted if it already
exists. On file systems that do not support deleting files (see Which features apply to my device?), the
space used by the existing /flash/main.mpy file is not reclaimed. While developing using flash upload
mode on these devices, you may have to reformat the device if it runs out of space.
device using XCTU or another terminal program. If you have previously loaded the module in
MicroPython with the import statement, you need to perform a soft-reboot (press Ctrl+D at a REPL
prompt) or use the following method to delete the old module and re-import it:
import sys
def reload(mod):
mod_name = mod.__name__
del sys.modules[mod_name]
return __import__(mod_name)
After running that code, you can type reload(foo) at a REPL prompt to reload a module from foo.py
or foo.mpy.
>>> import os
>>> os.chdir('lib')
>>> import gc
>>> gc.collect()
>>> gc.mem_alloc()
640
>>> os.compile('urequests.py')
stack: 644 out of 3584
GC: total: 32000, used: 640, free: 31360
No. of 1-blocks: 11, 2-blocks: 6, max blk sz: 8, max free sz: 1909
Parsing urequests.py...
stack: 644 out of 3584
GC: total: 32000, used: 8336, free: 23664
No. of 1-blocks: 19, 2-blocks: 11, max blk sz: 89, max free sz: 1407
Compiling...
stack: 644 out of 3584
GC: total: 32000, used: 3888, free: 28112
No. of 1-blocks: 44, 2-blocks: 34, max blk sz: 45, max free sz: 1225
Saving urequests.mpy...
>>> gc.collect()
>>> gc.mem_alloc()
1248
When the XBee device enters sleep mode, any MicroPython code currently executing is suspended
until the device comes out of sleep. When the XBee device comes out of sleep mode, MicroPython
execution continues where it left off.
If you use SM sleep, MicroPython can use XBee().wake_lock to force the device to stay awake during
critical operations, for example, when the device is configured for one of the ATSM sleep options
(excluding SM = 6 MicroPython Sleep). The following example shows how to use the XBee().wake_
lock:
Note wake_lock is a context manager. See Context Manager Documentation for more instructions on
usage.
import xbee
xb = xbee.XBee()
with xb.wake_lock:
# do important things
Note As of the x09 firmware, all time-related APIs include the time spent in sleep. Prior firmware
versions paused the millisecond timer used by time.sleep(), time.sleep_ms() and time.time(), so
having a 15-second SM (Sleep Mode)-triggered sleep occur during a MicroPython time.sleep(30)
would result in a 45 second delay in execution. With the x09 firmware, it only delays for 30 seconds.
sleep_now(timeout_ms, pin_wake=False)
n If pin_wake is set to True, the device will wake before timeout_ms if DIO8 transitions from
high to low—that is on a falling edge of the line.
n If timeout_ms is None then pin_wake must be set to True and the device will sleep
indefinitely until a falling edge on DIO8 occurs.
n If a timeout is specified—timeout_ms is not None—the function will return the actual elapsed
time in milliseconds after the device wakes.
n Throws an EALREADY OSError exception if SM is not configured correctly for MicroPython to
control sleep.
Note The sleep time reported includes code execution overhead—several milliseconds.
wake_reason()
Returns either xbee.RTC_WAKE if the full timeout_ms elapsed, or xbee.PIN_WAKE when enabled
and DIO8 woke the device early.
The following example shows power management with MicroPython:
x = xbee.XBee()
print("\n")
print("How to use this example:")
# pressing SW2 triggers sleep for 30 seconds
print("Option 1 press SW2 and let the program run until it wakes from 30
seconds sleep.")
print("Option 2 press SW2 to put the module under sleep for 30 seconds, "
"then while its sleeping toggle DTR by Close/Open MicroPython
Terminal Com port.")
print("Option 3 press SW2 then do ^C (cancel) to exit example program
while its sleeping")
while True:
sw2 = read_switch(dio0)
if sw2:
# sleep for 30 seconds, wake early DTR toggled active.
print("sleeping for 30 seconds")
sleep_ms = x.sleep_now(30000, True)
print("slept for %u ms" % sleep_ms)
if x.wake_reason() is xbee.PIN_WAKE:
print("woke early on DTR toggle")
Normally, an XBee device acting as a sleeping end device can receive data any time it is awake. If a
MicroPython application needs the device to be awake but does not need to receive RF transmissions,
the application can put the XBee device into an idle state. When the device is in the idle state, current
draw is reduced and the device will not receive any RF transmissions.
Note This only affects the device's primary RF interface—if Bluetooth is enabled, the device will still
be able to communicate over Bluetooth and the current reduction will be less.
Note xbee.poll_now() is a non-blocking call, meaning it will return before the polling is complete. It
can take approximately 10 ms after calling poll_now() before a message is available to xbee.receive
().
We recommend registering a callback for received packets when using xbee.poll_now(). That way,
once the packet is retrieved from the parent it is immediately handled by the application.
Since xbee.poll_now() only retrieves a single packet from the parent, it may need to be called more
than once if more than one message may be received between polls. One way to do so is by calling
xbee.poll_now() again every time a packet is received, or in the receive callback.
n SP determines how long the parent will hold on to messages for a sleeping device. The parent
will hold on to messages for three times the value of SP. If the end device always calls poll_
now() more frequently than this, no data will be dropped.
n ET must be set to at least the longest time the sleeping device will go between calls to poll_
now(). This value is used as a network timeout; if the end device goes longer than this without
polling, it is considered to have left the network and will need to rejoin the next time it polls.
Example
The following code shows some basic usage examples of the idle_radio and poll_now functions. A
more detailed sample application can be found in the xbee-micropython github repository.
import xbee
import time
Note Do not use the stdin methods readlines or readinto because they will be removed in future
firmware.
Use sys.stdin.buffer (instead of sys.stdin) for binary mode without any line ending conversions. The
read() method takes a single, optional parameter of the number of bytes to read. For a positive value,
read() blocks until receiving that many bytes from the standard stream methods primary UART. For
non-blocking, call read() without the parameter (or with a negative value) and it returns whatever
characters are available or None if no bytes are waiting.
sys.stdout supports the write() method in text mode, sending an additional carriage return (\r)
before each newline (\n). Use sys.stdout.buffer (instead of sys.stdout) for binary mode without any
line ending conversions. The write() method buffers its output, and can return before sending all
bytes out on the UART.
sys.stdin limitations
Note that sys.stdin provides access to a filtered input stream with the following limitations:
while True:
data = stdin.buffer.read(1)
import micropython
from sys import stdin, stdout
interrupt_char = -1
micropython.kbd_intr(interrupt_char)
for _ in range(15):
data = stdin.buffer.read(1)
stdout.buffer.write(data)
Note You can copy and paste code from the online version of the Digi MicroPython Programming
Guide. Use caution with the PDF version, as it may not maintain essential indentations.
print("Hello world")
4. Right-click at the MicroPython > prompt and select the Paste option.
5. Press Ctrl+D to save the paste action. An "OK" confirmation and the pasted code displays in
the line. The code is saved to the XBee device and immediately executed.
n If MicroPython is in raw REPL mode, press Ctrl+B to return to the regular REPL and print the
MicroPython banner.
n If MicroPython is in the regular REPL mode, press Ctrl+B to print the banner.
The banner displays the MicroPython version you are using and the build date for that version.
Pressing Ctrl+B does not reboot the REPL. If you need start a fresh REPL session, use the Ctrl+D:
Reboot the MicroPython REPLcommand to reboot the REPL.
Print the banner and verify that the memory was not wiped
In this example, a variable "a" is assigned the value "test". When you press Ctrl+B, the banner is
printed.
You can verify that the memory was not wiped by entering the variable "a" and seeing that the value
"test" is the output.
Note You can copy and paste code from the online version of the Digi MicroPython Programming
Guide. Use caution with the PDF version, as it may not maintain essential indentations.
Note You can copy and paste code from the online version of the Digi MicroPython Programming
Guide. Use caution with the PDF version, as it may not maintain essential indentations.
while True:
pass # This statement means "do nothing"
3. At the MicroPython >>> prompt, type Ctrl+E to enter paste mode. The terminal displays paste
mode; Ctrl-C to cancel, Ctrl-D to finish.
4. At the MicroPython >>> prompt, right-click and the select the Paste option. The code appears
in the terminal and each line is numbered, followed by ===. For example line 1 starts with
1===.
5. Press Ctrl+D to accept and run the pasted code. The code will run continuously until you
cancel it.
6. Press Ctrl+C to stop the code execution. A KeyboardInterrupt exception message prints to the
screen.
7. A MicroPython >>> prompt displays on a new line.
Note Paste mode evaluates each line in the pasted code block in order, as if the code had been typed
into the REPL.
print("Hello world")
3. At the MicroPython >>> prompt type Ctrl+E to enter paste mode. The terminal displays paste
mode; Ctrl-C to cancel, Ctrl-D to finish.
4. At the MicroPython >>> prompt, right-click and select the Paste option.
5. The code appears in the terminal and each line is numbered, followed by ===. For example line
1 starts with 1===.
6. Press Ctrl+D to complete the paste process and run the pasted code.
for x in range(10):
print("Current number: %d" % x)
if (x < 9):
print("Next number will be: %d\n" % (x + 1))
else:
print("This is the last number!")
Note You can copy and paste code from the online version of the Digi MicroPython Programming
Guide. Use caution with the PDF version, as it may not maintain essential indentations.
3. At the MicroPython >>> prompt type Ctrl+E to enter paste mode. The terminal displays paste
mode; Ctrl-C to cancel, Ctrl-D to finish.
4. At the MicroPython >>> prompt, right-click and select the Paste option.
5. The code appears in the terminal and each line is numbered, followed by ===. For example line
1 starts with 1===.
6. Press Ctrl+D to complete the paste process and run the pasted code. In this example, you
should see 10 statements print to the terminal that state the current number, and what the
next number will be. The numbers are from 0 to 9.
When the code is uploaded to the flash memory, the MicroPython volatile memory (RAM) is cleared of
any previously executed code. The uploaded code is saved on the XBee device. This means that only
the last code saved to the flash memory is available.
You can choose to automatically run the code currently stored in the flash memory when the XBee
device boots up.
Note You can copy and paste code from the online version of the Digi MicroPython Programming
Guide. Use caution with the PDF version, as it may not maintain essential indentations.
print("Hello world")
3. Press Ctrl+F.
4. At the MicroPython 1^^^ prompt, right-click and select the Paste option.
5. Press Ctrl+D to finish. The code is compiled and stored in flash memory.
Note The compilation report includes the number of used/available QSTR entries. The QSTR pool is
used to store string literals from uploaded code. If a piece of code contains too many string literals,
compilation fails and reports a QSTR pool overflow.
6. You can choose whether to have the code stored in the flash memory automatically run the
next time the XBee device is started. Press Enter to leave the setting unchanged (the default
value shown as uppercase).
o Y: Press Y to automatically run the code stored in flash memory upon startup. This sets
the PS command to 1. Note that this example only works on startup if you have a
Note This example assumes you have code stored to flash memory. For information about how to
store code to flash memory, see Load code to flash memory.
Ctrl+D
1. Access the MicroPython environment.
2. At the MicroPython >>> prompt, press Ctrl+F to enter flash mode. Do not enter or paste any
code.
3. At the MicroPython >>> prompt, press Ctrl+D to complete the process. A process message
displays:
4. When the process is complete the MicroPython >>> prompt displays in the terminal.
ATPYD command
The ATPYD command erases stored code and performs a soft reboot. For instructions, see the
MicroPython commands section in the appropriate user guide.
n Run stored code at start-up to flash LEDs (XBee Cellular Modem only)
n Disable code from running at start up
n Enable code to run at start-up
If you have stored code to the flash memory, you can choose to automatically run this code when the
XBee device boots up.
1. Use Ctrl+F to save code to the flash memory and choose to run it at start up.
2. At the Serial Console, enter Command mode by sending +++ and receiving an OK response.
3. At the prompt, type ATPS and press Enter. The terminal should echo back 1, since the code in
the flash memory is set to run at start up.
4. At the prompt, type ATPS0 and press Enter. This statement disables automatic code execution
at start up.
5. At the prompt, type ATWR and press Enter. This statement writes the change to the flash
memory.
6. At the prompt, type ATCN and press Enter. This statement exits Command mode.
7. Disconnect the USB cable from your computer.
8. Close the Serial Console.
9. Disconnect the power from the XBIB board.
10. After the LEDs on the XBIB board have all turned off, reconnect the power to the XBIB board.
11. Connect the USB cable to your computer. Notice that the LEDs do not blink, which verifies that
you have successfully disabled the automatic code execution at start up.
1. For this example, you need code stored in flash memory that will not automatically run at
start-up. Use Ctrl+F to save code to the flash memory. You can either:
n Press N and choose not to run it at start up.
n Press Y to run the code in flash memory at start-up. If you chose Yes, for this example
you should Disable code from running at start up.
Remember that in this example, when MicroPython is not set to automatically run at start-up,
the LEDs do not blink on module start-up.
2. At the Serial Console, enter Command mode by sending +++ and receiving an OK response.
3. At the prompt, type ATPS and press Enter. The terminal should echo back 0, since the code in
the flash memory is not set to run at start-up.
4. At the prompt, type ATPS1 and press Enter. This statement enables automatic code execution
at start up.
5. At the prompt, type ATWR and press Enter. This statement writes the change from the
previous statement to the flash memory.
6. At the prompt, type ATCN and press Enter. This statement exits command mode.
7. Press the Reset button on the XBIB board.
8. Notice that the LEDs blink ON and OFF, which verifies that you have successfully enabled the
automatic code execution at start up.
n On Cellular devices, you can perform a safe shutdown and reboot using network.Cellular
().shutdown(reset=True)
n On all devices, you can reboot the XBee using xbee.atcmd('FR') or machine.reset().
Note FR and machine.reset force an immediate reset of the XBee, and on Cellular should not be used
unless preceded by a safe shutdown.
Note This section only applies to devices that support the File System feature.
uos.chdir(dir)
Change the current working directory.
uos.getcwd()
Get the current working directory.
Note MicroPython maintains a separate working directory from the FS (File System) command
processor.
uos.ilistdir([dir])
This function returns an iterator which then yields tuples corresponding to the entries in the directory
that it is listing. With no argument it lists the current directory, otherwise it lists the directory given by
dir. The tuples have the form (name, type, inode, size):
n name: A string (or bytes if dir is a bytes object) and it is the name of the entry.
n type: An integer that specifies the type of the entry, with 0x4000 for directories and 0x8000 for
regular files.
n inode: An integer corresponding to the inode of the file. On XBee devices, set to 0 for regular
files and directories and -1 for secure files.
n size: An integer representing the size of the file or -1 if unknown. Its meaning is currently
undefined for directory entries.
uos.listdir([dir])
Returns a list of files in the given directory. With no argument it uses the current working directory (.).
uos.mkdir(dir)
Create a new directory.
uos.remove(file)
Remove a file.
uos.rmdir(dir)
Remove a directory. Fails if dir is not empty.
uos.rename(old_path, new_path)
Rename or move a file or directory. Fails if new_path already exists.
Note This function is only available on modules that support renaming files.
uos.replace(old_path, new_path)
Replace a file or directory (new_path) with another (old_path).
Note This function is only available on modules that support renaming files.
uos.sync()
Sync all file systems.
uos.compile(source_file, mpy_file=None)
This is an XBee extension to uos. Compile Python source code in source_file and store in a file with
an .mpy extension. Default is to remove the .py extension from source_file and append .mpy to
generate mpy_file. See Import modules from file system for details on using .mpy files.
Compilation involves three steps: parsing, compiling and saving to the file system. MicroPython prints
information about heap usage before each step so you can monitor heap requirements for a device,
and consider splitting it into two (or more) modules or compiling with the MicroPython cross compiler
(mpy-cross) on your computer instead of compiling on the XBee device.
>>> uos.compile('urequests.py')
stack: 644 out of 3584
GC: total: 32000, used: 688, free: 31312
No. of 1-blocks: 12, 2-blocks: 7, max blk sz: 8, max free sz: 1716
Parsing urequests.py...
stack: 644 out of 3584
GC: total: 32000, used: 8000, free: 24000
No. of 1-blocks: 20, 2-blocks: 12, max blk sz: 88, max free sz: 1415
Compiling...
stack: 644 out of 3584
GC: total: 32000, used: 3872, free: 28128
No. of 1-blocks: 45, 2-blocks: 35, max blk sz: 42, max free sz: 1254
Saving urequests.mpy...
>>> list(uos.ilistdir())
[('urequests.py', 32768, 0, 3407), ('urequests.mpy', 32768, 0, 2657)]
uos.format()
This is an XBee extension to uos. Reformats the SPI flash and creates the default directory structure.
uos.hash([secure_file])
This is an XBee extension to uos. Returns a 32-byte bytes object with the sha256 hash digest of a
secure file. You can use this value to verify that a secure file matches an unencrypted copy of the file.
See FS HASH filename for more information on using this digest. If secure_file is not specified, it
returns a string identifying the hash method (sha256). You can convert the 32-byte digest to a 64-
character hexdigest with the following code snippet:
b'\r\x85\xdbY\x0b\xfd\r\x00\x1aI\x08\xb8\x19\xd3\xb8\xa0\x03f\x85\x0fh\xb9
\xc9\x1f\x92;\xd8\xab\xa2\x0f\xfb\x16'
>>> hexdigest
'0d85db590bfd0d001a4908b819d3b8a00366850f68b9c91f923bd8aba20ffb16'
Character Meaning
'r' Open for reading (default).
'w' Open for writing, truncating file file. On modules that do not support editing files
after creation, this will fail if the file already exists.
'x' Open for exclusive creation, failing if the file already exists.
'a' Open for writing, always appending to the end of the file. Only available on modules
that support editing files after creation.
'b' Binary mode.
't' Text mode (default).
'+' Open a disk file for updating (reading and writing). Only available on modules that
support editing files after creation.
'*' (XBee extension) open a secure file for writing. Only available on modules that
support secure files.
The default mode is 'r'—open for reading text, a synonym of 'rt'. For binary read-write access, the
mode 'w+b' opens and truncates the file to 0 bytes. 'r+b' opens the file without truncation.
Python distinguishes between binary and text I/O. Files opened in binary mode—including 'b' in the
mode argument—return contents as bytes objects without any decoding. In text mode—the default, or
when 't' is included in the mode argument—the contents of the file are returned as str.
read(size=-1)
Read up to size bytes from the object and return them. As a convenience, if size is unspecified or -1,
all bytes until end-of-file (EOF) are returned.
readinto(b)
Read bytes into a pre-allocated, writable bytes-like object b, and return the number of bytes read.
readline(size=-1)
Read and return one line from the stream. If size is specified, at most size bytes are read.
readlines()
Read and return a list of lines from the stream. MicroPython does not support Python3's hint
parameter.
Note It is already possible to iterate on file objects using for line in file: ... without calling
file.readlines().
write(b)
Write the given bytes-like object, b, to the underlying raw stream, and return the number of bytes
written.
seek(offset, whence=0)
Note Seeking is disabled when writing to secure files.
Change the stream position to the given byte offset. offset is interpreted relative to the position
indicated by whence. The default value for whence is 0 (SEEK_SET). Values for whence are:
n 0 (SEEK_SET) – start of the stream (the default); offset should be zero or positive
n 1 (SEEK_CUR) – current stream position; offset may be negative
n 2 (SEEK_END) – end of the stream; offset is usually negative
Returns the new absolute stream position.
tell()
Return the current stream position.
flush()
Flush the write buffers of the stream if applicable. This does nothing for read-only streams.
close()
Flush and close the stream. This does nothing if the file is already closed.
On startup, the XBee device sets its sys.path to a default of ['', '/flash', '/flash/lib'].
Reload a module
If you want to reload a module after uploading a revised source file, use the following method to
discard the old module and re-import from the updated file.
Note This is also necessary if the previous import attempt failed due to a syntax error.
import sys
def reload(mod):
mod_name = mod.__name__
del sys.modules[mod_name]
return __import__(mod_name)
Note You should pass -mno-unicode and -msmall-int-bits=31 to mpy-cross when cross-compiling
for the XBee device.
The benefit of using a .mpy file is that MicroPython can load it to the heap with minimal overhead,
unlike the parsing and compiling process which could require a 32 kB heap to create a 7 kB .mpy file.
Since MicroPython checks for .py files in a given directory before .mpy files, you need to organize your
files so the .mpy comes up first during an import search. One technique is to keep the Python source
in lib/source/ and then compile to an .mpy file in lib/ after uploading new files; for example, with
/flash/lib as the current working directory, uos.compile('source/foo.py', 'foo.mpy').
Note This section applies to the XBee Cellular Modem and the XBee 3 Zigbee RF Module. See Which
features apply to my device? for a list of the supported features.
You can send and receive User Data Relay Frames from MicroPython using the relay module from the
xbee module. Import the module with the statement: from xbee import relay
Constants 68
Methods 68
Examples 69
Constants
relay.BLUETOOTH: 1
relay.MICROPYTHON: 2
Limits
relay.MAX_DATA_LENGTH: maximum length of data passed to relay.send()
Methods
relay.receive()
Returns None if a frame is not available, otherwise a dictionary with entries for the sender (one of the
interfaces, for example, relay.SERIAL), and message (a bytes object).
relay.send(dest, data)
Pass one of relay.SERIAL, relay.BLUETOOTH or relay.MICROPYTHON (for loopback) as dest. Can
use sender from the dictionary returned from receive() as dest parameter. The data parameter
should be a bytes or string object, or any other object that implements the buffer protocol. You can
send a maximum of relay.MAX_DATA_LENGTH bytes in a single frame.
Exceptions
The send() method throws exceptions in at least the following cases:
relay.callback(my_callback)
Note This section only applies to the XBee 3 Cellular Modem firmware x15 or later. See Which features
apply to my device? for a list of the supported features.
Register a callback that will be called whenever a user data relay frame is received.
The callback function must take one parameter:
Note When a callback is registered, using relay.callback() will raise an error as only one method of
relay frame delivery is supported at a time.
Examples
Digi has provided example applications which demonstrate how to use User Data Relay frames from
MicroPython.
You can read these examples on GitHub: https://github.com/digidotcom/xbee-
micropython/tree/master/samples/xbee/communication
If you use the Digi XBee MicroPython PyCharm Plugin you can load the examples using File> Import
XBee MicroPython Sample Project... in the XBEE / COMMUNICATION folder.
Note This section only applies to the XBee Cellular Modem. See Which features apply to my device?
for a list of the supported features.
On GitHub, we maintain modules and sample code for use on XBee devices with MicroPython. The
code is available at github.com/digidotcom/xbee-micropython. The samples include:
n Secure Sockets Layer (SSL) and Transport Layer Security (TLS). See The ussl module.
n Amazon Web Services (AWS). These samples demonstrate how to connect to AWS IoT and
publish and subscribe to topics using the umqtt.simple module. See Use AWS IoT from
MicroPython.
n File Transfer Protocol (FTP). Micro File Transfer Protocol client.
n MQ Telemetry Transport (MQTT). MQTT client for publish/subscribe. See Publish to a topic.
n Digi Remote Manager. An HTTP client for Digi Remote Manager.
XBee-specific functions 72
Standard modules and functions 72
Discover available modules 73
XBee-specific functions
The following functions are specifically for use with the XBee device.
n Machine module
n Cellular network configuration module
n XBee module
n digi.cloud module
Note The MicroPython modules starting with "u" have aliases to the standard Python module names.
Function Description
MicroPython Functions used to access and control MicroPython internals.
functions
Note The standard set of MicroPython functions work with the XBee device.
n sys.print_exception(exc, file=sys.stdout)
Available constants:
n sys.argv
n sys.byteorder
n sys.implementation
n sys.maxsize
n sys.modules
n sys.path
n sys.platform
n sys.version
n sys.version_info
ubinascii This module implements conversions between binary data and various encodings
of it in ASCII form (in both directions).
ucryptolib This module provides an Advanced Encryption Standard (AES) API in MicroPython
Function Description
to perform encryption and decryption of data or files.
uhashlib This module implements binary data hashing algorithms.
uio This module contains additional types of stream (file-like) objects and helper
functions.
ujson This module performs JSON encoding and decoding.
uselect This module provides functions to efficiently wait for events on multiple streams
(select streams which are ready for operations)
This is currently only available on the XBee Cellular Modem with firmware x15 and
later as it primarily applies to sockets.
usocket (XBee Cellular Modem only) This module provides access to the BSD socket
interface.
See Sockets for samples of using sockets with the XBee Cellular Modem.
ustruct This module provides functions to pack and unpack primitive data types.
utime XBee Cellular Modem: This module provides functions for getting the current time
and date, measuring time intervals, and for delays.
XBee 3 Zigbee RF Module: This module provides functions for measuring time
intervals, and for delays.
Note The MicroPython modules starting with "u" have aliases to the standard Python module names.
Reset-cause 75
Random numbers 75
Unique identifier 75
Class PWM (pulse width modulation) 75
Class ADC: analog to digital conversion 76
Class I2C: two-wire serial protocol 78
Class Pin 83
Class UART 83
Class WDT: watchdog timer 86
Access the XBee device's I/O pins 86
Use the Pin() constructor 88
Use mode() to configure a pin 89
Use pull() to configure an internal pull up/down resistor 90
Reset-cause
This function returns the cause of a reset. See Reset-cause for possible return values.
machine.reset_cause()
Constants
These return values describe the cause of a reset.
machine.BROWNOUT_RESET
machine.LOCKUP_RESET
machine.PWRON_RESET
machine.HARD_RESET
machine.WDT_RESET
machine.DEEPSLEEP_RESET
machine.SOFT_RESET
Note Some devices do not support reporting all of these reset causes. To see a list of possible values,
run:
import machine
help(machine)
Random numbers
The machine.rng() method returns a 30-bit random number that is generated by the software.
The uos.urandom(n) method returns a bytes object with n random bytes generated by the hardware
random number generator.
Unique identifier
The machine.unique_id() function returns a 64-bit bytes object with a unique identifier for the
processor on the XBee Cellular Modem.
In some MicroPython ports, the ID corresponds to the network MAC address.
This function uses the machine.PWM class. For information about the MicroPython machine module,
see machine — functions related to the hardware.
For XBee devices that support PWM1, change the instances of P0 to P1 in the example program.
Note Supported on XBee 3 cellular only. Not supported on XBee Cellular Cat 1 Verizon and XBee
Cellular 3G.
import machine
Constructors
You can create an ADC object associated with the assigned pin. You can then read analog values on
that pin.
class machine.ADC('D0')
Note For the XBee Cellular Modem the ADC analog reference is 2.5 V and the pin input range is 0 - 2.5
V. The ADC reference voltage and input range for XBee 3 Zigbee, DigiMesh and 802.15.4 are based on
the AV value which can be 0 = 1.25 V, 1 = 2.5 V or 2 = VDD.
Note The ADC reading value has a resolution of 12 bits with a range of 0 - 4095.
Methods
Read the analog value
This function allows you to read the ADC value.
apin.read()
Note apin.read() returns a raw ADC sample. Use the following equation to convert this value to mV:
apin.read_u16()
Note apin.read_u16() returns a raw ADC sample. Use the following equation to convert this value to
mV:
Note This function is available on XBee Cellular and XBee 3 Cellular products with firmware ending in
*16 or newer, and XBee 3 DigiMesh, 802.15.4 and Zigbee devices with firmware ending in *0B or
newer.
Sample program
The following sample program applies to the XBee 3 Zigbee, DigiMesh, and 802.15.4.
import machine
import xbee
x = xbee.XBee()
I2C is a two-wire protocol for communicating between devices. At the physical level it consists of two
wires: SCL and SDA, the clock and data lines respectively.
When created, I2C objects are associated with a specific two wire bus. They can be initialized when
created, or initialized later on.
Printing the I2C object gives you information about its configuration.
The XBee device can function as an I2C master controlled by MicroPython. This allows you to perform
basic sensing and actuation with I2C devices such as sensors and actuators via MicroPython without
an additional microcontroller.
The MicroPython API is the same as documented in the MicroPython library reference except that the
XBee device does not support primitive operations or the deinit operation.
The I2C implementation is provided through hardware, so when you use machine.I2C to initialize I2C,
use the id parameter to select the interface. The only valid value is 1, which uses DIO1 for SCL and
DIO11 for SDA. Using the scl and sda parameters to select pins is not valid on the XBee device.
Note You are not required to configure the XBee I/O using AT commands prior to creating an I2C
object. The appropriate I/O configuration will be performed automatically.
The following table shows the pin layout associated with the example below.
Constructors
class machine.I2C(id, *, freq=400000)
Construct and return a new I2C object using the following parameters:
General methods
I2C.scan()
Scan all I2C addresses between 0x08 and 0x77 inclusive and return a list of addresses of slave devices
that respond. A device responds if it pulls the SDA line low after its address (including a write bit) is
sent on the bus.
Sample programs
The following sample program applies to the HDC1080 I2C temperature and humidity sensor. This
sensor is available on the XBIB-CU-TH, XBIB-C-MMT, and XBIB-C-SMT XBee development boards.
Note Refer to the HDC1080 datasheet available at ti.com for detailed technical information.
class HDC1080:
def __init__(self, i2c, slave_addr=64):
""" Initialize a HDC1080 temperature and humidity sensor.
Keyword arguments:
i2c -- The i2c object used to interact with the I2C sensor.
slave_addr -- The slave address of the sensor (default 64 or
0x40).
"""
self.i2c = i2c
scan_result = self.i2c.scan()
assert slave_addr in scan_result, \
"Did not find slave %d in scan: %s" % (slave_addr, scan_
result)
self.addr = slave_addr
# Sleep for 15 ms to allow the temperature and humidity
# sensors to start recording.
sleep(0.015)
# Set temperature and humidity readings for independent
def read_humidity(self):
""" Read the relative humidity """
# Write to the pointer register, changing it to the humidity
register.
data = bytearray([HUMI_REG])
self.i2c.writeto(self.addr, data)
# Wait for conversion.
sleep(0.01)
data = self.i2c.readfrom(self.addr, 2) # Read two bytes.
# Convert big-endian array of bytes to integer.
value = int.from_bytes(data, "big")
return (value / (2 ** 16)) * 100
The following sample works with a DS1621 I2C temperature sensor. Make the following connections
before testing the code:
In addition, connect the address pins of the DC1621 (5, 6 and 7) to ground, and a pullup resistor from
the SDA line to VCC.
import machine
import utime
import ustruct
i2c = machine.I2C(1)
slave_addr = 0x48 # 0b100_1000. Assumes A0-2 are low.
def start_convert():
i2c.writeto(slave_addr, '\xEE', True)
def stop_convert():
i2c.writeto(slave_addr, '\x22', True)
def read_access_config():
i2c.writeto(slave_addr, '\xAC', False)
return i2c.readfrom(slave_addr, 1)
def write_access_config(value):
written = i2c.writeto(slave_addr, b'\xA1' + ustruct.pack('b', value))
assert written == 2, "Access Config write returned %d ?" % written
def display_continuous():
start_convert()
try:
while True:
print('%.1fF' % (read_temperature() * 9 / 10 + 32))
utime.sleep(2)
except:
stop_convert()
raise
# Perform a scan and make sure we find the slave device we want to talk
to.
devices = i2c.scan()
assert (slave_addr in devices,
"Did not see slave device address %d in scan result: %s" %
(slave_addr, devices))
display_continuous()
Class Pin
Note This section only applies to devices that support the Pin I/O feature.
Note Only pins D0-P2 are accessible using the Pin class.
You can use the Pin class with the XBee device. For information, see Class Pin: Control I/O pins.
Class UART
Note This section only applies to devices that support the Secondary UART feature.
MicroPython on the XBee Cellular Modem provides access to a 3-wire or 5-wire TTL-level serial port
(referred to as machine.UART(1)) on the following pins. The table also indicates the proper
connections when testing with an FTDI TTL-232R cable. Note that the FTDI cable's pin 3 (VCC) remains
unconnected.
FTDI TTL-232R
XBee
Pin Name Description Direction Pin Name
10 GND Ground N/A 1 GND
11 DIO4 Transmit (TX) XBee → 5 RXD
4 DIO12 Receive (RX) XBee ← 4 TXD
18 DIO2 Ready to Receive (RTS) XBee → 2 CTS#
17 DIO3 Clear to Send (CTS) XBee ← 6 RTS#
Using the RTS and CTS pins for hardware flow control is optional. The XBee Cellular Modem can use
RTS to signal the remote end to stop sending when its receive buffer is close to full, and it will
conversely monitor the CTS signal and only send when the remote end asserts the signal. Both RTS
and CTS are active low signals where 0 (GND) represents "asserted" (or "safe to send") and 1 (VCC)
represents "deasserted" (or "wait to send").
1. Open a terminal window to the MicroPython REPL on your XBee Cellular Modem.
2. Open a second terminal window to the TTL-232R cable you connected to DIO4/DIO12.
3. Leave DIO2/DIO3 disconnected and configure the second terminal window without any flow
control.
4. From the REPL prompt, press Ctrl-E to enter paste mode.
5. Paste the following test code (which uses the default baud rate of 115,200).
u = UART(1)
u.write('Testing from XBee\n')
while True:
uart_data = u.read()
if uart_data:
print(str(uart_data, 'utf8'), end='')
time.sleep_ms(5)
A UART object acts like a stream object and uses the standard stream methods for reading and
writing.
Constructors
class machine.UART(id, baudrate=115200, bits=8, parity=None, stop=1, *, flow=0, timeout=0,
timeout_char=0)
Note Unlike other MicroPython platforms, the XBee Cellular Modem uses a circular buffer to store
serial data, and the timeout and timeout_char settings do not apply to writes.
Methods
UART.init(baudrate=0, bits=0, parity=-1, stop=0, *, flow=-1, timeout=-1, timeout_char=-1)
See Constructors for descriptions of each keyword. The default values (used if a keyword is not
specified) leave the current setting unchanged. Calling UART.init() resets the port using the current
settings.
UART.deinit()
Turn off the UART bus. After calling deinit(), attempts to write to the UART result in an OSError
(EPERM) exception but reads continue to pull buffered bytes.
UART.any()
Returns an integer value of the number of bytes in the read buffer, or 0 if no bytes are available.
UART.read([nbytes])
Read characters. If nbytes is specified and a positive value, then read at most that many bytes,
otherwise read as much data as possible.
Return value: a bytes object containing the bytes read. Returns None on timeout.
UART.readinto(buf[, nbytes])
Read bytes into the buf. If nbytes is specified then read at most that many bytes. Otherwise, read at
most len(buf) bytes.
Return value: number of bytes read and stored into buf or None on timeout.
UART.readline()
Constants
Used to specify the flow control type.
UART.RTS
UART.CTS
n SOFT_RESET: resets only the MicroPython interpreter as if the soft_reset method in the device
had been called.
n HARD_RESET: Reboots the entire XBee device.
n CLEAN_SHUTDOWN: Shuts down the cellular component and then reboots. If the cellular
component cannot be cleanly shut down in two minutes it is reset anyway.
on -- <function>
toggle -- <function>
name -- <function>
names -- <function>
af_list -- <function>
mode -- <function>
pull -- <function>
af -- <function>
mapper -- <classmethod>
dict -- <classmethod>
board -- <class 'board'>
DISABLED -- 15
IN -- 0
OUT -- 1
OPEN_DRAIN -- 17
ALT -- 2
ALT_OPEN_DRAIN -- 18
ANALOG -- 3
PULL_UP -- 1
PULL_DOWN -- 2
AF0_COMMISSION -- 0
AF1_SPI_ATTN -- 1
AF2_SPI_SCLK -- 2
AF3_SPI_SSEL -- 3
AF4_SPI_MOSI -- 4
AF5_ASSOC_IND -- 5
AF6_RTS -- 6
AF7_CTS -- 7
AF7_RS485_ENABLE_LOW -- 71
AF7_RS485_ENABLE_HIGH -- 135
AF8_SLEEP_REQ -- 8
AF9_ON_SLEEP -- 9
AF10_RSSI -- 10
AF12_SPI_MISO -- 12
AF13_DOUT -- 13
AF14_DIN -- 14
AF15_SPI_MISO -- 15
AF16_SPI_MOSI -- 16
AF17_SPI_SSEL -- 17
AF18_SPI_SCLK -- 18
AF19_SPI_ATTN -- 19
To see a list of pins available on your hardware, get help on the Pin.board class:
>>> help(Pin.board)
object <class 'board'> is of type type
D0 -- Pin(Pin.board.D0, mode=Pin.ALT, pull=Pin.PULL_UP, alt=Pin.AF0_
COMMISSION)
D1 -- Pin(Pin.board.D1, mode=Pin.DISABLED)
D2 -- Pin(Pin.board.D2, mode=Pin.DISABLED)
D3 -- Pin(Pin.board.D3, mode=Pin.DISABLED)
D4 -- Pin(Pin.board.D4, mode=Pin.DISABLED)
D5 -- Pin(Pin.board.D5, mode=Pin.ALT, pull=Pin.PULL_UP, alt=Pin.AF5_ASSOC_
IND)
D6 -- Pin(Pin.board.D6, mode=Pin.DISABLED)
D7 -- Pin(Pin.board.D7, mode=Pin.ALT, pull=Pin.PULL_UP, alt=Pin.AF7_CTS)
D8 -- Pin(Pin.board.D8, mode=Pin.ALT, pull=Pin.PULL_UP, alt=Pin.AF8_SLEEP_
REQ)
D9 -- Pin(Pin.board.D9, mode=Pin.ALT, pull=Pin.PULL_UP, alt=Pin.AF9_ON_SLEEP)
From the list above, you can see the current configuration of all the pins. Note that pins P0 through
P9 have aliases of D10 through D19. Also, through-hole XBee 3 RF products (802.15.4, DigiMesh and
Zigbee) still list pins P5 through P9 even though they are only accessible on the surface-mount
products.
You can assign any of the Pin.board objects to a variable that is easier to type (for example, d0 =
Pin.board.D0) or more descriptive (for example, status_led = Pin.board.D3). Multiple names for a pin
all reference the same physical pin, so changes made through one name appear in all other names.
For example, to change pin D0 from operating as a commissioning button, you could do the following:
The names button and Pin.board.D0 both show the new configuration after using the mode()
method to make it an input. The example keeps the configuration of an internal pull up to Vcc to
simplify the button wiring—just short the pin to ground when you press the button. You can check the
status of the button using the value() method. It returns 0 when pressed (shorted to ground) and 1
otherwise (pulled up to Vcc).
Note By default pull is set to None and will disable a pull up/down resistor already configured for a
given pin.
The documentation for mode(), pull(), and value() also apply to those parameters in the Pin()
constructor. See Pin.ALT for usage of the alt parameter.
Pin.DISABLED
If you are not using a pin, configure it as Pin.DISABLED.
Pin.IN
Pin acts as an input that you can read with the value() method, which returns 1 for high and 0 for
low. See the pull() method for configuring an internal pull up/down resistor on input pins.
Pin.OUT
Pin acts as an output that you can set by passing a parameter to the value() method. Any value that
evaluates to True sets the pin high (Vcc) and all other values set it low (ground). Pin objects also
support the on() and off() methods as shortcuts for value(1) and value(0) respectively, and toggle()
to toggle the current value. For example, you can override the association indicator normally
configured for D5 and control it manually:
>>> d5 = Pin.board.D5
>>> d5.mode(Pin.OUT)
>>> # turn LED off
>>> d5.value(0)
>>> # turn LED on
>>> d5.value(1)
>>> # turn LED off
>>> d5.off()
>>> # turn LED on
>>> d5.on()
>>> # flash the LED at 2Hz (on .25 seconds, off .25 seconds)
>>> import time
>>> while True:
... d5.toggle()
... time.sleep(.25)
...
Traceback (most recent call last):
File "<stdin>", line 3, in <module>
KeyboardInterrupt:
>>>
Note Using the on() and off() names in your code could be confusing when using outputs wired as
"active low."
Pin.ALT
Selects an alternate function for the pin. Use the af_list() method on a Pin object for a list of
alternate functions available on a pin. You can select a pin's default alternate function by calling
mode(Pin.AF), but you need to use the Pin() constructor to select a specific alternate function if a pin
supports more than one. Use the af() method to see what a Pin's current alternate function is. Note
that af() returns an integer that you should compare to the Pin.AFx_XXX constants in your code, and
not reference directly as they may change between firmware releases.
>>> Pin.board.D5.af_list()
[Pin.AF5_ASSOC_IND]
>>> d5 = Pin('D5', mode=Pin.ALT, alt=Pin.AF5_ASSOC_IND)
>>> "is assoc" if d5.af() == Pin.AF5_ASSOC_IND else "not assoc"
'is assoc'
>>> d5.mode(Pin.IN)
>>> "is assoc" if d5.af() == Pin.AF5_ASSOC_IND else "not assoc"
'not assoc'
Pin.ANALOG
Use the machine.ADC() class instead of configuring a pin mode as Pin.ANALOG. A Pin object in use
by the ADC() class reports its mode as Pin.ANALOG.
automatically update the PR and PD parameter values and vice-versa. The Pin.pull() method and
pull parameter to the Pin() constructor take a single parameter:
import digi
Feature support 93
active() 93
config() 94
disconnect_code() 95
gap_connect() 95
gap_connection methods 96
UUID() 103
gap_scan() 104
gap_scan methods 104
gap_scan advertisement format 105
Use gap_scan as an iterator 105
Use gap_scan as a context manager 106
gap_advertise() 106
xbee_connect() 107
xbee_connection methods 108
digi.ble samples 108
Troubleshooting 109
Feature support
The following table shows which devices support the digi.ble module.
active()
Use this function to set or query whether BLE functionality is enabled on the XBee device. This
method is equivalent to the ATBT command.
ble.active([mode])
Without parameters:
config()
Query a BLE configuration value by name, or update one or more BLE configuration values.
ble.config(name)
ble.config([interval_ms=..., ][latency=..., ][timeout_ms=...])
Query a value
To query a BLE configuration value, pass the name of the value as a string. Currently supported values
are:
<interval_ms>
Update the initial connection interval to use on future GAP connections—see gap_connect().
The connection interval is the time between two data transfer events on the GAP connection. The
value will be rounded down to the nearest multiple of 1.25 milliseconds. interval_ms may be
between 8 and 4000 (4 seconds).
Default value (restored at XBee power-up): 50 milliseconds.
<latency>
Update the initial slave latency to use on future GAP connections—see gap_connect().
The slave latency is the number of consecutive connection events that the connected peripheral is
allowed to skip before the connection is dropped. latency may be between 0 and 500.
Default value (restored at XBee power-up): 0.
<timeout_ms>
Update the initial connection supervision timeout to use on future GAP connections—see gap_connect
().
The connection supervision timeout value is the time that the central device (in this case, the XBee)
will wait for a data transfer before assuming that the connection is lost. timeout_ms may be between
100 and 32000 (32 seconds). timeout_ms must be larger than 2 * interval_ms * (latency + 1) .
Default value (restored at XBee power-up): 1000 milliseconds (1 second).
disconnect_code()
When called on a connection which has been closed, returns a value from the Bluetooth Core
specification Vol 2, Part D (Error Codes) indicating the reason for the disconnect. Calling this on an
open connection returns zero.
The most common values to see here include:
8 - Connection timeout
19 - Remote user terminated
22 - Connection terminated by local host
gap_connect()
Connect to a BLE device. The address type and the address are required arguments.
<addr_type>
The <addr_type> parameter specifies the address type.
The possible values are defined as constants on the digi.ble module:
<address>
The <address> parameter is a bytes object which represents the BLE MAC address that is the target of
the connection.
<timeout_ms>
The <timeout_ms> parameter specifies the timeout before giving up on a connection. When a
connection times out, OSError ETIMEDOUT is raised.
Note The connection attempt will automatically time out if the remote peripheral does not respond
to a connection request within six connection intervals—see the <interval_ms> parameter.
<interval_us>, <window_us>
Use <interval_us> and <window_us> to optionally configure the duty cycle to scan for the remote
device. The scanner will run for <window_us> microseconds every <interval_us> microseconds.
The default interval and window are 20 milliseconds and 11.25 milliseconds, respectively. Both values
must be at least 2,500 microseconds (2.5 milliseconds) and no more than approximately 40.96
seconds (40,959,375 microseconds).
<onclose>
The <onclose> parameter assigns a function as a callback to be triggered on receiving a close event
on the connection. The onclose function will be called with two arguments, the ble_connection
object that received the disconnect event and the disconnect code.
Note The supplied disconnect code is also stored on the ble_connection object itself, see
disconnect_code() for more information on disconnect codes.
Return value
If the GAP connect operation is started successfully, a gap_connection object is returned.
If the GAP connect operation is not successful, an OSError is raised.
gap_connection methods
The methods available on a gap_connection object—returned by the gap_connect()\ function—are
as follows.
gattc_services()
Discover Generic Attribute Profile (GATT) services in the remote device's database. A specific service
can be discovered by specifying the UUID of the service.
connection.gattc_services([, uuid])
<uuid>
The <uuid> parameter is either a UUID object or a value that can construct a UUID object. When
specified, the iterator only returns the service with that UUID, otherwise all services are returned.
Return value
If the GATT service discovery operation is successful, an iterator is returned containing tuples with the
following information about each discovered service:
(handle, uuid)
<handle>
The <handle> is an integer used to reference the service.
<uuid>
The <uuid> is an UUID object.
If the GATT service discovery operation is not able to be started, an OSError is raised.
gattc_characteristics()
Discover GATT characteristics of a service in the remote device's database. A specific characteristic
can be discovered by specifying the UUID of the characteristic.
connection.gattc_characteristics(service[, uuid])
<service>
The <service> parameter is a service handle discovered from gattc_services().
<uuid>
The <uuid> parameter is either a UUID object or a value that can construct a UUID object. When
specified, the iterator or only returns the characteristic(s) with that UUID, otherwise all characteristics
are returned.
Return value
If the GATT characteristic discovery operation is successful, an iterator is returned containing tuples
with the following information about each discovered characteristic:
<handle>
The <handle> is an integer used to reference the characteristic.
<uuid>
The <uuid> is an UUID object.
<properties>
<properties> is an integer containing the property flags. These flags are defined as constants in the
digi.ble module.
They are the following:
n PROP_BROADCAST
n PROP_READ
n PROP_WRITE_NO_RESP
n PROP_WRITE
n PROP_NOTIFY
n PROP_INDICATE
n PROP_AUTH_SIGNED_WR
gattc_descriptors()
Return an iterator of all GATT descriptors of a characteristic in the remote device's database. Note
that this returns an iterator and the descriptor discovery will not be completed until the iterator is
emptied.
connection.gattc_descriptors(characteristic)
<characteristic>
The <characteristic> parameter is a characteristic handle discovered from gattc_characteristics.
Return value
If the GATT descriptor discovery operation is successful, an iterator is returned containing tuples with
the following information about each discovered descriptor:
(handle, uuid)
<handle>
The <handle> is an integer used to reference the descriptor.
<uuid>
The <uuid> is an UUID object.
If the GATT descriptor discovery operation is not able to be started, an OSError is raised.
gattc_read_characteristic()
Issue a remote read to the connected peripheral to the specified characteristic.
connection.gattc_read_characteristic(characteristic_handle)
<characteristic_handle>
The <characteristic_handle> parameter is a characteristic handle discovered from gattc_
characteristics.
Return value
gattc_read_characteristic returns a bytes object containing the characteristic attribute value.
If the characteristic passed in is invalid or the connection to the peripheral device is lost, an OSError
is raised.
If the required read permissions for the characteristic are not met then an empty bytes object is
returned.
gattc_configure()
Enable or disable notifications/indications for a given characteristic. This configures the remote server
to send notifications/indications and registers the passed callback to be called when one is received.
connection.gattc_configure(characteristic_handle,[ callback=None][,
notification=False]
<characteristic_handle>
The <characteristic_handle> parameter is a characteristic handle discovered from gattc_
characteristics, whose characteristic has the notify property—ble.PROP_NOTIFY—or the indicate
property—ble.PROP_INDICATE.
<callback>
The <callback> parameter is a user defined callback that is called whenever a notification or
indication is received from the passed characteristic.
This callback should have two parameters. The first is the data, a bytes object. The second is an
integer indicating the offset of the data.
If None is passed as the <callback> parameter or <callback> is not specified, notifications/indications
are disabled for the characteristic.
<notification>
The <notification> parameter is an optional parameter used to distinguish between using
notifications instead of indications. By default, indications are used. If <notification> is set to True,
notifications are used instead of indications.
Note Notifications are unacknowledged by the client and do not guarantee delivery of the data.
gattc_read_descriptor()
Issue a remote read to the connected peripheral to the specified descriptor.
connection.gattc_read_descriptor(descriptor_handle)
<descriptor_handle>
The <descriptor_handle> parameter is a descriptor handle discovered from gattc_descriptors.
Return value
gattc_read_descriptor returns a bytes object containing the descriptor attribute value.
If the descriptor handle passed in is invalid or the connection to the peripheral device is lost, an
OSError is raised.
If the required read permissions for the descriptor are not met then an empty bytes object will be
returned.
gattc_write_characteristic()
Issue a remote write to the connected peripheral to the specified characteristic.
connection.gattc_write_characteristic(characteristic_handle, data)
<characteristic_handle>
The <characteristic_handle> parameter is a characteristic handle discovered from gattc_
characteristics.
<data>
The <data> parameter specifies the data to be written to the remote characteristic.
Return value
gattc_write_characteristic returns None—in other words it has no return value.
If the characteristic handle passed in is invalid or the connection to the peripheral device is lost, an
OSError is raised.
gattc_write_descriptor()
Issue a remote write to the connected peripheral to the specified descriptor.
connection.gattc_write_descriptor(descriptor_handle, data)
<descriptor_handle>
The <descriptor_handle> parameter is a descriptor handle discovered from gattc_descriptors.
<data>
The <data> parameter specifies the data to be written to the remote descriptor.
Return value
gattc_write_descriptor returns None—in other words it has no return value.
If the descriptor handle passed in is invalid or the connection to the peripheral device is lost, an
OSError is raised.
addr()
Returns the BLE peripheral device's address and address type.
Return value
addr A 2-tuple containing the BLE addressing information of:
close()
Close the connection. The connection object will no longer be usable.
connection.close()
config()
Query a BLE connection configuration value by name, or update one or more BLE connection
configuration values.
connection.config(name)
connection.config([interval_ms=..., ][latency=..., ][timeout_ms=..])
Query a value
To query a connection's BLE configuration value, pass the name of the value as a string. Currently
supported values are:
connection.config(interval_ms=100, timeout_ms=1000)
<interval_ms>
The connection interval is the time between two data transfer events on the GAP connection. The
value will be rounded down to the nearest multiple of 1.25 milliseconds. interval_ms may be
between 8 and 4000 (4 seconds).
Default value (restored at XBee power-up): 50 milliseconds.
<latency>
The slave latency is the number of consecutive connection events which the connected peripheral is
allowed to skip before the connection is dropped. latency may be between 0 and 500.
Default value (restored at XBee power-up): 0.
<timeout_ms>
The connection supervision timeout value is the time that the central device—in this case, the XBee—
will wait for a data transfer before assuming that the connection is lost. timeout_ms may be between
100 and 32000 (32 seconds). timeout_ms must be larger than 2 * timeout_ms * (latency + 1) .
Default value—restored at XBee power-up: 1000 milliseconds (1 second).
If the configuration could not be updated, an OSError is raised.
security
The security argument takes a bit mask of the following values:
n PAIRING_REQUIRE_MITM: If set, MITM protection must be used during the pairing process. It
is an error to attempt to set this flag when no I/O callbacks have been set yet with the io_
callbacks() method.
n PAIRING_REQUIRE_BONDING: Require the use of bonding to enable encryption. When
connections are secured bonding table entries are created to remember the negotiated keys
for future sessions. The device will remember up to 13 bonding table entries. If an attempt to
bond with additional devices occurs when the bonding table is full the least recently used
bonding table entry is dropped to allow insertion of the new entry.
n PAIRING_DISABLE_LEGACY: Disables the use of legacy pairing when securing the connection,
only LE Secure Connections will be used.
isconnected()
Determines whether BLE is connected to a BLE peripheral device.
connection.isconnected()
Return value
isconnected returns True if the BLE is connected to BLE peripheral device, False otherwise.
secure()
Performs pairing/bonding on a connection.
secure(secure_cb)
<secure_cb>
A callback which is called upon completion of the pairing operation. It is passed the value zero if the
pairing succeeded, otherwise it is passed an error code as documented in the BLE Core specification.
Values between 0-127 are from Vol 11, Part F. Values from 128-255 are Pairing Errors and can be seen
in Vol 3, Part H, section 3.5.5 in Table 3.7.
See also the security argument to ble.config to guide the behavior of the pairing/bonding operation.
io_callbacks()
Provide callbacks that define IO capabilities for pairing.
<display_cb>
Callback to be used to present a passkey to the user.
<confirm_cb>
Callback to be used when the user must confirm (Y/N) a passkey. The passkey is provided as an
argument. The passkey should be presented to the user and the user's input should be fed back using
ble.passkey_confirm.
Note If you are providing a display_cb and request_cb, you must provide a confirm_cb. Based on
the I/O capabilities of the peer it may be necessary to perform either input or confirmation of a
passkey.
<request_cb>
Callback to indicate that the user must input a passkey value. The user should be prompted to enter a
passkey and the passkey provided by the user should be fed back using ble.passkey_enter.
Note The BLE standards recommend that the passkey be presented to the user as a six digit number
padded with leading zeros.
delete_bondings()
Remove all stored bonding table entries.
delete_bondings()
This function deletes the contents of the bonding table. This puts the device back into the initial state
and can be used to provision a device for redeployment or during development for device testing.
passkey_enter()
Allows user entry of a passkey value.
passkey_enter(passkey)
<passkey>
The numeric value of the passkey provided by the user.
passkey_confirm()
Allows user confirmation of BLE pairing passkey.
passkey_confirm(confirmation)
<confirmation>
Provide True if the passkey provided by the confirm_cb is correct, False otherwise.
UUID()
Create a UUID container.
ble.UUID(value)
<value>
The value parameter can be either:
Return value
A UUID object containing the passed UUID.
To read the UUID value, convert the UUID object into a bytes or bytearray object:
uuid = ble.UUID(0x1010)
uuid_value = bytes(uuid)
# b'\x10\x10'
The size, in bytes, of the UUID value can be determined using the built-in len function:
gap_scan()
Run a GAP scan/discovery operation to collect advertisements from nearby BLE devices.
<duration_ms>
The <duration_ms> parameter specifies the duration of the GAP scan operation, in milliseconds. To
scan indefinitely, set <duration_ms> to 0.
<interval_us>, <window_us>
Use <interval_us> and <window_us> to optionally configure the duty cycle. The scanner will run
for <window_us> microseconds every <interval_us> microseconds.
The default interval and window are 1.28 seconds and 11.25 milliseconds, respectively. Both values
must be at least 2,500 microseconds (2.5 milliseconds) and no more than approximately 40.96
seconds (40,959,375 microseconds).
<oldest>
Received GAP advertisements are stored in order from oldest (earliest-received) to newest (most-
recently-received). When the internal queue of advertisements is full, the default behavior is to
discard the oldest advertisement in order to make room for the newly-received advertisement.
If your application depends on retaining older advertisements at the expense of losing newer
advertisements, set the oldest argument to True. This will cause new advertisements to be discarded
if the internal queue is full.
Return value
If the GAP scan operation is started successfully, a gap_scan object is returned.
If the GAP scan operation is not able to be started, an OSError is raised.
gap_scan methods
The methods available on a gap_scan object—returned by the gap_scan() function—are as follows.
get()
Return a list of all received GAP advertisements currently in the internal queue. This list may be
empty.
If the GAP scan has timed out—see <duration_ms> argument—or stop() has been called, this method
will return any remaining advertisements, but no new advertisements will be stored.
any()
Returns True if there are any GAP advertisements in the internal queue, otherwise returns False.
stop()
Stop the ongoing GAP scan operation. Any already-received GAP advertisements will be retained—
see get().
stopped()
Returns True if the GAP scan operation has been stopped—using stop()—or has timed out, otherwise
returns False.
n address: The BLE MAC address of the received advertisement. Formatted as a bytes object.
n addr_type: The type of address contained in the address field. The possible values are defined
as constants on the digi.ble module:
n connectable: True if the advertising device indicates that BLE central-mode devices may
connect to it, False otherwise.
n rssi: The received signal strength of the advertisement, in dBm.
n payload: The raw advertisement payload. Formatted as a bytes object.
def find_advertisement(search_string):
scan = ble.gap_scan(duration_ms=0)
try:
for adv in scan:
if search_string in adv["payload"]:
return adv
finally:
# Make sure to call stop(), even if an exception is raised.
scan.stop()
If you instead use gap_scan as a context manager, using the with statement, you do not need a
try/finally block, nor do you need to call stop() yourself.
def find_advertisement(search_string):
with ble.gap_scan(duration_ms=0) as scan:
for adv in scan:
if search_string in adv["payload"]:
return adv
gap_advertise()
Start or stop GAP advertisements from the XBee device.
ble.gap_advertise(interval_us, adv_data=None)
<interval_us>
Start advertising at the specified interval, in microseconds. This value will be rounded down to the
nearest multiple of 625 microseconds. The interval, if not None, must be at least 20,000 microseconds
(20 milliseconds) and no larger than approximately 40.96 seconds (40,959,375 microseconds).
To stop advertising, set <interval_us> to None.
<adv_data>
This is the payload that will be included in GAP advertisement broadcasts. <adv_data> can be
a bytes or bytearray object up to 31 bytes in length, or None.
If <adv_data> is empty—for example b''—then GAP advertising will return to the default XBee
behavior, which is to advertise the product name—such as XBee3 Zigbee, or the value in ATBI.
If <adv_data> is None or not specified, then the data passed to the previous call to gap_advertise is
used, unless there was no previous call or the previous data was empty, in which case the behavior
will be as if an empty value—b''—was passed.
Otherwise, <adv_data> should consist of one or more Advertising Data (AD) elements, as defined in
the Bluetooth Core Specification Supplement, Part A Section 1.
n Each AD element consists of a length byte, a data type byte, and one or more bytes of data.
The length byte indicates how long the rest of the element is, for example a Complete Local
Name element with value My XBee would have a length byte 0x08 – 1 byte for type plus 7
bytes for the value.
n The Bluetooth SIG provides the list of defined Advertising Data element types
here: https://www.bluetooth.com/specifications/assigned-numbers/generic-access-profile/
Be aware that <adv_data> must be formatted as one or more Advertising Data elements in order to
be interpreted as a valid Bluetooth Low Energy advertisement by other devices. For example, to
advertise the name My XBee:
Return value
gap_advertise returns None—i.e. it has no return value.
If BLE functionality is not currently active—see active()—gap_advertise will raise an OSError.
xbee_connect()
Authenticates to a connected XBee 3 over BLE and provides access to the API Service running on the
remote XBee.
<gap_connection>
The <gap_connection> parameter takes the result of calling ble.gap_connect previously and the
connected device should be another XBee 3 device offering the BLE API Service.
CAUTION! If using xbee_connect refrain from using characteristics from the API service
directly as well because that will corrupt the state maintained by the xbee_connection
object.
For more information on the API Service see the user guide for your device, for example the BLE
Unlock API frame and XBee API BLE Service.
<receive>
The <receive> parameter takes a callable MicroPython function. The function should accept a single
argument and return None. After authentication with the remote XBee device, this callback will be
called whenever an API frame from the peer is ready to be processed. The callback will be called with
the entire frame as an object of type bytes, including initial delimiter and checksum. The checksum is
validated by the internal logic. Bad data from the peer will be dropped with no calls to the callback.
<password>
The <password> parameter is the password to be used to authenticate with the remote XBee device.
<timeout>
The <timeout> parameter is a value in seconds. If the authentication has not completed within
<timeout> seconds an exception of type OSError will be raised with the value ETIMEDOUT.
Acceptable values are within the range of 5-60 seconds.
Return value
On success an object of type xbee_connection is returned.
xbee_connection methods
Currently the xbee_connection object only offers a single method. The send method takes a bytes
object as an argument and transmits it to the connected remote peer over the encapsulated gap_
connection object. The bytes object should constitute a legal API frame for the remote peer to
process. The send method does not validate transmit data.
To ensure that an API frame has the correct format, consult the product user guide, for example: API
frame format.
digi.ble samples
On the digidotcom github there are Bluetooth sample programs found here. Read the accompanying
README for each sample for guidance on usage.
iBeacon samples
There are two samples available for iBeacon, both of which require the provided iBeacon Library.
The first sample is iBeacon_advertise, which forms and advertises iBeacon beacons.
The second sample is iBeacon_scan, which scans for and prints out any iBeacon beacons it discovers.
Troubleshooting
Note This section only applies to the XBee Cellular Modem. See Which features apply to my device?
for a list of the supported features.
The network configuration module provides network drivers for specific hardware, which you can use
to configure the hardware network interfaces.
Note The Digi version of MicroPython differs from MicroPython regarding the SSL API. The XBee
Cellular Modem supports secure sockets via the usocket.IPPROTO_SEC option to the usocket.socket
() constructor, but does not include the ussl module for wrapping sockets and providing certificates
and keys.
def uart_init():
u = UART(1)
u.write('Testing from XBee\n')
return u
def uart_relay(u):
while True:
uart_data = u.read(-1)
if uart_data:
sys.stdout.buffer.write(uart_data)
stdin_data = sys.stdin.buffer.read(-1)
if stdin_data:
u.write(stdin_data)
time.sleep_ms(5)
u = uart_init()
uart_relay(u)
For information about the cellular class, which provides a driver for the Cellular modem in the XBee,
see class Cellular.
class Cellular
Note This section only applies to the XBee Cellular Modem. See Which features apply to my device?
for a list of the supported features.
This class provides a driver for the cellular modem in the XBee device.
For example:
import network
import time
cellular = network.Cellular()
while not cellular.isconnected():
time.sleep_ms(50)
print(cellular.ifconfig())
Constructors
Use the constructor to create an XBee Cellular object.
class network.Cellular()
cellular.active([mode])
Without parameters:
Note No changes to the XBee Cellular Modem are made if the parameter matches the current mode.
cellular.isconnected()
n True: The XBee Cellular Modem is connected to a cellular network and has a valid IP address.
n False: Otherwise.
n deep=True: A more comprehensive search, but may take more time to run.
n deep=False: A quick check, but may return fewer results.
Note Refer to the documentation for the AS command on your Cellular device for more details on
how a “deep” scan may affect your network connectivity.
cellular.sms_send(phone, message)
where:
n phone: The phone number of the device to which the message should be sent. This variable
can be a string or an integer.
n message: The contents of the message. The message should be a string or a bytes object of 7-
bit ASCII characters.
Possible return values:
n None: The cellular network acknowledges receipt of the message. The method throws a
ValueError for invalid parameters.
Throws an OSError exception:
cellular.sms_receive()
cellular.sms_callback(my_callback)
Note When a callback is registered, using cellular.sms_receive() will raise an error as only one
method of SMS delivery is supported at a time.
cellular.shutdown(reset=[reset])
key
rsrp Reference Signal Received Power in dBm
rsrq Reference Signal Received Quality in dB
If the module is in a PSM dormant state, the signal() function will throw an ENOTCONN error.
It is possible for the device to be in a state where signal information is not provided in a timely
fashion, so the function will raise an OSError with value ETIMEDOUT should it take longer than five
seconds to attempt to retrieve the signal values.
This applies to all XBee Cellular LTE variants, but not to the XBee Cellular 3G Global Embedded
Modem.
Command Alternative
AS - Active Scan cellular.scan() method.
DB - RSSI networking.Cellular().signal() method.
DN - Discover Node
ED - Energy Detect
FS - Filesystem access Native Python file system methods.
IS - IO sampling The Pin class.
LA - DNS lookup Perform getaddrinfo() cal.
ND - Network Discovery xbee.discover() function.
PG - Ping
SD - Shutdown Cellular shutdown method.
SQ - RSRQ networking.Cellular().signal() method.
SW - RSRP networking.Cellular().signal() method.
!R - Cell module reset
Use this function to output information about the XBee device that is hosting MicroPython.
import xbee
x = xbee.XBee() #Create an XBee object
print(x.atcmd('MY'))
Constructors
Use this class to create an XBee Cellular object for the XBee Cellular Modem that is hosting
MicroPython.
class xbee.XBee()
Methods
Use this method to send an AT command to the XBee Cellular Modem.
x.atcmd(cmd[, value])
<cmd>
The <cmd> parameter is a two-character string that represents the command.
For detailed information about the AT commands that you can use with the XBee device, see the AT
commands section in the appropriate user guide.
<value>
The <value> parameter is optional.
n If the <value> parameter is NOT set: The function executes the AT command and, depending
on the command, returns the result as either a string, bytes object, an integer, or None. Some
commands simply return a value; other AT commands, such as special commands and
execution commands, change the behavior of the XBee device. For example, FR resets the
device.
n If the <value> parameter is set: You can specify a value in a string, btyearray, or integer format.
The function passes the value to set the AT command.
For examples of how to use the AT commands with the XBee device, see XBee device examples.
Functions
The xbee MicroPython module supports the following functions:
atcmd()
Use this function to set or query an AT command on the XBee device.
xbee.atcmd(cmd[, value])
<cmd>
The <cmd> parameter is a two-character string that represents the command.
Note Some AT commands do not work in MicroPython. See AT commands that do not work in
MicroPython.
For detailed information about the AT commands that you can use with the XBee device, see the AT
commands section in the appropriate user guide.
<value>
The <value> parameter is optional.
n If the <value> parameter is not set: The function executes the AT command and, depending on
the command, returns the result as either a string, bytes object, an integer, or None. Some
commands simply return a value; other AT commands, such as special commands and
execution commands, change the behavior of the XBee device. For example, FR resets the
device.
n If the <value> parameter is set: You can specify a value in a string, btyearray, or integer format.
The function passes the value to set the AT command.
For examples of how to use the AT commands with the XBee device, see XBee device examples.
discover()
Use this function to perform a network discovery, which is equivalent to issuing the ND command.
The timeout for the discovery is determined by the N? command.
xbee.discover()
This function accepts no parameters, and returns an iterator yielding a dictionary for each discovered
node.
Note xbee.discover() returns immediately, but querying the resulting iterator will block execution
until a response is available or the discovery times out (as determined by N?). See the xbee.discover
() examples for more information.
Note Some of these fields may be excluded depending on what protocol the XBee device is running.
{
'rssi': -20,
'node_id': ' ',
'device_type': 1179648,
'parent_nwk': 65534,
'sender_nwk': 41334,
'sender_eui64': b'\x00\x13\xa2\x00\x92w%`',
'node_type': 1
}
{
'rssi': -20,
'node_id': ' ',
'sender_nwk': 41334,
'sender_eui64': b'\x00\x13\xa2\x00\x92w%`',
}
{
'rssi': -20,
'node_id': ' ',
'device_type': 1179648,
'sender_eui64': b'\x00\x13\xa2\x00\x92w%`',
'node_type': 1
}
receive()
The XBee device has a MicroPython receive queue that stores up to four incoming packets.
If the device is operating in MicroPython REPL (AP is set to 4) and the receive queue is full, it silently
rejects any additional incoming packets:
n On the XBee 3 Zigbee device, the sending node receives a transmission status of 0x24
(Address not found).
n On the XBee 3 DigiMesh or XBee 3 802.15.4 device, the sending node receives a transmission
status of 0x00 (Success) in this case.
Note DigiMesh does not acknowledge packets at the application level, so if a packet is delivered to
the device while the receive queue is full the sender still sees it as a successful transmission. If you
need to verify that MicroPython has received data, you need to send an acknowledgment using
xbee.transmit() and look for that acknowledgment on the sender.
Note We recommend calling the receive() function in a loop so no data is lost. On devices where
there is a high volume of network traffic, there could be data lost if the messages are not pulled from
the queue fast enough.
xbee.receive()
This function accepts no parameters, and returns either None when there is no packet waiting, or a
dictionary containing the following entries:
n sender_nwk: the 16-bit network address of the sending node. This field is absent on DigiMesh
devices, as devices on a DigiMesh network do not have 16 bit addresses.
n sender_eui64: the 64-bit address (as a bytearray) of the sending node. If no 64-bit address is
present, such as when the sending device on an 802.15.4 network is using 16 bit addressing,
this field will have the value None.
n source_ep: the source endpoint as an integer
{
'cluster': 17,
'dest_ep': 232,
'broadcast': False,
'source_ep': 232,
'payload': b'Sample payload',
'profile': 49413,
'sender_nwk': 63941,
'sender_eui64': b'\x00\x13\xa2\x00\x92w%`'
}
receive_callback(rx_callback)
Register a callback function that will be called whenever an RF transmission is received by the device.
The callback function should take a single parameter, a dictionary in the same format used by the
receive() method. Calling receive_callback(None) de-registers the receive callback if one is
registered.
Note The receive() method cannot be called while a callback is registered. Attempting to do so raises
an exception.
transmit()
Use this function to transmit a packet to a specified destination address. This function either succeeds
and returns None, or raises an exception. Here is a partial list of the exceptions to expect:
<dest>
The <dest> parameter is the destination address of the message, and accepts any of the following:
n an integer for 16-bit addressing (only available on the XBee 3 Zigbee and 802.15.4)
n an 8-byte bytes object for 64-bit addressing
n the constant xbee.ADDR_BROADCAST to indicate a broadcast destination
n the constant xbee.ADDR_COORDINATOR to indicate the coordinator (only available on the
XBee 3 Zigbee and 802.15.4)
There are multiple ways to create the 8-byte bytes object for 64-bit addressing:
n as a bytestring: b'\x00\x13\xa2\x00\x41\x74\x07\xa6'
n using the bytes() constructor with a list of decimal values: bytes([0, 19, 162, 0, 65, 116, 7,
166])
n using the bytes() constructor with a tuple of hex values: bytes((0x00, 0x13, 0xa2, 0x00, 0x41,
0x74, 0x07, 0xa6))
Note You can also pass a list of hex values or a tuple of decimal values to bytes().
<payload>
The <payload> parameter should be a string (for example, 'Hello World!') or bytes object (useful for
sending binary data).
<source_ep>
Optional 8-bit Source Endpoint for the transmission, defaulting to xbee.ENDPOINT_DIGI_DATA.
<dest_ep>
Optional 8-bit Destination Endpoint for the transmission, defaulting to xbee.ENDPOINT_DIGI_DATA.
<cluster>
Optional 16-bit Cluster ID for the transmission, defaulting to xbee.CLUSTER_DIGI_SERIAL_DATA.
<profile>
Optional 16-bit Cluster ID for the transmission, defaulting to xbee.PROFILE_DIGI_XBEE.
<bcast_radius>
Optional 8-bit value to set the maximum number of hops a broadcast transmission can traverse.
Default is 0.
<tx_options>
Optional 8-bit bitfield that configures advanced transmission options. See the protocol-specific user
guide for TX Options usage.
Note All of the optional parameters are keyword-only, and require the following firmware versions or
higher:
* XBee 3 Zigbee: version 1007
* XBee 3 802.15.4: version 2004 - Endpoints, cluster ID, profile ID, and broadcast radius can be used on
802.15.4 but are effectively non-functional.
* XBee 3 DigiMesh 2.4: version 3003
modem_status
The modem_status module provides ways to handle modem status messages within MicroPython. All
modem statuses are reported to MicroPython with the exception of hardware reset/watchdog reset.
See the documentation for the Modem Status (0x8A) API frame of the device you use for a list of
possible status values.
Note Hardware/watchdog reset modem statuses are not sent to MicroPython. Use machine.reset_
cause() instead.
Note Modem statuses sent to MicroPython are stored on a queue with limited space. If modem
statuses are to be handled receive() should be called frequently or a callback should be registered
soon after the device boots to avoid missing data.
modem_status.receive()
If a modem status is available, the receive() function returns its status code. If no modem status is
available, the function returns None.
The following code polls for modem statuses and prints them as they are received:
import xbee
while True:
status = xbee.modem_status.receive()
if status is not None:
print("Received status: {:02X}".format(status))
modem_status.callback(my_callback)
Registers a callback that will be called whenever a modem status is received. The callback function
must take one parameter, an integer containing the status code.
The following code registers a callback to print modem statuses when they are received:
import xbee
def status_cb(status):
print("Received status: {:02X}".format(status))
xbee.modem_status.callback(status_cb)
Note This section only applies to the XBee Cellular Modem with firmware version ending in *11 or
newer. See Which features apply to my device? for a list of the supported features.
You can add multiple data points to a stream, and/or uploads points to multiple streams, in a single
request.
data = cloud.DataPoints()
data.add("stream1", 1234)
data.add("stream1", 2345)
data.add("stream2", "value")
data.send()
If you prefer, you can also use the digi.cloud module as follows:
import digi
data = digi.cloud.DataPoints()
class DataPoints
Constructor
Use the constructor to create a DataPoints object.
cloud.DataPoints([transport])
Optional parameter
n transport: The transport method used to deliver the data points. Acceptable values are
digi.cloud.TRANSPORT_TCP (the default transport) and digi.cloud.TRANSPORT_UDP.
If the Digi Remote Manager feature is disabled (bit 0 of ATDO is cleared), this will raise a TypeError
indicating that the Remote Manager feature is disabled.
If there are not enough resources available in the system to create the DataPoints object, or your
application has created too many DataPoints objects without allowing some to be garbage-collected,
an OSError will be raised with an error code of ENOBUFS.
Note DataPoints objects using the digi.cloud.TRANSPORT_UDP transport are limited to one data
point per DataPoints container.
Required parameters
n stream_name: Specifies the data stream name to which this data point is added.
n value: The value to assign to this data point. Currently the only supported types are integer
and string.
Return value
None.
If any of the parameters values are of an inappropriate type (such as an integer for stream name), a
TypeError or ValueError is raised indicating the problem.
This method will raise an OSError with the error code ENOSPC when there is not enough room to add
the data point to the upload buffer. The amount of space each data point consumes in the buffer
varies based on the length of the string value and how many of the optional parameters are specified.
Note DataPoints objects that use the TRANSPORT_UDP transport are limited to one data point per
DataPoints container.
data.send([timeout=30])
Return value
None.
If the Digi Remote Manager feature is disabled (bit 0 of ATDO is cleared), this raises a TypeError
indicating that the Remote Manager feature is disabled.
If there is no data to be uploaded, an OSError EINVAL is raised.
If a blocking upload fails (due to a network issue or command timeout), an OSError is raised.
If the "Sleepy Digi Remote Manager" feature is being used (ATMO bit 0 is cleared) and the transport
selected is TRANSPORT_TCP, this method causes a temporary TCP/SSL connection to be created.
data.status()
Return value
n digi.cloud.IDLE: send has never been called.
n digi.cloud.SENDING: The most recent send call is still being processed.
n digi.cloud.SUCCESS: The most recent send call has succeeded.
n Any other value is a negative uerrno value for the most recent send call. For example,
uerrno.EIO.
data.send()
# success
del data
The del statement is not necessary if the DataPoints object goes out of scope. One example of this is
when the DataPoints object was created inside of a function:
def upload_data(value):
data = cloud.DataPoints()
data.add("my_stream", value)
data.send()
upload_data(123)
Note that the DataPoints object will not be garbage-collected if another object holds a reference to
the DataPoints object. Placing the DataPoints object inside a container such as a list, tuple, or
dictionary will cause this.
data = cloud.DataPoints()
my_list = []
my_list.append(data) # my_list now keeps `data` alive
my_dict = {"data": data} # my_dict now keeps `data` alive
my_tuple = (data, 123) # same here
import time
from digi import cloud
while 1:
request = cloud.device_request_receive()
if request is not None:
body = request.read()
request.write(data)
request.close()
time.sleep(5)
If you prefer, you can also use the digi.cloud module as follows:
import digi
request = digi.cloud.device_request_receive()
class device_request
This class is returned from digi.cloud.device_request_receive().
The device_request class is a file-like object containing the payload of the request that can be read.
A response can be sent back to Digi Remote Manager using the write method.
request.read(size=-1)
request.readinto(b)
Note All data from the request should have been read before issuing a write.
request.write(b)
Note The request should not be written to or read after a close call.
request.close()
5. Replace the target_name value with micropython and enter the data for the device request
between the <device_request> XML tags.
<sci_request version="1.0">
<data_service>
<targets>
<device id="00000000-00000000-00000000-00000000"/>
</targets>
<requests>
<device_request target_name="micropython">
This is a Device Request sample
</device_request>
</requests>
</data_service>
</sci_request>
6. Click Send.
digi.cloud.Console() object
Note This applies to XBee 3 Cellular Modem modules in firmware x18 and newer.
Class providing access to the Digi Remote Manager console interface. To use the Digi Remote Manager
console you must establish a TCP session to Digi Remote Manager.
isconnected() method
Returns a boolean indicating whether a console session is attached from Digi Remote Manager.
read(size) method
Reads from the Digi Remote Manager console.
Reads up to size bytes from the object and returns them. As a convenience, if size is unspecified or -1,
all bytes until end-of-file (EOF) are returned.
Returns the data read, or None if no data is available.
readinto(buf) method
Reads from the Digi Remote Manager console into a buffer object.
Reads bytes into a pre-allocated writable bytes-like object and returns the number of bytes read or
None if no data is available. This call is non-blocking.
write(buf) method
Write to the Digi Remote Manager console.
Send the data in buf to a connected Digi Remote Manager console session. If no console is currently
attached the data is discarded. Returns the number of bytes written.
close() method
Close the session tracked by the current Console() object.
Note This section only applies to the XBee Cellular Modem. See Which features apply to my device?
for a list of the supported features.
n You can only wrap a socket created with protocol IPPROTO_SEC. Python3 uses IPPROTO_
TCP.
n You can only wrap a socket before calling the connect() method. Python3 allows for opening a
socket, performing unencrypted communications, and then upgrading the connection to use
TLS, for example, via the STARTTLS command supported in some protocols.
n In Python3, wrap_socket() creates a new ssl.SSLSocket object and the original socket.socket
remains intact. MicroPython on the XBee Cellular Modem converts the original socket.socket
to a ussl.SSLSocket with the same methods.
n Python3 allows for including the key with the device's certificate in a single file for the certfile
keyword parameter, but MicroPython on the XBee Cellular Modem requires separate files for
the certificate and key.
n If specifying a device certificate, you must also provide a ca_certs file.
Syntax
Usage
ussl.wrap_socket(sock, keyfile=None, certfile=None, ca_certs=None, server_side=False, server_
hostname=None)
n sock: Socket object created with IPPROTO_SEC and not already wrapped.
n keyfile: Name of a file containing the private key for certfile (also stored as a Base64 PEM file).
n certfile: Name of a file containing this device's public X.509 certificate as a Base64 PEM file.
When specifying certfile, you must also specify keyfile and ca_certs.
n ca_certs: Name of a file containing a single public X.509 certificate of the trusted certificate
authority (CA) for the remote host. Connections with remote devices only succeed if they have
a certificate signed by the CA listed in ca_certs. Unlike Python3, which supports multiple
certificates in ca_certs, MicroPython on the XBee Cellular Modem only supports a single
certificate in this file. In order to authenticate a server not participating in a PKI (using CAs) the
server must present a self-signed certificate. That certificate can be used in the ca_certs field
to authenticate that single server.
n server_side: currently ignored.
n server_hostname: reserved for future support of Server Name Indication (SNI).
wrap_socket() returns the wrapped socket object as a SSLSocket object. Filenames are relative to
MicroPython's current working directory, which defaults to /flash and changes via the uos.chdir()
method. Use an absolute path like /flash/cert/server.pem to ignore the current working directory
when resolving the filename.
single_acquisition(callback, timeout=60)
Request the GNSS location data to be acquired. This returns that location data using the location_cb
callback registered in the GNSS class constructor.
When this times out the callback is called with None.
Required parameter
callback
A user callback that will be called whenever new location data is requested. See the class methods
that follow for details on requesting location data.
The callback function must take one parameter:
A dictionary with the following keys:
Note On the XBee 3 Global LTE-M/NB-IoT modules, when gathering non-cached location data there
will be interruptions to the cellular network because the radio is shared.
Optional parameter
timeout
The amount of time to try to acquire a location before giving up.
If the timeout is zero, this will callback the cached location value or None if a cached value is
notavailable.
Return value
This always returns None.
If there is already a request active, an OSError EBUSY is raised.
raw_mode(callback)
Request access to NMEA 0183 data stream.
When a callback has been provided, the callback will be called periodically with NMEA 0183 sentences
containing location information.
CAUTION! On the XBee 3 Global LTE-M/NB-IoT modules, access to GNSS disables access to
the cellular network. The MicroPython application needs to enable and disable raw mode as
necessary.
Parameters
callback
Callback provided by the user, None to disable raw mode. The callback function should accept a
single bytes-type parameter which provides full NMEA 0183 sentences.
Errors
n OSError
EBUSY — Error when GNSS is already in use for other functionality —one_shot, and so forth.
GNSS examples
We have provided example applications which demonstrate how to use the GNSS module from
MicroPython. You can read these examples on GitHub:
n https://github.com/digidotcom/xbee-micropython/tree/master/samples/gnss_raw
n https://github.com/digidotcom/xbee-micropython/tree/master/samples/gnss_single
This example shows a typical acquisition of location data:
def my_location_callback(data):
if data is None:
print("The attempt to get a location timed out")
else:
print("Got a location: {}".format(data))
gnss.single_acquisition(my_location_callback)
dupterm(stream_obj, index=0)
Note This applies to XBee 3 Cellular Modem modules in firmware x18 and newer.
Note This section only applies to the XBee Cellular Modem. See Which features apply to my device?
for a list of the supported features.
You can use MicroPython to connect an XBee Cellular Modem to the Amazon Web Services (AWS) IoT
cloud.
1. If you do not already have one, sign up for a Basic AWS account with twelve months of free tier
access.
2. You can add devices and generate certificates, but they might not be able to connect until you
receive an email from Amazon confirming that your AWS account is ready.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"iot:Connect",
"iot:GetThingShadow",
"iot:Publish",
"iot:Receive",
"iot:Subscribe"
],
"Resource": [
"*"
]
}
]
}
Once you have things working, you can switch to a more restrictive policy that limits a Thing to
connecting with its ThingName as its ClientId, and publishing and subscribing only to topics under its
type/name in the topic hierarchy.
The client ARNs follow this format:
arn:aws:iot:your-region:your-aws-account:client/<my-client-id>
Note Replace the region and account numbers in the following sample code with your own
information.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "iot:Connect",
"Resource": "*",
"Condition": {
"Bool": {
"iot:Connection.Thing.IsAttached": [
"true"
]
},
"StringEquals": {
"iot:ClientId": "${iot:Connection.Thing.ThingName}"
}
}
},
{
"Effect": "Allow",
"Action": [
"iot:Publish",
"iot:Receive"
],
"Resource": [
"arn:aws:iot:us-east-
1:123456789012:topic/${iot:Connection.Thing.ThingTypeName}/${iot:Connectio
n.Thing.ThingName}",
"arn:aws:iot:us-east-
1:123456789012:topic/${iot:Connection.Thing.ThingTypeName}/${iot:Connectio
n.Thing.ThingName}/*"
]
},
{
"Effect": "Allow",
"Action": [
"iot:Subscribe"
],
"Resource": [
"arn:aws:iot:us-east-
1:123456789012:topicfilter/${iot:Connection.Thing.ThingTypeName}/${iot:Con
nection.Thing.ThingName}",
"arn:aws:iot:us-east-
1:123456789012:topicfilter/${iot:Connection.Thing.ThingTypeName}/${iot:Con
nection.Thing.ThingName}/*"
]
}
]
}
Create a Thing
From the AWS services page, choose IoT Core.
In AWS IoT:
1ATS endpoints include -ats as part of the hostname. ATS endpoint <host_prefix>-ats.iot.<aws_
region>.amazonaws.com where <host_prefix>-ats is the full hostname and <aws_region> is the region of your
endpoint. Legacy endpoints omit the -ats postfix string so the endpoint becomes <host_prefix>.iot.<aws_
region>.amazonaws.com.
Use XCTU or ATFS commands in a terminal emulator to upload the three files to the cert/ directory on
the XBee device. For security, use ATFS XPUT to upload the aws.key as a secure file. We recommend
using the Starfield Services Root Certificate from amazontrust.com/repository/ as the intermediate CA
certificates provided by Amazon do not work on some cellular modules. Note the Verisign certificate is
now considered legacy by Amazon.
Many of the intermediate root certificate authorities on the AWS repository
(amazontrust.com/repository/) do not work with the TLS implementation on the XBee Cellular
Modems. To ensure that you have success, you need to use a specifc Starfield Technologies Root
Certificate Authority depending on which XBee you are using.
If you are using one of the CAT 1 XBee Cellular devices, use the Starfield Class 2 Certification
Authority Root Certificate instead of the ones recommended by Amazon. If you are using the LTE-
M/NB-IoT or 3G devices, you need to use the Starfield Services Root Certificate Authority
certificate. Note that the Amazon certificates are in the trust chain of these two certificates. It has the
following SHA-256 thumbprint and can be obtained from Starfield Technologies.
Authority -
G2
s = socket.socket()
w = ssl.wrap_socket(s,
keyfile='cert/aws.key',
certfile='cert/aws.crt',
ca_certs='cert/aws.ca')
w.connect((aws_endpoint, 8443))
w.write(b'GET /things/%s/shadow HTTP/1.0\r\nHost: %s\r\n\r\n' % (thing_
name, aws_endpoint))
print(str(w.read(1024), 'utf-8'))
w.close()
You should see sample output something like this on you computer:
HTTP/1.1 200 OK
content-type: application/json
content-length: 61
date: Thu, 05 Jul 2018 01:24:15 GMT
x-amzn-RequestId: 37e93081-06f5-0bc2-1384-5a129eb0ac30
connection: keep-alive
{"state":{},"metadata":{},"version":1,"timestamp":1530753855}
Once you confirm that the certificates and policy on your AWS account are correct, you can test on
the XBee device with the following code. It configures the socket as non-blocking in order to return
any amount of data read instead of blocking until receiving the full byte count (for rexample, 1024
below).
Note It is easiest to use paste mode by pressing CTRL-E from the REPL.
while True:
try:
w.connect((aws_endpoint, 8443))
break # connection complete
except OSError as e:
# Nonblocking socket will raise OSError EINPROGRESS
# until the connection is complete or an error occurs.
if e.args[0] == uerrno.EINPROGRESS:
# Sleep for a moment before checking connection status again.
time.sleep_ms(100)
else:
# Some other error (such as ETIMEDOUT) occurred.
raise
while True:
data = w.read(1024)
if data:
print(str(data, 'utf-8'))
break
w.close()
The XBee device includes additional blank lines because the HTTP response uses CRLF for line
endings, and starts with the return value of the w.write() call (in this case, 92 bytes written):
92
HTTP/1.1 200 OK
content-type: application/json
content-length: 61
x-amzn-RequestId: 0744caf6-2162-1d4f-c4f9-67a2d7ff2ce9
connection: keep-alive
{"state":{},"metadata":{},"version":1,"timestamp":1530818883}
Publish to a topic
You can use the umqtt.simple module to publish data to a topic. This code demonstrates publishing
to a topic based on the Thing type and name.
"""
Copyright (c) 2018, Digi International, Inc.
Sample code released under MIT License.
Instructions:
- If you want to change any of the params in the method, call the method
again
and pass in the params you want
"""
conn = network.Cellular()
while not conn.isconnected():
print("waiting for network connection...")
time.sleep(4)
print("network connected")
# topic: "sample/xbee"
# message: {message: AWS Samples are cool!}
print("publishing message...")
c.publish("sample/xbee", '{"message": "AWS Sample Message"}')
print("published")
c.disconnect()
print("DONE")
publish_test()
Note You will not see old messages, so open the Test console before running the sample code on
your device.
You can also navigate to your Thing and choose Activity to monitor when your Thing makes an MQTT
connection and then disconnects it.
"""
Copyright (c) 2018, Digi International, Inc.
Sample code released under MIT License.
Instructions:
- If you want to change any of the params in the method, call the method
again
and pass in the params you want
"""
msgs_received = 0
conn = network.Cellular()
while not conn.isconnected():
print("waiting for network connection...")
time.sleep(4)
print("network connected")
subscribe_test()
Note This section only applies to devices that support the Real Time Clock feature.
Use the time module to get the current time on the cellular network. The XBee Cellular Modem must
be connected to the cellular network.
The following examples describe coding the time module.
Note Day of week is 0 - 6 for Monday - Sunday and day of year is 1 - 366.
Note You can copy and paste code from the online version of the Digi MicroPython Programming
Guide. Use caution with the PDF version, as it may not maintain essential indentations.
import time
print("\nPreparing to print the current time 5 times, once every 5
seconds.")
print("The time format is (year, month, day, hour, second, day,
yearday)\n")
for _ in range(5): # Loop 5 times.
print(time.localtime()) # Print out the current time.
print("Pause 5 seconds")
time.sleep(5)
print("Done!")
Pause 5 seconds
(2017, 5, 10, 11, 31, 5, 2, 130)
Pause 5 seconds
(2017, 5, 10, 11, 31, 10, 2, 130)
Pause 5 seconds
(2017, 5, 10, 11, 31, 15, 2, 130)
Pause 5 seconds
Done!
Note You can copy and paste code from the online version of the Digi MicroPython Programming
Guide. Use caution with the PDF version, as it may not maintain essential indentations.
import time
Note This section only applies to the XBee Cellular Modem. See Which features apply to my device?
for a list of the supported features.
You can use MicroPython code to check network connection on the XBee Cellular Modem.
The coding samples in the sections below show different methods you can use to check the network
connection.
n False: The XBee Cellular Modem is not connected to the cellular network. The IP address
reported by ifconfig() is 0.0.0.0.
n True: The XBee Cellular Modem is connected to the cellular network. All connection elements
should be populated.
Note that the connection elements that print depend on the XBee Cellular Modem network
configuration.
Note You can copy and paste code from the online version of the Digi MicroPython Programming
Guide. Use caution with the PDF version, as it may not maintain essential indentations.
Note You can copy and paste code from the online version of the Digi MicroPython Programming
Guide. Use caution with the PDF version, as it may not maintain essential indentations.
import network
import time
It is now connected
My IP address is 166.184.xxx.xxx
Note You can copy and paste code from the online version of the Digi MicroPython Programming
Guide. Use caution with the PDF version, as it may not maintain essential indentations.
import network
import time
Note This section only applies to the XBee Cellular Modem. See Which features apply to my device?
for a list of the supported features.
Sockets 156
Basic socket operations: sending and receiving data, and closing the network connection 156
Specialized receiving: send received data to a specific memory location 158
DNS lookup 159
Set the timeout value and blocking/non-blocking mode 160
Send an HTTP request and dump the response 162
Socket errors 163
Unsupported methods 163
Sockets
A socket provides a reliable data stream between connected network devices. You must import the
usocket module so that you can create and use socket objects.
If you are trying different socket examples and you have not power-cycled the XBee Cellular Modem or
cleared the MicroPython volatile memory (RAM), it is not necessary to re-type the following code, as it
remains in the memory.
Note You can copy and paste code from the online version of the Digi MicroPython Programming
Guide. Use caution with the PDF version, as it may not maintain essential indentations.
import usocket
# Create a TCP socket that can communicate over the internet.
socketObject = usocket.socket(usocket.AF_INET, usocket.SOCK_STREAM)
# Create a "request" string, which is how we "ask" the web server for
data.
request = "GET /ks/test.html HTTP/1.1\r\nHost:
www.micropython.org\r\n\r\n"
# Connect the socket object to the web server
socketObject.connect(("www.micropython.org", 80))
# Send the "GET" request to the MicroPython web server.
# A "GET" request asks the server for the web page data.
bytessent = socketObject.send(request)
print("\r\nSent %d byte GET request to the web server." % bytessent)
socketObject.readline()
socketObject.readline()
# The first 3 lines of the server's response
# will be received and output to the terminal.
HTTP/1.1 200 OK
Server: nginx/1.8.1
Date: Tue, 28 Mar 2017 21:31:22 GMT
First line
The first line in the response depends on whether a valid request was sent.
n Valid request: If a valid request was sent and it was processed correctly, the first line should
always be "HTTP/1.1 200 OK".
n Invalid request: If an invalid request was sent, a response similar to "HTTP/1.1 400 Bad
Request" is received. This can occur if a typographical error is the original request, or if you do
not specify the host in the request with the line "Host: www.example.com".
recv() call
The recv() call receives the remainder of the page data. In this example, the requested page is small,
so all of the data remaining after the 3 readline() calls is received in this one call.
Several more "response headers" are visible in the reply to this call, followed by some HTML tags,
such as "<!DOCTYPE>" and "<head>". The web page being requested in the example consists only of a
header that reads "Test", with text underneath it reading "It's working if you can read this!" This
content is visible within the response, all of the content is inside of "<body>" tags, and the header is
inside of "<h1>" tags, also visible in the response.
Additional examples
If you want to try this example on other web servers, and see the different responses, you can repeat
the previous steps, but replace the following:
n /ks/test.html: This is inside the "request" variable and you can replace it with with "/" or a
specific path on a server.
n www.micropython.org: This is inside the "request" variable AND inside the "address" variable
and you can replace it with the address of the site you want to test.
Note If you have not power-cycled the XBee Cellular Modem, and have not cleared the MicroPython
volatile memory (RAM) with a soft reboot, you do not need to re-type lines 2 or 4 of the above
example, since you already imported usocket and created the socket object. If you power off the XBee
Cellular Modem, however, or clear the MicroPython heap with a soft reboot, you need to import
usocket again and create the socket object again. Any variables you created will also no longer be in
memory.
Note You can copy and paste code from the online version of the Digi MicroPython Programming
Guide. Use caution with the PDF version, as it may not maintain essential indentations.
The following example shows how to receive data from a socket and save it to a buffer. The readinto
() method performs a read on the socket, as can be done with recv(), but puts the data into a buffer
specified by the user. This is useful for processing data since you can reuse a dedicated buffer for
received data, and processing operations can simply read from that buffer.
import usocket
# Create socket object.
socketObject = usocket.socket(usocket.AF_INET, usocket.SOCK_STREAM)
# Create address variable.
address = ("www.micropython.org", 80)
# Create request variable.
request = "GET /ks/test.html HTTP/1.1\r\nHost:
www.micropython.org\r\n\r\n"
# Create a blank array of bytes in memory, which can be used as a buffer.
buff = bytes object(1024)
# Connect the socket object to the web server specified in "address".
socketObject.connect(address)
# Send the GET request to the MicroPython web server.
bytessent = socketObject.send(request)
print("\nSent %d byte GET request to server\n" % bytessent)
DNS lookup
You can use the getaddrinfo() function in the socket module to perform a DNS lookup of a of a
domain name, or retrieve information about a domain name or IP address.
In this example, this code imports the socket module and uses getaddrinfo() to perform a
DNS lookup on www.micropython.org. The target port is 80.
For detailed information about getaddrinfo(), see
micropython.org/resources/docs/en/latest/wipy/library/usocket.html.
Note You can copy and paste code from the online version of the Digi MicroPython Programming
Guide. Use caution with the PDF version, as it may not maintain essential indentations.
import socket
# Return tuple (family, type, proto, canonname, sockaddr)
print("\nCalling getaddrinfo() for micropython.org on port 80,")
print("this will return information about the host address in the")
print("following format:")
print("[family, type, proto, canonname, sockaddr]\n")
print(socket.getaddrinfo('www.micropython.org', 80))
5. Once pasted, the code should execute immediately. The output should be similar to the output
shown below.
('176.58.119.26', 80)
176.58.119.26
Value Description
2 <family>
An integer that represents the type of connection the socket is using.
Represents the usocket.AF_INET, meaning an internet family of connection.
1 <type>
An integer that represents the type of connection the socket is using.
Represents usocket.SOCK_STREAM, meaning a TCP connection.
0 <protocol>
An integer that represents the type of connection the socket is using.
Represents usocket.IPPROTO_IP, meaning the IP protocol.
176.58.119.26, <sockaddr>
80 The IP address and port number of the machine you queried.
n Non-negative integer: Defines the length of time for the timeout value. The time is measured
in seconds.
n Floating-point value: Defines the length of time for the timeout value. The time is measured in
seconds.
n 0 (zero): Makes the socket non-blocking. The socket returns immediately, regardless of
whether there is anything to read.
n None: Makes the socket blocking. The socket waits indefinitely for data to become available to
read, or waits up until the socket times out or closes.
Note You can copy and paste code from the online version of the Digi MicroPython Programming
Guide. Use caution with the PDF version, as it may not maintain essential indentations.
Note You can copy and paste code from the online version of the Digi MicroPython Programming
Guide. Use caution with the PDF version, as it may not maintain essential indentations.
import socket
def http_get(url):
scheme, _, host, path = url.split('/', 3)
s = socket.socket()
try:
s.connect((host, 80))
request=bytes('GET /%s HTTP/1.1\r\nHost: %s\r\n\r\n' % (path,
host), 'utf8')
print("Requesting /%s from host %s\n" % (path, host))
s.send(request)
while True:
print(str(s.recv(500), 'utf8'), end = '')
finally:
s.close()
5. After pasting the code, press Ctrl+D to finish. You can now retrieve URLs a the MicroPython
>>> prompt.
http_get('http://www.micropython.org/ks/test.html')
Socket errors
Note This section only applies to the XBee Cellular Modem. See Which features apply to my device?
for a list of the supported features.
n Close abandoned sockets: Initiate garbage collection (gc.collect()) to close any abandoned
MicroPython sockets. For example, an abandoned socket could occur if a socket was created in
a function but not returned. For information about the gc module, see the MicroPython
garbage collection documentation.
n Close all allocated sockets: Press Ctrl+D to perform a soft reset of the MicroPython REPL to
close all allocated sockets and return them to the socket pool.
Unsupported methods
The following methods are standard features of the Python socket interface that are not supported on
this version of the XBee Cellular Modem.
n setsockopt()
Note This section only applies to devices that support the Pin I/O feature.
The following sections include code samples for changing the XBee device's pins.
Note You can replace P0 with Pin.board.P0 as P0 is a quoted string and Pin.board.P0 is an object
reference. Pin.board.P0 only works if you have previously entered from machine import Pin.
Note MicroPython does not currently support identifying a pin with an integer ID.
The pins available to the system can be seen after importing the machine module by typing dir
(machine.Pin.board).
Note The pin list may vary between XBee devices that have different I/O capabilities.
Note You can copy and paste code from the online version of the Digi MicroPython Programming
Guide. Use caution with the PDF version, as it may not maintain essential indentations.
The following example demonstrates a simple loop that waits for the user to press a button on the
XBIB board, which is connected to a pin on the XBee device. This sample uses the value() method to
return the current value on an input pin, and uses polling to monitor a pin.
ad0.value()
while True:
if ad0.value() == 0:
print("SW2 has been pressed!")
break
11. Press Enter until "..." is no longer displayed on the left. The code that was entered is now
running. It is waiting for the value of the pin to go from 1 to 0.
12. Press the SW2 button on the XBIB board. It is below and left of the RESET button, with the USB
port facing you. The terminal should output SW2 has been pressed!, then go back to the
MicroPython >>> prompt on a new line.
Note You can copy and paste code from the online version of the Digi MicroPython Programming
Guide. Use caution with the PDF version, as it may not maintain essential indentations.
print("The modes can be seen by printing the values of the main pin
modes:")
print("Pin.IN: ", Pin.IN) # This should print "0", this is input mode.
print("Pin.OUT: ", Pin.OUT) # This should print "1", this is output mode.
print("Pin.ALT: ", Pin.ALT) # This should print "2", this is ALT mode.
# ALT stands for "alternate", and is usually a port-specific function.
print("Pin.OPEN_DRAIN: ", Pin.OPEN_DRAIN) # This should print "17".
# Open Drain is an output configuration referring to the circuit
positioning
# of the drive transistor.
print("Pin.ANALOG: %d\n" % Pin.ANALOG)
# This should print "3", this is analog mode.
3. At the MicroPython >>> prompt type Ctrl+E to enter paste mode. The terminal displays paste
mode; Ctrl-C to cancel, Ctrl-D to finish.
4. At the MicroPython >>> prompt, right-click and select the Paste option.
5. Once pasted, the code should execute immediately. You should see output showing the
different values generated by the print and mode commands.
n Pin.PULL_UP: The pin has a default "high" value by connecting it to voltage using a resistor:
"pulling up".
n Pin.PULL_DOWN: The pin has a default "low" value by connecting it to ground with a resistor:
"pulling down".
The following example demonstrates how to check the pull direction of one of the pins on the XBee
device and the resultant values on the pin.
Note You can copy and paste code from the online version of the Digi MicroPython Programming
Guide. Use caution with the PDF version, as it may not maintain essential indentations.
# Now, make a pin object for pin AD0/DIO0, set as an input, and pulled
# down to ground (0).
print("Creating a pin object for AD0/DIO0, pulled DOWN...")
d0 = Pin("D0", Pin.IN, Pin.PULL_DOWN)
print("Checking the pull direction of this pin...")
pinpull = d0.pull()
print("Pull direction of AD0/DIO0: %d\n" % pinpull)
# This should return "2", since it was just set to "PULL_DOWN".
print("Checking the value present on the pin...")
pinval = d0.value()
print("Value on AD0/DIO0: %d" % pinval)
print("This should return 0, since the pin is pulled down to ground.\n")
# Now that DIO0 is pulled up, we can examine how a pulled-up input works.
# Holding down the button "SW2"/"DIO0", check the value on the pin again.
print("Now we can examine how a pulled-up pin acts when connected to
ground.")
_ = input("Press and hold SW2 on the XBIB board, then press Enter.")
pinval = d0.value()
print("\nValue on AD0/DIO0: %d" % pinval)
print("The value should now be 0. This is because SW2 connected the pin
to")
print("ground, causing current to flow through the pull-up resistor,
which")
print("dropped the voltage to 0.")
3. At the MicroPython >>> prompt, type Ctrl+E to enter paste mode. The terminal displays paste
mode; Ctrl-C to cancel, Ctrl-D to finish.
4. At the MicroPython >>> prompt, right-click and select the Paste option.
5. Once pasted, the code should execute immediately. You should see output showing the
different values generated by the pull and value commands.
n The first read() call produces a high value, even though the pin is not connected to anything.
This is known as "floating" pin. The high value is caused by voltage being generated at the pin
from electromagnetic waves coming from other circuits on the board as well as the electrical
power at your location. If a multimeter that is set to measure DC voltage is connected between
the pin and ground, the read() method returns a low value, between 0 and 500. Generally a
low value is under 100.
n The second read() call is almost always 0, or very close to 0. This is because the pin is
connected directly to ground by the SW2 button. A multimeter has a high input impedance,
compared to the low (almost zero) impedance of a switch or button.
This example can be repeated with AD1, AD2, and AD3. Just replace "D0" with "D1", "D2", or "D3",
respectively. The button for AD1 is SW3 (DIO1), for AD2 is SW4 (DIO2), and for AD3 is SW5 (DIO3). All
four ADC channels work the same way and can all be used at the same time.
Note You can copy and paste code from the online version of the Digi MicroPython Programming
Guide. Use caution with the PDF version, as it may not maintain essential indentations.
3. At the MicroPython >>> prompt type Ctrl+E to enter paste mode. The terminal displays paste
mode; Ctrl-C to cancel, Ctrl-D to finish.
4. At the MicroPython >>> prompt, right-click and select the Paste option.
5. Once pasted, the code should execute immediately. You should see output showing the
different values generated by the ADC read commands.
Note This section only applies to the XBee Cellular Modem. See Which features apply to my device?
for a list of the supported features.
You can use MicroPython code to send and receive short message service (SMS) messages. You can
specify a phone number and send a message of up to 160 characters. A received message includes the
phone number from which the message was sent and the message text.
The following sections include code samples for sending and receiving an SMS message from and to
the XBee Cellular Modem.
n Phone number: The phone number of the device that should receive the message. The phone
number can be either a string, such as ('19525551212') or ('+19525551212'), or an integer
(19525551212).
n Message: A message of up to 160 characters.
If the message is sent successfully, sms_send( ) returns None. If the message fails, an error message
is returned.
Note In the example below, replace the sample phone number 1123456789 with a valid mobile
telephone number.
import network
import time
c = network.Cellular()
while not c.isconnected():
print("waiting to be connected to the cellular network...")
time.sleep_ms(1500) # Pause 1.5 seconds between checking connection
print("The module is connected to the cellular network. Now send the
message")
try:
c.sms_send(number, message)
print("Message sent successfully to " + number)
except Exception as e:
print("Send failure: " + str(e))
3. At the MicroPython >>> prompt type Ctrl+E to enter paste mode. The terminal displays paste
mode; Ctrl-C to cancel, Ctrl-D to finish.
4. At the MicroPython >>> prompt, right-click and select the Paste option.
5. Once pasted, the code should execute immediately. If the SMS message sends successfully, a
message prints.
The module is connected to the cellular network. Now send the message
Message sent successfully to "xxxxxxxxxx"
Sample code
The code in this example commands the device to wait for and then output the incoming SMS
message.
Note You can copy and paste code from the online version of the Digi MicroPython Programming
Guide. Use caution with the PDF version, as it may not maintain essential indentations.
import network
import time
# Check for incoming sms message, output the message if there is any.
def check_sms():
# Return the incoming message, or "None" if there isn't one.
msg = c.sms_receive()
if msg:
print('SMS received at %s from %s:\n%s' %
(timestamp(msg['timestamp']), msg['sender'], msg['message']))
return msg
def wait_for_sms():
while not check_sms(): # Wait until a message arrives.
print("Waiting for message...")
time.sleep_ms(1500)
wait_for_sms()
3. At the MicroPython >>> prompt type Ctrl+E to enter paste mode. The terminal displays paste
mode; Ctrl-C to cancel, Ctrl-D to finish.
4. At the MicroPython >>> prompt, right-click and select the Paste option.
5. Press Ctrl+D to compile and run the code. The device starts waiting for an incoming message.
6. Once this is running, an SMS message must be sent to the 10-digit phone number associated
with the XBee Cellular Modem for a message to be received. The received message prints,
including the time the message was received and the phone number from which the message
was sent.
import network
def my_callback(sms):
print("SMS received from %s >> %s" % (sms['sender'], sms['message']))
cellular.sms_callback(my_callback)
n The first parameter is the 2-character AT command. If a second parameter is not specified, the
command executes the first command and returns the result as an integer, string, or bytes
object, depending on the settings in the internal XBee command table.
n Use an optional second parameter to set an AT value to an integer, bytes object or string.
Note See AT commands that do not work in MicroPython for commands that the xbee().atcmd()
method does not support on XBee Cellular Modem and XBee 3 Zigbee RF Module.
To perform a network discovery equivalent to an ND command, use the xbee.discover() function.
The following sections include MircroPython AT command code samples you can use with the XBee
device.
Note You can copy and paste code from the online version of the Digi MicroPython Programming
Guide. Use caution with the PDF version, as it may not maintain essential indentations.
import xbee
x = xbee.XBee()
# AT command 'MY' records the current IP address assigned to the module.
print("Current IP address on module: " + x.atcmd('MY'))
3. At the MicroPython >>> prompt type Ctrl+E to enter paste mode. The terminal displays paste
mode; Ctrl-C to cancel, Ctrl-D to finish.
4. At the MicroPython >>> prompt, right-click and select the Paste option.
5. Once pasted, the code should execute immediately. You should see a list of the items
generated by the print command:
Note You can copy and paste code from the online version of the Digi MicroPython Programming
Guide. Use caution with the PDF version, as it may not maintain essential indentations.
import xbee
# AT commands 'SH' + 'SL' combine to form the module's 64-bit address.
addr64 = xbee.atcmd('SH') + xbee.atcmd('SL')
print("64-bit address: " + repr(addr64))
3. At the MicroPython >>> prompt type Ctrl+E to enter paste mode. The terminal displays paste
mode; Ctrl-C to cancel, Ctrl-D to finish.
4. At the MicroPython >>> prompt, right-click and select the Paste option.
5. Once pasted, the code should execute immediately. You should see a list of the items
generated by the print command:
Note You can copy and paste code from the online version of the Digi MicroPython Programming
Guide. Use caution with the PDF version, as it may not maintain essential indentations.
import xbee
x = xbee.XBee()
'DO', 'DL', 'DE', 'MY', 'BD', 'NB', 'SB', 'RO', 'TD', 'FT', 'AP',
dump_atcmds()
print()
dump_iocmds()
import xbee
at_cmds = {
"01. Network": ["CE", "ID", "ZS", "CR", "NJ",
"NW", "JV", "JN", "DO", "DC"],
"02. Operating_Network": ["AI", "OP", "OI", "CH", "NC"],
"03. Security": ["EE", "EO", "KY", "NK", "KT", "I?"],
"04. Addressing": ["SH", "SL", "MY", "MP", "DH",
"DL", "NI", "NH", "BH", "AR",
"DD", "NT", "NO", "NP"],
"05. Zigbee Addressing": ["TO", "SE", "DE", "CI"],
"06. RF Interfacing": ["PL", "PP", "SC", "SD", "DB"],
"07. UART Interface": ["BD", "NB", "SB", "AP", "AO",
"RO", "D6", "D7", "P3", "P4"],
"08. AT Command Options": ["CT", "GT", "CC"],
"09. MicroPython Options": ["PS"],
"10. Sleep Modes": ["SM", "SP", "ST", "SN", "SO",
"WH", "PO"],
"11. I/O Settings": ["D0", "D1", "D2", "D3", "D4",
"D5", "D6", "D7", "D8", "D9",
"P0", "P1", "P2", "P3", "P4",
"P5", "P6", "P7", "P8", "P9",
"PR", "PD", "LT", "RP"],
"12. I/O Sampling": ["IR", "IC", "V+"],
"13. Diagnostics": ["VR", "VH", "HV", "%V", "TP", "CK"]
}
3. At the MicroPython >>> prompt type Ctrl+E to enter paste mode. The terminal displays paste
mode; Ctrl-C to cancel, Ctrl-D to finish.
4. At the MicroPython >>> prompt, right-click and select the Paste option.
5. After you press Ctrl+D to compile and run the code, a list of AT commands and I/O parameter
values is printed:
xbee.discover() examples
Since the call to xbee.discover() returns an iterator which will block each time it is queried, the way
that elements in the returned list are accessed can affect the timing of the application. The following
examples shows two ways you can use xbee.discover() (the examples assume an N? time of 10
seconds).
import xbee
for i in xbee.discover():
print(i)
3. At the MicroPython >>> prompt type Ctrl+E to enter paste mode. The terminal displays paste
mode; Ctrl-C to cancel, Ctrl-D to finish.
4. At the MicroPython >>> prompt, right-click and select the Paste option.
5. Press Ctrl+D to run the code.
Running the above code prints out each response as it is received over the course of 10 seconds. Keep
the processing for each response (in other words the code in the for loop) to a minimum to avoid
missing responses.
>import xbee
for i in list(xbee.discover()):
print(i)
2. At the MicroPython >>> prompt type Ctrl+E to enter paste mode. The terminal displays paste
mode; Ctrl-C to cancel, Ctrl-D to finish.
3. At the MicroPython >>> prompt, right-click and select the Paste option.
4. Press Ctrl+D to run the code.
Running the above code will wait for 10 seconds then print out a list of all the responses that were
received during that time. This method has less chance of missing a response due to processing, but
uses more memory at run time as it has to keep track of all the responses at once.
xbee.transmit() examples
Note You can copy and paste code from the online version of the Digi MicroPython Programming
Guide. Use caution with the PDF version, as it may not maintain essential indentations.
import xbee
test_data = 'Hello World!'
xbee.transmit(xbee.ADDR_BROADCAST,test_data)
3. At the MicroPython >>> prompt type Ctrl+E to enter paste mode. The terminal displays paste
mode; Ctrl-C to cancel, Ctrl-D to finish.
4. At the MicroPython >>> prompt, right-click and select the Paste option.
5. Once pasted, the code should execute immediately. If the transmission attempt is successful,
the MicroPython prompt is returned or else the appropriate error message is displayed.
import xbee
test_data = 'Hello World!'
xbee.transmit(b'\x00\x13\xa2\xff\xad\x95\x5a\xa8', test_data)
3. At the MicroPython >>> prompt type Ctrl+E to enter paste mode. The terminal displays paste
mode; Ctrl-C to cancel, Ctrl-D to finish.
4. At the MicroPython >>> prompt, right-click and select the Paste option.
5. Once pasted, the code should execute immediately. If the transmission attempt is successful,
the MicroPython prompt is returned or else the appropriate error message is displayed.