Pycom
Pycom
Pycom
of Contents
About
Preface 1.1
Pycom Products 1.2
1. Getting Started
1.1 Introduction 2.1
1.2 Unboxing/Setup 2.2
1.3 Installing Software 2.3
1.3.1 Updating Firmware 2.3.1
1.3.2 Pymakr Plugin 2.3.2
1.4 Device Registration 2.4
1.5 Introduction to MicroPython 2.5
1.5.1 Examples 2.5.1
3. Pymakr Plugin
3.1 Introduction 4.1
1
3.2 Installation 4.2
3.2.1 Atom 4.2.1
3.2.2 Visual Studio Code 4.2.2
3.3 Tools/Features 4.3
2
5.2.14 Modbus 6.2.14
5.2.15 OTA update 6.2.15
5.2.16 RMT 6.2.16
5.3 LoRa Examples 6.3
5.3.1 LoRa-MAC (Raw LoRa) 6.3.1
5.3.2 LoRaWAN with OTAA 6.3.2
5.3.3 LoRaWAN with ABP 6.3.3
5.3.4 LoRa-MAC Nano-Gateway 6.3.4
5.3.5 LoPy to LoPy 6.3.5
5.3.6 LoRaWAN Nano-Gateway 6.3.6
5.3.7 RN2483 to LoPy 6.3.7
5.3.8 Objenious 6.3.8
5.4 Sigfox Examples 6.4
5.4.1 Register Device 6.4.1
5.4.2 Disengage Sequence Number 6.4.2
5.5 LTE Examples 6.5
5.5.1 Module IMEI 6.5.1
5.6 Pytrack Examples 6.6
5.7 Pysense Examples 6.7
3
6.2.1.10 Timer 7.2.1.10
6.2.1.11 SD 7.2.1.11
6.2.1.12 CAN 7.2.1.12
6.2.1.13 RMT 7.2.1.13
6.2.2 network 7.2.2
6.2.2.1 WLAN 7.2.2.1
6.2.2.2 Server 7.2.2.2
6.2.2.3 Bluetooth 7.2.2.3
6.2.2.3.1 GATT 7.2.2.3.1
6.2.2.3.2 GATTCConnection 7.2.2.3.2
6.2.2.3.3 GATTCService 7.2.2.3.3
6.2.2.3.4 GATTCCharacteristic 7.2.2.3.4
6.2.2.3.5 GATTSService 7.2.2.3.5
6.2.2.3.6 GATTSCharacteristic 7.2.2.3.6
6.2.2.4 LoRa 7.2.2.4
6.2.2.5 Sigfox 7.2.2.5
6.2.2.6 LTE 7.2.2.6
6.2.2.6.1 Cat M1 7.2.2.6.1
6.2.2.6.2 NB-IoT (soon) 7.2.2.6.2
6.2.3 AES 7.2.3
6.2.4 pycom 7.2.4
6.3 MicroPython Modules 7.3
6.3.1 micropython 7.3.1
6.3.2 uctypes 7.3.2
6.3.3 sys 7.3.3
6.3.4 uos 7.3.4
6.3.5 array 7.3.5
6.3.6 cmath 7.3.6
6.3.7 math 7.3.7
6.3.8 gc 7.3.8
6.3.9 ubinascii 7.3.9
6.3.10 ujson 7.3.10
6.3.11 ure 7.3.11
6.3.12 usocket 7.3.12
4
6.3.13 select 7.3.13
6.3.14 utime 7.3.14
6.3.15 uhashlib 7.3.15
6.3.16 ussl 7.3.16
6.3.17 ucrypto 7.3.17
6.3.18 ustruct 7.3.18
6.3.19 _thread 7.3.19
6.3.20 Builtin 7.3.20
7. Datasheets
7.1 Introduction 8.1
7.2 Development Modules 8.2
7.2.1 WiPy 2.0 8.2.1
7.2.2 WiPy 3.0 8.2.2
7.2.3 LoPy 8.2.3
7.2.4 LoPy 4 8.2.4
7.2.5 SiPy 8.2.5
7.2.6 GPy 8.2.6
7.2.7 FiPy 8.2.7
7.3 OEM Modules 8.3
7.3.1 W01 8.3.1
7.3.2 L01 8.3.2
7.3.3 L04 8.3.3
7.3.4 G01 8.3.4
7.3.5 L01 OEM Baseboard Reference 8.3.5
7.3.6 Universal OEM Baseboard Reference 8.3.6
7.4 Expansion Boards and Shields 8.4
7.4.1 Expansion Board 8.4.1
7.4.2 Pytrack 8.4.2
7.4.3 Pysense 8.4.3
7.4.4 Deep Sleep Shield 8.4.4
7.4.4.1 Deep Sleep API 8.4.4.1
5
7.5 Notes 8.5
8. Pybytes Beta
8.1 Introduction 9.1
8.2 Adding device quickly 9.2
8.3 Adding device by flashing Pybytes library 9.3
9. Documentation Notes
9.1 Introduction 10.1
9.2 Syntax 10.2
9.3 REPL vs Scripts 10.3
11. License
11.1 License 12.1
6
Preface
Pycom Documentation
Welcome to the Pycom documentation site. The documentation is split into 5 sections; we
recommend reading through all the sections to familiarise yourself with the various tools and
features available to you to help you develop on your Pycom module.
All the new Pycom modules are based on the same ESP32 chip and therefore share similar
schematics, pinouts & firmware. Majority of the documentation is applicable for all Pycom
devices, with separate sections for tutorials and firmware references.
To get started, read through the Quickstart Guide then feel free to jump straight into the
tutorials and examples in Tutorials & Examples to begin building your projects.
7
Pycom Products
Pycom Products
This documentation is applicable for all of the devices below. To find out more about these
products and where to buy them, visit the Pycom Webshop.
Development Devices
WiPy 3.0
WiFi and Bluetooth (ESP32 Dev Kit)
LoPy
WiFi, Bluetooth and LoRa (ESP32 Dev Kit)
SiPy
WiFi, Bluetooth and Sigfox (ESP32 Dev Kit)
LoPy4
WiFi, Bluetooth, LoRa and Sigfox (ESP32 Dev Kit)
8
Pycom Products
GPy
WiFi, Bluetooth and LTE-M (NB-IoT) (ESP32 Dev Kit)
FiPy
WiFi, Bluetooth, LoRa, Sigfox and LTE-M (NB-IoT) (ESP32 Dev Kit)
OEM Devices
W01
WiFi and Bluetooth (ESP32 OEM)
L01
WiFi, Bluetooth and LoRa (ESP32 OEM)
9
Pycom Products
L04
WiFi, Bluetooth, LoRa and Sigfox (ESP32 OEM)
G01
WiFi, Bluetooth and LTE-M (NB-IoT) (ESP32 OEM)
Expansion Boards
Pysense
Accelerometer, Humidity, Pressure, Temperature and Light Sensor Shield
10
Pycom Products
Pytrack
GPS and Accelerometer Equipped Shield
Expansion Board
I/O Expansion Shield
11
Pycom Products
12
1.1 Introduction
Getting Started
Let’s start with a quick description of what to do after you unpack your brand new Pycom
Device. The aim of this guide is not to bug you with complex details about it, but instead get
you up and running as quickly as possible!
This chapter help you with the unboxing of and getting started with your device. If you come
across any issues along the way, there is a Troubleshooting section that addresses the
common problems. In case you can not find the answer to your issue, you can always ask
questions in our Forum.
13
1.2 Unboxing/Setup
Select below the tab that matches your configuration for a step by step guide.
Expansion Board
Pysense/PyTrack
Look for the reset button on the module (located at a corner of the board, next to the
LED).
Locate the USB connector on the expansion board.
Insert the module on the expansion board with the reset button pointing towards the
USB connector. It should firmly click into place and the pins should now no longer be
visible.
It’s that simple! For confirmation, here’s a picture demonstrating how to correctly align a
Pycom device with the expansion board:
Before connecting your module to a PySense/PyTrack board, you should update the
firmware on the PySense/PyTrack. Instructions on how to do this can be found here.
Look for the reset button on the module (located at a corner of the board, next to the
LED).
14
1.2 Unboxing/Setup
Video Tutorial
15
1.2 Unboxing/Setup
Video link
Some devices, such as the LoPy, will cover the USB connector. This is normal;
remember to keep the orientation as shown in the image above.
Be gentle when plugging/unplugging the USB cable. Whilst the USB connector is
soldered and relatively strong, it can break off and will be difficult to fix.
Static electricity can damage components on the board and may destroy them. If there
is a lot of static electricity in the area (e.g. dry and cold climates), take extra care not to
shock the device. If the device came in a ESD bag (Silver packaging), the best way to
store and carry the device is inside this bag as it will be protected against static
discharges.
In a few seconds, the LED should start blinking every 4 seconds. This means that everything
is working correctly! If the LED is not blinking, please disconnect the power supply and re-
check the board’s position on the expansion board.
16
1.2 Unboxing/Setup
We highly recommend you update the firmware of your module before trying to use it.
Instructions on how to do this can be found in the next chapter.
17
1.3 Installing Software
18
1.3.1 Updating Firmware
Here are the download links to the update tool. Please download the appropriate one for
your OS and follow the instructions on the screen.
Windows
MacOS (10.11 or Higher)
Linux (requires dialog and python-serial package)
Previous versions of firmware are available for download on the Pycom forum.
19
1.3.1 Updating Firmware
If you are having any issues, make sure the TX jumper is present on your expansion board,
as the jumpers sometimes come loose in the box during transport. Without this jumper, the
updater will fail.
When using a Pysense/Pytrack to update your module you are not required to make a
connection between P2 and GND, the Pysense/Pytrack will do this automatically.
1. Before connecting your module to a PySense/PyTrack board, you should update the
firmware on the PySense/PyTrack. Instructions on how to do this can be found here.
2. Disconnect your device from your computer
3. Insert module into expansion board
4. Reconnect the board via USB to your computer
5. Run the Firmware Upgrade tool
20
1.3.1 Updating Firmware
6. Disconnect the USB cable from the board and reconnect it, your device is now ready to
use!
After you’re done with upgrading, you can use the Pymakr Plugins to upload and run
programs in your device.
21
1.3.2 Pymakr Plugin
Extended info about these Plugins, such as how to use the Pycom console and other
features can be found under Tools & Features.
Please be aware that Pymakr IDE has been retired and that plugins for Atom and
Visual Studio Code are under development, with intention to replace Pymakr. Please
read this forum post for more information.
22
1.3.2 Pymakr Plugin
For beginners, users getting started with MicroPython & Pycom as well as Atom text editor
users, we recommend the Pymakr Plugin for Atom. This section will help you get started
using the Atom Text Editor & Pymakr Plugin.
23
1.3.2 Pymakr Plugin
2. Navigate to the Install page, via Atom > Preferences > Install
3. Search for Pymakr and select the official Pycom Pymakr Plugin.
4. You should now see and click the Install button. This will download and install the
Pymakr Plugin.
24
1.3.2 Pymakr Plugin
Initial Configuration
After installing the Pymakr Plugin, you need to take a few seconds to configure it for first
time use. Please follow these steps:
1. Connect your Pycom device to your computer via USB. Remove the wire between
GND and G23, before plugging in your device, if you have just finished upgrading your
firmware!
2. Open Atom and ensure that the Pymakr Plugin has correctly installed.
3. Open the Pymakr console by clicking the '^' button, located in the lower right side of the
Atom window.
4. Click, 'More' followed by 'Get Serial Ports'. This will copy the serial address of your
expansion board to your clipboard.
25
1.3.2 Pymakr Plugin
6. Paste the serial address you copied earlier into the text field 'Device Address'
7. Press connect and the Pymakr console should show three arrows '>>>', indicating that
you are connected!
26
1.3.2 Pymakr Plugin
You can also connect to your device via WiFi as the device can open a telnet server. For
more information please see Telnet.
Writing Code
We'll revisit this section later on in this getting started guide but you can quickly test out
MicroPython by typing commands into the Pymakr Console. For example, try changing the
colour of the device's LED!
We'll first import the 'pycom' library, turn the blinking LED off and then set the LED to the
hexadecimal colour '0x00ff00' (green).
27
1.4 Device Registration
Not all Pycom devices require activation; most features work immediately out of the
box! Currently the registration/activation only applies to the SiPy, in order to connect it to
the Sigfox Network.
28
1.5 Introduction to MicroPython
Introduction to MicroPython
Our boards work with MicroPython; a Python 3.5 implementation that is optimised to run on
microcontrollers. This allows for much faster and more simple development process than
using C.
The folder structure in /flash looks like the picture below. The files can be managed either
using FTP or using the Pymakr Plugin.
29
1.5 Introduction to MicroPython
Micropython shares majority of the same syntax as Python 3.5. The intention of this design
is to provide compatibility upwards from Micropython to Python 3.5, meaning that code
written for Micropython should work in a similar manner in Python 3.5. There are some minor
variations and these should taken viewed as implementation differences.
Micropython also has a number of Micropython specific libraries for accessing hardware
level features. Specifics relating to those libraries can be found in the Firmware API
Reference section of this documentation.
Micropython, unlike C/C++ or Arduino, does not use braces {} to indicate blocks of
code specified for class and function definitions or flow control. Blocks of code are
denoted by line indentation, which is strictly enforced.
The number of spaces in the indentation is variable but all statements within a block
must be indented the same amount.
30
1.5.1 Examples
MicroPython Examples
To get you started with Python (MicroPython) syntax, we've provided you with a number of
code examples.
Variable Assignment
As with Python 3.5, variables can be assigned to and referenced. Below is an example of
setting a variable equal to a string and then printing it to the console.
Conditional Statements
Conditional statements allow control over which elements of code run depending on specific
cases. The example below shows how a temperature sensor might be implemented in code.
temperature = 15
target = 10
if temperature > target:
print("Too High!")
elif temperature < target:
print("Too Low!")
else:
print("Just right!")
For loops allow you to control how many times a block of code runs for within a range.
x = 0
for y in range(0,9):
x += 1
print(x)
31
1.5.1 Examples
While loops are similar to For loops, however they allow you to run a loop until a specific
conditional is true/false. In this case, the loop checks if x is less than 9 each time the loop
passes.
x = 0
while x < 9:
x += 1
print(x)
Functions
Functions are blocks of code that are referred to by name. Data can be passed into it to be
operated on (i.e., the parameters) and can optionally return data (the return value). All data
that is passed to a function is explicitly passed.
The function below takes two numbers and adds them together, outputting the result.
The next function takes an input name and returns a string containing a welcome phrase.
def welcome(name):
welcome_phrase = "Hello, " + name + "!"
print(welcome_phrase)
Data Structures
Python has a number of different data structures for storing and manipulating variables. The
main difference (regarding data structures) between C and Python is that Python manages
memory for you. This means there’s no need to declare the sizes of lists, dictionaries,
strings, etc.
Lists
A data structure that holds an ordered collection (sequence) of items.
32
1.5.1 Examples
Dictionaries
A dictionary is like an address-book where you can find the address or contact details of a
person by knowing only his/her name, i.e. keys (names) are associate with values (details).
Tuple
Similar to lists but are immutable, i.e. you cannot modify tuples after instantiation.
For more Python examples, check out these tutorials. Be aware of the implementation
differences between Micropython and Python 3.5.
33
2.1 Introduction
34
2.2 Pycom Modules
Click the links in the list above to see more details on that feature. For all available modules
and libraries, please visit the Firmware API Reference section.
35
2.3 REPL & Uploading Code
The following pages will explain how to use the REPL with both Serial USB and Telnet
connections.
Input history: use arrow up and arrow down to scroll through the history
Tab completion: press tab to auto-complete variables or module names
Halt any executing code: with Ctrl-C
Copy/paste code or output: Ctrl-C and Ctrl-V
There are a number of useful shortcuts for interacting with the MicroPython REPL. See
below for the key combinations;
Ctrl-A on a blank line will enter raw REPL mode. This is similar to permanent
Ctrl-E enters ‘paste mode’ that allows you to copy and paste chunks of text. Exit
36
2.3.1 Serial USB
In order to connect to the REPL over USB serial, there are multiple methods. Detailed below
are the explanations of how to do it in MacOS, Linux and Windows.
Upon exiting screen , press CTRL-A CTRL-. If the keyboard does not support the -key (i.e.
an obscure combination for \ like ALT-SHIFT-7 is required), the key combination can be
remapped for the quit command:
create ~/.screenrc
add bind q to the exit command
On Linux, picocom or minicom may be used instead of screen . The usb serial
address might also be listed as /dev/ttyUSB01 or a higher increment for ttyUSB.
Additionally, the elevated permissions to access the device (eg group uucp/dialout or
use sudo) may be required.
Windows
To use the serial USB REPL with Windows, first ensure that the FTDI drivers are installed or
install them from here. A terminal emulator is needed to open the connection from Windows;
the easiest option is to download the free program, PuTTY.
COM Port
37
2.3.1 Serial USB
To use PuTTY the serial port (COM port) in which the Pycom device is connected, must be
located. In Windows, this information can be found from the 'Device Manager' program.
1. Open the Windows start menu and search for 'Device Manager'
2. The COM port for the Pycom device will be listed as 'USB Serial Device' or a similar
name
3. Copy/Write down the associated COM port (e.g. COM4)
Using Putty
38
2.3.2 Telnet
Telnet REPL
Pycom devices also support a connection via telnet, using the device's on board
WiFi/WLAN. Connect to the device's WiFi Access Point (AP) and using the following
credentials to connect to the AP. The WiFi SSID will appear upon powering on a Pycom
Device for the first time (e.g. lopy-). To re-enable this feature at a later date, please see
network.WLAN.
password : www.pycom.io
Telnet Server
Additionally, to use the MircoPython REPL over telnet, further authentication is required. The
default credentials for the telnet server are:
username : micro
password : python
$ telnet 192.168.4.1
Upon connection, the telnet program will prompt for the username and password in the
section above.
Windows
A terminal emulator is needed to open a telnet connection from Windows; the easiest option
is to download the free program, PuTTY.
1. With PuTTY open, select telnet as connection type and leave the default port (23)
2. Next enter the IP address of the Pycom device (192.168.4.1)
3. Finally click Open
39
2.3.2 Telnet
When using a Pycom device with a personal, home or office WiFi access point, the
telnet connection may still be used. In this instance, the user will need to determine the
Pycom device's local IP address and substitute this for 192.168.4.1 , referred to in the
earlier sections.
40
2.4 FTP
The file system is accessible via the native FTP server running on each Pycom device.
Open an FTP client and connect to:
url : ftp://192.168.4.1
username : micro
password : python
See network.server for information on how to change the defaults. The recommended clients
are:
$ ftp 192.168.4.1
The FTP server doesn’t support active mode, only passive mode. Therefore, if using the
native unix ftp client, immediately after logging in, run the following command:
ftp> passive
The FTP server only supports one connection at a time. If using other FTP Clients, please
check their documentation for how to limit the maximum allowed connections to one at a
time.
FileZilla
If using FileZilla, it's important to configure the settings correctly.
Do not use the quick connect button. Instead, open the site manager and create a new
configuration. Within the General tab, ensure that encryption is set to: Only use plain FTP
(insecure) .
41
2.4 FTP
In the Transfer Settings tab, limit the max number of connections to one. Other FTP clients
may behave in a similar ways; visit their documentation for more specific information.
42
2.5 Boot Modes
Boot Modes
Bootloader Mode
In order to put Pycom modules into bootloader mode to allow firmware to be upgraded, P2
must be pulled low during boot. When this is done the device will print waiting for
download . After this it is ready to receive an update via the firmware updater.
Safe boot
If powering up normally or upon pressing the reset button, a Pycom device will boot into
standard mode; the boot.py file will be executed first, followed by main.py .
This boot sequence may be overridden by pulling P12 ( G28 on the expansion board)
high (i.e. connect it to the 3V3 output pin), during reset cycle. After reset, if P12 pin is
held high, the heartbeat LED will begin flashing orange slowly, this will indicate the execution
of boot.py and main.py will be skipped. This can be useful when the code in these files
prevents you from accessing the device, e.g. disabling the UART and WiFi.
If after 3 seconds the pin is still held high, the LED will start blinking faster. If the device has
been updated using the OTA procedure, this will trigger the device to boot its previous
firmware (more details on this can be found below)
Firmware slots
Pycom modules feature two firmware slots. When you perform a firmware upgrade using our
updater tool, this is always written to slot 0. When an OTA is applied, either by FTP or our
provided OTA functions, it will be written to the currently unused slot. Once the OTA is
completed and the new firmware is verified, the active slot is swapped.
Reset
Pycom devices support both soft and hard resets. A soft reset clears the state of the
MicroPython virtual machine but leaves hardware peripherals unaffected. To do a soft reset,
press Ctrl+D on the REPL or from within a script, run:
43
2.5 Boot Modes
A hard reset is the same as performing a power cycle to the device. In order to hard reset
the device, press the reset switch or run:
>>> import os
>>> os.mkfs('/flash')
Be aware, resetting the flash filesystem will delete all files inside the internal device
storage (not the SD card) and restores the files boot.py and main.py to their factory
states after the next reset.
44
2.6 Notes
Notes
Interrupt Handling
In Pycom’s ESP32 MicroPython port there are no restrictions on what can be done within an
interrupt handler. For example, other ports do not allow allocating memory inside the handler
or the use of sockets.
These limitations were raised by handling the interrupt events differently. When an interrupt
happens, a message is posted into a queue, notifying a separate thread that the appropriate
callback handler should be called. Such handler would receive an argument. By default it is
the object associated with the event.
The user can do whatever is required inside of the callback, such as creating new variables,
or even sending network packets. Bear in mind that interrupts are processed sequentially
and thus it is ideal to keep the handlers as short as possible in order to attend all of them in
the minimum time.
Currently, there are 2 classes that support interrupts; the Alarm and Pin classes. Both
classes provide the .callback() method that enables the interrupt and registers the given
handler. For more details about interrupt usage along with examples, please visit their
respective sections.
45
3.1 Introduction
Pymakr Plugins
To make it as easy as possible Pycom has developed a series of tools known as the Pymakr
Plugins, which allow a user to connect to and program their Pycom devices. These Plugins
have been built for a number of text editors and IDEs to allow for users to select their
favourite development environments.
46
3.2 Installation
Installation
Pymakr Plugin is currently under development for 2 platforms; Atom and Visual Studio Code.
The following sections detail the installation process for the various platforms.
Please be aware that Pymakr IDE has been retired and that plugins for Atom and
Visual Studio Code are under development, with intention to replace Pymakr. Please
read this forum post for more information.
47
3.2.1 Atom
Initial Configuration
After installing the Pymakr Plugin, you need to take a few seconds to configure it for first
time use. Please follow these steps:
1. Connect your Pycom device to your computer via USB. Remove the wire between
48
3.2.1 Atom
GND and G23, before plugging in your device, if you have just finished upgrading your
firmware!
2. Open Atom and ensure that the Pymakr Plugin has correctly installed.
3. In the menu, go to Atom > Preferences > Packages > Pymakr. This may vary depending
on your operating system!
4. Open the Pymakr console by clicking the 'Open' button, located in the lower right side of
the Atom window.
5. Click, 'More' followed by 'Get Serial Ports'. This will copy the serial address of your
expansion board to your clipboard.
6. Navigate to 'Settings' > 'Global Settings'.
7. Paste this into the text field 'Device Address'.
8. Press connect and the Pymakr console should show three arrows '>>>', indicating that
you are connected!
You can also connect to your device via WiFi as the device can open a telnet server. For
more information please see the section below.
1. Ensure that the Pycom device is turned on and connected (Normal or Safe Boot Mode)
2. Open Atom and verify that the Pymakr Plugins has been installed.
3. Click Open on the Pymakr Console, followed by the More tab.
4. Next click get serial ports . This will copy the first serial port to the editor's clipboard.
5. Navigate to Global Settings and paste this address into the Device Address text field
6. Click Connect
49
3.2.1 Atom
If there are issues connecting over USB with the Pymakr Plugins, ensure that the
correct FTDI drivers are installed. This issue is related to missing Windows drivers.
In the lower portion of the screen, within the console, press Connect and the connection
process will take place. Upon completion, a message stating ‘Connecting on 192.168.4.1...’
will appear, followed a >>> prompt if successful.
50
3.2.2 Visual Studio Code
You will also need NodeJS installed on your PC. Please download the latest LTS version
available from the NodeJS website.
51
3.2.2 Visual Studio Code
1. Ensure that the Pycom device is turned on and connected (Normal or Safe Boot Mode)
2. Open Visual Studio Code and verify that the Pymakr extension has been installed
3. Open the terminal if it wasn't open yet, using View -> Intergrated Terminal (or the
`^+`` shortcut)
4. Now click the All commands button on the bottom and click Pymakr > List serial
ports . This will copy the first serial port to the editor's clipboard
5. Open the Global Settings file by clicking the All commands button and then Pycom >
Global Settings and paste this address into the 'address' field
6. Click All commands then Pymakr > Connect to connect to your device
If there are issues connecting over USB with the Pymakr Plugins, ensure that the
correct FTDI drivers are installed. This issue is related to missing Windows drivers.
1. Ensure that Pycom device is turned on and connected (Normal or Safe Boot Mode)
2. Open Visual Studio Code and verify that the Pymakr extension has been installed
3. Open the terminal if it wasn't open yet, using View -> Intergrated Terminal (or the
`^+`` shortcut)
4. Connect the host computer to the WiFi Access Point named after your board (the SSID
will be as follows e.g. lopy-wlan-xxxx , wipy-wlan-xxxx ). The password is
www.pycom.io . You may also connect your Pycom device to your router with a fixed IP
different.
52
3.2.2 Visual Studio Code
7. The default username and password are micro and python , respectively.
8. Click All commands then Pymakr > Connect to connect to your device
Use either the Connect command or click the Pycom console button on the left bottom and
the connection process will take place. Upon completion, a message stating ‘Connecting on
192.168.4.1...’ will appear, followed a >>> prompt if successful.
53
3.3 Tools/Features
You can change the colour by adjusting the hex RGB value.
The console can be used to run any python code, also functions or loops.
Use print() to output contents of variables to the console for you to read. Returned values
from functions will also be displayed if they are not caught in a variable. This will not happen
for code running from the main or boot files. Here you need to use print() to output to the
console.
Note that after writing or pasting any indented code like a function or a while loop, the
user will have to press enter up to three times to tell MicroPython the code is to be
closed (this is standard MicroPython & Python behaviour).
Also be aware that code written into the REPL is not saved after the device is powered
off/on again.
Run
To test code on a device, create a new .py file or open an existing one, type the desired
code, save the file and then press the Run button. This will run the code directly onto the
Pycom board and output the results of the script to the REPL.
54
3.3 Tools/Features
Changes made to files won’t be automatically uploaded to the board upon restarting or
exiting the Run feature, as the Pycom board will not store this code. In order to push
the code permanently to a device, use the Sync feature.
Projects
Pymakr Plugin supports user projects, allowing for pre-configured settings such as default
serial address/credentials, files to be ignored and folders to sync.
pymakr.conf
Pymakr Plugin supports local project settings using a file called pymakr.conf . This can be
used to store the default serial address of a device, which files to ignore and other settings.
An example pymakr.conf is shown below:
{
"address": "/dev/cu.usbserial-AB001234",
"username": "micro",
"password": "python",
"sync_folder": "scripts"
}
Sync
The Pymakr Plugins have a feature to Sync and upload code to a device. This can be used
for both uploading code to a device as well as testing out scripts by running them live on the
device. The following steps demonstrate how to use this feature.
To start using the Sync feature, ensure that a project folder has been created for the
device. For example, if using the pymakr.conf from above, this project folder should be
named 'scripts'. This folder should have the following structure:
Library files should be placed into the lib folder, certificates into the cert folder and so
on. The Sync button will take the highest level folder (currently open) and upload this to the
connected Pycom device. The files will be pushed to the device in exactly the same
55
3.3 Tools/Features
More
Clicking the 'More' button within the Pymakr Plugin allows for some additional features. See
the options below for specific functionality.
Retrieves the firmware version of the Pycom device connected to the Pymakr Plugin
instance.
Retrieves the default WiFi Access Point SSID of the Pycom device connected to the Pymakr
Plugin instance.
Retrieves the various serial ports that are available to the Pymakr Plugin instance.
56
4.1 Introduction
Pytrack
Pytrack is a location enabled version of the Expansion Board, intended for use in GPS
applications such as asset tracking or monitoring.
Serial USB
3-Axis Accelerometer (LIS2HH12)
Battery Charger (BQ24040 with JST connector)
GPS and GLONASS (L76-L)
MicroSD Card Reader
All of the included sensors are connected to the Pycom device via the I2C interface. These
pins are located at P22 (SDA) and P21 (SCL).
Pysense
57
4.1 Introduction
Pysense is a sensor packed version of the Expansion Board, intended for use in
environment sensing applications such as temperature & humidity monitoring as well light
sensing.
Serial USB
3-Axis Accelerometer (LIS2HH12)
Battery Charger (BQ24040 with JST connector)
Digital Ambient Light Sensor (LTR-329ALS-01)
Humidity and Temperature Sensor (Si7006-A20)
Barometric Pressure Sensor with Altimeter (MPL3115A2)
MicroSD Card Reader
All of the included sensors are connected to the Pycom device via the I2C interface. These
pins are located at P22 (SDA) and P21 (SCL).
58
4.2 Installing Software
Installing Software
As the development for these devices are on going with additional features being added,
every week, it is essential to ensure you frequently check for updates on the
Pytrack/Pysense. As well as updating the device firmware, it is important to check the
GitHub repository for the respective library files as they as also being updated, to include
additional features/functionality.
59
4.2.1 Updating Firmware
Updating Firmware
To update the firmware on the Pysense/Pytrack, please see the following instructions. The
firmware of both Pysense and Pytrack can be updated via the USB port using the terminal
tool, DFU-util.
The latest firmware is v0.0.8. The DFU file can be downloaded from the links below:
Pytrack DFU
Pysense DFU
While the the normal, application mode, the Pysense and Pytrack require a Serial USB CDC
driver, in DFU, bootloader mode, the DFU driver is required. Bellow, the USB Product ID is
depicted for each case.
If using homebrew :
If using MacPorts :
Linux
Ubuntu or Debian:
Fedora:
60
4.2.1 Updating Firmware
Arch:
Windows
To uploaded the latest DFU firmware to the Pytrack/Pysense, first install the DFU drivers
to the host computer. Open Zadig and select libusbK as the driver.
61
4.2.1 Updating Firmware
Open the command prompt and navigate to the directory where the DFU-util and the
firmware was downloaded (must be in same directory). Repeat the procedure to get the
board in DFU-mode and run the command below but replace X.X.X with the firmware
version and replace pysense with pytrack if it is the pytrack that is to be updated (e.g:
pytrack_0.0.8.dfu ):
dfu-util-static.exe -D pysense_X.X.X.dfu
If the update was successful, a message, “Done!” should appear in the bottom of the
command prompt.
If, by mistake, the libusbk driver was installed while the USB ID is the Application mode
(0xF013 for Pytrack or 0xF012 for Pysense), then the Serial USB (CDC) driver has to be
installed for application mode. This will allow Windows to allocate a COM port, which is
required for REPL console.
62
4.2.1 Updating Firmware
$ dfu-util -D pytrack_0.0.8.dfu
An output, similar to the one below, will appear upon successful installation:
63
4.2.1 Updating Firmware
dfu-util 0.9
Debugging
Using lsusb command, the Pytrack/Pysense device should be visible in both normal and
bootloader modes.
Bus 020 Device 004: ID 04d8:f014 Microchip Technology Inc. Application Specific
Device
this is bootloader mode (f014 is USB PID), active just for 7-8 seconds, if the reset
button was just pressed before plugging USB connector.
Bus 020 Device 005: ID 04d8:f013 Microchip Technology Inc. Pytrack Serial: Pyabcde0
this is normal, application mode (f013 is USB PID), this means the bootloader
verified application partition and it boot-up correctly.
64
4.2.2 Installing Drivers - Windows 7
Windows 7 Drivers
Pytrack and Pysense will work out of the box for Windows 8/10/+, Mac OS as well as Linux.
If using Windows 7, drivers to support the boards will need to be installed.
Download
Please download the driver software from the link below.
Pytrack/Pysense Driver
Installation
First navigate open the Windows start menu and search/navigate to Device Manager . You
should see your Pytrack/Pysense in the dropdown under other devices.
65
4.2.2 Installing Drivers - Windows 7
Next you will need to navigate to where you downloaded the driver to (e.g. Downloads
Folder).
66
4.2.2 Installing Drivers - Windows 7
Specify the folder in which the drivers are contained. If you haven't extracted the .zip file,
please do this before selecting the folder.
You may receive a warning, suggesting that windows can't verify the publisher of this driver.
Click Install this driver software anyway as this link points to our official driver.
67
4.2.2 Installing Drivers - Windows 7
If the installation was successful, you should now see a window specifying that the driver
was correctly installed.
To confirm that the installation was correct, navigate back to the Device Manager and click
the dropdown for other devices. The warning label should now be gone and
Pytrack/Pysense should be installed.
68
4.2.2 Installing Drivers - Windows 7
69
4.2.3 Installing Libraries
Installing Libraries
To utilise the sensors on the Pytrack and Pysense, Pycom has written libraries to make
reading to/from the various sensors accessible via an API. These libraries reside at the
Pycom GitHub repository and the latest versions can be found under the releases page.
GitHub Repository
Download the repository as a .zip file, navigate to the correct device (Pysense/Pytrack),
extract the files and then upload the desired files to the device in the instructions below.
the only Accelerometer and the Light Sensor, they should place the following .py files into
the device's /lib folder:
pysense.py
LIS2HH12.py
LTR329ALS01.py
In addition to the Pysense or Pytrack specific libraries, you also need to upload the
pycoproc.py file from the lib/pycoproc folder inside the libraries archive.
The Pytrack and Pysense boards behave the same as the Expansion Board. Sync ,
Run and upload code to Pycom modules via the Pymakr Plugin, in exactly the same
process.
70
4.2.3 Installing Libraries
py = Pysense()
lt = LTR329ALS01(py)
print(lt.light())
71
4.3 API Reference
API Reference
To simplify usability, APIs for the libraries have been created, abstracting away the low level
interactions with the sensors. The next following pages refer to the respective libraries for
the Pytrack and Pysense.
72
4.3.1 Pytrack
Pytrack API
This chapter describes the various libraries which are designed for the Pytrack Board. This
includes details about the various methods and classes available for each of the Pytrack’s
sensors.
Constructors
class LIS2HH12(pytrack = None, sda = 'P22', scl = 'P21')
Creates a LIS2HH12 object, that will return values for acceleration, roll, pitch and yaw.
Constructor must be passed a Pytrack or I2C object to successfully construct.
Methods
LIS2HH12.acceleration()
Read the acceleration from the LIS2HH12. Returns a tuple with the 3 values of acceleration
(G).
LIS2HH12.roll()
Read the current roll from the LIS2HH12. Returns a float in degrees in the range -180 to
180.
LIS2HH12.pitch()
Read the current pitch from the LIS2HH12. Returns a float in degrees in the range -90 to 90.
Once the board tilts beyond this range the values will repeat. This is due to a lack of yaw
measurement, making it not possible to know the exact orientation of the board.
73
4.3.1 Pytrack
Constructors
class L76GNSS(pytrack = None, sda = 'P22', scl = 'P21', timeout = None)
Creates a L76GNSS object, that will return values for longitude and latitude. Constructor
must be passed a Pytrack or I2C object to successfully construct. Set the timeout to a time
period (in seconds) for the GPS to search for a lock. If a lock is not found by the time the
timeout has expired, the coordinates method will return (None, None) .
Methods
L76GNSS.coordinates(debug = False)
Read the longitude and latitude from the L76GNSS. Returns a tuple with the longitude and
latitude. With debug set to True the output from the GPS is verbose.
Please note that more functionality is being added weekly to these libraries. If a required
feature is not available, feel free to contribute with a pull request at the Libraries GitHub
repository
74
4.3.2 Pysense
Pysense API
This chapter describes the various libraries which are designed for the Pysense Board. This
includes details about the various methods and classes available for each of the Pysense’s
sensors.
Constructors
class LIS2HH12(pysense = None, sda = 'P22', scl = 'P21')
Creates a LIS2HH12 object, that will return values for acceleration, roll, pitch and yaw.
Constructor must be passed a Pysense or I2C object to successfully construct.
Methods
LIS2HH12.acceleration()
Read the acceleration from the LIS2HH12. Returns a tuple with the 3 values of acceleration
(G).
LIS2HH12.roll()
Read the current roll from the LIS2HH12. Returns a float in degrees in the range -180 to
180.
LIS2HH12.pitch()
Read the current pitch from the LIS2HH12. Returns a float in degrees in the range -90 to 90.
Once the board tilts beyond this range the values will repeat. This is due to a lack of yaw
measurement, making it not possible to know the exact orientation of the board.
75
4.3.2 Pysense
Constructors
class LTR329ALS01(pysense = None, sda = 'P22', scl = 'P21', gain = ALS_GAIN_1X,
integration = ALS_INT_100, rate = ALS_RATE_500)
Creates a LTR329ALS01 object, that will return values for light in lux. Constructor must be
passed a Pysense or I2C object to successfully construct.
Methods
LTR329ALS01.light()
Read the light levels of both LTR329ALS01 sensors. Returns a tuple with two values for
light levels in lux.
Arguments
The following arguments may be passed into the constructor.
gain
Constructors
class SI7006A20(pysense = None, sda = 'P22', scl = 'P21')
Creates a SI7006A20 object, that will return values for humidity (%) and temperature ('C).
Constructor must be passed a Pysense or I2C object to successfully construct.
76
4.3.2 Pysense
Methods
SI7006A20.humidity()
Read the relative humidity of the SI7006A20. Returns a float with the percentage relative
humidity.
SI7006A20.temperature()
Read the external temperature of the SI7006A20. Returns a float with the temperature.
Constructors
class MPL3115A2(pysense = None, sda = 'P22', scl = 'P21', mode = PRESSURE)
Creates a MPL3115A2 object, that will return values for pressure (Pa), altitude (m) and
temperature ('C). Constructor must be passed a Pysense or I2C object to successfully
construct.
Methods
MPL3115A2.pressure()
Read the atmospheric pressure of the MPL3115A2. Returns a float with the pressure in
(Pa).
MPL3115A2.altitude()
Read the altitude of the MPL3115A2. Returns a float with the altitude in (m).
MPL3115A2.temperature()
Read the temperature of the MPL3115A2. Returns a float with the temperature in ('C).
Arguments
The following arguments may be passed into the constructor.
mode
77
4.3.2 Pysense
PRESSURE ALTITUDE
Please note that more functionality is being added weekly to these libraries. If a required
feature is not available, feel free to contribute with a pull request at the Libraries GitHub
repository
78
4.3.3 Sleep
79
4.3.3 Sleep
#py = Pytrack()
py = Pysense()
# display the reset reason code and the sleep remaining in seconds
# possible values of wakeup reason are:
# WAKE_REASON_ACCELEROMETER = 1
# WAKE_REASON_PUSH_BUTTON = 2
# WAKE_REASON_TIMER = 4
# WAKE_REASON_INT_PIN = 8
acc = LIS2HH12()
# enable activity and also inactivity interrupts, using the default callback handler
py.setup_int_wake_up(True, True)
# set the acceleration threshold to 2000mG (2G) and the min duration to 200ms
acc.enable_activity_interrupt(2000, 200)
Methods
pytrack.get_sleep_remaining()
In the event of a sleep session that was awoken by an asynchronous event (Accelerometer,
INT pin or Reset button) the approximate sleep remaining interval (expressed in seconds)
can be found out. The user has to manually use setup_sleep() to configure the next sleep
interval.
pytrack.get_wake_reason()
80
4.3.3 Sleep
As in the above example, this method should be called at the beginning of the script, to find
out the reset (wakeup) reason.
pytrack.go_to_sleep([gps=True])
Puts the board in sleep mode, for the duration, which has to be set previously with
pytrack.setup_sleep(timout_sec). The optional boolean parameter sets the GPS state
during sleep.
Micropython code, which is after this function, is not executed, as wakeup will restart
micropython.
pytrack.setup_int_wake_up(rising, falling])
Enables as wakeup source, the accelerometer INT pin (PIC - RA5). The boolean parameters
will indicate rising edge (activity detection) and/or falling edge (inactivity detection) is
configured.
The accelerometer (class LIS2HH12) has to be also configured for a certain acceleration
threshold and duration. Code snippet:
py = Pytrack()
acc = LIS2HH12()
# enable activity and also inactivity interrupts, using the default callback handler
py.setup_int_wake_up(True, True)
# set the acceleration threshold to 2000mG (2G) and the min duration to 200ms
acc.enable_activity_interrupt(2000, 200)
pytrack.setup_int_pin_wake_up([rising_edge = True])
Enables as wakeup source, the INT pic (PIC - RC1). Either rising or falling edge has to be
set, by default it's rising edge.
pytrack.setup_sleep(time_seconds)
81
4.3.3 Sleep
Sets the sleep interval, specified in seconds. The actual sleep will be started by calling
go_to_sleep() method.
Please note that more functionality is being added weekly to these libraries. If a required
feature is not available, feel free to contribute with a pull request at the Libraries GitHub
repository
82
5.1 Introduction
General Pycom tutorials contains tutorials that may be run on any Pycom device, such as
connecting to a WIFI network, Bluetooth, controlling I/O pins etc. Later sections are specific
to the LoPy and SiPy devices such as setting up a LoRa node or connecting to the Sigfox
network. The final sections are related to examples using the Pytrack and Pysense.
Before starting, ensure that any Pycom devices are running the latest firmware; for
instructions see Firmware Updates.
The source code for these tutorials, along with the required libraries can be found in in the
pycom-libraries repository.
83
5.2 All Pycom Device Examples
84
5.2.1 REPL
In the example above, the >>> characters should not be typed. They are there to indicate
that the text should be placed after the prompt. Once the text has been entered
print("Hello LoPy!") and pressed Enter , the output should appear on screen, identical to
If this is not working, try either a hard reset or a soft reset; see below.
Here are some other example, utilising the device's hardware features:
will appear:
85
5.2.1 REPL
>>>
PYB: soft reboot
MicroPython v1.4.6-146-g1d8b5e5 on 2016-10-21; LoPy with ESP32
Type "help()" for more information.
>>>
If that still isn’t working a hard reset can be performed (power-off/on) by pressing the RST
switch (the small black button next to the RGB LED). Using telnet, this will end the session,
disconnecting the program that was used to connect to the Pycom Device.
86
5.2.2 WLAN
WLAN
The WLAN is a system feature of all Pycom devices, therefore it is enabled by default.
The current mode (WLAN.AP after power up) may be checked by running:
>>> wlan.mode()
When changing the WLAN mode, if following the instructions below, the WLAN
connection to the Pycom device will be broken. This means commands will not run
interactively over WiFi.
1. Put this setup code into the boot.py file of the Pycom device so that it gets executed
automatically after reset.
2. Duplicate the REPL on UART. This way commands can be run via Serial USB.
Connecting to a Router
The WLAN network class always boots in WLAN.AP mode; to connect it to an existing
network, the WiFi class must be configured as a station:
87
5.2.2 WLAN
nets = wlan.scan()
for net in nets:
if net.ssid == 'mywifi':
print('Network found!')
wlan.connect(net.ssid, auth=(net.sec, 'mywifikey'), timeout=5000)
while not wlan.isconnected():
machine.idle() # save power while waiting
print('WLAN connection succeeded!')
break
import machine
from network import WLAN
wlan = WLAN() # get current object, without changing the mode
if machine.reset_cause() != machine.SOFT_RESET:
wlan.init(mode=WLAN.STA)
# configuration below MUST match your home router settings!!
wlan.ifconfig(config=('192.168.178.107', '255.255.255.0', '192.168.178.1', '8.8.8.
8'))
if not wlan.isconnected():
# change the line below to match your network ssid, security and password
wlan.connect('mywifi', auth=(WLAN.WPA2, 'mywifikey'), timeout=5000)
while not wlan.isconnected():
machine.idle() # save power while waiting
Notice how we check for the reset cause and the connection status, this is crucial in
order to be able to soft reset the LoPy during a telnet session without breaking the
connection.
88
5.2.2 WLAN
import os
import machine
known_nets = {
'<net>': {'pwd': '<password>'},
'<net>': {'pwd': '<password>', 'wlan_config': ('10.0.0.114', '255.255.0.0', '10.0
.0.1', '10.0.0.1')}, # (ip, subnet_mask, gateway, DNS_server)
}
if machine.reset_cause() != machine.SOFT_RESET:
from network import WLAN
wl = WLAN()
wl.mode(WLAN.STA)
original_ssid = wl.ssid()
original_auth = wl.auth()
except Exception as e:
print("Failed to connect to any known network, going into AP mode")
wl.init(mode=WLAN.AP, ssid=original_ssid, auth=original_auth, channel=6, anten
na=WLAN.INT_ANT)
89
5.2.2 WLAN
wlan = WLAN(mode=WLAN.STA)
wlan.connect(ssid='mywifi', auth=(WLAN.WPA2_ENT,), identity='myidentity', ca_certs='/f
lash/cert/ca.pem', keyfile='/flash/cert/client.key', certfile='/flash/cert/client.crt'
)
wlan = WLAN(mode=WLAN.STA)
wlan.connect(ssid='mywifi', auth=(WLAN.WPA2_ENT, 'username', 'password'), identity='my
identity', ca_certs='/flash/cert/ca.pem')
90
5.2.3 Bluetooth
Bluetooth
At present, basic BLE functionality is available. More features will be implemented in the
near future, such as pairing. This page will be updated in line with these features.
Full info on bluetooth can be found within bluetooth page of the Firmware API Reference.
91
5.2.3 Bluetooth
92
5.2.3 Bluetooth
while True:
adv = bt.get_adv()
if adv and bt.resolve_adv_data(adv.data, Bluetooth.ADV_NAME_CMPL) == 'Heart Rate':
try:
conn = bt.connect(adv.mac)
services = conn.services()
for service in services:
time.sleep(0.050)
if type(service.uuid()) == bytes:
print('Reading chars from service = {}'.format(service.uuid()))
else:
print('Reading chars from service = %x' % service.uuid())
chars = service.characteristics()
for char in chars:
if (char.properties() & Bluetooth.PROP_READ):
print('char {} value = {}'.format(char.uuid(), char.read()))
conn.disconnect()
break
except:
pass
else:
time.sleep(0.050)
93
5.2.3 Bluetooth
import binascii
from network import Bluetooth
bluetooth = Bluetooth()
bluetooth.start_scan(20)
while bluetooth.isscanning():
adv = bluetooth.get_adv()
if adv:
# try to get the complete name
print(bluetooth.resolve_adv_data(adv.data, Bluetooth.ADV_NAME_CMPL))
if mfg_data:
# try to get the manufacturer data (Apple's iBeacon data is sent here)
print(binascii.hexlify(mfg_data))
94
5.2.4 HTTPS
HTTPS
Basic connection using ssl.wrap_socket() .
import socket
import ssl
s = socket.socket()
ss = ssl.wrap_socket(s)
ss.connect(socket.getaddrinfo('www.google.com', 443)[0][-1])
Certificate was downloaded from the blynk examples folder and placed in /flash/cert/ on
the device.
import socket
import ssl
s = socket.socket()
ss = ssl.wrap_socket(s, cert_reqs=ssl.CERT_REQUIRED, ca_certs='/flash/cert/ca.pem')
ss.connect(socket.getaddrinfo('cloud.blynk.cc', 8441)[0][-1])
For more info, check the ssl module in the API reference.
95
5.2.5 MQTT
MQTT
MQTT is a lightweight messaging protocol that is ideal for sending small packets of data to
and from IoT devices via WiFi.
The broker used in this example is the [IO Adafruit](https://io.adafruit.com) platform, which is
free and allows for tinkering with MQTT.
Visit IO Adafruit and create an account. You'll need to get hold of an API Key as well as your
credentials. Visit this guide for more information about MQTT and how to use it with
Adafruit's Broker.
This example will send a message to a topic on the Adafruit MQTT broker and then also
subscribe to the same topic, in order to show how to use the subscribe functionality.
wlan = WLAN(mode=WLAN.STA)
wlan.connect("yourwifinetwork", auth=(WLAN.WPA2, "wifipassword"), timeout=5000)
client.set_callback(sub_cb)
client.connect()
client.subscribe(topic="youraccount/feeds/lights")
while True:
print("Sending ON")
client.publish(topic="youraccount/feeds/lights", msg="ON")
time.sleep(1)
print("Sending OFF")
client.publish(topic="youraccount/feeds/lights", msg="OFF")
client.check_msg()
time.sleep(1)
96
5.2.5 MQTT
97
5.2.6 AWS
Configuration (config.py):
98
5.2.6 AWS
This file contains the wifi, certificate paths and application specific settings that need to be
updated by the user.
# wifi configuration
WIFI_SSID = 'my_wifi_ssid'
WIFI_PASS = 'my_wifi_password'
Go to the AWS Iot page, click on manage and choose your device
From the left hand side, choose Activity and then click MQTT client.
Choose the topic name you entered in the configuration file.
99
5.2.6 AWS
pycomAwsMQTTClient.configureOfflinePublishQueueing(config.OFFLINE_QUEUE_SIZE)
pycomAwsMQTTClient.configureDrainingFrequency(config.DRAINING_FREQ)
pycomAwsMQTTClient.configureConnectDisconnectTimeout(config.CONN_DISCONN_TIMEOUT)
pycomAwsMQTTClient.configureMQTTOperationTimeout(config.MQTT_OPER_TIMEOUT)
pycomAwsMQTTClient.configureLastWill(config.LAST_WILL_TOPIC, config.LAST_WILL_MSG, 1)
# Subscribe to topic
pycomAwsMQTTClient.subscribe(config.TOPIC, 1, customCallback)
time.sleep(2)
100
5.2.6 AWS
pycomAwsMQTTShadowClient.configureConnectDisconnectTimeout(config.CONN_DISCONN_TIMEOUT
)
pycomAwsMQTTShadowClient.configureMQTTOperationTimeout(config.MQTT_OPER_TIMEOUT)
deviceShadowHandler = pycomAwsMQTTShadowClient.createShadowHandlerWithName(config.THIN
G_NAME, True)
101
5.2.6 AWS
pycomAwsMQTTShadowClient.configureConnectDisconnectTimeout(config.CONN_DISCONN_TIMEOUT
)
pycomAwsMQTTShadowClient.configureMQTTOperationTimeout(config.MQTT_OPER_TIMEOUT)
deviceShadowHandler = pycomAwsMQTTShadowClient.createShadowHandlerWithName(config.THIN
G_NAME, True)
# Listen on deltas
deviceShadowHandler.shadowRegisterDeltaCallback(customShadowCallback_Delta)
# Loop forever
while True:
time.sleep(1)
102
5.2.7 ADC
ADC
This example is a simple ADC sample. For more information please see ADC .
Calibration
Currently the ESP32's ADC is not calibrated from the factory. This means it must be
calibrated each time you wish to use it. To do this you must firstly measure the internal
voltage reference. The following code will connect the 1.1v reference to P22
Now that the voltage reference is externally accessable you should measure it with the most
accurate voltmeter you have access to. Note down the reading in millivolts, e.g. 1120 . To
disconnect the 1.1v reference from P22 please reset your module. You can now calibrate
the ADC by telling it the true value of the internal reference. You should then check your
calibration by connecting the ADC to a known voltage source.
103
5.2.8 I2C
I2C
The following example receives data from a light sensor using I2C. Sensor used is the
BH1750FVI Digital Light Sensor.
import time
from machine import I2C
import bh1750fvi
while(True):
data = light_sensor.read()
print(data)
time.sleep(1)
class BH1750FVI:
MEASUREMENT_TIME = const(120)
def read(self):
self.time += self.period
if self.time >= MEASUREMENT_TIME:
self.time = 0
data = self.i2c.readfrom(self.addr, 2)
self.value = (((data[0] << 8) + data[1]) * 1200) // 1000
return self.value
104
5.2.8 I2C
import socket
import time
import pycom
import struct
from network import LoRa
from machine import I2C
import bh1750fvi
LORA_PKG_FORMAT = "!BH"
LORA_CONFIRM_FORMAT = "!BB"
DEVICE_ID = 1
pycom.heartbeat(False)
while(True):
msg = struct.pack(LORA_PKG_FORMAT, DEVICE_ID, light_sensor.read())
lora_sock.send(msg)
pycom.rgbled(0x150000)
wait = 5
while (wait > 0):
wait = wait - 0.1
time.sleep(0.1)
recv_data = lora_sock.recv(64)
time.sleep(1)
105
5.2.8 I2C
106
5.2.9 Onewire Driver
Onewire Driver
This tutorial explains how to connect and read data from a DS18x20 temperature sensor.
The onewire library is also available at the pycom-libraries GitHub Repository.
Basic usage
import time
from machine import Pin
from onewire import DS18X20
from onewire import OneWire
while True:
print(temp.read_temp_async())
time.sleep(1)
temp.start_convertion()
time.sleep(1)
Library
#!/usr/bin/env python3
"""
OneWire library for MicroPython
"""
import time
import machine
class OneWire:
CMD_SEARCHROM = const(0xf0)
CMD_READROM = const(0x33)
CMD_MATCHROM = const(0x55)
CMD_SKIPROM = const(0xcc)
def reset(self):
"""
107
5.2.9 Onewire Driver
pin(0)
sleep_us(480)
i = disable_irq()
pin(1)
sleep_us(60)
status = not pin()
enable_irq(i)
sleep_us(420)
return status
def read_bit(self):
sleep_us = time.sleep_us
enable_irq = machine.enable_irq
pin = self.pin
pin(1) # half of the devices don't match CRC without this line
i = machine.disable_irq()
pin(0)
sleep_us(1)
pin(1)
sleep_us(1)
value = pin()
enable_irq(i)
sleep_us(40)
return value
def read_byte(self):
value = 0
for i in range(8):
value |= self.read_bit() << i
return value
i = machine.disable_irq()
pin(0)
sleep_us(1)
108
5.2.9 Onewire Driver
pin(value)
sleep_us(60)
pin(1)
sleep_us(1)
machine.enable_irq(i)
def scan(self):
"""
Return a list of ROMs for all attached devices.
Each ROM is returned as a bytes object of 8 bytes.
"""
devices = []
diff = 65
rom = False
for i in range(0xff):
rom, diff = self._search_rom(rom, diff)
if rom:
devices += [rom]
if diff == 0:
109
5.2.9 Onewire Driver
break
return devices
class DS18X20(object):
def __init__(self, onewire):
self.ow = onewire
self.roms = [rom for rom in self.ow.scan() if rom[0] == 0x10 or rom[0] == 0x28
]
def isbusy(self):
"""
Checks wether one of the DS18x20 devices on the bus is busy
performing a temperature convertion
"""
return not self.ow.read_bit()
110
5.2.9 Onewire Driver
ow = self.ow
ow.reset()
ow.select_rom(rom)
ow.write_byte(0x44) # Convert Temp
111
5.2.10 Threading
Threading
MicroPython supports spawning threads by the _thread module. The following example
demonstrates the use of this module. A thread is simply defined as a function that can
receive any number of parameters. Below 3 threads are started, each one perform a print at
a different interval.
import _thread
import time
for i in range(3):
_thread.start_new_thread(th_func, (i + 1, i))
Using Locks:
import _thread
a_lock = _thread.allocate_lock()
with a_lock:
print("a_lock is locked while this executes")
112
5.2.11 RGB LED
RGB LED
By default the heartbeat LED flashes in blue colour once every 4s to signal that the system
is alive. This can be overridden through the pycom module.
import pycom
pycom.heartbeat(False)
pycom.rgbled(0xff00) # turn on the RGB LED in green colour
The heartbeat LED is also used to indicate that an error was detected.
The following piece of code uses the RGB LED to make a traffic light that runs for 10 cycles.
import pycom
import time
pycom.heartbeat(False)
for cycles in range(10): # stop after 10 cycles
pycom.rgbled(0x007f00) # green
time.sleep(5)
pycom.rgbled(0x7f7f00) # yellow
time.sleep(1.5)
pycom.rgbled(0x7f0000) # red
time.sleep(4)
113
5.2.11 RGB LED
114
5.2.12 Timers
Timers
Detailed information about this class can be found in Timer .
Chronometer
The Chronometer can be used to measure how much time has elapsed in a block of code.
The following example uses a simple stopwatch.
chrono = Timer.Chrono()
chrono.start()
time.sleep(1.25) # simulate the first lap took 1.25 seconds
lap = chrono.read() # read elapsed time without stopping
time.sleep(1.5)
chrono.stop()
total = chrono.read()
print()
print("\nthe racer took %f seconds to finish the race" % total)
print(" %f seconds in the first lap" % lap)
print(" %f seconds in the last lap" % (total - lap))
Alarm
The Alarm can be used to get interrupts at a specific interval. The following code executes a
callback every second for 10 seconds.
115
5.2.12 Timers
class Clock:
def __init__(self):
self.seconds = 0
self.__alarm = Timer.Alarm(self._seconds_handler, 1, periodic=True)
clock = Clock()
There are no restrictions to what can be done in an interrupt. For example, it is possible
to even do network requests with an interrupt. However, it is important to keep in mind
that interrupts are handled sequentially, so it’s good practice to keep them short. More
information can be found in Interrupt Handling .
116
5.2.13 PIR Sensor
PIR Sensor
This code reads PIR sensor triggers from this simple PIR sensor and sends an HTTP
request for every trigger, in this case to a Domoticz installation. When motion is constantly
detected, this PIR sensor keeps the pin high, in which case this code will keep sending
HTTP requests every 10 seconds (configurable with the hold_time variable).
Main (main.py)
import time
from network import WLAN
from machine import Pin
from domoticz import Domoticz
wl = WLAN(WLAN.STA)
d = Domoticz("<ip>", 8080 ,"<hash>")
#config
hold_time_sec = 10
#flags
last_trigger = -10
pir = Pin('G4',mode=Pin.IN,pull=Pin.PULL_UP)
# main loop
print("Starting main loop")
while True:
if pir() == 1:
if time.time() - last_trigger > hold_time_sec:
last_trigger = time.time()
print("Presence detected, sending HTTP request")
try:
return_code = d.setVariable('Presence:LivingRoom','1')
print("Request result: "+str(return_code))
except Exception as e:
print("Request failed")
print(e)
else:
last_trigger = 0
print("No presence")
time.sleep_ms(500)
117
5.2.13 PIR Sensor
Boot (boot.py)
For more wifi scripts, see the wlan step by step tutorial.
import os
import machine
known_nets = {
'NetworkID': {'pwd': '<password>', 'wlan_config': ('10.0.0.8', '255.255.0.
0', '10.0.0.1', '10.0.0.1')},
}
if machine.reset_cause() != machine.SOFT_RESET:
wl.mode(WLAN.STA)
original_ssid = wl.ssid()
original_auth = wl.auth()
except Exception as e:
print("Failed to connect to any known network, going into AP mode")
wl.init(mode=WLAN.AP, ssid=original_ssid, auth=original_auth, channel=6, anten
na=WLAN.INT_ANT)
118
5.2.13 PIR Sensor
import socket
class Domoticz:
except Exception:
print("HTTP request failed")
return 0
119
5.2.14 Modbus
Modbus Protocol
Modbus is a messaging protocol that defines the packet sructure for transferring data
between devices in a master/slave architecure. The protocol is independent of the
transmission medium and is usually transmissed over TCP (MODBUS TCP) or over serial
communication (MODBUS RTU). Modbus is intended to be a request/reply protocol and
delivers services specified by function codes. The function code in the request tells the
addressed slave what kind of action to perform. The function codes most commonly
supported by devices are listed below.
For more information on the MODBUS RTU see the following PDF File. Information on the
MODBUS TCP can be found here.
Read Coils
This function code requests the status (ON/OFF) of discrete coils in a remote device. The
slave device address, the address of the first coil and the number of coils must be specified
in the request. The address of the first coil is 0 and a maximum of 2000 contiguous coils can
be read. Python sample code is shown below.
120
5.2.14 Modbus
slave_addr=0x0A
starting_address=0x00
coil_quantity=100
slave_addr=0x0A
starting_address=0x0
input_quantity=100
slave_addr=0x0A
starting_address=0x00
register_quantity=100
signed=True
121
5.2.14 Modbus
slave_addr=0x0A
starting_address=0x00
register_quantity=100
signed=True
slave_addr=0x0A
output_address=0x00
output_value=0xFF00
slave_addr=0x0A
register_address=0x01
register_value=-32768
signed=True
122
5.2.14 Modbus
This function code is used to set a contigous sequence of coils, in a remote device, to either
ON or OFF. The slave address, the starting address of the coils and an array with the coil
states must be specified.
slave_addr=0x0A
starting_address=0x00
output_values=[1,1,1,0,0,1,1,1,0,0,1,1,1]
slave_addr=0x0A
register_address=0x01
register_values=[2, -4, 6, -256, 1024]
signed=True
123
5.2.15 OTA update
Overview
Pycom modules come with the ability to update the devices firmware, while it is still running,
we call this an "over the air" (OTA) update. The pycom library provides several functions to
achieve this. This example will demonstrate how you could potentially use this functionality
to update deployed devices. The full source code of this example can be found here.
Method
Here we will describe one possible update methodology you could use that is implemented
by this example.
Imagine you a smart metering company and you wish to roll out an update for your pycom
based smart meter. These meters usually send data back via LoRa. Unfortunately LoRa
downlink messages have a very limited size and several hundred if not thousand would be
required to upload a complete firmware image. To get around this you can have your devices
sending their regular data via LoRa and when they receive a special command via a
downlink message, the devices will connect to a wifi network. It is unfeasible to ask
customers to allow your device to connect to their home network so instead this network
could be provided by a vehicle. This vehicle will travel around a certain geographic area in
which the devices have been sent the special downlink message to initiate the update. The
devices will look for the WiFi network being broadcast by the vehicle and connect.The
devices will then connect to a server running on this WiFi network. This server (also shown
in this example) will generate manifest files that instruct the device on what it should update,
and where to get the update data from.
Server
Code available here.
This script runs a HTTP server on port 8000 that provisions over the air (OTA) update
manifests in JSON format as well as serving the update content. This script should be run in
a directory that contains every version of the end devices code, in the following structure:
124
5.2.15 OTA update
- server directory
|- this_script.py
|- 1.0.0
| |- flash
| | |- lib
| | | |- lib_a.py
| | |- main.py
| | |- boot.py
| |- sd
| |- some_asset.txt
| |- asset_that_will_be_removed.wav
|- 1.0.1
| |- flash
| | |- lib
| | | |- lib_a.py
| | | |- new_lib.py
| | |- main.py
| | |- boot.py
| |- sd
| |- some_asset.txt
|- firmware_1.0.0.bin
|- firmware_1.0.1.bin
The top level directory that contains this script can contain one of two things:
Update directory: These should be named with a version number compatible with the
python LooseVersion versioning scheme
(http://epydoc.sourceforge.net/stdlib/distutils.version.LooseVersion-class.html). They
should contain the entire file system of the end device for the corresponding version
number.
Firmware: These files should be named in the format "firmare_VERSION.bin", where
VERSION is a a version number compatible with the python LooseVersion versioning
scheme (http://epydoc.sourceforge.net/stdlib/distutils.version.LooseVersion-class.html).
This file should be in the format of the appimg.bin created by the pycom firmware build
scripts.
How to use
Once the directory has been setup as described above you simply need to start this script
using python3. Once started this script will run a HTTP server on port 8000 (this can be
changed by changing the PORT variable). This server will serve all the files in directory as
expected along with one additional special file, "manifest.json". This file does not exist on the
file system but is instead generated when requested and contains the required changes to
125
5.2.15 OTA update
bring the end device from its current version to the latest available version. You can see an
example of this by pointing your web browser at: http://127.0.0.1:8000/manifest.json?
current_ver=1.0.0
The current_ver field at the end of the URL should be set to the current firmware version of
the end device. The generated manifest will contain lists of which files are new, have
changed or need to be deleted along with SHA1 hashes of the files. Below is an example of
what such a manifest might look like:
{
"delete": [
"flash/old_file.py",
"flash/other_old_file.py"
],
"firmware": {
"URL": "http://192.168.1.144:8000/firmware_1.0.1b.bin",
"hash": "ccc6914a457eb4af8855ec02f6909316526bdd08"
},
"new": [
{
"URL": "http://192.168.1.144:8000/1.0.1b/flash/lib/new_lib.py",
"dst_path": "flash/lib/new_lib.py",
"hash": "1095df8213aac2983efd68dba9420c8efc9c7c4a"
}
],
"update": [
{
"URL": "http://192.168.1.144:8000/1.0.1b/flash/changed_file.py",
"dst_path": "flash/changed_file.py",
"hash": "1095df8213aac2983efd68dba9420c8efc9c7c4a"
}
],
"version": "1.0.1b"
}
new : the URL, path on end device and SHA1 hash of all new files
update : the URL, path on end device and SHA1 hash of all files which existed before
previous_version : The version the client is currently on before applying this update
126
5.2.15 OTA update
Note: The version number of the files might not be the same as the firmware. The highest
available version number, higher than the current client version is used for both firmware and
files. This may differ between the two.
In order for the URL's to be properly formatted you are required to send a "host" header
along with your HTTP get request e.g:
Client Library
A micropyton library for interfacing with the server described above is available here.
This library is split into two layers. The top level OTA class implements all the high level
functionality such as parsing the JSON file, making back copies of files being updated
incase the update fails, etc. The layer of the library is agnostic to your chosen transport
method. Below this is the WiFiOTA class. This class implements the actual transport
mechanism of how the device fetches the files and update manifest (via WiFi as the class
name suggests). The reason for this split is so that the high level functionality can be reused
regardless of what transport mechanism you end up using. This could be implemented on
top of Bluetooth for example, or the sever changed from HTTP to FTP.
Although the above code is functional, it is provided only as an example of how an end
user might implement a OTA update mechanism. It is not 100% feature complete e.g.
even though it does backup previous versions of files, the roll back procedure is not
implemented. This is left of the end user to do.
Example
Below is am example implementing the methodology previously explained in this tutorial to
initiate an OTA update.
The example below will only work on a Pycom device with LoRa capabilities. If want to
test it out on a device without LoRa functionality then simply comment out any code
relating to LoRa. Leaving just the WiFiOTA initialisation and they ota.connect() and
ota.update()
127
5.2.15 OTA update
# Setup OTA
ota = WiFiOTA(WIFI_SSID,
WIFI_PW,
SERVER_IP, # Update server address
8000) # Update server port
app_eui = binascii.unhexlify('70B3D57ED0008CD6')
app_key = binascii.unhexlify('B57F36D88691CEC5EE8659320169A61C')
while True:
# send some data
s.send(bytes([0x04, 0x05, 0x06]))
128
5.2.15 OTA update
sleep(5)
129
5.2.16 RMT
RMT
Detailed information about this class can be found in RMT .
The RMT (Remote Control) peripheral of the ESP32 is primarily designed to send and
receive infrared remote control signals that use on-off-keying of a carrier frequency, but due
to its design it can be used to generate various types of signals, this class will allow you to
do this.
The RMT has 7 channels, of which 5 are available and can be mapped to any GPIO pin
(Note: Pins P13 - P18 can only be used as inputs).
6 3125nS 102.4 ms
7 3125nS 102.4 ms
Transmitting
The following examples create an RMT object on channel 4, configure it for transmission
and send some data in various forms. The resolution of channel 4 is 1000 nano seconds, the
given values are interpreted accordingly.
In this first example, we define the signal as a tuple of binary values that define the shape of
the desired signal along with the duration of a bit.
130
5.2.16 RMT
In this example we define the signal by a tuple of durations and what state the signal starts
in.
# The list of durations for each pulse to be, these are in units of the channels
# resolution:
# duration = Desired pulse length / Channel Resolution
duration = (8000,11000,8000,11000,6000,13000,6000,3000,8000)
# `start_level` defines if the signal starts off as LOW or HIGH, it will then
# toggle state between each duration
rmt.pulses_send(duration, start_level=RMT.HIGH)
131
5.2.16 RMT
This third example, is a combination of the above two styles of defining a signal. Each pulse
has a defined duration as well as a state. This is useful if you don't always want the signal to
toggle state.
The following example creates an RMT object on channel 4 and configures it for
transmission with carrier modulation.
132
5.2.16 RMT
The following example creates an RMT object on channel 2, configures it for receiving, then
waits for the first, undefined number of pulses without timeout
data = rmt.pulses_get()
If tx_idle_level is not set to the opposite of the third value in the tx_carrier tuple,
the carrier wave will continue to be generated when the RMT channel is idle.
Receiving
The following example creates an RMT object on channel 2, configures it for receiving a
undefined number of pulses, then waits maximum of 1000us for the first pulse.
# Get a undefined number of pulses, waiting a maximum of 500us for the first
# pulse (unlike other places where the absolute duration was based on the RMT
# channels resolution, this value is in us) until a pulse longer than
# rx_idle_threshold occurs.
data = rmt.pulses_get(timeout=500)
The following example creates an RMT object on channel 2, configures it for receiving, filters
out pulses with width < 20*100 nano seconds, then waits for 100 pulses
133
5.2.16 RMT
# Receive 100 pulses, pulses shorter than 2us or longer than 100us will be
# ignored. That means if it receives 80 valid pulses but then the signal
# doesn't change for 10 hours and then 20 more pulses occur, this function
# will wait for 10h
data = rmt.pulses_get(pulses=100)
134
5.3 LoRa Examples
LoRa Tutorials
The following tutorials demonstrate the use of the LoRa functionality on LoRa enabled
Pycom modules. LoRa can work in 2 different modes; LoRa-MAC (which we also call Raw-
LoRa) and LoRaWAN mode.
LoRa-MAC mode basically accesses the radio directly and packets are sent using the LoRa
modulation on the selected frequency without any headers, addressing information or
encryption. Only a CRC is added at the tail of the packet and this is removed before the
received frame is passed on to the application. This mode can be used to build any higher
level protocol that can benefit from the long range features of the LoRa modulation. Typical
uses cases include LoPy to LoPy direct communication and a LoRa packet forwarder.
LoRaWAN mode implements the full LoRaWAN stack for a class A device. It supports both
OTAA and ABP connection methods, as well as advanced features like adding and removing
custom channels to support “special” frequencies plans like those used in New Zealand.
135
5.3.1 LoRa-MAC (Raw LoRa)
For the example below, you will need two LoPys. A while loop with a random delay time is
used to minimize the chances of the 2 LoPy’s transmitting at the same time. Run the code
below on the 2 LoPy modules and you will see the word 'Hello' being received on both sides.
while True:
# send some data
s.setblocking(True)
s.send('Hello')
136
5.3.2 LoRaWAN with OTAA
LoRaWAN (OTAA)
OTAA stands for Over The Air Authentication. With this method the LoPy sends a Join
request to the LoRaWAN Gateway using the APPEUI and APPKEY provided. If the keys are
correct the Gateway will reply to the LoPy with a join accept message and from that point on
the LoPy is able to send and receive packets to/from the Gateway. If the keys are incorrect
no response will be received and the has_joined() method will always return False .
The example below attempts to get any data received after sending the frame. Keep in mind
that the Gateway might not be sending any data back, therefore we make the socket non-
blocking before attempting to receive, in order to prevent getting stuck waiting for a packet
that will never arrive.
137
5.3.2 LoRaWAN with OTAA
138
5.3.3 LoRaWAN with ABP
LoRaWAN (ABP)
ABP stands for Authentication By Personalisation. It means that the encryption keys are
configured manually on the device and can start sending frames to the Gateway without
needing a 'handshake' procedure to exchange the keys (such as the one performed during
an OTAA join procedure).
The example below attempts to get any data received after sending the frame. Keep in mind
that the Gateway might not be sending any data back, therefore we make the socket non-
blocking before attempting to receive, in order to prevent getting stuck waiting for a packet
that will never arrive.
139
5.3.3 LoRaWAN with ABP
140
5.3.4 LoRa-MAC Nano-Gateway
For more information and discussions about this code, see this forum post.
Gateway Code
import socket
import struct
from network import LoRa
# A basic package header, B: 1 byte for the deviceId, B: 1 byte for the pkg size, %ds:
Formatted string for string
_LORA_PKG_FORMAT = "!BB%ds"
# A basic ack package, B: 1 byte for the deviceId, B: 1 byte for the pkg size, B: 1 by
te for the Ok (200) or error messages
_LORA_PKG_ACK_FORMAT = "BBB"
# Open a LoRa Socket, use rx_iq to avoid listening to our own messages
# Please pick the region that matches where you are using the device:
# Asia = LoRa.AS923
# Australia = LoRa.AU915
# Europe = LoRa.EU868
# United States = LoRa.US915
lora = LoRa(mode=LoRa.LORA, rx_iq=True, region=LoRa.EU868)
lora_sock = socket.socket(socket.AF_LORA, socket.SOCK_RAW)
lora_sock.setblocking(False)
while (True):
recv_pkg = lora_sock.recv(512)
if (len(recv_pkg) > 2):
recv_pkg_len = recv_pkg[1]
# If the uart = machine.UART(0, 115200) and os.dupterm(uart) are set in the boot.py th
is print should appear in the serial port
print('Device: %d - Pkg: %s' % (device_id, msg))
141
5.3.4 LoRa-MAC Nano-Gateway
Node
142
5.3.4 LoRa-MAC Nano-Gateway
import os
import socket
import time
import struct
from network import LoRa
# A basic package header, B: 1 byte for the deviceId, B: 1 byte for the pkg size
_LORA_PKG_FORMAT = "BB%ds"
_LORA_PKG_ACK_FORMAT = "BBB"
DEVICE_ID = 0x01
# Open a Lora Socket, use tx_iq to avoid listening to our own messages
# Please pick the region that matches where you are using the device:
# Asia = LoRa.AS923
# Australia = LoRa.AU915
# Europe = LoRa.EU868
# United States = LoRa.US915
lora = LoRa(mode=LoRa.LORA, tx_iq=True, region=LoRa.EU868)
lora_sock = socket.socket(socket.AF_LORA, socket.SOCK_RAW)
lora_sock.setblocking(False)
while(True):
# Package send containing a simple string
msg = "Device 1 Here"
pkg = struct.pack(_LORA_PKG_FORMAT % len(msg), DEVICE_ID, len(msg), msg)
lora_sock.send(pkg)
# Wait for the response from the gateway. NOTE: For this demo the device does an i
nfinite loop for while waiting the response. Introduce a max_time_waiting for you appl
ication
waiting_ack = True
while(waiting_ack):
recv_ack = lora_sock.recv(256)
time.sleep(5)
143
5.3.4 LoRa-MAC Nano-Gateway
The node is always sending packages and waiting for the ack from the gateway.
Put a max waiting time for the ack to arrive and resend the package or mark it as
invalid
Increase the package size changing the _LORA_PKG_FORMAT to 'BH%ds'. The H will
allow the keeping of 2 bytes for size (for more information about struct format)
Reduce the package size with bitwise manipulation
Reduce the message size (for this demo, a string) to something more useful for
specific development
144
5.3.5 LoPy to LoPy
Node A
# Please pick the region that matches where you are using the device:
# Asia = LoRa.AS923
# Australia = LoRa.AU915
# Europe = LoRa.EU868
# United States = LoRa.US915
lora = LoRa(mode=LoRa.LORA, region=LoRa.EU868)
s = socket.socket(socket.AF_LORA, socket.SOCK_RAW)
s.setblocking(False)
while True:
if s.recv(64) == b'Ping':
s.send('Pong')
time.sleep(5)
Node B
# Please pick the region that matches where you are using the device:
# Asia = LoRa.AS923
# Australia = LoRa.AU915
# Europe = LoRa.EU868
# United States = LoRa.US915
lora = LoRa(mode=LoRa.LORA, region=LoRa.EU868)
s = socket.socket(socket.AF_LORA, socket.SOCK_RAW)
s.setblocking(False)
while True:
s.send('Ping')
time.sleep(5)
145
5.3.5 LoPy to LoPy
146
5.3.6 LoRaWAN Nano-Gateway
LoRaWAN Nano-Gateway
This example allows to connect a LoPy to a LoRaWAN network such as The Things Network
(TTN) or Loriot to be used as a nano-gateway.
This example uses settings specifically for connecting to The Things Network within the
European 868 MHz region. For another usage, please see the config.py file for relevant
sections that need changing.
Up to date versions of these snippets can be found at the following GitHub Repository. For
more information and discussion about this code, see this forum post.
Nano-Gateway
The Nano-Gateway code is split into 3 files, main.py , config.py and nanogateway.py .
These are used to configure and specify how the gateway will connect to a preferred
network and how it can act as packet forwarder.
Gateway ID
Most LoRaWAN network servers expect a Gateway ID in the form of a unique 64-bit
hexadecimal number (called a EUI-64). The recommended practice is to produce this ID
from your board by expanding the WiFi MAC address (a 48-bit number, called MAC-48). You
can obtain that by running this code prior to configuration:
Main (main.py)
This file runs at boot and calls the library and config.py files to initalise the nano-gateway.
Once configuration is set, the nano-gateway is then started.
147
5.3.6 LoRaWAN Nano-Gateway
import config
from nanogateway import NanoGateway
if __name__ == '__main__':
nanogw = NanoGateway(
id=config.GATEWAY_ID,
frequency=config.LORA_FREQUENCY,
datarate=config.LORA_GW_DR,
ssid=config.WIFI_SSID,
password=config.WIFI_PASS,
server=config.SERVER,
port=config.PORT,
ntp_server=config.NTP,
ntp_period=config.NTP_PERIOD_S
)
nanogw.start()
nanogw._log('You may now press ENTER to enter the REPL')
input()
Configuration (config.py)
This file contains settings for the server and network it is connecting to. Depending on the
nano-gateway region and provider (TTN, Loriot, etc.) these will vary. The provided example
will work with The Things Network (TTN) in the European, 868Mhz, region.
The Gateway ID is generated in the script using the process described above.
Please change the WIFI_SSID and WIFI_PASS variables to match your desired WiFi
network
148
5.3.6 LoRaWAN Nano-Gateway
import machine
import ubinascii
WIFI_MAC = ubinascii.hexlify(machine.unique_id()).upper()
# Set the Gateway ID to be the first 3 bytes of MAC address + 'FFFE' + last 3 bytes o
f MAC address
GATEWAY_ID = WIFI_MAC[:6] + "FFFE" + WIFI_MAC[6:12]
SERVER = 'router.eu.thethings.network'
PORT = 1700
NTP = "pool.ntp.org"
NTP_PERIOD_S = 3600
WIFI_SSID = 'my-wifi'
WIFI_PASS = 'my-wifi-password'
# for EU868
LORA_FREQUENCY = 868100000
LORA_GW_DR = "SF7BW125" # DR_5
LORA_NODE_DR = 5
# for US915
# LORA_FREQUENCY = 903900000
# LORA_GW_DR = "SF7BW125" # DR_3
# LORA_NODE_DR = 3
Library (nanogateway.py)
The nano-gateway library controls all of the packet generation and forwarding for the LoRa
data. This does not require any user configuration and the latest version of this code should
be downloaded from the Pycom GitHub Repository.
149
5.3.6 LoRaWAN Nano-Gateway
PROTOCOL_VERSION = const(2)
PUSH_DATA = const(0)
PUSH_ACK = const(1)
PULL_DATA = const(2)
PULL_ACK = const(4)
PULL_RESP = const(3)
TX_ERR_NONE = "NONE"
TX_ERR_TOO_LATE = "TOO_LATE"
TX_ERR_TOO_EARLY = "TOO_EARLY"
TX_ERR_COLLISION_PACKET = "COLLISION_PACKET"
TX_ERR_COLLISION_BEACON = "COLLISION_BEACON"
TX_ERR_TX_FREQ = "TX_FREQ"
TX_ERR_TX_POWER = "TX_POWER"
TX_ERR_GPS_UNLOCKED = "GPS_UNLOCKED"
TX_ACK_PK = {"txpk_ack":{"error":""}}
class NanoGateway:
def __init__(self, id, frequency, datarate, ssid, password, server, port, ntp='poo
l.ntp.org', ntp_period=3600):
self.id = id
self.frequency = frequency
self.sf = self._dr_to_sf(datarate)
self.ssid = ssid
self.password = password
self.server = server
self.port = port
self.ntp = ntp
self.ntp_period = ntp_period
self.rxnb = 0
self.rxok = 0
self.rxfw = 0
self.dwnb = 0
150
5.3.6 LoRaWAN Nano-Gateway
self.txnb = 0
self.stat_alarm = None
self.pull_alarm = None
self.uplink_alarm = None
self.udp_lock = _thread.allocate_lock()
self.lora = None
self.lora_sock = None
def start(self):
# Change WiFi to STA mode and connect
self.wlan = WLAN(mode=WLAN.STA)
self._connect_to_wifi()
def stop(self):
# TODO: Check how to stop the NTP sync
151
5.3.6 LoRaWAN Nano-Gateway
def _connect_to_wifi(self):
self.wlan.connect(self.ssid, auth=(None, self.password))
while not self.wlan.isconnected():
time.sleep(0.5)
print("WiFi connected!")
def _make_stat_packet(self):
now = self.rtc.now()
STAT_PK["stat"]["time"] = "%d-%02d-%02d %02d:%02d:%02d GMT" % (now[0], now[1],
now[2], now[3], now[4], now[5])
STAT_PK["stat"]["rxnb"] = self.rxnb
STAT_PK["stat"]["rxok"] = self.rxok
STAT_PK["stat"]["rxfw"] = self.rxfw
STAT_PK["stat"]["dwnb"] = self.dwnb
STAT_PK["stat"]["txnb"] = self.txnb
return json.dumps(STAT_PK)
def _pull_data(self):
token = os.urandom(2)
152
5.3.6 LoRaWAN Nano-Gateway
def _udp_thread(self):
while True:
try:
data, src = self.sock.recvfrom(1024)
_token = data[1:3]
_type = data[3]
if _type == PUSH_ACK:
print("Push ack")
elif _type == PULL_ACK:
153
5.3.6 LoRaWAN Nano-Gateway
print("Pull ack")
elif _type == PULL_RESP:
self.dwnb += 1
ack_error = TX_ERR_NONE
tx_pk = json.loads(data[4:])
tmst = tx_pk["txpk"]["tmst"]
t_us = tmst - time.ticks_us() - 5000
if t_us < 0:
t_us += 0xFFFFFFFF
if t_us < 20000000:
self.uplink_alarm = Timer.Alarm(handler=lambda x: self._send_d
own_link(binascii.a2b_base64(tx_pk["txpk"]["data"]),
tx_pk["txpk"]["tmst"] - 10, tx_pk["txpk"]["datr"],
int(tx_pk["txpk"]["freq"] * 1000000)), us=t_us)
else:
ack_error = TX_ERR_TOO_LATE
print("Downlink timestamp error!, t_us:", t_us)
self._ack_pull_rsp(_token, ack_error)
print("Pull rsp")
except socket.timeout:
pass
except OSError as e:
if e.errno == errno.EAGAIN:
pass
else:
print("UDP recv OSError Exception")
except Exception:
print("UDP recv Exception")
# Wait before trying to receive again
time.sleep(0.025)
154
5.3.6 LoRaWAN Nano-Gateway
Once an account has been registered, the nano-gateway can then be registered. To do this,
navigate to the TTN Console web page.
of a new nano-gateway.
155
5.3.6 LoRaWAN Nano-Gateway
On the Register Gateway page, you will need to set the following settings:
These are unique to each gateway, location and country specific frequency. Please verify
that correct settings are selected otherwise the gateway will not connect to TTN.
You need to tick the "I'm using the legacy packet forwarder" to enable the right
settings. This is because the Nano-Gateway uses the 'de facto' standard Semtech UDP
protocol.
156
5.3.6 LoRaWAN Nano-Gateway
Option Value
The Gateway EUI should match your Gateway ID from the config.py file. We suggest you
follow the procedure described near the top of this document to create your own unique
Gateway ID.
Once these settings have been applied, click Register Gateway . A Gateway Overview page
will appear, with the configuration settings showing. Next click on the Gateway Settings and
configure the Router address to match that of the gateway (default:
router.eu.thethings.network).
The Gateway should now be configured. Next, one or more nodes can now be configured to
use the nano-gateway and TTN applications may be built.
LoPy Node
157
5.3.6 LoRaWAN Nano-Gateway
There are two methods of connecting LoPy devices to the nano-gateway, Over the Air
Activation (OTAA) and Activation By Personalisation (ABP). The code and instructions for
registering these methods are shown below, followed by instruction for how to connect them
to an application on TTN.
It’s important that the following code examples (also on GitHub) are used to connect to
the nano-gateway as it only supports single channel connections.
""" OTAA Node example compatible with the LoPy Nano Gateway """
# set the 3 default channels to the same frequency (must be before sending the OTAA jo
in request)
lora.add_channel(0, frequency=868100000, dr_min=0, dr_max=5)
lora.add_channel(1, frequency=868100000, dr_min=0, dr_max=5)
lora.add_channel(2, frequency=868100000, dr_min=0, dr_max=5)
158
5.3.6 LoRaWAN Nano-Gateway
time.sleep(5.0)
Device Address
Application Session Key
Network Session Key
159
5.3.6 LoRaWAN Nano-Gateway
""" ABP Node example compatible with the LoPy Nano Gateway """
TTN Applications
160
5.3.6 LoRaWAN Nano-Gateway
Now that the gateway & nodes have been setup, a TTN Application can be built; i.e. what
happens to the LoRa data once it is received by TTN. There are a number of different
setups/systems that can be used, however the following example demonstrates the HTTP
request integration.
Registering an Application
Selecting the Applications tab at the top of the TTN console, will bring up a screen for
registering applications. Click register and a new page, similar to the one below, will open.
Now the LoPy nodes must be registered to send data up to the new Application.
In the Register Device panel, complete the forms for the Device ID and the Device EUI .
The Device ID is user specified and is unique to the device in this application. The Device
EUI is also user specified but must consist of exactly 8 bytes, given in hexadecimal.
161
5.3.6 LoRaWAN Nano-Gateway
Once the device has been added, change the Activation Method between OTAA and ABP
depending on user preference. This option can be found under the Settings tab.
Upon clicking add integration , a screen with 4 different options will appear. These have
various functionality and more information about them can be found on the TTN
website/documentation.
For this example, use the HTTP Integration to forward the LoRaWAN Packets to a remote
server/address.
162
5.3.6 LoRaWAN Nano-Gateway
Click HTTP Integration to connect up an endpoint that can receive the data.
For testing, a website called RequestBin may be used to receive the data that TTN forwards
(via POST Request). To set this up, navigate to RequestBin and click the Create a
RequestBin .
Copy the URL that is generated and past this into the URL form under the Application
Settings .
163
5.3.6 LoRaWAN Nano-Gateway
This is the address that TTN will forward data onto. As soon as a LoPy starts sending
messages, TTN will forward these onto RequestBin and they will appear at the unique
RequestBin URL .
164
5.3.7 RN2483 to LoPy
RN2483 to LoPy
This example shows how to send data between a Microchip RN2483 and a LoPy via raw
LoRa.
RN2483
mac pause
radio set freq 868000000
LoPy
s = socket.socket(socket.AF_LORA, socket.SOCK_RAW)
165
5.3.8 Objenious
Identifiers
To connect a Pycom LoRa device (LoPy, LoPy4, FiPy) to Objenious you'll need to provision
it. This requires three pieces of information
Device EUI
This comes from the device itself and can be obtained from lora.mac() .
To obtain the required hexadecimal representation you can run the following code on your
LoPy:
lora = LoRa()
print("DevEUI: %s" % (binascii.hexlify(lora.mac()).decode('ascii')))
For testing purposes we provide a script which generates a random Application EUI from our
assignment and a series of Application Keys:
(note: the Application EUI produced by this script is not guaranteed to be unique)
166
5.3.8 Objenious
To use the script make sure you are using Python 3.6 on your computer and run it (on your
computer, not on the Pycom board) as:
python generate_keys.py 1
AppEUI: 70b3d54923e36a89
AppKeys:
78fe712d96f46784a98b574a8cd616fe
If you are registering multiple devices you can generate more Applications Keys by changing
"1" to your desired number of devices.
Provisioning
Once you have the three identifiers for your device you need to register them on the
Objenius portal.
Follow "Importer des capteurs" under "Statuc do Parc" and select "Provisioning Unitaire":
Once there give your device a name and enter the DevEUI, AppEUI and AppKey obtained
from the steps above:
167
5.3.8 Objenious
168
5.4 Sigfox Examples
Sigfox Tutorials
To ensure your device has been provisioned with Device ID and PAC number, please
update to the latest firmware.
The following tutorials demonstrate how to register and get started with Sigfox enabled
Pycom module. These modules can be configured for operation in various countries based
upon specified RCZ zones (see the Sigfox class for more info). All our modules support
both uplink and downlink Sigfox messages. The SiPy also supports device to device
communication via its FSK Mode.
169
5.4.1 Register Device
In order to send a Sigfox message, the device need to register with the Sigfox Backend.
Navigate to https://backend.sigfox.com/activate to find the list of Sigfox enabled
development kits.
Next choose a Sigfox Operator for the country where the device will be activated. Find the
specific country and select the operator to continue.
170
5.4.1 Register Device
The Device ID and PAC number are retrievable through a couple of commands via the
REPL.
# initalise Sigfox for RCZ1 (You may need a different RCZ Region)
sigfox = Sigfox(mode=Sigfox.SIGFOX, rcz=Sigfox.RCZ1)
See Sigfox for more info about the Sigfox Class and which RCZ region to use.
171
5.4.1 Register Device
Once the device's Device ID and PAC number have been entered, create an account.
Provide the required information including email address and click to continue.
An email confirming the creation of a Sigfox Backend account and the successful
registration of the device should arrive at the users inbox.
172
5.4.2 Disengage Sequence Number
You can use the 'Disengage sequence number' button on the device information or on the
device type information page of the Sigfox backend to reset the number expected by the
backend. If the sequence number of your next message is different from the last trashed
sequence number, the message will be accepted.
Issues with the sequence number can occur when a lot of messages are sent when outside
of Sigfox coverage for instance.
Firstly you will need to log into the Sigfox Backend, navigate to device, and click on the
Sigfox ID of the affected SiPy.
You should now see the Information page with an entry Device Type: followed by a link.
Please follow the link
173
5.4.2 Disengage Sequence Number
Finally, on this page click on Disengage sequence number button in the upper right corner.
174
5.5.1 Module IMEI
>>> import os
>>> os.uname()
(sysname='GPy', nodename='GPy', release='1.17.0.b1', version='v1.8.6-849-d0dc708 on 20
18-02-27', machine='GPy with ESP32')
Once you have a compatible firmware, you can run the following code to get your modules
IMEI number:
You’ll get a return string like this \r\n+CGSN: "354347xxxxxxxxx"\r\n\r\nOK . The value
between the double quotes is your IMEI.
175
5.6 Pytrack Examples
Accelerometer
Both the Pysense and Pytrack use the same accelerometer. Please see the Pysense
Examples to see how to use the accelerometer.
176
5.7 Pysense Examples
Sensor Demos
Accelerometer
This basic example shows how to read pitch and roll from the on-board accelerometer and
output it in comma separated value (CSV) format over serial.
while True:
pitch = acc.pitch()
roll = acc.roll()
print('{},{}'.format(pitch,roll))
time.sleep_ms(100)
If you want to visualise the data output by this script a Processing sketch is available here
that will show the board orientation in 3D.
177
5.7 Pysense Examples
178
6.1 Introduction
Introduction
This chapter describes modules (function and class libraries) that are built into MicroPython.
There are a number of categories for the available modules:
Modules which implement a subset of standard Python functionality and are not
intended to be extended by the user.
Modules which implement a subset of Python functionality, with a provision for
extension by the user (via Python code).
Modules which implement MicroPython extensions to the Python standard libraries.
Modules specific to a particular port and thus not portable.
Note about the availability of modules and their contents: This documentation in general
aspires to describe all modules and functions/classes which are implemented in
MicroPython. However, MicroPython is highly configurable, and each port to a particular
board/embedded system makes available only a subset of MicroPython libraries. For
officially supported ports, there is an effort to either filter out non-applicable items, or mark
individual descriptions with “Availability:” clauses describing which ports provide a given
feature. With that in mind, please still be warned that some functions/classes in a module (or
even the entire module) described in this documentation may be unavailable in a particular
build of MicroPython on a particular board. The best place to find general information of the
availability/non-availability of a particular feature is the “General Information” section which
contains information pertaining to a specific port.
Beyond the built-in libraries described in this documentation, many more modules from the
Python standard library, as well as further MicroPython extensions to it, can be found in the
micropython-lib repository.
179
6.2 Pycom Modules
Pycom Modules
These modules are specific to the Pycom devices and may have slightly different
implementations to other variations of MicroPython (i.e. for Non-Pycom devices). Modules
include those which support access to underlying hardware, e.g. I2C, SPI, WLAN, Bluetooth,
etc.
180
6.2.1 machine
module machine
The machine module contains specific functions related to the board.
import machine
Reset Functions
machine.reset()
Resets the device in a manner similar to pushing the external RESET button.
machine.reset_cause()
Get the reset cause. See constants for the possible return values.
Interrupt Functions
machine.disable_irq()
Disable interrupt requests. Returns and integer representing the previous IRQ state. This
return value can be passed to enable_irq to restore the IRQ to its original state.
machine.enable_irq([state])
Enable interrupt requests. The most common use of this function is to pass the value
returned by disable_irq to exit a critical section. Another options is to enable all interrupts
which can be achieved by calling the function with no parameters.
Power Functions
machine.freq()
181
6.2.1 machine
machine.idle()
Gates the clock to the CPU, useful to reduce power consumption at any time during short or
long periods. Peripherals continue working and execution resumes as soon as any interrupt
is triggered (on many ports this includes system timer interrupt occurring at regular intervals
on the order of millisecond).
machine.deepsleep([time_ms])
Stops the CPU and all peripherals, including the networking interfaces (except for LTE).
Execution is resumed from the main script, just as with a reset. If a value in milliseconds is
given then the device will wake up after that period of time, otherwise it will remain in deep
sleep until the reset button is pressed.
The products with LTE connectivity (FiPy, GPy, G01), require the LTE radio to be disabled
separately via the LTE class before entering deepsleep. This is required due to the LTE
radio being powered independently and allowing use cases which require the system to be
taken out from deepsleep by an event from the LTE network (data or SMS received for
instance).
Configure pins to wake up from deep sleep mode. The pins which have this capability are:
P2, P3, P4, P6, P8 to P10 and P13 to P23.
pins a list or tuple containing the GPIO to setup for deepsleep wakeup.
mode selects the way the configure GPIOs can wake up the module. The possible
sleep. If this variable is set to True, then ULP or capactive touch wakeup cannot be
used in combination with GPIO wakeup.
machine.wake_reason()
Get the wake reason. See constants for the possible return values. Returns a tuple of the
form: (wake_reason, gpio_list). When the wakeup reason is either GPIO or touch pad, then
the second element of the tuple is a list with GPIOs that generated the wakeup.
machine.remaining_sleep_time()
Returns the remaining timer duration (in milliseconds) if the ESP32 is woken up from deep
sleep by something other than the timer. For Example if you set the timer for 30 seconds
(30000 ms) and it wakes up after 10 seconds then this function will return 20000 .
182
6.2.1 machine
Miscellaneous Functions
machine.main(filename)
Set the filename of the main script to run after boot.py is finished. If this function is not called
then the default file main.py will be executed.
machine.rng()
machine.unique_id()
Returns a byte string with a unique identifier of a board/SoC. It will vary from a board/SoC
instance to another, if underlying hardware allows. Length varies by hardware (so use
substring of a full value if you expect a short ID). In some MicroPython ports, ID corresponds
to the network MAC address.
Use binascii.hexlify() to convert the byte string to hexadecimal form for ease of
manipulation and use elsewhere.
machine.info()
Returns the high water mark of the stack associated with various system tasks, in words (1
word = 4 bytes on the ESP32). If the value is zero then the task has likely overflowed its
stack. If the value is close to zero then the task has come close to overflowing its stack.
Constants
Reset Causes
machine.PWRON_RESET machine.HARD_RESET machine.WDT_RESET
machine.DEEPSLEEP_RESET machine.SOFT_RESET machine.BROWN_OUT_RESET
Wake Reasons
machine.PWRON_WAKE machine.PIN_WAKE machine.RTC_WAKE machine.ULP_WAKE
183
6.2.1 machine
machine.WAKEUP_ALL_LOW machine.WAKEUP_ANY_HIGH
184
6.2.1.1 ADC
import machine
Constructors
class machine.ADC(id=0)
Create an ADC object; associate a channel with a pin. For more info check the hardware
section.
Methods
adc.init( * , bits=12)
Enable the ADC block. This method is automatically called on object creation.
Bits can take values between 9 and 12 and selects the number of bits of resolution of
adc.deinit()
185
6.2.1.1 ADC
adc.vref(vref)
If called without any arguments, this function returns the current calibrated voltage (in
millivolts) of the 1.1v reference. Otherwise it will update the calibrated value (in millivolts) of
the internal 1.1v reference.
adc.vref_to_pin(pin)
Connects the internal 1.1v to external GPIO. It can only be connected to P22 , P21 or P6 .
It is recommended to only use P6 on the WiPy, on other modules this pin is connected to
the radio.
Constants
ADC.ATTN_0DB ADC.ATTN_2_5DB ADC.ATTN_6DB ADC.ATTN_11DB
ADC channel attenuation values
class ADCChannel
Read analog values from internal/external sources. ADC channels can be connected to
internal points of the MCU or to GPIO pins. ADC channels are created using the
ADC.channel method.
Methods
adcchannel()
adcchannel.value()
adcchannel.init()
(Re)init and enable the ADC channel. This method is automatically called on object creation.
adcchannel.deinit()
adcchannel.voltage()
Reads the channels value and converts it into a voltage (in millivolts)
186
6.2.1.1 ADC
adcchannel.value_to_voltage(value)
Converts the provided value into a voltage (in millivolts) in the same way voltage does.
ADC pin input range is 0-1.1V. This maximum value can be increased up to 3.3V using
the highest attenuation of 11dB. Do not exceed the maximum of 3.3V, to avoid
damaging the device.
187
6.2.1.2 DAC
import machine
Constructors
class class machine.DAC(pin)
Create a DAC object, that will let you associate a channel with a pin. pin can be a string
argument.
Methods
dac.init()
Enable the DAC block. This method is automatically called on object creation.
dac.deinit()
dac.write(value)
Set the DC level for a DAC pin. value is a float argument, with values between 0 and 1.
dac.tone(frequency, amplitude)
Sets up tone signal to the specified frequency at amplitude scale. frequency can be from
125Hz to 20kHz in steps of 122 Hz. amplitude is an integer specifying the tone amplitude to
write the DAC pin. Amplitude value represents: 0 is 0dBV (~ 3Vpp at 600 Ohm load), 1 is
188
6.2.1.2 DAC
-6dBV (~1.5 Vpp), 2 is -12dBV (~0.8 Vpp), 3 is -18dBV (~0.4 Vpp). The generated signal is a
sine wave with an DC offset of VDD/2.
189
6.2.1.3 I2C
I2C objects are created attached to a specific bus. They can be initialized when created, or
initialized later on.
i2c = I2C(0, pins=('P10','P11')) # create and use non-default PIN assignments (P10
=SDA, P11=SCL)
i2c.init(I2C.MASTER, baudrate=20000) # init as a master
i2c.deinit() # turn off the peripheral
Printing the i2c object gives you information about its configuration.
i2c.init(I2C.MASTER)
i2c.writeto(0x42, '123') # send 3 bytes to slave with address 0x42
i2c.writeto(addr=0x42, b'456') # keyword for address
190
6.2.1.3 I2C
Constructors
class machine.I2C(bus, ...)
Construct an I2C object on the given bus. bus can only be 0, 1 or 2. If the bus is not given,
the default one will be selected (0). Buses 0 and 1 use the ESP32 I2C hardware peripheral
while bus 2 is implemented with a bit-banged software driver.
General Methods
i2c.init(mode, * , baudrate=100000, pins=(SDA, SCL))
pins is an optional tuple with the pins to assign to the I2C bus. The default I2C pins are
P9 (SDA) and P10 (SCL)
i2c.scan()
Scan all I2C addresses between 0x08 and 0x77 inclusive and return a list of those that
respond. A device responds if it pulls the SDA line low after its address (including a read bit)
is sent on the bus.
191
6.2.1.3 I2C
i2c.readfrom(addr, nbytes)
Read nbytes from the slave specified by addr. Returns a bytes object with the data read.
i2c.readfrom_into(addr, buf)
Read into buf from the slave specified by addr. The number of bytes read will be the length
of buf.
Write the bytes from buf to the slave specified by addr. The argument buf can also be an
integer which will be treated as a single byte. If stop is set to False then the stop condition
won’t be sent and the I2C operation may be continued (typically with a read transaction).
Memory Operations
Some I2C devices act as a memory device (or set of registers) that can be read from and
written to. In this case there are two addresses associated with an I2C transaction: the slave
address and the memory address. The following methods are convenience functions to
communicate with such devices.
Read nbytes from the slave specified by addr starting from the memory address specified by
memaddr. The addrsize argument is specified in bits and it can only take 8 or 16.
Read into buf from the slave specified by addr starting from the memory address specified
by memaddr. The number of bytes read is the length of buf. The addrsize argument is
specified in bits and it can only take 8 or 16.
192
6.2.1.3 I2C
Write buf to the slave specified by addr starting from the memory address specified by
memaddr. The argument buf can also be an integer which will be treated as a single byte.
The addrsize argument is specified in bits and it can only take 8 or 16.
Constants
I2C.MASTER
Used to initialise the bus to master mode.
193
6.2.1.4 Pin
Constructors
class machine.Pin(id, ...)
Create a new Pin object associated with the string id. If additional arguments are given, they
are used to initialise the pin. See pin.init().
Methods
pin.init(mode, pull, * , alt)
194
6.2.1.4 Pin
Returns: None .
pin.id()
pin.value([value])
pin([value])
Pin objects are callable. The call method provides a (fast) shortcut to set and get the value
of the pin.
Example:
pin.toggle()
pin.mode([mode])
pin.pull([pull])
pin.hold([hold])
195
6.2.1.4 Pin
Get or set the pin hold. You can apply a hold to a pin by passing True (or clear it by
passing False ). When a pin is held, its value cannot be changed by using Pin.value() or
Pin.toggle() until the hold is released. This Can be used to retain the pin state through a
core reset and system reset triggered by watchdog time-out or Deep-sleep events. Only pins
in the RTC power domain can retain their value through deep sleep or reset. These are:
P2 , P3 , P4 , P6 , P8 , P9 , P10 , P13 , P14 , P15 , P16 , P17 , P18 , P19 , P20 ,
Set a callback to be triggered when the input level at the pin changes.
trigger is the type of event that triggers the callback. Possible values are:
Pin.IRQ_FALLING interrupt on falling edge.
Pin.IRQ_RISING interrupt on rising edge.
Pin.IRQ_LOW_LEVEL interrupt on low level.
Pin.IRQ_HIGH_LEVEL interrupt on high level.
handler is the function to be called when the event happens. This function will receive
one argument. Set handler to None to disable it.
arg is an optional argument to pass to the callback. If left empty or set to None, the
function will receive the Pin object that triggered it.
Example:
def pin_handler(arg):
print("got an interrupt in pin %s" % (arg.id()))
For more information on how Pycom’s products handle interrupts, see here.
Attributes
class pin.exp_board
196
6.2.1.4 Pin
Pin.exp_board.G16
led = Pin(Pin.exp_board.G16, mode=Pin.OUT)
Pin.exp_board.G16.id()
class pin.module
Pin.module.P9
led = Pin(Pin.module.P9, mode=Pin.OUT)
Pin.module.P9.id()
Constants
The following constants are used to configure the pin objects. Note that not all constants are
available on all ports.
Pin.PULL_UP Pin.PULL_DOWN
Enables the pull up or pull down resistor.
197
6.2.1.5 PWM
Constructors
class machine.PWM(timer, frequency)
Create a PWM object. This sets up the timer to oscillate at the specified frequency .
timer is an integer from 0 to 3. frequency is an integer from 1 Hz to 78 KHz (this values
Methods
pwm.channel(id, pin * , duty_cycle=0.5)
Connect a PWM channel to a pin, setting the initial duty cycle. id is an integer from 0 to 7.
pin is a string argument. duty_cycle is a keyword-only float argument, with values
Set the duty cycle for a PWM channel. value is a float argument, with values between 0
and 1.
198
6.2.1.6 RTC
rtc = RTC()
rtc.init((2014, 5, 1, 4, 13, 0, 0, 0))
print(rtc.now())
Constructors
class machine.RTC(id=0, ...)
Methods
rtc.init(datetime=None, source=RTC.INTERNAL_RC)
datetime when passed it sets the current time. It is a tuple of the form: (year, month,
and RTC.XTAL_32KHZ
For example:
199
6.2.1.6 RTC
rtc.now()
rtc.ntp_sync(server, * , update_period=3600)
Set up automatic fetch and update the time using NTP (SNTP).
server is the URL of the NTP server. Can be set to None to disable the periodic
updates.
update_period is the number of seconds between updates. Shortest period is 15
seconds.
rtc.synced()
Returns True if the last ntp_sync has been completed, False otherwise:
rtc.synced()
Constants
RTC.INTERNAL_RC RTC.XTAL_32KHZ
clock source
200
6.2.1.7 SPI
See usage model of I2C; SPI is very similar. Main difference is parameters to init the SPI
bus:
Only required parameter is mode, must be SPI.MASTER. Polarity can be 0 or 1, and is the
level the idle clock line sits at. Phase can be 0 or 1 to sample data on the first or second
clock edge respectively.
201
6.2.1.7 SPI
Constructors
class machine.SPI(id, ...)
Construct an SPI object on the given bus. id can be only 0. With no additional parameters,
the SPI object is created but not initialised (it has the settings from the last initialisation of the
bus, if any). If extra arguments are given, the bus is initialised. See init for parameters of
initialisation.
Methods
spi.init(mode, baudrate=1000000, * , polarity=0, phase=0, bits=8, firstbit=SPI.MSB,
pins=(CLK, MOSI, MISO))
polarity can be 0 or 1, and is the level the idle clock line sits at.
phase can be 0 or 1 to sample data on the first or second clock edge respectively.
bits is the width of each transfer, accepted values are 8, 16 and 32.
pins is an optional tuple with the pins to assign to the SPI bus. If the pins argument is
not given the default pins will be selected ( P10 as CLK, P11 as MOSI and P14 as
MISO). If pins is passed as None then no pin assignment will be made.
spi.deinit()
spi.write(buf)
202
6.2.1.7 SPI
Write the data contained in buf . Returns the number of bytes written.
spi.read(nbytes, * , write=0x00)
Read the nbytes while writing the data specified by write . Return the number of bytes
read.
spi.readinto(buf, * , write=0x00)
Read into the buffer specified by buf while writing the data specified by write . Return the
number of bytes read.
spi.write_readinto(write_buf, read_buf)
Write from write_buf and read into read_buf . Both buffers must have the same length.
Returns the number of bytes written
Constants
SPI.MASTER
for initialising the SPI bus to master
SPI.MSB
set the first bit to be the most significant bit
SPI.LSB
set the first bit to be the least significant bit
203
6.2.1.8 UART
Bits can be 5, 6, 7, 8. Parity can be None, UART.EVEN or UART.ODD. Stop can be 1, 1.5 or
2.
A UART object acts like a stream object therefore reading and writing is done using the
standard stream methods:
204
6.2.1.8 UART
Constructors
class machine.UART(bus, ...)
Construct a UART object on the given bus. bus can be 0, 1 or 2. If the bus is not given, the
default one will be selected (0) or the selection will be made based on the given pins.
Methods
uart.init(baudrate=9600, bits=8, parity=None, stop=1, * , timeout_chars=2, pins=(TXD,
RXD, RTS, CTS))
timeout_chars Rx timeout defined in number of characters. The value given here will
205
6.2.1.8 UART
Any of the pins can be None if one wants the UART to operate with limited functionality.
If the RTS pin is given the the RX pin must be given as well. The same applies to CTS.
When no pins are given, then the default set of TXD (P1) and RXD (P0) pins is taken,
and hardware flow control will be disabled. If pins=None, no pin assignment will be
made.
uart.deinit()
uart.any()
uart.read([nbytes])
Read characters. If nbytes is specified then read at most that many bytes.
Return value: a bytes object containing the bytes read in. Returns None on timeout.
uart.readall()
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()
Read a line, ending in a newline character. If such a line exists, return is immediate. If the
timeout elapses, all available data is returned regardless of whether a newline exists.
uart.write(buf)
uart.sendbreak()
206
6.2.1.8 UART
Send a break condition on the bus. This drives the bus low for a duration of 13 bits. Return
value: None .
uart.wait_tx_done(timeout_ms)
Waits at most timeout_ms for the last Tx transaction to complete. Returns True if all data
has been sent and the TX buffer has no data in it, otherwise returns False.
Constants
UART.EVEN UART.ODD
parity types (along with None )
UART.RX_ANY
IRQ trigger sources
207
6.2.1.9 WDT
Constructors
class machine.WDT(id=0, timeout)
Create a WDT object and start it. The id can only be 0. See the init method for the
parameters of initialisation.
Methods
wdt.init(timeout)
Initialises the watchdog timer. The timeout must be given in milliseconds. Once it is running
the WDT cannot be stopped but the timeout can be re-configured at any point in time.
wdt.feed()
Feed the WDT to prevent it from resetting the system. The application should place this call
in a sensible place ensuring that the WDT is only fed after verifying that everything is
functioning correctly.
208
6.2.1.10 Timer
Chrono : used to measure time spans. Alarm : to get interrupted after a specific interval.
Constructors
class Timer.Chrono()
handler : will be called after the interval has elapsed. If set to None, the alarm will be
specified, the function will receive the object that triggered the alarm. s, ms, us: the
interval can be specified in seconds (float), miliseconds (integer) or microseconds
(integer). Only one at a time can be specified.
periodic : an alarm can be set to trigger repeatedly by setting this parameter to True.
Methods
Timer.sleep_us()
Delay for a given number of microseconds, should be positive or 0 (for speed, the condition
is not enforced). Internally it uses the same timer as the other elements of the Timer class. It
compensates for the calling overhead, so for example, 100 us should be really close to
100us. For times bigger than 10,000 us it releases the GIL to let other threads run, so
exactitude is not guaranteed for delays longer than that.
209
6.2.1.10 Timer
class Chrono
Can be used to measure time spans.
Methods
chrono.start()
chrono.stop()
chrono.reset()
chrono.read()
chrono.read_ms()
chrono.read_us()
Example:
210
6.2.1.10 Timer
chrono = Timer.Chrono()
chrono.start()
time.sleep(1.25) # simulate the first lap took 1.25 seconds
lap = chrono.read() # read elapsed time without stopping
time.sleep(1.5)
chrono.stop()
total = chrono.read()
print()
print("\nthe racer took %f seconds to finish the race" % total)
print(" %f seconds in the first lap" % lap)
print(" %f seconds in the last lap" % (total - lap))
class Alarm – get interrupted after a specific interval
Methods
alarm.callback(handler, * , arg=None)
Specify a callback handler for the alarm. If set to None, the alarm will be disabled.
An optional argument arg can be passed to the callback handler function. If None is
specified, the function will receive the object that triggered the alarm.
alarm.cancel()
Example:
class Clock:
def __init__(self):
self.seconds = 0
self.__alarm = Timer.Alarm(self._seconds_handler, 1, periodic=True)
clock = Clock()
211
6.2.1.10 Timer
For more information on how Pycom’s products handle interrupts, see notes.
212
6.2.1.11 SD
P8: DAT0 , P23: SCLK and P4: CMD (no external pull-up resistors are needed)
If you have one of the Pycom expansion boards, then simply insert the card into the micro
SD socket and run your script.
sd = SD()
os.mount(sd, '/sd')
Constructors
class machine.SD(id, ...)
Methods
213
6.2.1.11 SD
sd.init(id=0)
sd.deinit()
Please note that the SD card library currently supports FAT16/32 formatted SD cards up
to 32 GB. Future firmware updates will increase compatibility with additional formats and
sizes.
214
6.2.1.12 CAN
The ESP32 has a built-in CAN controller, but the transceiver needs to be added externally. A
recommended device is the SN65HVD230.
Constructors
class machine.CAN(bus=0, ...)
Methods
can.init(mode=CAN.NORMAL, baudrate=500000, *, frame_format=CAN.FORMAT_STD,
rx_queue_len=128, pins=('P22', 'P23'))
mode can take either CAN.NORMAL or CAN.SILENT. Silent mode is useful for sniffing
the bus.
baudrate setups the bus speed. Acceptable values are between 1 and 1000000.
frame_format defines the frame format to be accepted by the receiver. Useful for
filtering frames based on the identifier length. Can tale either CAN.FORMAT_STD or
CAN.FORMAT_EXT or CAN.FORMAT_BOTH. If CAN.FORMAT_STD is selected,
extended frames won't be received and viceversa.
215
6.2.1.12 CAN
rx_queue_len defines the number of messages than can be queued by the receiver.
Due to CAN being a high traffic bus, large values are recommended (>= 128), otherwise
messages will be dropped specially when no filtering is applied.
pins selects the Tx and Rx pins (in that order).
can.deinit()
data can take up to 8 bytes. It must be left empty is the message to be sent is a
extnted specifies if the message identifier width should be 11bit (standard) or 29bit
(extended).
can.send(id=0x010, data=bytes([0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08])) # sen
ds 8 bytes with an standard identifier
can.recv(timeout=0)
Get a message from the receive queue, and optionally specify a timeout value in s (can be a
floating point value e.g. 0.2 ). This function returns None if no messages available. If a
message is present, it will be returned as a named tuple with the following form:
(id, data, rtr, extended)
>>> can.recv()
(id=0x012, data=b'123', rtr=False, extended=False)
can.soft_filter(mode, filter_list)
216
6.2.1.12 CAN
Specify a software filter accepting only the messages that pass the filter test.
With software filters all messages in the bus are received by the CAN controller but only the
matching ones are passed to the RX queue. This means that the queue won't be filled up
with non relevant messages, but the interrupt overhead will remain as normal. The
filter_list can contain up to 32 elements.
For example:
trigger is the type of event that triggers the callback. Possible values are:
CAN.RX_FRAME interrupt whenever a new frame is received.
CAN.RX_FIFO_NOT_EMPTY interrupt when a frame is received on an empty
FIFO.
CAN.RX_FIFO_OVERRUN interrupt when a message is received and the FIFO is
full.
handler is the function to be called when the event happens. This function will receive
one argument. Set handler to None to disable the callback.
arg is an optional argument to pass to the callback. If left empty or set to None, the
function will receive the CAN object that triggered it.
217
6.2.1.12 CAN
def can_cb(can_o):
print('CAN Rx:', can_o.recv())
can.callback(handler=can_cb, trigger=CAN.RX_FRAME)
can.events()
This method returns a value with bits sets (if any) indicating the events that have occured in
the bus. Please note that by calling this function the internal events registry is cleared
automatically, therefore calling it immediately for a second time will most likely return a value
of 0.
Constants
CAN.NORMAL CAN.SILENT CAN.FORMAT_STD CAN.FORMAT_EXT
CAN.FORMAT_BOTH CAN.RX_FRAME CAN.RX_FIFO_NOT_EMPTY
CAN.RX_FIFO_OVERRUN CAN.FILTER_LIST CAN.FILTER_RANGE CAN.FILTER_MASK
218
6.2.1.13 RMT
import machine
import machine
# create a RMT object
rmt = machine.RMT(channel=3)
# Configure RTM for receiving
rmt.init(gpio="P20", rx_idle_threshold=12000)
# wait for any number of pulses until one longer than rx_idle_threshold
data = rmt.recv_pulses()
Constructors
class machine.RMT(channel,...)
Construct an RMT object on the given channel. channel can be 2-7. With no additional
parameters, the RMT object is created but not initialised. If extra arguments are given, the
RMT is initialised for transmission or reception. See init for parameters of initialisation.
The resolution which a pulse can be sent/received depends on the selected channel:
219
6.2.1.13 RMT
3 100nS 3.2768 ms
4 1000nS 32.768 ms
5 1000nS 32.768 ms
6 3125nS 102.4 ms
7 3125nS 102.4 ms
Methods
rmt.init(gpio, rx_idle_threshold, rx_filter_threshold, tx_idle_level, tx_carrier)
Initialize the RMT peripheral with the given parameters:
rx_idle_threshold is the maximum duration of a valid pulse. The represented time unit
RMT.HIGH or RMT.LOW.
tx_carrier is the modulation of the pulses to send.
with duration less than rx_idle_threshold . tx_carrier is not mandatory parameters. If not
given no modulation is used on the sent pulses.
rmt.deinit()
Deinitialize the RMT object.
220
6.2.1.13 RMT
If an RMT object needs to be reconfigured from RX/TX to TX/RX, then either first
deinit() must be called or the init() again with the desired configuration.
rmt.pulses_get(pulses, timeout)
Reads in pulses from the GPIO pin.
pulses if not specified, this function will keep reading pulses until the
rx_idle_threshold is exceeded. If it is specified this function will return the exactly that
timeout is specified, this function will return if the first pulse does not occur within
Return value: Tuple of items with the following structure: (level, duration):
duration represents the duration of the received pulse, the time unit (resolution)
Maximum of 128 pulses can be received in a row without receiving "idle" signal. If the
incoming pulse sequence contains more than 128 pulses the rest is dropped and the
receiver waits for another sequence of pulses. The pulses_get function can be called
to receive more than 128 pulses, however the above mentioned limitation should be
kept in mind when evaluating the received data.
duration represents the duration of the pulses to be sent, the time unit (resolution)
or 1 elements.
start_level defines the state (HIGH/LOW) of the first pulse given by duration if
data must be a tuple and duration can be a tuple or a single number, with data being
optional. In the case that only duration is provided, it must be a tuple and you must also
provide start_level which will dictate the level of the first duration, the signal level then
toggles between each duration value. If data is provided and duration is a single number,
221
6.2.1.13 RMT
each pulse in data will have have an equal length as set by duration . If data and
duration are provided as tuples, they must be of the same number of elements, with each
Constants
RMT.LOW RMT.HIGH
Defines the level of the pulse.
222
6.2.2 network
module network
This module provides access to network drivers and routing configuration. Network drivers
for specific hardware are available within this module and are used to configure specific
hardware network interfaces.
223
6.2.2.1 WLAN
class WLAN
This class provides a driver for the WiFi network processor in the module. Example usage:
import network
import time
# setup as a station
wlan = network.WLAN(mode=network.WLAN.STA)
wlan.connect('your-ssid', auth=(network.WLAN.WPA2, 'your-key'))
while not wlan.isconnected():
time.sleep_ms(50)
print(wlan.ifconfig())
import machine
from network import WLAN
Constructors
class network.WLAN(id=0, ...)
Create a WLAN object, and optionally configure it. See init for params of configuration.
The WLAN constructor is special in the sense that if no arguments besides the id are
given, it will return the already existing WLAN instance without re-configuring it. This is
because WLAN is a system feature of the WiPy. If the already existing instance is not
initialised it will do the same as the other constructors an will initialise it with default
values.
224
6.2.2.1 WLAN
Methods
wlan.init(mode, * , ssid=None, auth=None, channel=1, antenna=None,
power_save=False)
Arguments are:
ssid is a string with the ssid name. Only needed when mode is WLAN.AP.
auth is a tuple with (sec, key). Security can be None , WLAN.WEP, WLAN.WPA or
WLAN.WPA2. The key is a string with the network password. If sec is WLAN.WEP the
key must be a string representing hexadecimal values (e.g. ‘ABC1DE45BF’). Only
needed when mode is WLAN.AP.
channel a number in the range 1-11. Only needed when mode is WLAN.AP.
antenna selects between the internal and the external antenna. Can be either
or:
# configure as an station
wlan.init(mode=WLAN.STA)
wlan.deinit()
Connect to a wifi access point using the given SSID, and other security parameters.
auth is a tuple with (sec, key). Security can be None, WLAN.WEP, WLAN.WPA,
225
6.2.2.1 WLAN
sec is WLAN.WEP the key must be a string representing hexadecimal values (e.g.
‘ABC1DE45BF’). If sec is WLAN.WPA2_ENT then the auth tuple can have either 3
elements: (sec, username, password), or just 1: (sec,). When passing the 3 elemnt
tuple, the keyfile and certifle arguments must not be given.
bssid is the MAC address of the AP to connect to. Useful when there are several APs
ca_certs is the path to the CA certificate. This argument is not mandatory. keyfile is the
path to the client key. Only used if username and password are not part of the auth
tuple.
certfile is the path to the client certificate. Only used if username and password are
wlan.scan()
Performs a network scan and returns a list of named tuples with (ssid, bssid, sec, channel,
rssi). Note that channel is always None since this info is not provided by the WiPy.
wlan.disconnect()
wlan.isconnected()
In case of STA mode, returns True if connected to a wifi access point and has a valid IP
address. In AP mode returns True when a station is connected, False otherwise.
When id is 0, the configuration will be get/set on the Station interface. When id is 1 the
configuration will be done for the AP interface.
if dhcp is passed as a parameter then the DHCP client is enabled and the IP params are
negotiated with the AP.
wlan.mode([mode])
226
6.2.2.1 WLAN
wlan.ssid([ssid])
wlan.auth([auth])
wlan.channel([channel])
wlan.antenna([antenna])
wlan.mac()
Get a 6-byte long bytes object with the WiFI MAC address.
Constants
WLAN.STA WLAN.AP WLAN.STA_AP
WLAN mode
WLAN.INT_ANT WLAN.EXT_ANT
Antenna type
227
6.2.2.2 Server
class Server
The Server class controls the behaviour and the configuration of the FTP and telnet services
running on the Pycom Device. Any changes performed using this class’ methods will affect
both.
Example:
import network
server = network.Server()
server.deinit() # disable the server
# enable the server again with new settings
server.init(login=('user', 'password'), timeout=600)
Constructors
class network.Server(id, ...)
Methods
server.init(* , login=('micro', 'python'), timeout=300)
Init (and effectively start the server). Optionally a new user , password and timeout (in
seconds) can be passed.
server.deinit()
server.timeout([timeout_in_seconds])
228
6.2.2.2 Server
server.isrunning()
229
6.2.2.3 Bluetooth
class Bluetooth
This class provides a driver for the Bluetooth radio in the module. Currently, only basic BLE
functionality is available.
while True:
adv = bt.get_adv()
if adv and bt.resolve_adv_data(adv.data, Bluetooth.ADV_NAME_CMPL) == 'Heart Rate':
try:
conn = bt.connect(adv.mac)
services = conn.services()
for service in services:
time.sleep(0.050)
if type(service.uuid()) == bytes:
print('Reading chars from service = {}'.format(service.uuid()))
else:
print('Reading chars from service = %x' % service.uuid())
chars = service.characteristics()
for char in chars:
if (char.properties() & Bluetooth.PROP_READ):
print('char {} value = {}'.format(char.uuid(), char.read()))
conn.disconnect()
break
except:
print("Error while connecting or reading from the BLE device")
break
else:
time.sleep(0.050)
230
6.2.2.3 Bluetooth
GAP allows for devices to take various roles but generic flow works with devices that are
either a Server (low power, resource constrained, sending small payloads of data) or a Client
device (commonly a mobile device, PC or Pycom Device with large resources and
processing power). Pycom devices can act as both a Client and a Server.
Constructors
class network.Bluetooth(id=0, ...)
Create a Bluetooth object, and optionally configure it. See init for params of configuration.
Example:
Methods
bluetooth.init(id=0, mode=Bluetooth.BLE, antenna=None)
antenna selects between the internal and the external antenna. Can be either
bluetooth.deinit()
bluetooth.start_scan(timeout)
Starts performing a scan listening for BLE devices sending advertisements. This function
always returns immediately, the scanning will be performed on the background. The return
value is None . After starting the scan the function get_adv() can be used to retrieve the
advertisements messages from the FIFO. The internal FIFO has space to cache 16
advertisements.
timeout specifies the amount of time in seconds to scan for advertisements, cannot be
231
6.2.2.3 Bluetooth
zero. If timeout is > 0, then the BLE radio will listen for advertisements until the specified
value in seconds elapses. If timeout < 0, then there’s no timeout at all, and stop_scan()
needs to be called to cancel the scanning process.
Examples:
bluetooth.stop_scan()
bluetooth.isscanning()
bluetooth.get_adv()
Gets an named tuple with the advertisement data received during the scanning. The tuple
has the following structure: ( mac , addr_type , adv_type , rssi , data )
mac is the 6-byte ling mac address of the device that sent the advertisement.
addr_type is the address type. See the constants section below for more details.
adv_type is the advertisement type received. See the constants section below fro more
details.
rssi is signed integer with the signal strength of the advertisement.
data contains the complete 31 bytes of the advertisement message. In order to parse
the data and get the specific types, the method resolve_adv_data() can be used.
import binascii
bluetooth = Bluetooth()
bluetooth.start_scan(20) # scan for 20 seconds
adv = bluetooth.get_adv() #
binascii.hexlify(adv.mac) # convert hexidecimal to ascii
bluetooth.get_advertisements()
Sames as the get_adv() method, but this one returns a list with all the advertisements
received.
232
6.2.2.3 Bluetooth
bluetooth.resolve_adv_data(data, data_type)
Parses the advertisement data and returns the requested data_type if present. If the data
type is not present, the function returns None.
Arguments:
data_type is the data type to resolve from from the advertisement data. See constants
Example:
import binascii
from network import Bluetooth
bluetooth = Bluetooth()
bluetooth.start_scan(20)
while bluetooth.isscanning():
adv = bluetooth.get_adv()
if adv:
# try to get the complete name
print(bluetooth.resolve_adv_data(adv.data, Bluetooth.ADV_NAME_CMPL))
if mfg_data:
# try to get the manufacturer data (Apple's iBeacon data is sent here)
print(binascii.hexlify(mfg_data))
bluetooth.connect(mac_addr)
Opens a BLE connection with the device specified by the mac_addr argument. This function
blocks until the connection succeeds or fails. If the connections succeeds it returns a object
of type GATTCConnection .
Creates a callback that will be executed when any of the triggers occurs. The arguments
are:
Bluetooth.CLIENT_CONNECTED or Bluetooth.CLIENT_DISCONNECTED
handler is the function that will be executed when the callback is triggered.
233
6.2.2.3 Bluetooth
arg is the argument that gets passed to the callback. If nothing is given the bluetooth
An example of how this may be used can be seen in the bluetooth.events() method.
bluetooth.events()
Returns a value with bit flags identifying the events that have occurred since the last call.
Calling this function clears the events.
Example of usage:
bluetooth = Bluetooth()
bluetooth.set_advertisement(name='LoPy', service_uuid=b'1234567890123456')
bluetooth.callback(trigger=Bluetooth.CLIENT_CONNECTED | Bluetooth.CLIENT_DISCONNECTED,
handler=conn_cb)
bluetooth.advertise(True)
Configure the data to be sent while advertising. If left with the default of None the data won’t
be part of the advertisement message.
Example:
bluetooth.set_advertisement(name="advert", manufacturer_data="lopy_v1")
234
6.2.2.3 Bluetooth
bluetooth.advertise([Enable])
Start or stop sending advertisements. The set_advertisement() method must have been
called prior to this one.
Create a new service on the internal GATT server. Returns a object of type
BluetoothServerService .
uuid is the UUID of the service. Can take an integer or a 16 byte long string or bytes
object.
isprimary selects if the service is a primary one. Takes a bool value.
nbr_chars specifies the number of characteristics that the service will contain.
bluetooth.service('abc123')
bluetooth.disconnect_client()
Constants
Bluetooth.BLE
Bluetooth mode
235
6.2.2.3 Bluetooth
Bluetooth.ADV_MANUFACTURER_DATA
Advertisement data type
Bluetooth.CHAR_READ_EVENT Bluetooth.CHAR_WRITE_EVENT
Bluetooth.NEW_ADV_EVENT Bluetooth.CLIENT_CONNECTED
Bluetooth.CLIENT_DISCONNECTED Bluetooth.CHAR_NOTIFY_EVENT
Characteristic callback events
Bluetooth.INT_ANT Bluetooth.EXT_ANT
Antenna type
236
6.2.2.3 Bluetooth
Generic Attribute
GATT stands for the Generic Attribute Profile and it defines the way that two Bluetooth Low
Energy devices communicate between each other using concepts called Services and
Characteristics. GATT uses a data protocol known as the Attribute Protocol (ATT), which is
used to store/manage Services, Characteristics and related data in a lookup table.
GATT comes into use once a connection is established between two devices, meaning that
the device will have already gone through the advertising process managed by GAP. It’s
important to remember that this connection is exclusive; i.e. that only one client is connected
to one server at a time. This means that the client will stop advertising once a connection
has been made. This remains the case, until the connection is broken or disconnected.
The GATT Server, which holds the ATT lookup data and service and characteristic
definitions, and the GATT Client (the phone/tablet), which sends requests to this server.
237
6.2.2.3 Bluetooth
class GATTCConnection
The GATT Client is the device that requests data from the server, otherwise known as the
master device (commonly this might be a phone/tablet/PC). All transactions are initiated by
the master, which receives a response from the slave.
connection.disconnect()
connection.isconnected()
Example:
connection.services()
Performs a service search on the connected BLE peripheral (server) a returns a list
containing objects of the class GATTCService if the search succeeds.
Example:
238
6.2.2.3 Bluetooth
239
6.2.2.3 Bluetooth
class GATTCService
Services are used to categorise data up into specific chunks of data known as
characteristics. A service may have multiple characteristics, and each service has a unique
numeric ID called a UUID.
service.isprimary()
service.uuid()
Returns the UUID of the service. In the case of 16-bit or 32-bit long UUIDs, the value
returned is an integer, but for 128-bit long UUIDs the value returned is a bytes object.
service.instance()
service.characteristics()
Performs a get characteristics request on the connected BLE peripheral a returns a list
containing objects of the class GATTCCharacteristic if the request succeeds.
240
6.2.2.3 Bluetooth
class GATTCCharacteristic
The smallest concept in GATT is the Characteristic, which encapsulates a single data point
(though it may contain an array of related data, such as X/Y/Z values from a 3-axis
accelerometer, longitude and latitude from a GPS, etc.).
characteristic.uuid()
Returns the UUID of the service. In the case of 16-bit or 32-bit long UUIDs, the value
returned is an integer, but for 128-bit long UUIDs the value returned is a bytes object.
characteristic.instance()
characteristic.properties()
Returns an integer indicating the properties of the characteristic. Properties are represented
by bit values that can be ORed together. See the constants section for more details.
characteristic.read()
Read the value of the characteristic, sending a request to the GATT server. Returns a bytes
object representing the characteristic value.
characteristic.value()
Returns the locally stored value of the characteristic whithout sending a read request to the
GATT server. If the characteristic value hasn't been read from the GATT server yet, the value
returned will be 0.
characteristic.write(value)
Writes the given value on the characteristic. For now it only accepts bytes object
representing the value to be written.
characteristic.write(b'x0f')
241
6.2.2.3 Bluetooth
handler is the function that will be executed when the callback is triggered.
arg is the argument that gets passed to the callback. If nothing is given, the
242
6.2.2.3 Bluetooth
class GATTSService
The GATT Server allows the device to act as a peripheral and hold its own ATT lookup data,
server & characteristic definitions. In this mode, the device acts as a slave and a master
must initiate a request.
Services are used to categorise data up into specific chunks of data known as
characteristics. A service may have multiple characteristics, and each service has a unique
numeric ID called a UUID.
service.start()
service.stop()
uuid is the UUID of the service. Can take an integer or a 16 byte long string or bytes
object.
permissions configures the permissions of the characteristic. Takes an integer with a
flags.
value sets the initial value. Can take an integer, a string or a bytes object.
service.characteristic('temp', value=25)
243
6.2.2.3 Bluetooth
class GATTSCharacteristic
The smallest concept in GATT is the Characteristic, which encapsulates a single data point
(though it may contain an array of related data, such as X/Y/Z values from a 3-axis
accelerometer, longitude and latitude from a GPS, etc.).
characteristic.value([value])
Gets or sets the value of the characteristic. Can take an integer, a string or a bytes object.
Creates a callback that will be executed when any of the triggers occurs. The arguments
are:
Bluetooth.CHAR_WRITE_EVENT.
handler is the function that will be executed when the callback is triggered.
arg is the argument that gets passed to the callback. If nothing is given, the
characteristic.events()
Returns a value with bit flags identifying the events that have occurred since the last call.
Calling this function clears the events.
244
6.2.2.3 Bluetooth
bluetooth = Bluetooth()
bluetooth.set_advertisement(name='LoPy', service_uuid=b'1234567890123456')
bluetooth.callback(trigger=Bluetooth.CLIENT_CONNECTED | Bluetooth.CLIENT_DISCONNECTED,
handler=conn_cb)
bluetooth.advertise(True)
char1_read_counter = 0
def char1_cb_handler(chr):
global char1_read_counter
char1_read_counter += 1
events = chr.events()
if events & Bluetooth.CHAR_WRITE_EVENT:
print("Write request with value = {}".format(chr.value()))
else:
if char1_read_counter < 3:
print('Read request on char 1')
else:
return 'ABC DEF'
245
6.2.2.3 Bluetooth
246
6.2.2.4 LoRa
class LoRa
This class provides a LoRaWAN 1.0.2 compliant driver for the LoRa network processor in
the LoPy and FiPy. Below is an example demonstrating LoRaWAN Activation by
Personalisation usage:
247
6.2.2.4 LoRa
Additional Examples
For various other complete LoRa examples, check here for additional examples.
Constructors
class network.LoRa(id=0, ...)
Create and configure a LoRa object. See init for params of configuration.
Methods
lora.init(mode, * ,region=LoRa.EU868, frequency=868000000, tx_power=14,
bandwidth=LoRa.BW_125KHZ, sf=7, preamble=8, coding_rate=LoRa.CODING_4_5,
power_mode=LoRa.ALWAYS_ON, tx_iq=False, rx_iq=False, adr=False, public=True,
tx_retries=1, device_class=LoRa.CLASS_A)
This method is used to set the LoRa subsystem configuration and to specific raw LoRa or
LoRaWAN.
LoRa.US915. If not provided this will default to LoRa.EU868 . If they are not specified,
this will also set appropriate defaults for frequency and tx_power .
frequency accepts values between 863000000 and 870000000 in the 868 band, or
LoRa.BW_125KHZ and LoRa.BW_250KHZ. In the 915 band the accepted values are
LoRa.BW_125KHZ and LoRa.BW_500KHZ.
sf sets the desired spreading factor. Accepts values between 7 and 12.
248
6.2.2.4 LoRa
LoRa.CODING_4_7 or LoRa.CODING_4_8.
power_mode can be either LoRa.ALWAYS_ON, LoRa.TX_ONLY or LoRa.SLEEP. In
ALWAYS_ON mode, the radio is always listening for incoming - packets whenever a
transmission is not taking place. In TX_ONLY the radio goes to sleep as soon as the
transmission completes. In SLEEP mode the radio is sent to sleep permanently and
won’t accept any commands until the power mode is changed.
tx_iq enables TX IQ inversion.
LoRa.CLASS_C.
LoRaWAN stack.
or:
Join a LoRaWAN network. Internally the stack will automatically retry every 15 seconds until
a Join Accept message is received. The parameters are:
249
6.2.2.4 LoRa
timeout : is the maximum time in milliseconds to wait for the Join Accept message to
be received. If no timeout (or zero) is given, the call returns immediatelly and the status
of the join request can be checked with lora.has_joined() .
dr : is an optional value to specify the initial data rate for the Join Request. Possible
In the case of LoRa.OTAA the authentication tuple is: ( dev_eui , app_eui , app_key ) where
dev_eui is optional. If it is not provided the LoRa MAC will be used.
Example:
In the case of LoRa.ABP the authentication tuple is: ( dev_addr , nwk_swkey , app_swkey ).
Example:
250
6.2.2.4 LoRa
lora.bandwidth([bandwidth])
Get or set the bandwidth in raw LoRa mode (LoRa.LORA). Can be either LoRa.BW_125KHZ
(0), LoRa.BW_250KHZ (1) or LoRa.BW_500KHZ (2):
lora.frequency([frequency])
Get or set the frequency in raw LoRa mode (LoRa.LORA). The allowed range is between
863000000 and 870000000 Hz for the 868 MHz band version or between 902000000 and
928000000 Hz for the 915 MHz band version.:
251
6.2.2.4 LoRa
lora.coding_rate([coding_rate]) Get or set the coding rate in raw LoRa mode (LoRa.LORA).
The allowed values are: LoRa.CODING_4_5 (1), LoRa.CODING_4_6 (2),
LoRa.CODING_4_7 (3) and LoRa.CODING_4_8 (4).
lora.preamble([preamble])
Get or set the number of preamble symbols in raw LoRa mode (LoRa.LORA):
lora.sf([sf])
Get or set the spreading factor value in raw LoRa mode (LoRa.LORA). The minimum value
is 7 and the maximum is 12:
lora.power_mode([power_mode])
Get or set the power mode in raw LoRa mode (LoRa.LORA). The accepted values are:
LoRa.ALWAYS_ON, LoRa.TX_ONLY and LoRa.SLEEP:
lora.stats()
Return a named tuple with useful information from the last received LoRa or LoRaWAN
packet. The named tuple has the following form:
Example:
252
6.2.2.4 LoRa
lora.stats()
Where:
precision.
rssi holds the received signal strength in dBm.
snr contains the signal to noise ratio id dB (as a single precision float).
sfrx tells the data rate (in the case of LORAWAN mode) or the spreading factor (in the
tx_time_on_air is the time on air of the last transmitted packet (in ms).
lora.has_joined()
Add a LoRaWAN channel on the specified index. If there’s already a channel with that index
it will be replaced with the new one.
index : Index of the channel to add. Accepts values between 0 and 15 for EU and
Examples:
lora.remove_channel(index)
253
6.2.2.4 LoRa
Removes the channel from the specified index. On the 868MHz band the channels 0 to 2
cannot be removed, they can only be replaced by other channels using the lora.add_channel
method. A way to remove all channels except for one is to add the same channel, 3 times on
indexes 0, 1 and 2. An example can be seen below:
lora.remove_channel()
lora.mac()
Returns a byte object with the 8-Byte MAC address of the LoRa radio.
Specify a callback handler for the LoRa radio. The trigger types are
LoRa.RX_PACKET_EVENT, LoRa.TX_PACKET_EVENT and LoRa.TX_FAILED_EVENT
An example of how this callback functions can be seen the in method lora.events().
lora.ischannel_free(rssi_threshold)
This method is used to check for radio activity on the current LoRa channel, and if the rssi
of the measured activity is lower than the rssi_threshold given, the return value will be
True , otherwise False . Example:
lora.ischannel_free(-100)
lora.set_battery_level(level)
Set the battery level value that will be sent when the LoRaWAN MAC command that
retrieves the battery level is received. This command is sent by the network and handled
automatically by the LoRaWAN stack. The values should be according to the LoRaWAN
specification:
254
6.2.2.4 LoRa
1..254 specifies the battery level, 1 being at minimum and 254 being at maximum.
255 means that the end-device was not able to measure the battery level.
lora.events()
This method returns a value with bits sets (if any) indicating the events that have triggered
the callback. Please note that by calling this function the internal events registry is cleared
automatically, therefore calling it immediately for a second time will most likely return a value
of 0.
Example:
def lora_cb(lora):
events = lora.events()
if events & LoRa.RX_PACKET_EVENT:
print('Lora packet received')
if events & LoRa.TX_PACKET_EVENT:
print('Lora packet sent')
lora.nvram_save()
Save the LoRaWAN state (joined status, network keys, packet counters, etc) in non-volatile
memory in order to be able to restore the state when coming out of deepsleep or a power
cycle.
lora.nvram_save()
lora.nvram_restore()
Restore the LoRaWAN state (joined status, network keys, packet counters, etc) from non-
volatile memory. State must have been previously stored with a call to nvram_save before
entering deepsleep. This is useful to be able to send a LoRaWAN message immediately
after coming out of deepsleep without having to join the network again. This can only be
used if the current region matches the one saved.
lora.nvram_restore()
lora.nvram_erase()
255
6.2.2.4 LoRa
Remove the LoRaWAN state (joined status, network keys, packet counters, etc) from non-
volatile memory.
lora.nvram_erase()
Constants
LoRa.LORA LoRa.LORAWAN LoRa stack mode
import socket
s = socket.socket(socket.AF_LORA, socket.SOCK_RAW)
And they must be created after initialising the LoRa network card.
LoRa sockets support the following standard methods from the socket module:
socket.close()
Usage:
s.close()
socket.bind(port_number)
Usage:
256
6.2.2.4 LoRa
s.bind(1)
The bind() method is only applicable when the radio is configured in LoRa.LORAWAN
mode.
socket.send(bytes)
Usage:
s.send(bytes([1, 2, 3]))
or:
s.send('Hello')
socket.recv(bufsize)
Usage:
s.recv(128)
socket.recvfrom(bufsize)
This method is useful to know the destination port number of the message received. Returns
a tuple of the form: (data, port)
Usage:
s.recvfrom(128)
Set the value of the given socket option. The needed symbolic constants are defined in the
socket module (SO_* etc.). In the case of LoRa the values are always integers. Examples:
257
6.2.2.4 LoRa
Socket options are only applicable when the LoRa radio is used in LoRa.LORAWAN
mode. When using the radio in LoRa.LORA mode, use the class methods to change the
spreading factor, bandwidth and coding rate to the desired values.
socket.settimeout(value)
Sets the socket timeout value in seconds. Accepts floating point values.
Usage:
s.settimeout(5.5)
socket.setblocking(flag)
Usage:
s.setblocking(True)
258
6.2.2.5 Sigfox
class Sigfox
Sigfox is a Low Power Wide Area Network protocol that enables remote devices to connect
using ultra-narrow band, UNB technology. The protocol is bi-directional, messages can both
be sent up to and down from the Sigfox servers.
When operating in RCZ2 and RCZ4 the module can only send messages on the default
macro-channel (this is due to Sigfox network limitations). Therefore, the device needs to
reset automatically to the default macro-channel after every 2 transmissions. However,
due to FCC duty cycle limitations, there must a minimum of a 20s delay after resetting to
the default macro-channel. Our API takes care of this, (and in real life applications you
should not be in the need to send Sigfox messages that often), so it will wait for the
necessary amount of time to make sure that the duty cycle restrictions are fulfilled.
This class provides a driver for the Sigfox network processor in the Sigfox enabled Pycom
Devices.
259
6.2.2.5 Sigfox
Constructors
class network.Sigfox(id=0, ...)
Create and configure a Sigfox object. See init for params of configuration. Examples:
# configure radio for the Sigfox network, using RCZ1 (868 MHz)
sigfox = Sigfox(mode=Sigfox.SIGFOX, rcz=Sigfox.RCZ1)
Methods
sigfox.init(mode=Sigfox.SIGFOX, rcz=Sigfox.RCZ1, * , frequency=None)
modulation and protocol while Sigfox.FSK allows to create point to point communication
260
6.2.2.5 Sigfox
928 MHz.
The SiPy comes in 2 different hardware flavours: a +14dBm Tx power version which can
only work with RCZ1 and RCZ3 and a +22dBm version which works exclusively on
RCZ2 and RCZ4.
sigfox.mac()
Returns a byte object with the 8-Byte MAC address of the Sigfox radio.
sigfox.id()
Returns a byte object with the 4-Byte bytes object with the Sigfox ID.
sigfox.rssi()
Returns a signed integer with indicating the signal strength value of the last received packet.
sigfox.pac()
Returns a byte object with the 8-Byte bytes object with the Sigfox PAC.
To return human-readable values you should import binascii and convert binary
values to hexidecimal representation. For example:
print(binascii.hexlify(sigfox.mac()))
sigfox.frequencies()
sigfox.public_key([public])
Sets or gets the public key flag. When called passing a True value the Sigfox public key
will be used to encrypt the packets. Calling it without arguments returns the state of the flag.
261
6.2.2.5 Sigfox
Constants
sigfox.SIGFOX sigfox.FSK Sigfox radio mode. SIGFOX to specify usage of the Sigfox Public
Network. FSK to specify device to device communication.
import socket
s = socket.socket(socket.AF_SIGFOX, socket.SOCK_RAW)
And they must be created after initialising the Sigfox network card.
Sigfox sockets support the following standard methods from the socket module:
socket.close()
socket.send(bytes)
In Sigfox mode the maximum data size is 12 bytes. In FSK the maximum is 64.
socket.recv(bufsize)
262
6.2.2.5 Sigfox
Set the value of the given socket option. The needed symbolic constants are defined in the
socket module (SO_* etc.). In the case of Sigfox the values are always an integer.
Examples:
Sending a Sigfox packet with a single bit is achieved by sending an empty string, i.e.:
import socket
s = socket.socket(socket.AF_SIGFOX, socket.SOCK_RAW)
# send a 1 bit
s.setsockopt(socket.SOL_SIGFOX, socket.SO_BIT, True)
s.send('')
socket.settimeout(value)
# set timeout for the socket, e.g. 5 seconds
s.settimeout(5.0)
socket.setblocking(flag)
# specifies if socket should be blocking based upon Boolean flag.
s.setblocking(True)
If the socket is set to blocking, your code will be wait until the socket completes
sending/receiving.
Sigfox Downlink
263
6.2.2.5 Sigfox
A Sigfox capable Pycom devices (SiPy) can both send and receive data from the Sigfox
network. To receive data, a message must first be sent up to Sigfox, requesting a downlink
message. This can be done by passing a True argument into the setsockopt() method.
Device 1:
s = socket.socket(socket.AF_SIGFOX, socket.SOCK_RAW)
s.setblocking(True)
while True:
s.send('Device-1')
time.sleep(1)
print(s.recv(64))
Device 2:
264
6.2.2.5 Sigfox
s = socket.socket(socket.AF_SIGFOX, socket.SOCK_RAW)
s.setblocking(True)
while True:
s.send('Device-2')
time.sleep(1)
print(s.recv(64))
Remember to use the correct frequency for your region (868 MHz for Europe, 912 MHz
for USA, etc.)
265
6.2.2.6 LTE
class LTE
The LTE class provides access to the LTE-M/NB-IoT modem on the GPy and FiPy. LTE-
M/NB-IoT are new categories of cellular protocols developed by the 3GPP and optimized for
long battery life power and longer range. These are new protocols currently in the process of
being deployed by mobile networks across the world.
Cat-M1: also known as LTE-M defines a 1.4 MHz radio channel size and about 375
kbps of throughput. It is optimized for coverage and long battery life, outperforming
2G/GPRS, while being similar to previous LTE standards.
Cat-NB1 also known as NB-IoT, defines a 200 kHz radio channel size and around 60
kbps of uplink speed. It's optimized for ultra low throughput and specifically designed for
IoT devices with a very long battery life. NB-IoT shares some features with LTE such as
operating in licensed spectrum, but it's a very different protocol.
Please note: The GPy and FiPy only support the two protocols above and are not
compatible with older LTE standards.
LTE Cat M1
AT Commands
The AT commands for the Sequans Monarch modem on the GPy/FiPy are available in a
PDF file.
266
6.2.2.6 LTE
Once the lte.connect() function has completed all the IP socket functions - including SSL -
will be routed through this connection. This mean any code using WLAN can be adapted to
Cat M1 by simply adding the connection setup step first and disconnect after.
For example to connect over LTE Cat M1 to Google's web server over secure SSL:
import socket
import ssl
import time
from network import LTE
s = socket.socket()
s = ssl.wrap_socket(s)
s.connect(socket.getaddrinfo('www.google.com', 443)[0][-1])
s.send(b"GET / HTTP/1.0\r\n\r\n")
print(s.recv(4096))
s.close()
lte.disconnect()
lte.dettach()
IMPORTANT: Once the LTE radio is initialized, it must be de-nitialized before going to
deepsleep in order to ensure minimum power consumption. This is required due to the LTE
radio being powered independently and allowing use cases which require the system to be
taken out from deepsleep by an event from the LTE network (data or SMS received for
instance).
When using the expansion board and the FiPy together, the RTS/CTS jumpers MUST be
removed as those pins are being used byt the LTE radio. Keeping those jumpers in place will
lead to erratic operation and higher current consumption specially while in deepsleep.
267
6.2.2.6 LTE
Constructors
class network.LTE(id=0, ...)
Create and configure a LTE object. See init for params of configuration.
Methods
LTE.init(*, carrier=None)
This method is used to set up the LTE subsystem. After a deinit() this method can take
several seconds to return waiting for the LTE modem to start-up. Optionally specify a carrier
name. The available options are: "verizon", "at&t" and "standard". Standard is generic for
any carrier, and it's also the option used when no arguments are given.
lte.deinit()
Disables LTE modem completely. This reduces the power consumption to the minimum. Call
this before entering deepsleep.
lte.attach(*, band=None)
Enable radio functionality and attach to the LTE Cat M1 network authorized by the inserted
SIM card. Optionally specify the band to scan for networks. If no band (or None) is specified,
all 6 bands will be scanned. The possible values for the band are: 3, 4, 12, 13, 20 and 28.
lte.isattached()
Returns True if the cellular mode is attached to the network. False otherwise.
lte.dettach()
Dettach the modem from the LTE Cat M1 and disable the radio functionality.
lte.connect(*, cid=1)
Start a data session and obtain and IP address. Optionally specify a CID (Connection ID) for
the data session. The arguments are:
- ``cid`` is a Connection ID. This is carrier specific, for Verizon use cid=3. For oth
ers like Telstra it should be cid=1.
268
6.2.2.6 LTE
lte.isconnected()
Returns True if there is an active LTE data session and IP address has been obtained.
False otherwise.
lte.disconnect()
lte.send_at_cmd(cmd)
Send an AT command directly to the modem. Returns the raw response from the modem as
a string object. IMPORTANT: If a data session is active (i.e.: the modem is connected),
sending the AT commands requires to pause and then resume the data session. This is all
done automatically, but makes the whole request take around 2.5 seconds.
Example:
def send_at_cmd_pretty(cmd):
response = lte.send_at_cmd(cmd).split('\r\n')
for line in response:
print(line)
lte.imei()
Returns a string object witht the IMEI number of the LTE modem.
lte.iccid()
Returns a string object witht the ICCID number of the SIM card.
lte.reset()
Perform a hardware reset on the cellular modem. This function can take up to 5 seconds tu
return as it waits for the modem to shutdown and reboot.
269
6.2.2.6 LTE
270
6.2.2.6 LTE
NB-IoT
NB-IoT firmware is under development by our modem manufacturer. We will have
information on how to use this soon.
271
6.2.3 AES
Constructors
class ucrypto.AES(key, mode, IV, * , counter, segment_size)
Create an AES object that will let you encrypt and decrypt messages.
key (byte string) is the secret key to use. It must be 16 (AES-128), 24 (AES-192), or
AES.MODE_ECB.
IV (byte string) initialisation vector. Should be 16 bytes long. It is ignored in modes
not be reused.
272
6.2.3 AES
segment_size is the number of bits plaintext and ciphertext are segmented in. Is
Methods
ucrypto.encrypt()
Encrypt data with the key and the parameters set at initialisation.
ucrypto.decrypt()
Decrypt data with the key and the parameters set at initialisation.
Constants
AES.MODE_ECB
Electronic Code Book. Simplest encryption mode. It does not hide data patterns well (see
this article for more info).
AES.MODE_CBC
Cipher-Block Chaining. An Initialisation Vector (IV) is required.
AES.MODE_CFB
Cipher feedback. plaintext and ciphertext are processed in segments of segment_size
bits. Works a stream cipher.
AES.MODE_CTR
Counter mode. Each message block is associated to a counter which must be unique across
all messages that get encrypted with the same key.
AES.SEGMENT_8 AES.SEGMENT_128
Length of the segment for AES.MODE_CFB.
To avoid security issues, IV should always be a random number and should never be
reused to encrypt two different messages. The same applies to the counter in CTR
mode. You can use crypto.getrandbits() for this purpose.
273
6.2.4 pycom
import pycom
Functions
pycom.heartbeat([enable])
Get or set the state (enabled or disabled) of the heartbeat LED. Accepts and returns boolean
values (True or False).
pycom.heartbeat_on_boot([enable])
Allows you permanently disable or enable the heartbeat LED. Once this setting is set, it will
persist between reboots. Note, this only comes into effect on the next boot, it does not stop
the already running heartbeat.
pycom.rgbled(color)
Set the colour of the RGB LED. The color is specified as 24 bit value representing red, green
and blue, where the red colour is represented by the 8 most significant bits. For instance,
passing the value 0x00FF00 will light up the LED in a very bright green.
pycom.nvs_set(key, value)
Set the value of the specified key in the NVRAM memory area of the external flash. Data
stored here is preserved across resets and power cycles. Value can only take 32-bit integers
at the moment. Example:
274
6.2.4 pycom
import pycom
pycom.nvs_set('temp', 25)
pycom.nvs_set('count', 10)
pycom.nvs_get(key)
Get the value the specified key from the NVRAM memory area of the external flash.
Example:
import pycom
pulses = pycom.nvs_get('count')
pycom.nvs_erase(key)
pycom.nvs_erase_all()
pycom.wifi_on_boot([enable])
Get or set the WiFi on boot flag. When this flag is set to True, the AP with the default ssid
('lopy-wlan-xxx' for example) will be enabled as part of the boot process. If the flag is set to
False, the module will boot with WiFi disabled until it's enabled by the script via the WLAN
class. This setting is stored in non-volatile memory which preserves it across resets and
power cycles. Example:
import pycom
pycom.wdt_on_boot([enable])
Enables the WDT at boot time with the timeout in ms set by the function
wdt_on_boot_timeout . If this flag is set, the application needs to reconfigure the WDT with a
275
6.2.4 pycom
import pycom
pycom.wdt_on_boot_timeout([timeout])
Sets or gets the WDT on boot timeout in milliseconds. The minimum value is 5000 ms.
import pycom
pycom.pulses_get(pin, timeout)
Return a list of pulses at pin. The methods scans for transitions at pin and returns a list of
tuples, each telling the pin value and the duration in microseconds of that value. pin is a pin
object, which must have set to INP or OPEN_DRAIN mode. The scan stops if not transitions
occurs within timeout milliseconds. Example:
pycom.ota_start()
pycom.ota_write(buffer)
pycom.ota_finish()
Perform a firmware update. These methods are internally used by a firmware update though
ftp. The update starts with a call to ota_start(), followed by a series of calls to
ota_write(buffer), and is terminated with ota_finish(). After reset, the new image gets active.
buffer shall hold the image data to be written, in arbitrary sizes. A block size of 4096 is
recommended.
276
6.2.4 pycom
Example:
BLOCKSIZE = const(4096)
APPIMG = "/sd/appimg.bin"
sd = SD()
mount(sd, '/sd')
Instead of reading the data to be written from a file, it can obviously also be received from a
server using any suitable protocol, without the need to store it in the devices file system.
277
6.3 MicroPython Modules
Micropython libraries
The following list contains the standard Python libraries, MicroPython-specific libraries and
Pycom specific modules that are available on the Pycom devices.
The standard Python libraries have been “micro-ified” to fit in with the philosophy of
MicroPython. They provide the core functionality of that module and are intended to be a
drop-in replacement for the standard Python library.
Some modules are available by an u-name, and also by their non-u-name. The non-u-
name can be overridden by a file of that name in your package path. For example,
import json will first search for a file json.py or directory json and load that package if
it is found. If nothing is found, it will fallback to loading the built-in ujson module.
278
6.3.1 micropython
Allocate size bytes of RAM for the emergency exception buffer (a good size is around 100
bytes). The buffer is used to create exceptions in cases when normal RAM allocation would
fail (eg within an interrupt handler) and therefore give useful traceback information in these
situations.
A good way to use this function is to place it at the start of a main script (eg boot.py or
main.py) and then the emergency exception buffer will be active for all the code following it.
micropython.const(expr)
Used to declare that the expression is a constant so that the compile can optimise it. The
use of this function should be as follows:
CONST_X = const(123)
CONST_Y = const(2 * CONST_X + 1)
Constants declared this way are still accessible as global variables from outside the module
they are declared in. On the other hand, if a constant begins with an underscore then it is
hidden, it is not available as a global variable, and does not take up any memory during
execution.
This const function is recognised directly by the MicroPython parser and is provided as part
of the micropython module mainly so that scripts can be written which run under both
CPython and MicroPython, by following the above pattern.
micropython.opt_level([level])
If level is given then this function sets the optimisation level for subsequent compilation of
scripts, and returns None. Otherwise it returns the current optimisation level.
micropython.mem_info([verbose])
279
6.3.1 micropython
Print information about currently used memory. If the verbose argument is given then extra
information is printed.
The information that is printed is implementation dependent, but currently includes the
amount of stack and heap used. In verbose mode it prints out the entire heap indicating
which blocks are used and which are free.
micropython.qstr_info([verbose])
Print information about currently interned strings. If the verbose argument is given then extra
information is printed.
The information that is printed is implementation dependent, but currently includes the
number of interned strings and the amount of RAM they use. In verbose mode it prints out
the names of all RAM-interned strings.
micropython.stack_use()
Return an integer representing the current amount of stack that is being used. The absolute
value of this is not particularly useful, rather it should be used to compute differences in
stack usage at different points.
micropython.heap_lock()
micropython.heap_unlock()
Lock or unlock the heap. When locked no memory allocation can occur and a MemoryError
will be raised if any heap allocation is attempted.
These functions can be nested, ie heap_lock() can be called multiple times in a row and the
lock-depth will increase, and then heap_unlock() must be called the same number of times
to make the heap available again.
micropython.kbd_intr(chr)
Set the character that will raise a KeyboardInterrupt exception. By default this is set to 3
during script execution, corresponding to Ctrl-C. Passing -1 to this function will disable
capture of Ctrl-C, and passing 3 will restore it.
This function can be used to prevent the capturing of Ctrl-C on the incoming stream of
characters that is usually used for the REPL, in case that stream is used for other purposes.
280
6.3.2 uctypes
Module ustruct Standard Python way to access binary data structures (doesn’t scale
well to large and complex structures).
a structure start.
Scalar types:
"field_name": uctypes.UINT32 | 0
In other words, value is scalar type identifier OR-ed with field offset (in bytes) from the start
of the structure.
Recursive structures:
"sub": (2, {
"b0": uctypes.UINT8 | 0,
"b1": uctypes.UINT8 | 1,
})
i.e. value is a 2-tuple, first element of which is offset, and second is a structure descriptor
dictionary (note: offsets in recursive descriptors are relative to a structure it defines).
281
6.3.2 uctypes
i.e. value is a 2-tuple, first element of which is ARRAY flag OR-ed with offset, and second is
scalar element type ORed number of elements in array.
i.e. value is a 3-tuple, first element of which is ARRAY flag OR-ed with offset, second is a
number of elements in array, and third is descriptor of element type.
i.e. value is a 2-tuple, first element of which is PTR flag ORed with offset, and second is
scalar element type.
i.e. value is a 2-tuple, first element of which is PTR flag ORed with offset, second is
descriptor of type pointed to.
Bitfields:
i.e. value is type of scalar value containing given bitfield (typenames are similar to scalar
types, but prefixes with “BF”), OR-ed with offset for scalar value containing the bitfield, and
further OR-ed with values for bit offset and bit length of the bitfield within scalar value,
shifted by BF_POS and BF_LEN positions, respectively. Bitfield position is counted from the
least significant bit, and is the number of right-most bit of a field (in other words, it’s a
number of bits a scalar needs to be shifted right to extra the bitfield).
In the example above, first UINT16 value will be extracted at offset 0 (this detail may be
important when accessing hardware registers, where particular access size and alignment
are required), and then bitfield whose rightmost bit is least-significant bit of this UINT16, and
282
6.3.2 uctypes
length is 8 bits, will be extracted - effectively, this will access least-significant byte of
UINT16.
Note that bitfield operations are independent of target byte endianness, in particular,
example above will access least-significant byte of UINT16 in both little- and big-endian
structures. But it depends on the least significant bit being numbered 0. Some targets may
use different numbering in their native ABI, but uctypes always uses normalised numbering
described above.
Module Contents
class uctypes.struct(addr, descriptor, layout_type=NATIVE)
uctypes.LITTLE_ENDIAN
Layout type for a little-endian packed structure. (Packed means that every field occupies
exactly as many bytes as defined in the descriptor, i.e. the alignment is 1).
uctypes.BIG_ENDIAN
uctypes.NATIVE
Layout type for a native structure - with data endianness and alignment conforming to the
ABI of the system on which MicroPython runs.
uctypes.sizeof(struct)
Return size of data structure in bytes. Argument can be either structure class or specific
instantiated structure object (or its aggregate field).
uctypes.addressof(obj)
Return address of an object. Argument should be bytes, bytearray or other object supporting
buffer protocol (and address of this buffer is what actually returned).
uctypes.bytes_at(addr, size)
Capture memory at the given address and size as bytes object. As bytes object is
immutable, memory is actually duplicated and copied into bytes object, so if memory
contents change later, created object retains original value.
283
6.3.2 uctypes
uctypes.bytearray_at(addr, size)
Capture memory at the given address and size as bytearray object. Unlike bytes_at()
function above, memory is captured by reference, so it can be both written too, and you will
access current value at the given memory address.
Structure objects
Structure objects allow accessing individual fields using standard dot notation:
my_struct.substruct1.field1 . If a field is of scalar type, getting it will produce a primitive
value (Python integer or float) corresponding to the value contained in a field. A scalar field
can also be assigned to.
If a field is an array, its individual elements can be accessed with the standard subscript
operator [] - both read and assigned to.
Summing up, accessing structure fields generally follows C syntax, except for pointer
dereference, when you need to use [0] operator instead of * .
Limitations
Accessing non-scalar fields leads to allocation of intermediate objects to represent them.
This means that special care should be taken to layout a structure which needs to be
accessed when memory allocation is disabled (e.g. from an interrupt). The
recommendations are:
284
6.3.2 uctypes
Note that these recommendations will lead to decreased readability and conciseness of
layouts, so they should be used only if the need to access structure fields without allocation
is anticipated (it’s even possible to define 2 parallel layouts - one for normal usage, and a
restricted one to use when memory allocation is prohibited).
285
6.3.3 sys
Terminate current program with a given exit code. Underlyingly, this function raise as
SystemExit exception. If an argument is given, its value given as an argument to
SystemExit.
sys.print_exception(exc, file=sys.stdout)
Print exception with a traceback to a file-like object file (or sys.stdout by default).
Difference to CPython
Constants
sys.argv
A mutable list of arguments the current program was started with.
sys.byteorder
The byte order of the system (“little” or “big”).
sys.implementation
Object with information about the current Python implementation. For MicroPython, it has
following attributes:
Difference to CPython
286
6.3.3 sys
CPython mandates more attributes for this object, but the actual useful bare minimum is
implemented in MicroPython.
sys.maxsize
Maximum value which a native integer type can hold on the current platform, or maximum
value representable by MicroPython integer type, if it’s smaller than platform max value (that
is the case for MicroPython ports without long int support).
This attribute is useful for detecting “bitness” of a platform (32-bit vs 64-bit, etc.). It’s
recommended to not compare this attribute to some value directly, but instead count number
of bits in it:
bits = 0
v = sys.maxsize
while v:
bits += 1
v >>= 1
if bits > 32:
# 64-bit (or more) platform
else:
# 32-bit (or less) platform
# Note that on 32-bit platform, value of bits may be less than 32
# (e.g. 31) due to peculiarities described above, so use "> 16",
# "> 32", "> 64" style of comparisons.
sys.modules
Dictionary of loaded modules. On some ports, it may not include builtin modules.
sys.path
A mutable list of directories to search for imported modules.
sys.platform
The platform that MicroPython is running on. For OS/RTOS ports, this is usually an identifier
of the OS, e.g. linux . For baremetal ports it is an identifier of a board, e.g. pyboard for the
original MicroPython reference board. It thus can be used to distinguish one board from
another. If you need to check whether your program runs on MicroPython (vs other Python
implementation), use sys.implementation instead.
sys.stderr
Standard error stream.
sys.stdin
Standard input stream.
287
6.3.3 sys
sys.stdout
Standard output stream.
sys.version
Python language version that this implementation conforms to, as a string.
sys.version_info
Python language version that this implementation conforms to, as a tuple of ints.
288
6.3.4 uos
Port Specifics
The filesystem has / as the root directory and the available physical drives are accessible
from here. They are currently:
Functions
uos.uname()
Return information about the system, firmware release version, and micropython interpreter
version.
uos.chdir(path)
uos.getcwd()
uos.listdir([dir])
With no argument, list the current directory. Otherwise list the given directory.
uos.mkdir(path)
uos.remove(path)
Remove a file.
uos.rmdir(path)
Remove a directory.
289
6.3.4 uos
uos.rename(old_path, new_path)
Rename a file.
uos.stat(path)
uos.getfree(path)
Returns the free space (in KiB) in the drive specified by path.
uos.sync()
uos.urandom(n)
uos.unlink(path)
Mounts a block device (like an SD object) in the specified mount point. Example:
os.mount(sd, '/sd')
uos.unmount(path)
290
6.3.4 uos
uos.mkfs(block_device or path)
Formats the specified path, must be either /flash or /sd . A block device can also be
passed like an SD object before being mounted.
uos.dupterm(stream_object)
Duplicate the terminal (the REPL) on the passed stream-like object. The given object must
at least implement the read() and write() methods.
Constants
uos.sep
Separation character used in paths
291
6.3.5 array
Classes
class array.array(typecode[, iterable])
Create array with elements of given type. Initial contents of the array are given by an
iterable. If it is not provided, an empty array is created.
array.append(val)
array.extend(iterable)
Append new elements as contained in an iterable to the end of array, growing it.
292
6.3.6 cmath
Functions
cmath.cos(z)
cmath.exp(z)
cmath.log(z)
Return the natural logarithm of z. The branch cut is along the negative real axis.
cmath.log10(z)
Return the base-10 logarithm of z. The branch cut is along the negative real axis.
cmath.phase(z)
cmath.polar(z)
cmath.rect(r, phi)
cmath.sin(z)
cmath.sqrt(z)
293
6.3.6 cmath
Constants
cmath.e
base of the natural logarithm
cmath.pi
the ratio of a circle’s circumference to its diameter
294
6.3.7 math
Functions
math.acos(x)
math.acosh(x)
math.asin(x)
math.asinh(x)
math.atan(x)
math.atan2(y, x)
math.atanh(x)
math.ceil(x)
math.copysign(x, y)
math.cos(x)
295
6.3.7 math
math.cosh(x)
math.degrees(x)
math.erf(x)
math.erfc(x)
math.exp(x)
math.expm1(x)
Return exp(x) - 1.
math.fabs(x)
math.floor(x)
math.fmod(x, y)
math.frexp(x)
Decomposes a floating-point number into its mantissa and exponent. The returned value is
the tuple (m, e) such that x == m 2*e exactly. If x == 0 then the function returns (0.0, 0),
otherwise the relation 0.5 <= abs(m) < 1 holds.
math.gamma(x)
296
6.3.7 math
math.isfinite(x)
math.isinf(x)
math.isnan(x)
math.ldexp(x, exp)
Return x (2*exp).
math.lgamma(x)
math.log(x)
math.log10(x)
math.log2(x)
math.modf(x)
Return a tuple of two floats, being the fractional and integral parts of x. Both return values
have the same sign as x.
math.pow(x, y)
math.radians(x)
math.sin(x)
297
6.3.7 math
math.sinh(x)
math.sqrt(x)
math.tan(x)
math.tanh(x)
math.trunc(x)
Constants
math.e
base of the natural logarithm
math.pi
the ratio of a circle’s circumference to its diameter
298
6.3.8 gc
gc – Garbage Collector
Functions
gc.enable()
gc.disable()
Disable automatic garbage collection. Heap memory can still be allocated, and garbage
collection can still be initiated manually using gc.collect().
gc.collect()
gc.mem_alloc()
gc.mem_free()
299
6.3.9 ubinascii
Functions
ubinascii.hexlify(data[, sep])
Difference to CPython
ubinascii.unhexlify(data)
Convert hexadecimal data to binary representation. Returns bytes string. (i.e. inverse of
hexlify)
ubinascii.a2b_base64(data)
ubinascii.b2a_base64(data)
300
6.3.10 ujson
Functions
ujson.dumps(obj)
ujson.loads(str)
Parse the JSON str and return an object. Raises ValueError if the string is not correctly
formed.
ujson.load(fp)
301
6.3.11 ure
. Match any character. [] Match set of characters. Individual characters and ranges are
supported. ^
$
??
*?
+?
Counted repetitions ({m,n}), more advanced assertions, named groups, etc. are not
supported.
Functions
ure.compile(regex)
ure.match(regex, string)
Match regex against string. Match always happens from starting position in a string.
ure.search(regex, string)
Search regex in a string. Unlike match, this will search string for first position which matches
regex (which still may be 0 if regex is anchored).
ure.DEBUG
302
6.3.11 ure
Regex objects
Compiled regular expression. Instances of this class are created using ure.compile().
regex.match(string)
regex.search(string)
regex.split(string, max_split=-1)
Match objects
Match objects as returned by match() and search() methods.
match.group([index])
303
6.3.12 usocket
Functions
socket.socket(socket.AF_INET, socket.SOCK_STREAM, socket.IPPROTO_TCP)
Create a new socket using the given address family, socket type and protocol number.
socket.getaddrinfo(host, port)
Translate the host/port argument into a sequence of 5-tuples that contain all the necessary
arguments for creating a socket connected to that service. The list of 5-tuples has following
structure:
(family, type, proto, canonname, sockaddr) The following example shows how to connect to
a given url:
s = socket.socket()
s.connect(socket.getaddrinfo('www.micropython.org', 80)[0][-1])
Exceptions
socket.error socket.timeout
Constants
socket.AF_INET socket.AF_LORA
family types
304
6.3.12 usocket
socket types
socket.IPPROTO_UDP socket.IPPROTO_TCP
socket protocols
socket.SO_REUSEADDR
IP socket options
socket.SO_CONFIRMED socket.SO_DR
LoRa socket options
class Socket
Methods
socket.close()
Mark the socket closed. Once that happens, all future operations on the socket object will
fail. The remote end will receive no more data (after queued data is flushed).
Sockets are automatically closed when they are garbage-collected, but it is recommended to
close() them explicitly, or to use a with statement around them.
socket.bind(address)
Bind the socket to address. The socket must not already be bound. The address parameter
must be a tuple containing the IP address and the port.
In the case of LoRa sockets, the address parameter is simply an integer with the port
number, for instance: s.bind(1)
socket.listen([backlog])
Enable a server to accept connections. If backlog is specified, it must be at least 0 (if it’s
lower, it will be set to 0); and specifies the number of unaccepted connections that the
system will allow before refusing new connections. If not specified, a default reasonable
value is chosen.
305
6.3.12 usocket
socket.accept()
Accept a connection. The socket must be bound to an address and listening for connections.
The return value is a pair (conn, address) where conn is a new socket object usable to send
and receive data on the connection, and address is the address bound to the socket on the
other end of the connection.
socket.connect(address)
socket.send(bytes) Send data to the socket. The socket must be connected to a remote
socket.
socket.sendall(bytes)
Alias of socket.send(bytes).
socket.recv(bufsize)
Receive data from the socket. The return value is a bytes object representing the data
received. The maximum amount of data to be received at once is specified by bufsize.
socket.sendto(bytes, address)
Send data to the socket. The socket should not be connected to a remote socket, since the
destination socket is specified by address.
socket.recvfrom(bufsize)
Receive data from the socket. The return value is a pair (bytes, address) where bytes is a
bytes object representing the data received and address is the address of the socket
sending the data.
Set the value of the given socket option. The needed symbolic constants are defined in the
socket module (SO_* etc.). The value can be an integer or a bytes-like object representing a
buffer.
socket.settimeout(value)
Set a timeout on blocking socket operations. The value argument can be a nonnegative
floating point number expressing seconds, or None. If a non-zero value is given, subsequent
socket operations will raise a timeout exception if the timeout period value has elapsed
306
6.3.12 usocket
before the operation has completed. If zero is given, the socket is put in non-blocking mode.
If None is given, the socket is put in blocking mode.
socket.setblocking(flag)
Set blocking or non-blocking mode of the socket: if flag is false, the socket is set to non-
blocking, else to blocking mode.
socket.makefile(mode='rb')
Return a file object associated with the socket. The exact returned type depends on the
arguments given to makefile(). The support is limited to binary modes only (‘rb’ and ‘wb’).
CPython’s arguments: encoding , errors and newline are not supported.
The socket must be in blocking mode; it can have a timeout, but the file object’s internal
buffer may end up in a inconsistent state if a timeout occurs.
Difference to CPython
Closing the file object returned by makefile() WILL close the original socket as well.
socket.read(size)
Read up to size bytes from the socket. Return a bytes object. If size is not given, it
behaves just like socket.readall(), see below.
socket.readall()
Read all data available from the socket until EOF. This function will not return until the socket
is closed.
socket.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.
socket.readline()
307
6.3.12 usocket
socket.write(buf)
308
6.3.13 select
Pyboard specifics
Polling is an efficient way of waiting for read/write activity on multiple objects. Current
objects that support polling are: pyb.UART, pyb.USB_VCP.
Functions
select.poll()
This function is provided for compatibility and is not efficient. Usage of Poll is recommended
instead.
class Poll
Methods
poll.register(obj[, eventmask])
select.POLLIN | select.POLLOUT .
poll.unregister(obj)
309
6.3.13 select
poll.modify(obj, eventmask)
poll.poll([timeout])
Wait for at least one of the registered objects to become ready. Returns list of ( obj , event ,
...) tuples, event element specifies which events happened with a stream and is a
combination of select.POLL* constants described above. There may be other elements in
tuple, depending on a platform and version, so don’t assume that its size is 2. In case of
timeout, an empty list is returned.
Timeout is in milliseconds.
310
6.3.14 utime
Time Epoch: Pycom’s ESP32 port uses standard for POSIX systems epoch of 1970-01-01
00:00:00 UTC.
Maintaining actual calendar date/time: This requires a Real Time Clock (RTC). On systems
with underlying OS (including some RTOS), an RTC may be implicit. Setting and maintaining
actual calendar time is responsibility of OS/RTOS and is done outside of MicroPython, it just
uses OS API to query date/time. On baremetal ports however system time depends on
machine.RTC() object. The current calendar time may be set using
If actual calendar time is not maintained with a system/MicroPython RTC, functions below
which require reference to current absolute time may behave not as expected.
Functions
utime.gmtime([secs])
Convert a time expressed in seconds since the Epoch (see above) into an 8-tuple which
contains: (year, month, mday, hour, minute, second, weekday, yearday) If secs is not
provided or None, then the current time from the RTC is used.
311
6.3.14 utime
utime.localtime([secs])
Like gmtime() but converts to local time. If secs is not provided or None, the current time
from the RTC is used.
utime.mktime()
This is inverse function of localtime. It’s argument is a full 8-tuple which expresses a time as
per localtime. It returns an integer which is the number of seconds since Jan 1, 2000.
utime.sleep(seconds)
Sleep for the given number of seconds. Seconds can be a floating-point number to sleep for
a fractional number of seconds. Note that other MicroPython ports may not accept floating-
point argument, for compatibility with them use sleep_ms() and sleep_us() functions.
utime.sleep_ms(ms)
utime.sleep_us(us)
utime.ticks_ms()
utime.ticks_us()
utime.ticks_cpu()
Similar to ticks_ms and ticks_us , but with higher resolution (25 ns).
utime.ticks_diff(old, new)
Measure period between consecutive calls to ticksms(), ticks_us(), or ticks_cpu(). The value
returned by these functions may wrap around at any time, so directly subtracting them is not
supported. ticks_diff() should be used instead. “old” value should actually precede “new”
value in time, or result is undefined. This function should not be used to measure arbitrarily
long periods of time (because ticks*() functions wrap around and usually would have short
period). The expected usage pattern is implementing event polling with timeout:
312
6.3.14 utime
utime.time()
Returns the number of seconds, as an integer, since the Epoch, assuming that underlying
RTC is set. If an RTC is not set, this function returns number of seconds since power up or
reset). If you want to develop portable MicroPython application, you should not rely on this
function to provide higher than second precision. If you need higher precision, use
ticks_ms() and ticks_us() functions, if you need calendar time, localtime() without an
utime.timezone([secs])
Set or get the timezone offset, in seconds. If secs is not provided, it returns the current
value.
313
6.3.15 uhashlib
Constructors
class uhashlib.md5([data])
Create a MD5 hasher object and optionally feed data into it.
class uhashlib.sha1([data])
Create a SHA-1 hasher object and optionally feed data into it.
class uhashlib.sha224([data])
Create a SHA-224 hasher object and optionally feed data into it.
class uhashlib.sha256([data])
Create a SHA-256 hasher object and optionally feed data into it.
class uhashlib.sha384([data])
Create a SHA-384 hasher object and optionally feed data into it.
class uhashlib.sha512([data])
Create a SHA-512 hasher object and optionally feed data into it.
Methods
hash.update(data)
hash.digest()
Return hash for all data passed through hash, as a bytes object. After this method is called,
more data cannot be fed into hash any longer.
hash.hexdigest()
314
6.3.15 uhashlib
315
6.3.16 ussl
Functions
ssl.wrap_socket(sock, keyfile=None, certfile=None, server_side=False,
cert_reqs=CERT_NONE, ca_certs=None)
import socket
import ssl
s = socket.socket()
ss = ssl.wrap_socket(s)
ss.connect(socket.getaddrinfo('www.google.com', 443)[0][-1])
Certificates must be used in order to validate the other side of the connection, and also to
authenticate ourselves with the other end. Such certificates must be stored as files using the
FTP server, and they must be placed in specific paths with specific names.
For instance to connect to the Blynk servers using certificates, take the file ca.pem located
in the blynk examples folder and put it in /flash/cert/ . Then do:
import socket
import ssl
s = socket.socket()
ss = ssl.wrap_socket(s, cert_reqs=ssl.CERT_REQUIRED, ca_certs='/flash/cert/ca.pem')
ss.connect(socket.getaddrinfo('cloud.blynk.cc', 8441)[0][-1])
SSL sockets inherit all methods and from the standard sockets, see the usocket module.
Exceptions
ssl.SSLError
Constants
316
6.3.16 ussl
317
6.3.17 ucrypto
ucrypto — Cryptography
This module provides native support for cryptographic algorithms. It’s loosely based on
PyCrypto.
Classes
class AES - Advanced Encryption Standard
Methods
crypto.getrandbits(bits)
Returns a bytes object filled with random bits obtained from the hardware random number
generator.
According to the ESP32 Technical Reference Manual, such bits ”... can be used as the
basis for cryptographical operations”. “These true random numbers are generated based on
the noise in the Wi-Fi/BT RF system. When Wi-Fi and BT are disabled, the random number
generator will give out pseudo-random numbers.”
Cryptography is not a trivial business. Doing things the wrong way could quickly result in
decreased or no security. Please document yourself in the subject if you are depending
on encryption to secure important information.
318
6.3.18 ustruct
Functions
ustruct.calcsize(fmt)
Pack the values v1, v2, ... according to the format string fmt. The return value is a bytes
object encoding the values.
Pack the values v1, v2, ... according to the format string fmt into a buffer starting at offset.
offset may be negative to count from the end of buffer.
ustruct.unpack(fmt, data)
Unpack from the data according to the format string fmt. The return value is a tuple of the
unpacked values.
Unpack from the data starting at offset according to the format string fmt. offset may be
negative to count from the end of buffer. The return value is a tuple of the unpacked values.
319
6.3.19 _thread
import _thread
import time
for i in range(2):
_thread.start_new_thread(th_func, (i + 1, i))
Functions
_thread.start_new_thread(function, args[, kwargs])
Start a new thread and return its identifier. The thread executes the function with the
argument list args (which must be a tuple). The optional kwargs argument specifies a
dictionary of keyword arguments. When the function returns, the thread silently exits. When
the function terminates with an unhandled exception, a stack trace is printed and then the
thread exits (but other threads continue to run).
_thread.exit()
Raise the SystemExit exception. When not caught, this will cause the thread to exit silently.
_thread.allocate_lock()
Return a new lock object. Methods of locks are described below. The lock is initially
unlocked.
_thread.get_ident()
320
6.3.19 _thread
Return the ‘thread identifier’ of the current thread. This is a nonzero integer. Its value has no
direct meaning; it is intended as a magic cookie to be used e.g. to index a dictionary of
thread-specific data. Thread identifiers may be recycled when a thread exits and another
thread is created.
_thread.stack_size([size])
Return the thread stack size (in bytes) used when creating new threads. The optional size
argument specifies the stack size to be used for subsequently created threads, and must be
0 (use platform or configured default) or a positive integer value of at least 4096 (4KiB). 4KiB
is currently the minimum supported stack size value to guarantee sufficient stack space for
the interpreter itself.
Objects
_thread.LockType
This is the type of lock objects.
Methods
Lock objects have the following methods:
lock.acquire(waitflag=1, timeout=-1)
Without any optional argument, this method acquires the lock unconditionally, if necessary
waiting until it is released by another thread (only one thread at a time can acquire a lock —
that’s their reason for existence).
If the integer waitflag argument is present, the action depends on its value: if it is zero, the
lock is only acquired if it can be acquired immediately without waiting, while if it is nonzero,
the lock is acquired unconditionally as above.
If the floating-point timeout argument is present and positive, it specifies the maximum wait
time in seconds before returning. A negative timeout argument specifies an unbounded wait.
You cannot specify a timeout if waitflag is zero.
The return value is True if the lock is acquired successfully, False if not.
lock.release()
Releases the lock. The lock must have been acquired earlier, but not necessarily by the
same thread.
321
6.3.19 _thread
lock.locked()
Return the status of the lock: True if it has been acquired by some thread, False if not.
In addition to these methods, lock objects can also be used via the with statement, e.g.:
import _thread
a_lock = _thread.allocate_lock()
with a_lock:
print("a_lock is locked while this executes")
322
6.3.20 Builtin
Builtin Functions
All builtin functions are described here. They are also available via builtins module.
abs()
all()
any()
bin()
class bool
class bytearray
class bytes
callable()
chr()
class method()
compile()
323
6.3.20 Builtin
class complex
class dict
dir()
divmod()
enumerate()
eval()
exec()
filter()
class float
class frozenset
getattr()
globals()
324
6.3.20 Builtin
hasattr()
hash()
hex()
id()
input()
class int
isinstance()
issubclass()
iter()
len()
class list
locals()
map()
325
6.3.20 Builtin
max()
class memoryview
min()
next()
class object
oct()
open()
ord()
pow()
print()
property()
range()
326
6.3.20 Builtin
repr()
reversed()
round()
class set
setattr()
sorted()
staticmethod()
class str
sum()
super()
class tuple
type()
zip()
327
6.3.20 Builtin
328
7.1 Introduction
Datasheets
This section contains all of the datasheets for Pycom devices. This includes pinouts and
schematics (for certain devices).
329
7.2 Development Modules
Development Devices
This section contains all of the datasheets for the Pycom Development Devices. This
includes the WiPy 2.0, LoPy, SiPy, GPy and FiPy.
330
7.2.1 WiPy 2.0
WiPy 2.0
Pinout
The pinout of the WiPy 2.0 is available as a PDF File.
Specsheets
The specsheet of the WiPy 2.0 is available as a PDF File.
Please note that the PIN assignments for UART1 (TX1/RX1), SPI (CLK,MOSI,MISO) and
I2C (SDA,SCL) are defaults and can be changed in Software.
331
7.2.2 WiPy 3.0
WiPy 3.0
Pinout
The pinout of the WiPy 3.0 is available as a PDF File.
Specsheets
The specsheet of the WiPy 3.0 is available as a PDF File.
332
7.2.2 WiPy 3.0
Please note that the PIN assignments for UART1 (TX1/RX1), SPI (CLK,MOSI,MISO) and
I2C (SDA,SCL) are defaults and can be changed in Software.
333
7.2.3 LoPy
LoPy
Pinout
The pinout of the LoPy is available as a PDF File.
Specsheets
The specsheet of the LoPy is available as a PDF File.
Please note that the PIN assignments for UART1 (TX1/RX1), SPI (CLK,MOSI,MISO) and
I2C (SDA,SCL) are defaults and can be changed in Software.
334
7.2.4 LoPy 4
LoPy 4
Pinout
The pinout of the LoPy 4 is available as a PDF File.
Specsheets
The specsheet of the LoPy 4 is available as a PDF File.
Please note that the PIN assignments for UART1 (TX1/RX1), SPI (CLK,MOSI,MISO) and
I2C (SDA,SCL) are defaults and can be changed in Software.
335
7.2.4 LoPy 4
336
7.2.5 SiPy
SiPy
Pinout
The pinout of the SiPy is available as a PDF File.
Specsheets
The specsheet of the SiPy is available as a PDF File.
Please note that the PIN assignments for UART1 (TX1/RX1), SPI (CLK,MOSI,MISO) and
I2C (SDA,SCL) are defaults and can be changed in Software.
337
7.2.6 GPy
GPy
Pinout
The pinout of the GPy is available as a PDF File.
Specsheets
The specsheet of the GPy is available as a PDF File.
Please note that the PIN assignments for UART1 (TX1/RX1), SPI (CLK,MOSI,MISO) and
I2C (SDA,SCL) are defaults and can be changed in Software.
AT Commands
The AT commands for the Sequans Monarch modem on the GPy are available in a PDF file.
338
7.2.6 GPy
339
7.2.7 FiPy
FiPy
Pinout
The pinout of the FiPy is available as a PDF File.
Specsheets
The specsheet of the FiPy is available as a PDF File.
Please note that the PIN assignments for UART1 (TX1/RX1), SPI (CLK,MOSI,MISO) and
I2C (SDA,SCL) are defaults and can be changed in Software.
AT Commands
The AT commands for the Sequans Monarch modem on the FiPy are available in a PDF file.
340
7.2.7 FiPy
341
7.3 OEM Modules
OEM Devices
This section contains all of the datasheets for the Pycom OEM Devices. This includes the
W01, L01 and G01.
342
7.3.1 W01
W01
Pinout
The pinout of the W01 is available as a PDF File.
Specsheets
The specsheet of the W01 is available as a PDF File.
343
7.3.1 W01
Drawings
The drawings for the W01 is available as a PDF File.
Please note that the PIN assigments for UART1 (TX1/RX1), SPI (CLK,MOSI,MISO) and I2C
(SDA,SCL) are defaults and can be changed in Software.
344
7.3.2 L01
L01
Pinout
The pinout of the L01 is available as a PDF File.
Specsheets
The specsheet of the L01 is available as a PDF File.
345
7.3.2 L01
Drawings
The drawings for the L01 is available as a PDF File.
Please note that the PIN assigments for UART1 (TX1/RX1), SPI (CLK,MOSI,MISO) and I2C
(SDA,SCL) are defaults and can be changed in Software.
346
7.3.3 L04
L04
Pinout
The pinout of the L04 is available as a PDF File.
Specsheets
The specsheet of the L04 is available as a PDF File.
347
7.3.3 L04
Drawings
The drawings for the L04 is available as a PDF File.
Please note that the PIN assigments for UART1 (TX1/RX1), SPI (CLK,MOSI,MISO) and I2C
(SDA,SCL) are defaults and can be changed in Software.
348
7.3.4 G01
G01
Pinout
The pinout of the G01 is available as a PDF File.
Specsheets
The specsheet of the G01 is available as a PDF File.
349
7.3.4 G01
Drawings
The drawings for the G01 is available as a PDF File.
Please note that the PIN assigments for UART1 (TX1/RX1), SPI (CLK,MOSI,MISO) and I2C
(SDA,SCL) are defaults and can be changed in Software.
350
7.3.5 L01 OEM Baseboard Reference
The L01 OEM reference board is a reference design suitable L01 as well as W01 making it
possible to have a single PCB design that can accommodate both OEM modules.
If you require a reference board for the L04 or G01, this design is not suitable as it does
not feature a SIM slot or the double antenna connection. For the G01 or L04 please use
the Universal OEM Baseboard Reference
Features
Suits both L01 or W01 OEM Modules
U.FL connector for the L01's LoRa output.
On-board 2.4GHz antenna for WiFi and Bluetooth, with the ability to switch to a external
antenna via a U.FL connector.
WS2812B RGB LED
3.5-5.5 Input switch mode DC-DC regulator with low current draw during deep sleep
Reset button
Layout
The layout of the L01 baseboard reference is available as a PDF File.
351
7.3.5 L01 OEM Baseboard Reference
Schematic
The schematic of the L01 baseboard reference is available as a PDF File.
352
7.3.5 L01 OEM Baseboard Reference
353
7.3.6 Universal OEM Baseboard Reference
The universal OEM reference board is a reference design suitable W01, L01, L04 and G01
OEM modules, making it possible to have a single PCB design that can accommodate all
our OEM modules.
If you require a reference board for the G01, only this design is suitable. The L01
reference board does not contain the necessary SIM slot.
Features
Suits all OEM modules (L01, L04, W01, G01)
On-board 2.4GHz antenna for WiFi and Bluetooth, with the ability to switch to a external
antenna via a U.FL connector.
3 U.FL connectors for all the outputs available on the OEM modules
WS2812B RGB LED
3.5-5.5 Input switch mode DC-DC regulator with low current draw during deep sleep
Reset button
Layout
The layout of the OEM baseboard reference is available as a PDF File.
354
7.3.6 Universal OEM Baseboard Reference
Schematic
The schematic of the OEM baseboard reference is available as a PDF File.
355
7.3.6 Universal OEM Baseboard Reference
356
7.4 Expansion Boards and Shields
357
7.4.1 Expansion Board
Expansion Board
Pinout
The pinout of the Expansion Board is available as a PDF File.
358
7.4.1 Expansion Board
Be gentle when plugging/unplugging from the USB connector. Whilst the USB connector
is soldered and is relatively strong, if it breaks off it can be very difficult to fix.
Battery Charger
The expansion board features a single cell Li-Ion/Li-Po charger. When the board is being
powered via the micro USB connector, the expansion board will charger the battery (if
connected). When the CHG jumper is present the battery will be charged at 450mA . If this
value is too high for your application, removing the jumper lowers the charge current to
100mA .
Specsheets
The specsheet of the Expansion Board is available as a PDF File.
359
7.4.2 Pytrack
Pytrack
Pinout
The pinout of the Pytrack is available as a PDF File.
Battery Charger
The expansion board features a single cell Li-Ion/Li-Po charger. When the board is being
powered via the micro USB connector, the expansion board will charger the battery (if
connected).
360
7.4.2 Pytrack
Specsheets
The specsheet of the Pytrack is available as a PDF File.
361
7.4.3 Pysense
Pysense
Pinout
The pinout of the Pysense is available as a PDF File.
Battery Charger
The expansion board features a single cell Li-Ion/Li-Po charger. When the board is being
powered via the micro USB connector, the expansion board will charger the battery (if
connected).
Specsheets
362
7.4.3 Pysense
363
7.4.4 Deep Sleep Shield
Pinout
The pinout of the Deep Sleep Shield is available as a PDF File.
To correctly connect a WiPy 2.0, LoPy or SiPy to the Deep Sleep Shield, align the white
triangle on the Shield with the LED of the Pycom Device. Once the Pycome Device is
seated onto the Deep Sleep Shield, this can then be connected to the Exapnsion Board.
364
7.4.4 Deep Sleep Shield
365
7.4.4.1 Deep Sleep API
To use this library, please upload the associated Deep Sleep Library to /lib on the target
Pycom Device.
Quick Example
ds = DeepSleep()
# get the wake reason and the value of the pins during wake up
wake_s = ds.get_wake_status()
print(wake_s)
if wake_s['wake'] == deepsleep.PIN_WAKE:
print("Pin wake up")
elif wake_s['wake'] == deepsleep.TIMER_WAKE:
print("Timer wake up")
else: # deepsleep.POWER_ON_WAKE:
print("Power ON reset")
DeepSleep
The Deep Sleep Shield allows for waking up via a user trigger and also via an external
interrupt (i.e. Accelerometer, Button).
Constructors
class DeepSleep()
Creates a DeepSleep object, that will control the board's sleep features. For example;
ds = DeepSleep()
366
7.4.4.1 Deep Sleep API
Methods
deepsleep.enable_auto_poweroff()
This method allows for a critical battery voltage to be set. For example, if the external power
source (e.g. LiPo Cell) falls below 3.3V, turn off the Pycom Device. This is intended to
protect the hardware from under voltage.
deepsleep.enable_pullups(pins)
This method allows for pullup pins to be enabled. For example, if an external trigger occurs,
wake the Pycom Device from Deep Sleep. pins may be passed into the method as a list,
i.e. ['P17', 'P18'] .
deepsleep.disable_pullups(pins)
This method allows for pullup pins to be disabled. For example, if an external trigger occurs,
wake the Pycom Device from Deep Sleep. pins may be passed into the method as a list,
i.e. ['P17', 'P18'] .
deepsleep.enable_wake_on_raise(pins)
This method allows for pullup pins to trigger on a rising voltage. For example, if an external
rising voltage triggers occurs, wake the Pycom Device from Deep Sleep. pins may be
passed into the method as a list, i.e. ['P17', 'P18'] .
deepsleep.disable_wake_on_raise(pins)
This method allows for disabling pullup pins that trigger on a rising voltage. pins may be
passed into the method as a list, i.e. ['P17', 'P18'] .
deepsleep.enable_wake_on_fall(pins)
This method allows for pullup pins to trigger on a falling voltage. For example, if an external
falling voltage triggers occurs, wake the Pycom Device from Deep Sleep. pins may be
passed into the method as a list, i.e. ['P17', 'P18'] .
deepsleep.disable_wake_on_fall(pins)
This method allows for disabling pullup pins that trigger on a falling voltage. pins may be
passed into the method as a list, i.e. ['P17', 'P18'] .
deepsleep.get_wake_status()
This method returns the status of the pins at wakeup from deep sleep. The method returns a
dict with the states of wake , P10 , P17 , P18 .
367
7.4.4.1 Deep Sleep API
deepsleep.set_min_voltage_limit(value)
This method relates to the enable_auto_poweroff method and allows the user to specify the
minimum power off voltage as a value.
deepsleep.go_to_sleep(seconds)
This method sends the board into deep sleep for a period of seconds or until an external
interrupt has triggered (see set_pullups ).
deepsleep.hw_reset()
This method resets the PIC controller and resets it to the state previous to the pins/min-
voltage being set.
Please note that more functionality is being added weekly to these libraries. If a required
feature is not available, feel free to contribute with a pull request at the Pycom Libraries
GitHub repository.
368
7.5 Notes
Notes
Powering with an external power source
The devices can be powered by a battery or other external power source.
Be sure to connect the positive lead of the power supply to VIN, and ground to GND.
Please DO NOT power the board via the 3.3V pin as this may damage the device.
ONLY use the VIN pin for powering Pycom Devices.
The battery connector for the expansion board is a JST PHR-2 variant. The expansion board
exposes the male connector and an external battery should use a female adapter in order to
connect and power the expansion board. The polarity of the battery should be checked
before being plugged into the expansion board, the cables may require swapping.
The GPIO pins of the modules are NOT 5V tolerant, connecting them to voltages higher
than 3.3V might cause irreparable damage to the device.
Static electricity can damage components on the device and may destroy them. If there
is a lot of static electricity in the area (e.g. dry and cold climates), take extra care not to
shock the device. If the device came in a ESD bag (Silver packaging), the best way to
store and carry the device is inside this bag as it will be protected against static
discharges.
369
8.1 Introduction
Pybytes Beta
Pybytes is Pycom's IOT cloud platform available for all Pycom modules. Pybytes is running
in Closed Beta from March 2018.
Please read the following sections for more information about how to add device to Pybytes.
370
8.2 Adding device quickly
If you manually uploaded Pybytes library on your device before. Make sure to do factory
reset of your device filesystem. Otherwise code in /flash folder will have priority over
build in library in /frozen folder.
371
8.2 Adding device quickly
372
8.2 Adding device quickly
Now firmware updater is updating your firmware. It is asking Pybytes for your device
credentials like WiFi password. It will write these information to device's config block.
373
8.2 Adding device quickly
374
8.3 Adding device by flashing Pybytes library
Still if you want to extend Pybytes library or add your code main.py file you have an option
to flash Pybytes library manually.
Pybytes library written to /flash folder and will take precedence over build in firmware
libraries in /frozen folder.
375
8.3 Adding device by flashing Pybytes library
{
"address": "PASTE_YOUR_SERIAL_PORT_HERE",
"username": "micro",
"password": "python",
"sync_folder": "flash"
}
5. Checkout your flash/config.py file. It will be pre-filled with your information from
Pybytes Like deviceToken or WiFi credentials. You can change e.g. your WiFy
password here.
6. Put your device in safe boot mode.
7. Upload code to your device by clicking on Upload button in Pymakr. After all Pybytes
library files are uploaded to device, device will restart and will connect to Pybytes.
376
9.1 Introduction
Documentation Notes
The Pycom documentation aims to be straightforward and to adhere to typical Python
documentation to allow for ease of understanding. However, there may be some unusual
features for those not used to Python documentation or that are new to the MicroPython
Language. This section of the documentation aims to provide clarity for any of the design
specifics that might be confusing for those new to Python and this style of documentation.
377
9.2 Syntax
Documentation Syntax
The Pycom documentation follows standard Python Library format using the popular Sphinx
Docs tool. There are some notable points regarding the syntax of classes, methods and
constants. Please see the notes below and familiarise yourself with the specific details
before reviewing the documentation.
Keyword Arguments
Keyword Arguments refer to the arguments that are passed into a constructor (upon
referencing a class object). When passing values into a MicroPython constructor it is not
always required to specify the name of the argument and instead rely on the order of the
arguments passed as to describe what they refer to. In the example below, it can be seen
that the argument mode is passed into the i2c.init() method without specifying a name.
The values of the arguments (as seen in the examples/docs) refer to the default values that
are passed into the constructor if nothing is provided.
It can be seen that a value for baudrate was not passed into the method and thus
MicroPython will assume a default value of 100000. Also the first argument mode was not
specified by name, as the constructor does not require it, denoted by the lack of an ‘=’
symbol in the constructor documentation.
Keyword
378
9.2 Syntax
An astrik ‘ * ’ in a method description (in the docs), denotes that the following arguments
require a keyword, i.e. pin='P16' in the example below.
pin is a required argument and the method channel will not execute unless it is passed
as with a keyword.
Another example shows how the PWM class, pwm.channel() requires a keyword argument
for pin but does not for id .
Value
The documentation may refer to a method that takes an argument listed by name but does
allow for a keyword to be passed. For example, the pycom class contains a method
rgbled . This lists that the method accepts a value for color , however this may not be
specified by keyword , only value . This is intentional as the value being passed is the
only argument valid for this method
pycom.rgbled(color)
If the argument is passed into the method with a keyword, it will return an error stating
TypeError: function does not take keyword arguments.
import pycom
pycom.rgbled(color=0xFF0000) # Incorrect
pycom.rgbled(0xFF0000) # Correct
Another example of a method that only accepts value input. In this case, the RTC.init()
method require a value ( tuple ) input for the datetime . It will not accept a keyword.
rtc.init(datetime)
379
9.2 Syntax
rtc = RTC()
rtc.init(datetime=(2014, 5, 1, 4, 13, 0, 0, 0)) # Incorrect
rtc.init((2014, 5, 1, 4, 13, 0, 0, 0)) # Correct
Constants
The constants section of a library within the docs refers to specific values from that library’s
class. These might be used when constructing an object from that class or when utilising a
method from within that class. These are generally listed by the library name followed by the
specific value. See the example below:
I2C.MASTER()
Be aware that you can only reference these constants upon importing and constructing
a object from a library.
380
9.3 REPL vs Scripts
REPL vs Scripts
Users of this documentation should be aware that examples given in the docs are under the
expection that they are being executed using the MicroPython REPL. This means that when
certain functions are called, their output may not necessarily be printed to the console if they
are run from a script. When using the REPL many classes/functions automatically produce a
printed output displaying the return value of the function to the console. The code snippet
below demonstrates some examples of classes/functions that might display this behaviour.
Basic Arithmetic
Calling Methods
import binascii
In order to use these functions that do not print out any values, you will need to either wrap
them in a print() statement or assign them to variables and call them later when you wish
to use them.
For example:
381
10.1 Firmware Downgrade
Firmware Downgrade
The firmware upgrade tool usually updates your device to the latest available firmware
version. If you require to downgrade your device to a previous firmware there are two
methods to achieve this.
If you are using an expansion board 1.0 or 2.0, you will need to have a jumper
connected between P2 and GND to use either procedure below. You will also need to
press the reset button before beginning.
WiPy
LoPy
SiPy
GPy
FiPy
LoPy4
Note: Prior to version 1.16.0.b1 the firmware for modules with LoRa functionality was
frequency specific. From 1.16.0.b1 and onward, the firmware is region agnostic and this
can either be set programatically or via the config block (see here).
GUI
As of version 1.12.0.b0 of the firmware update tool, you can now provide a .tar or .tar.gz
archive of the firmware you wish to upload to the board.
When you start the update tool you will see the following screen:
382
10.1 Firmware Downgrade
When you tick the Flash from local file option, an address bar will appear. Click the ...
button and locate the .tar(.gz) file with the firmware you wish to flash to your device. From
this point the updater will behave just like a regular update but using the local file instead of
downloading the latest.
Command line
You can also use the CLI version of the update tool to downgrade your device. Will need to
get a .tar or .tar.gz archive of the firmware you wish to upload to the board. Then run the
following commands:
383
10.2 CLI Updater
Mac
In order to get access to the CLI tool on mac you will need to right click on the mac version
of the updater tool and click Show Package Contents , then navigate to contents/resources ,
here you will find the pycom-fwtool-cli .
Linux
The linux version of the updater tool does not come with a precompiled pycom-fwtool-cli
binary, but rather raw the python script. This can be found in bin/updater.py
Usage
384
10.2 CLI Updater
usage: pycom-fwtool-cli [-h] [-v] [-q] [-p PORT] [-s SPEED] [-c] [-x] [--ftdi]
[--pic]
{list,chip_id,wmac,smac,sigfox,exit,flash,write,write_remote,c
b,nvs,ota,lpwan,erase_fs,erase_all}
...
Update your Pycom device with the specified firmware image file
positional arguments:
{list,chip_id,wmac,smac,sigfox,exit,flash,write,write_remote,cb,nvs,ota,lpwan,erase_
fs,erase_all}
list Get list of available COM ports
chip_id Show ESP32 chip_id
wmac Show WiFi MAC
smac Show LPWAN MAC
sigfox Show sigfox details
exit Exit firmware update mode
flash Write firmware image to flash
write Write to flash memory
write_remote Write remote config to flash memory
cb Read/Write config block
nvs Read/Write non volatile storage
ota Read/Write ota block
lpwan Get/Set LPWAN parameters
erase_fs Erase flash file system area
erase_all Erase entire flash!
optional arguments:
-h, --help show this help message and exit
-v, --verbose show verbose output from esptool
-q, --quiet suppress success messages
-p PORT, --port PORT the serial port to use
-s SPEED, --speed SPEED baudrate
-c, --continuation continue previous connection
-x, --noexit do not exit firmware update mode (Pysense/Pytrack only)
--ftdi force running in ftdi mode
--pic force running in pic mode (Pysense/Pytrack)
Modes
list
Get list of available serial ports ports.
optional arguments:
-h, --help show this help message and exit
385
10.2 CLI Updater
Example:
$pycom-fwtool-cli list
/dev/cu.usbmodemPy343431 [Pytrack] [USB VID:PID=04D8:F013 SER=Py343434 LOCATION=20-2]
/dev/cu.Bluetooth-Incoming-Port [n/a] [n/a]
or on windows
If you are using an expansion board 1.0 or 2.0, you will need to have a jumper
connected between P2 and GND to use any of the commands below. You will also
need to press the reset button before running each command.
chip_id
Shows the unique ID of the ESP32 on the connected module.
optional arguments:
-h, --help show this help message and exit
wmac
Shows the WiFi MAC of the connected module.
optional arguments:
-h, --help show this help message and exit
smac
Shows the LPWAN MAC of the connected module.
optional arguments:
-h, --help show this help message and exit
386
10.2 CLI Updater
sigfox
Show sigfox details
optional arguments:
-h, --help show this help message and exit
exit
If a Pysense/Pytrack has previously been left in firmware update mode by using the -x
option, this command can be used to exit the firmware update mode.
optional arguments:
-h, --help show this help message and exit
flash
Writes firmware image to flash, must be as a tar(.gz) file as provided by Pycom. These files
can be found on GitHub.
optional arguments:
-h, --help show this help message and exit
-t TAR, --tar TAR perform the upgrade from a tar[.gz] file
write
Write to a specific location in flash memory.
optional arguments:
-h, --help show this help message and exit
-a ADDRESS, --address ADDRESS
address to write to
--contents CONTENTS contents of the memory to write (base64)
write_remote
387
10.2 CLI Updater
This is an internal function used by the GUI update tool. This is not intended to be used by
end users.
cb
Read/Write config block (LPMAC, Sigfox PAC & ID, etc.). You can find the structure of this
block here.
optional arguments:
-h, --help show this help message and exit
-f FILE, --file FILE name of the backup file
-b, --backup backup cb partition to file
-r, --restore restore cb partition from file
nvs
Read/Write non-volatile storage.
optional arguments:
-h, --help show this help message and exit
-f FILE, --file FILE name of the backup file
-b, --backup backup cb partition to file
-r, --restore restore cb partition from file
ota
388
10.2 CLI Updater
Read/Write ota block, this contains data relating to OTA updates such as the hash of the
OTA firmware.
optional arguments:
-h, --help show this help message and exit
-f FILE, --file FILE name of the backup file
-b, --backup backup cb partition to file
-r, --restore restore cb partition from file
lpwan
Get/Set LPWAN parameters saved to non-volatile storage. Please see here for more details.
optional arguments:
-h, --help show this help message and exit
--region REGION Set default LORA region
--erase_region Erase default LORA region
--lora_region Output only LORA region
erase_fs
Erase flash file system area. This is useful if some code running on the device is reventing
access to the REPL.
optional arguments:
-h, --help show this help message and exit
erase_all
Erase entire flash, only use this if you are sure you know what you are doing. This will
remove your devices lpwan mac addresses etc.
389
10.2 CLI Updater
optional arguments:
-h, --help show this help message and exit
390
11.1 License
Permission is hereby granted, free of charge, to any person obtaining a copy of this software
and associated documentation files (the “Software”), to deal in the Software without
restriction, including without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
This software is licensed under the GNU GPL version 3 or any later version, with permitted
additional terms. For more information see the Pycom Licence v1.0 document supplied with
this file, or available at https://www.pycom.io/opensource/licensing
391