Skip to content
Boris Lovosevic edited this page Sep 2, 2018 · 7 revisions

Curl module

This module uses libcurl to implement various client protocols.

Features

  • http and https
    • get send GET request to the http/https server, get response to string or file
    • post send OST` request to the http/https server, posted data can be numbers, strings or files
  • ftp
    • get, put and list commands are implemented
  • smtp
    • sendmail send mail, gMail supported, multiple attachments supported

Note:
If TLS is enabled, the module uses mbedTLS and more memory is required.
If not using psRAM, you may need to lower the MicroPython heap (72 KB will usually be enough).
You may try to set
→ Component config → mbedTLS → TLS maximum message content length
to a lower value than default 16 kB, for example to 4 kB. It will usually work, but the TLS may fail if the server side does not support TLS Maximum Fragment Length Negotiation Extension.



Methods


curl.options(print, verbose, progress, timeout, maxfsize, hdrlen, bodylen, nodecode)

Get or set curl options.
All arguments are optional. All, except ṗrint, arguments are kw arguments and must be entered in arg=value format.

Arg Description
print Default: True; print the current options.
False can be used when setting the option(s) from Python script
verbose if True, detailed report about curl operations is printed
progress if True, prints the progress during the file upload/download
timeout Default: 60 sek; set the timeout curl operations in seconds. Minimal value allowed is 10 seconds
maxfsize Default: 300000
Maximum download file size. If the requested file size is bigger, the whole file will be downloaded, but the file on filesystem will be truncated at that value.
hdrlen Default: 512 or 1024 if psRAM is used
The size of the header buffer. Header buffer is returned as the 2nd item in curl operations result and contains the http header or other information
bodylen Default: 1024 or 4096 if psRAM is used
The size of the body buffer. Body buffer is returned as 3rd item in curl operations result and contains the response from the server.
nodecode if set to True, do not allow using compression in http requests
>>> import curl
>>> curl.options()
Curl options(
  Verbose: True, Progress: 0, Timeout: 60, Max fsize: 300000, Header len: 1024, Body len: 4096, Decode content: True
)
>>> 

curl.info()

Print information about libcurl version and supported protocols

>>> curl.info()
Curl Info (
  Curl version info
    version: 7.58.0-DEV - 473600
  Host: MicroPython-ESP32
    - IP V6 supported
    - SSL supported
    - LIBZ supported
    - DEBUG NOT supported
  Protocols:
    - ftp
    - ftps
    - http
    - https
    - imap
    - imaps
    - scp
    - sftp
    - smtp
    - smtps
)
>>> 

curl.get(url [, file])

Send GET request to http/https server.

url is the reference to the http resource. It must start with http:// or https://
It can contain the parameters to be passed to the server.

file argument is optional, if not used, the file/request result will be downloaded into response buffer (and truncated to its size).
If used, the remote file will be downloaded to the file on MicroPython file system.
Special file name can be used: simulate. The file will be downloaded, but no actual saving to file will occur.

The method returns tuple of 3 items: (res_code, hdr, body)
On succes res_code will have the value 0, on fail the error code.

>>> res = curl.get('loboris.eu/ESP32/info.txt')
>>> res[0]
0
>>> print(res[1])
HTTP/1.1 200 OK
Date: Mon, 22 Jan 2018 12:36:24 GMT
Server: Apache/2.4.7 (Ubuntu)
Last-Modified: Thu, 05 Oct 2017 11:08:15 GMT
ETag: "181-55acabda6ed78-gzip"
Accept-Ranges: bytes
Vary: Accept-Encoding
Content-Encoding: gzip
Content-Length: 267
Content-Type: text/plain


>>> print(res[2])
================
Welcome to ESP32
================

The ESP32 is a low cost, low power microcontroller
with integrated Wi-Fi & dual-mode Bluetooth,
which employs a dual-core
Tensilica Xtensa LX6 microprocessor.

ESP32 is created and developed by Espressif Systems,
a Shanghai-based Chinese company,
and is manufactured by TSMC using their 40 nm process.

---------
2017 LoBo
---------
>>> res = curl.get("loboris.eu/ESP32/test.php?param1=12345&param2=Hi_from_MicroPython&temper=8.34")
>>> print(res[1])
HTTP/1.1 200 OK
Date: Mon, 22 Jan 2018 12:48:39 GMT
Server: Apache/2.4.7 (Ubuntu)
X-Powered-By: PHP/5.5.9-1ubuntu4.22
Vary: Accept-Encoding
Content-Encoding: gzip
Content-Length: 241
Content-Type: text/html


>>> print(res[2])
============
Method: GET
============

--------------------------
Number of uploaded files: 0
    Number of GET params: 3
   Number of POST params: 0
--------------------------

===========
Debug info:
===========

-----------
POST DATA: 
-----------
Array
(
)
-----------
 GET DATA:  
-----------
Array
(
    [param1] => 12345
    [param2] => Hi_from_MicroPython
    [temper] => 8.34
)
-----------
FILE DATA: 
-----------
Array
(
)
-----------

=====================================
LoBo test server, 2018/01/22 13:48:39
=====================================

>>> 

curl.post(url, params)

Send POST request to http/https server.

url is the reference to the http resource. It must start with http:// or https://

params is dictionary containing the data to be posted to the server.
The dictionary values can be integers, floats, strings or file names.

>>> param = {'Name': 'Micro', 'temper': 12.34, 'code': 8367, 'file': 'boot.py'}
>>> res = curl.post("loboris.eu/ESP32/test.php", param)
>>> res[0]
0
>>> print(res[1])
HTTP/1.1 200 OK
Date: Mon, 22 Jan 2018 13:21:57 GMT
Server: Apache/2.4.7 (Ubuntu)
X-Powered-By: PHP/5.5.9-1ubuntu4.22
Vary: Accept-Encoding
Content-Encoding: gzip
Content-Length: 317
Content-Type: text/html


>>> print(res[2])
============
Method: POST
============

--------------------------
Number of uploaded files: 1
    Number of GET params: 0
   Number of POST params: 3
--------------------------

===========
Debug info:
===========

-----------
POST DATA: 
-----------
Array
(
    [code] => 8367
    [Name] => Micro
    [temper] => 12.340000
)
-----------
 GET DATA:  
-----------
Array
(
)
-----------
FILE DATA: 
-----------
Array
(
    [file] => Array
        (
            [name] => boot.py
            [type] => application/octet-stream
            [tmp_name] => /tmp/phpCxLKoj
            [error] => 0
            [size] => 113
        )

)
-----------

=====================================
LoBo test server, 2018/01/22 14:21:57
=====================================

>>> 

curl.ftp_list(url [, file])

List files on FTP server

url is the reference to the ftp resource. It must start with ftp://

file argument is optional, if not used, the list result will be saved into response buffer (and truncated to its size).
If used, the list will be saved to the file on MicroPython file system.
Special file name can be used: simulate. The list will be downloaded, but no actual saving to file will occur.

The method returns tuple of 3 items: (res_code, hdr, body)
On succes res_code will have the value 0, on fail the error code.

>>> res=curl.ftp_list('ftp://loboris.eu','esp32','esp32user')
>>> res[0]
0
>>> print(res[1])
220 LoBo FTP Server
500 AUTH not understood
500 AUTH not understood
331 Password required for esp32
230 Anonymous access granted, restrictions apply
257 "/" is the current directory
227 Entering Passive Mode (82,196,4,208,192,20).
200 Type set to A
150 Opening ASCII mode data connection for file list
226 Transfer complete
221 Goodbye.

>>> print(res[2])
-rw-r--r--   1 esp32    esp32group  2427146 May  1  2017 big.jpg
-rw-r--r--   1 esp32    esp32group  2427146 May  2  2017 bigimg.jpg
-rw-r--r--   1 esp32    esp32group    97543 Sep 26 17:59 bmp.bmp
-rw-r--r--   1 esp32    esp32group    23278 May 10  2017 door.php
-rw-r--r--   1 root     root          609 May  5  2017 ftptest.txt
-rw-r--r--   1 esp32    esp32group    97543 Sep 26 18:11 moujib.jpg
-rw-r--r--   1 esp32    esp32group    97543 Jan 13 22:57 put_test.jpg
-rw-r--r--   1 esp32    esp32group     4092 Jan  2 08:58 put_test.txt
-rw-r--r--   1 esp32    esp32group    97543 Sep 23 17:47 put_test1.jpg
-rw-r--r--   1 esp32    esp32group    97543 Sep 26 17:09 put_test2 .jpg
-rw-r--r--   1 esp32    esp32group    97543 Sep 25 10:13 put_test2.jpg
-rw-r--r--   1 esp32    esp32group    97543 Sep 26 17:13 put_test3.jpg
-rw-r--r--   1 esp32    esp32group    97543 Sep 26 17:20 put_test6.jpg
drwxr-xr-x   1 esp32    esp32group        0 Apr 26  2017 test
-rw-r--r--   1 esp32    esp32group      583 May  1  2017 test.txt
-rw-r--r--   1 esp32    esp32group   230456 Apr 30  2017 tiger.bmp
-rw-r--r--   1 esp32    esp32group    97543 Jan 30  2017 tiger240.jpg

>>> 

curl.ftp_get(url [, file])

Download the file from FTP server

url is the reference to the ftp resource. It must start with ftp://
The remote file name to download must be at the end of url.

file argument is optional, if not used, the file content will be saved into response buffer (and truncated to its size).
If used, the file will be saved to the file on MicroPython file system.
Special file name can be used: simulate. The file will be downloaded, but no actual saving to file will occur.

The method returns tuple of 3 items: (res_code, hdr, body)
On succes res_code will have the value 0, on fail the error code.

>>> res=curl.ftp_get('ftp://loboris.eu/ftptest.txt','esp32','esp32user')
>>> print(res[1])
220 LoBo FTP Server
500 AUTH not understood
500 AUTH not understood
331 Password required for esp32
230 Anonymous access granted, restrictions apply
257 "/" is the current directory
227 Entering Passive Mode (82,196,4,208,192,10).
200 Type set to I
213 609
150 Opening BINARY mode data connection for ftptest.txt (609 bytes)
226 Transfer complete
221 Goodbye.

>>> print(res[2])
=== Do you speak Latin ?
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Nam rhoncus odio id venenatis volutpat.
Vestibulum dapibus bibendum ullamcorper.
Maecenas finibus elit augue, vel condimentum odio maximus nec.
In hac habitasse platea dictumst.
Vestibulum vel dolor et turpis rutrum finibus ac at nulla.
Vivamus nec neque ac elit blandit pretium vitae maximus ipsum.
Quisque sodales magna vel erat auctor, sed pellentesque nisi rhoncus.
Donec vehicula maximus pretium.
Aliquam eu tincidunt lorem.
Ut placerat, sem eu pharetra mattis, ante lacus fringilla diam, a consequat quam eros eget erat.

>>> 
>>> 
>>> os.listdir()
['boot.py']
>>> res=curl.ftp_get('ftp://loboris.eu/ftptest.txt','esp32','esp32user', 'ftptest.txt')
>>> res[0]
0
>>> os.listdir()
['boot.py', 'ftptest.txt']
>>> 

curl.ftp_put(url, file)

Upload the file to FTP server

url is the reference to the ftp resource. It must start with ftp://
The remote file name must be at the end of url.

file argument is mandatory, the file file on MicroPython file system wil be uploaded to the server.
Special file name can be used: simulate in which case the simulated file upload will be performed.

The method returns tuple of 3 items: (res_code, hdr, body)
On succes res_code will have the value 0, on fail the error code.

>>> res=curl.ftp_list('ftp://loboris.eu/test/','esp32','esp32user')
>>> print(res[1])
220 LoBo FTP Server
500 AUTH not understood
500 AUTH not understood
331 Password required for esp32
230 Anonymous access granted, restrictions apply
257 "/" is the current directory
250 CWD command successful
227 Entering Passive Mode (82,196,4,208,192,19).
200 Type set to A
150 Opening ASCII mode data connection for file list
226 Transfer complete
221 Goodbye.

>>> print(res[2])

>>> res=curl.ftp_put('ftp://loboris.eu/test/uploaded_boot.py','esp32','esp32user', 'boot.py')
>>> print(res[1])
220 LoBo FTP Server
500 AUTH not understood
500 AUTH not understood
331 Password required for esp32
230 Anonymous access granted, restrictions apply
257 "/" is the current directory
250 CWD command successful
227 Entering Passive Mode (82,196,4,208,191,254).
200 Type set to I
150 Opening BINARY mode data connection for uploaded_boot.py
226 Transfer complete
221 Goodbye.

>>> print(res[2])
Uploaded file /_#!#_spiffs/boot.py, size=113
>>> res=curl.ftp_list('ftp://loboris.eu/test/','esp32','esp32user')
>>> print(res[2])
-rw-r--r--   1 esp32    esp32group      113 Jan 22 15:10 uploaded_boot.py

>>> 

curl.sendmail(user, password, to, subject, msg [, cc, attach, server, port, protocol])

Send the email.
Arguments cc, attach, server, port and protocol are optional. They are kw arguments and must be entered in arg=value format.

Arg Description
user user name to login to SMTP server
password user's password
to the recipient's email address.
String argument can be entered to send to the single recipient.
Tuple of strings can be entered to send to multiple recipients.
subject String argument, the email subject
msg String argument, the email body
cc Optional; the Cc (Carbon Copy) recipient's email address.
String argument can be entered to send to the single Cc recipient.
Tuple of strings can be entered to send to multiple Cc recipients.
bcc Optional; the Bcc (Blind Carbon Copy) recipient's email address.
String argument can be entered to send to the single Bcc recipient.
Tuple of strings can be entered to send to multiple Bcc recipients.
attach Optional; name(s) of the file(s) to be attached to the email.
String argument can be entered to attach single file.
Tuple of file names can be entered to attach multiple files (max 4).
server Optional; Default: smtp.gmail.com, SMTP server domain name or IP address.
port Optional; Default: 465, SMTP server port.
protocol Optional; Default: SMTPS, use secure or unsecure protocol
Constants curl.SMTP or curl.SMTPS can be used

Returns True on success, False on error.

>>> curl.options(verbose=True)
Curl options(
  Verbose: True, Progress: 0, Timeout: 60, Max fsize: 300000, Header len: 1024, Body len: 4096, Decode content: True
)
>>> curl.sendmail('myusername', 'mypassword', '[email protected]', 'Test email', 'Hi from MicriPython, boot.py attached', attach='boot.py')
* Rebuilt URL to: smtps://smtp.gmail.com:465/
* timeout on name lookup is not supported
*   Trying 108.177.15.108...
* TCP_NODELAY set
* Connected to smtp.gmail.com (108.177.15.108) port 465 (#0)
* Error reading ca cert file /certs/ca-certificates.crt - mbedTLS: (-0x3E00) PK - Read/write of file failed
* mbedTLS: Connecting to smtp.gmail.com:465
* mbedTLS: Set min SSL version to TLS 1.0
* mbedTLS: Handshake complete, cipher is TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256
* Dumping cert info:
* cert. version     : 3
* serial number     : 63:62:47:2E:54:18:FE:13
* issuer name       : C=US, O=Google Trust Services, CN=Google Internet Authority G3
* subject name      : C=US, ST=California, L=Mountain View, O=Google Inc, CN=smtp.gmail.com
* issued  on        : 2018-01-10 10:28:39
* expires on        : 2018-04-04 09:41:00
* signed using      : RSA with SHA-256
* RSA key size      : 2048 bits
* basic constraints : CA=false
* subject alt name  : smtp.gmail.com
* ext key usage     : TLS Web Server Authentication

* SSL connected
< 220 smtp.gmail.com ESMTP g64sm5972562wmf.20 - gsmtp
> EHLO localhost
< 250-smtp.gmail.com at your service, [94.253.205.23]
< 250-SIZE 35882577
< 250-8BITMIME
< 250-AUTH LOGIN PLAIN XOAUTH2 PLAIN-CLIENTTOKEN OAUTHBEARER XOAUTH
< 250-ENHANCEDSTATUSCODES
< 250-PIPELINING
< 250-CHUNKING
< 250 SMTPUTF8
> AUTH LOGIN
< 334 VXNlcm5hbWU6
> bG9ib3Jpc0BnbWFpbC5jb20=
< 334 UGFzc3dvcmQ6
> MTQxMkxvQm85NTYzMzAwMDk=
< 235 2.7.0 Accepted
> MAIL FROM:<loboris@gmail.com>
< 250 2.1.0 OK g64sm5972562wmf.20 - gsmtp
> RCPT TO:<loboris@gmail.com>
< 250 2.1.5 OK g64sm5972562wmf.20 - gsmtp
> DATA
< 354  Go ahead g64sm5972562wmf.20 - gsmtp
< 250 2.0.0 OK 1516632622 g64sm5972562wmf.20 - gsmtp
> QUIT
< 221 2.0.0 closing connection g64sm5972562wmf.20 - gsmtp
* Closing connection 0

True
>>> 

curl.getmail(options, user, password [, server, port, file])

Perform IMAP operation.
Raw response is returned, no parsing is done.
Arguments server, port, file are optional. They are kw arguments and must be entered in arg=value format.

Arg Description
options IMAP commands/options
user user name to login to IMAP server
password user's password
server Optional; Default: imap.gmail.com, IMAP server domain name or IP address.
port Optional; Default: 993, IMAP server port.
file Optional; Default: None, get IMAP response to file.

Returns 3-item tuple (result, header, response)

Top level list of folders:

>>> res = curl.getmail('','[email protected]','my_password')
=== URL=[imaps://imap.gmail.com:993/]
>>> print(res[2])
* LIST (\HasNoChildren) "/" "CIRUS"
* LIST (\HasNoChildren) "/" "Call log"
* LIST (\HasNoChildren) "/" "Fritz"
* LIST (\HasNoChildren) "/" "Harkom"
* LIST (\HasNoChildren) "/" "Hidroing"
* LIST (\HasNoChildren) "/" "Higra"
* LIST (\HasNoChildren) "/" "INBOX"
* LIST (\HasNoChildren) "/" "Info"
* LIST (\HasNoChildren) "/" "Jana"
* LIST (\HasNoChildren) "/" "Kupovina"
* LIST (\HasNoChildren) "/" "Luka"
* LIST (\HasNoChildren) "/" "Oblak"
* LIST (\HasNoChildren) "/" "Poslovno"
* LIST (\HasNoChildren) "/" "Programiranje"
* LIST (\HasNoChildren) "/" "SMS"
* LIST (\HasNoChildren) "/" "Sent"
* LIST (\HasNoChildren) "/" "Software"
* LIST (\HasNoChildren) "/" "Trash"
* LIST (\HasChildren \Noselect) "/" "[Gmail]"
* LIST (\HasNoChildren \Sent) "/" "[Gmail]/Poslana po&AWE-ta"
* LIST (\Flagged \HasNoChildren) "/" "[Gmail]/Sa zvjezdicom"
* LIST (\Drafts \HasNoChildren) "/" "[Gmail]/Skice"
* LIST (\All \HasNoChildren) "/" "[Gmail]/Sva po&AWE-ta"
* LIST (\HasNoChildren \Important) "/" "[Gmail]/Va&AX4-no"
* LIST (\HasNoChildren) "/" "&AX0-ibrat"

>>> 

Search messages containing 'test' in subject:

>>> res = curl.getmail('INBOX?SUBJECT test','[email protected]','mypassword')
=== URL=[imaps://imap.gmail.com:993/INBOX?SUBJECT%20test]
>>> print(res[2])
* SEARCH 21 99 303 1748 1761 2444 2445 2446 2450 2498 2816 2956 2957 3308 3309 3432 3433 3648 3700 3703 3775 3776 3777 3817 3845 3846 4751 4928 5820 5821 5822 8263 8264 8265 8353 9509 9520 9843 9868

>>> 

Get full message with UID 9863:

>>> res = curl.getmail('INBOX;UID=5820','[email protected]','mypassword')
=== URL=[imaps://imap.gmail.com:993/INBOX;UID=5820]
>>> print(res[2])
Return-Path: <[email protected]>
Received: from 37.244.129.249 ([37.244.129.249])
        by mx.google.com with ESMTPSA id pe8sm1375452wic.3.2014.10.16.02.52.28
        for <[email protected]>
        (version=TLSv1 cipher=RC4-SHA bits=128/128);
        Thu, 16 Oct 2014 02:52:31 -0700 (PDT)
Message-ID: <[email protected]>
MIME-Version: 1.0
Content-Type: text/plain;
	charset="ASCII"
Content-Transfer-Encoding: 7bit
Content-class: urn:content-classes:message
Subject: SIM900 Test
Date: Sat, 01 Jan 2000 23:22:23 +0000
X-MS-Has-Attach: 
X-MS-TNEF-Correlator: 
From: boris <[email protected]>
To: boris <[email protected]>

eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee

>>> 

Get message body of the message with UID 9863:

>>> res = curl.getmail('INBOX;UID=5820;SECTION=1','[email protected]','mypassword')
=== URL=[imaps://imap.gmail.com:993/INBOX;UID=5820;SECTION=1]
>>> print(res[2])
eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee

>>> 
>>> res = curl.getmail('INBOX;UID=5820;SECTION=TEXT','[email protected]','mypassword')
=== URL=[imaps://imap.gmail.com:993/INBOX;UID=5820;SECTION=TEXT]
>>> print(res[2])
eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee

>>> 

Get messages UIDs received since date:

>>> res = curl.getmail('INBOX?SINCE 31-aug-2018','[email protected]','mypassword')
=== URL=[imaps://imap.gmail.com:993/INBOX?SINCE%2031-aug-2018]
>>> print(res[2])
* SEARCH 11564 11565 11566 11567 11568 11569 11570 11571 11572 11573 11574 11575

>>> 

Get messages UIDs received before date:

>>> res = curl.getmail('INBOX?BEFORE 31-aug-2008','[email protected]','mypassword')
=== URL=[imaps://imap.gmail.com:993/INBOX?BEFORE%2031-aug-2008]
>>> print(res[2])
* SEARCH 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109

>>>