Arduino library for Quectel EC200U (CN-AA firmware) providing a robust AT-command wrapper and advanced examples for easier integration of cellular connectivity into your projects.
Repository: https://github.com/MISTERNEGATIVE21/QuectelEC200U
- Sharvi Electronics ESP32-S3 with EC200U: Buy Here
More information on Custom ESP32-S3 with EC200U: Sharvi Electronics ESP32-S3 with EC200U
- Capuf EC200U-CN Module: Buy Here
More information on Capuf Module: Capuf Module
- Core & State Management: Initialization, AT command interface, state tracking.
- Network: SIM/registration, PDP attach/activation, signal strength, operator info.
- TCP/IP: TCP sockets (QIOPEN/QISEND/QIRD).
- SSL/TLS: Secure sockets (QSSLCFG/QSSLOPEN), CA certificate management.
- HTTP/HTTPS: GET and POST requests.
- MQTT: Connect, publish, subscribe, disconnect (with TLS support).
- SMS: Send, read, delete, and count SMS messages.
- Voice Calls: Dial, answer, hang up, list calls, and manage caller ID.
- USSD: Send and receive USSD messages.
- GNSS: Start/stop, get location (NMEA or parsed), and configure GNSS.
- NTP & Time: Synchronize time with an NTP server, get/set the module's clock.
- Filesystem: List, upload, read, and delete files on the module's filesystem.
- TTS (Text-to-Speech): Play text as speech.
- FTP: Login, download files, and logout.
- Audio: Control speaker volume, microphone gain, sidetone, and audio routing.
- Power Management: Power save mode (PSM), power off, and reboot.
- Debugging: Debug output stream for easier troubleshooting.
- Download the latest release from the GitHub repository.
- In the Arduino IDE, go to
Sketch > Include Library > Add .ZIP Library...and select the downloaded file. - The library will be available in
Sketch > Include Library > QuectelEC200U.
Here is a simple example of how to initialize the modem, connect to the network, and make an HTTP GET request.
#include <QuectelEC200U.h>
// Define pins for your board
#define EC200U_RX_PIN 16
#define EC200U_TX_PIN 17
#if defined(ARDUINO_ARCH_ESP32)
HardwareSerial SerialAT(1);
QuectelEC200U modem(SerialAT, 115200, EC200U_RX_PIN, EC200U_TX_PIN);
#elif defined(ARDUINO_ARCH_ZEPHYR)
HardwareSerial& SerialAT = Serial1;
QuectelEC200U modem(SerialAT, 115200, EC200U_RX_PIN, EC200U_TX_PIN);
#else
#include <SoftwareSerial.h>
SoftwareSerial SerialAT(7, 8); // RX, TX
QuectelEC200U modem(SerialAT);
#endif
void setup() {
Serial.begin(115200);
#if defined(ARDUINO_ARCH_ZEPHYR)
SerialAT.begin(115200);
#elif !defined(ARDUINO_ARCH_ESP32)
SerialAT.begin(9600); // SoftwareSerial default
#endif
Serial.println("Initializing modem...");
if (modem.begin()) {
Serial.println("Modem initialized.");
} else {
Serial.print("Failed to initialize modem. Error: ");
Serial.println(modem.getLastErrorString());
while (1);
}
Serial.println("Waiting for network...");
if (modem.waitForNetwork()) {
Serial.println("Network connected.");
} else {
Serial.print("Failed to connect to network. Error: ");
Serial.println(modem.getLastErrorString());
while (1);
}
Serial.println("Attaching to data network...");
modem.attachData("your.apn"); // Replace with your APN
String response;
Serial.println("Performing HTTP GET...");
if (modem.httpGet("http://example.com", response)) {
Serial.println("Response:");
Serial.println(response);
} else {
Serial.print("HTTP GET failed. Error: ");
Serial.println(modem.getLastErrorString());
}
}
void loop() {
// Your code here
}Most ESP32 examples share the same wiring so you can copy/paste between sketches:
| Signal | ESP32 Pin | Description |
|---|---|---|
EC200U_RX_PIN |
16 | Connects to the modem TX (ESP32 receives data) |
EC200U_TX_PIN |
17 | Connects to the modem RX (ESP32 transmits data) |
EC200U_PWRKEY_PIN |
10 | Drive LOW for ~2 s to toggle modem power |
EC200U_STATUS_PIN |
2 | Optional status feedback (HIGH when modem is on) |
Update the macros at the top of each sketch if your carrier board routes the modem elsewhere. Non‑ESP32 boards still use the same macro names so the documentation stays consistent.
For users in India, you may need to set the APN (Access Point Name) for your mobile carrier. Here is a list of common APNs:
- Jio:
jionet - Airtel:
airtelgprs.com - Vodafone Idea (Vi):
www - BSNL:
bsnlnet
You can use the getOperator() function to identify the network and then set the APN accordingly. For a detailed example, see examples/Indian_APN_Demo/Indian_APN_Demo.ino.
This library can be used with the PPPOSClient library to establish a PPP connection with the EC200U modem. This allows you to use standard networking libraries like WiFiClient and HTTPClient over the cellular connection.
For a detailed example, see examples/PPPOS_Demo/PPPOS_Demo.ino.
For raw sockets (e.g. pushing bytes to a custom server), the pattern is the same: bring up data, open a socket with tcpOpen, send with tcpSend, and read with tcpRecv. The new examples/TCP_Client_Quickstart/TCP_Client_Quickstart.ino sketch contains a full walk-through; the core loop looks like this:
const char HOST[] = "postman-echo.com";
int socketId = modem.tcpOpen(HOST, 80, 1, 0);
if (socketId >= 0) {
modem.tcpSend(socketId, "GET /get HTTP/1.1\r\nHost: postman-echo.com\r\n\r\n");
String response;
if (modem.tcpRecv(socketId, response, 1024, 8000)) {
Serial.println(response);
}
modem.tcpClose(socketId);
}To talk to HTTPS endpoints you must provision a CA certificate once, configure an SSL context, and then call httpsGet/httpsPost. See examples/HTTPS_Client_Quickstart/HTTPS_Client_Quickstart.ino for a ready-to-run sketch. The critical steps are:
modem.sslUploadCert(cloudflare_ca_cert, "cloudflare.pem");
modem.sslConfigure(1, "cloudflare.pem");
String response;
if (modem.httpsGet("https://www.cloudflare.com/", response)) {
Serial.println(response);
} else {
Serial.println(modem.getLastErrorString());
}Under the examples/experimental/ folder, you will find more complex demos that rely on third-party integrations or external libraries:
Uploads JSON telemetry data over a secure socket. It loads the Consentium IoT TLS cert, configures SSL (sslConfigure), and posts metrics to https://api.consentiumiot.com. It can optionally set a receiveKey to fetch recent updates immediately after sending.
Demonstrates using the new QuectelTelegramBot helper class to natively interact with the Telegram API. Instead of relying on unwieldy external Wi-Fi libraries or PPPoS, this lightweight class hooks directly into the modem's built-in httpsGet and httpsPost commands. It easily processes incoming JSON updates and handles sending messages effortlessly.
The WebUI Hotspot example has grown into a full control panel with REST endpoints you can also script against:
| Endpoint | Purpose |
|---|---|
GET /api/status |
Adds RSRP/RAT details, APN origin, and MQTT summary fields. |
GET /api/device/sensors |
Battery status (+CBC percent/voltage) plus on-board ADC sample. |
GET/POST /api/pdp/* |
Inspect PDP selection, activate/deactivate a context, or clear a saved APN. |
GET/POST /api/mqtt/* |
Track broker state, connect with APN overrides, publish payloads, and subscribe to topics. |
GET /api/call/status, POST /api/call/answer, POST /api/call/volume |
Surface active calls, answer incoming rings, and bump speaker volume from the UI. |
The corresponding frontend now shows a Power & Sensors card, PDP controls, MQTT client section, and a richer Phone tab (answer button, live log, and speaker volume slider). These APIs are ideal for integrating the modem with external dashboards without touching the AT layer.
begin(bool forceReinit = false): Initializes the modem.sendAT(const String &cmd, const String &expect = "OK", uint32_t timeout = 3000): Sends an AT command.readResponse(char* buffer, size_t length, uint32_t timeout): Reads the response from the modem into the provided buffer.getIMEI(): Gets the modem's IMEI.getModemInfo(): Gets information about the modem.factoryReset(): Resets the modem to factory defaults.powerOff(): Powers off the modem.reboot(): Reboots the modem.
getLastError(): Returns the last error code as anErrorCodeenum.getLastErrorString(): Returns a string description of the last error.
getState(): Returns the current modem state (ModemStateenum).isInitialized(): Returnstrueif the modem is initialized.isNetworkReady(): Returnstrueif the modem is registered on the network.setState(ModemState state): Sets the modem state.
enableDebug(Stream &debugStream): Enables debug output to the specified stream.
waitForNetwork(uint32_t timeoutMs = 60000): Waits for the modem to register on the network.attachData(const String &apn, const String &user = "", const String &pass = "", int auth = 0): Attaches to the data network.activatePDP(int ctxId = 1): Activates the Packet Data Protocol context.deactivatePDP(int ctxId = 1): Deactivates the PDP context.getRegistrationStatus(bool eps = true): Gets the network registration status.isSimReady(): Returnstrueif the SIM card is ready.getOperator(): Gets the name of the network operator.getSignalStrength(): Gets the signal strength (RSSI).setAPN(const String &apn): Sets the Access Point Name (APN).
httpGet(const String &url, String &response): Performs an HTTP GET request.httpPost(const String &url, const String &data, String &response): Performs an HTTP POST request.httpsGet(const String &url, String &response): Performs an HTTPS GET request. Note: You must callsslConfigure()before using this function.httpsPost(const String &url, const String &data, String &response): Performs an HTTPS POST request. Note: You must callsslConfigure()before using this function.
mqttConnect(const String &server, int port): Connects to an MQTT broker.mqttPublish(const String &topic, const String &message): Publishes a message to an MQTT topic.mqttSubscribe(const String &topic): Subscribes to an MQTT topic.mqttDisconnect(): Disconnects from the MQTT broker.
tcpOpen(const String &host, int port, int ctxId = 1, int socketId = 0): Opens a TCP socket.tcpSend(int socketId, const String &data): Sends data over a TCP socket.tcpRecv(int socketId, String &out, size_t bytes = 512, uint32_t timeout = 5000): Receives data from a TCP socket.tcpClose(int socketId): Closes a TCP socket.
sendUSSD(const String &code, String &response): Sends a USSD code.
ntpSync(const String &server = "pool.ntp.org", int timezone = 0): Synchronizes the time with an NTP server.getClock(): Gets the current time from the modem.setClock(const String &datetime): Sets the time on the modem.
startGNSS(): Starts the GNSS receiver.stopGNSS(): Stops the GNSS receiver.isGNSSOn(): Returnstrueif the GNSS receiver is on.setGNSSConfig(const String &item, const String &value): Configures a GNSS parameter.getNMEASentence(const String &type = "RMC"): Gets a raw NMEA sentence.getGNSSLocation(): Gets the parsed GNSS location.getGNSSLocation(uint32_t fixWaitMs): Gets the parsed GNSS location, waiting for a fix.
playTTS(const String &text): Plays the given text as speech.
ftpLogin(const String &server, const String &user, const String &pass): Logs in to an FTP server.ftpDownload(const String &filename, String &data): Downloads a file from the FTP server.ftpLogout(): Logs out from the FTP server.
fsList(String &out): Lists the files on the modem's filesystem.fsUpload(const String &path, const String &content): Uploads content to a file.fsRead(const String &path, String &out, size_t length = 0): Reads a file.fsDelete(const String &path): Deletes a file.fsExists(const String &path): Checks if a file exists.
sslConfigure(int ctxId, const String &caPath, bool verify = true): Configures SSL/TLS for a context.
enablePSM(bool enable): Enables or disables Power Save Mode (PSM).
setSpeakerVolume(int level): Sets the speaker volume.setRingerVolume(int level): Sets the ringer volume.setMicMute(bool mute): Mutes or unmutes the microphone.setMicGain(int channel, int level): Sets the microphone gain.setSidetone(bool enable, int level): Enables or disables sidetone.setAudioChannel(int channel): Sets the audio channel.setAudioInterface(const String ¶ms): Configures the audio interface.audioLoopback(bool enable): Enables or disables audio loopback.
The library provides two constructors to accommodate different hardware setups:
For boards like ESP32, you can use a HardwareSerial port. You can also specify the RX and TX pins.
#include <QuectelEC200U.h>
HardwareSerial& SerialAT = Serial1;
QuectelEC200U modem(SerialAT, 115200, /* RX */ 16, /* TX */ 17);For other boards or configurations (e.g., SoftwareSerial), you can use any Stream object.
#include <SoftwareSerial.h>
#include <QuectelEC200U.h>
SoftwareSerial SerialAT(7, 8); // RX, TX
QuectelEC200U modem(SerialAT);The library uses a state machine to track the modem's status. You can get the current state using modem.getState(). The possible states are:
MODEM_UNINITIALIZED: The modem has not been initialized.MODEM_INITIALIZING: The modem is currently initializing.MODEM_READY: The modem is initialized and ready to receive commands.MODEM_ERROR: An error occurred during initialization. UsegetLastError()orgetLastErrorString()to get more information.MODEM_NETWORK_CONNECTED: The modem is registered on the network.MODEM_DATA_READY: The modem has an active data connection.
You can enable debug messages to a Stream object (e.g., Serial) to get more insight into the library's operation.
void setup() {
Serial.begin(115200);
modem.enableDebug(Serial);
// ...
}Contributions are welcome! Please open an issue or submit a pull request on the GitHub repository.
MisterNegative21 misternegative21@gmail.com
This library is released under the MIT License. See the LICENSE file for details.
Quectel, EC200U, and related marks are trademarks or registered trademarks of Quectel Wireless Solutions Co., Ltd. This library is unofficial and not affiliated with Quectel.
- GPS Optimization: Added
GNSSDatastruct and robustgetGNSSDatamethod to parse NMEA sentences directly into simple properties. - WebUI Hotspot Refactor: Improved
WebUI_Hotspot.inoto use struct-based GPS parsing, added automatic data connectivity on startup with stored APNs. - Example Cleanup: Removed redundant legacy examples to reduce clutter, favoring unified examples (like
HTTP_HTTPS_Unified_Demo).
- New Platform Support: Added support for Arduino Q Uno (Zephyr-based) using
ARDUINO_ARCH_ZEPHYR. - Optimization: Converted library to use
const char*for string parameters, significantly reducing memory usage and overhead. - Compatibility: Added
Stringoverloads to maintain backward compatibility and fixF()macro usage issues. - Examples: Updated all 35+ examples to support ESP32, Zephyr, and SoftwareSerial platforms automatically.
- Fixes: Resolved duplicate code blocks in advanced examples.
- Initial major release with advanced features (SSL, MQTT, GNSS, etc.).


