Skip to content

Add support for PPP Modems to Arduino #9518

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Apr 19, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -95,6 +95,7 @@ set(ARDUINO_ALL_LIBRARIES
LittleFS
NetBIOS
Network
PPP
Preferences
RainMaker
SD_MMC
@@ -157,6 +158,10 @@ set(ARDUINO_LIBRARY_LittleFS_SRCS libraries/LittleFS/src/LittleFS.cpp)

set(ARDUINO_LIBRARY_NetBIOS_SRCS libraries/NetBIOS/src/NetBIOS.cpp)

set(ARDUINO_LIBRARY_PPP_SRCS
libraries/PPP/src/PPP.cpp
libraries/PPP/src/ppp.c)

set(ARDUINO_LIBRARY_Preferences_SRCS libraries/Preferences/src/Preferences.cpp)

set(ARDUINO_LIBRARY_RainMaker_SRCS
10 changes: 10 additions & 0 deletions Kconfig.projbuild
Original file line number Diff line number Diff line change
@@ -321,6 +321,16 @@ config ARDUINO_SELECTIVE_Networking
depends on ARDUINO_SELECTIVE_COMPILATION
default y

config ARDUINO_SELECTIVE_Ethernet
bool "Enable Ethernet"
depends on ARDUINO_SELECTIVE_COMPILATION
default y

config ARDUINO_SELECTIVE_PPP
bool "Enable PPP"
depends on ARDUINO_SELECTIVE_COMPILATION
default y

config ARDUINO_SELECTIVE_ArduinoOTA
bool "Enable ArduinoOTA"
depends on ARDUINO_SELECTIVE_COMPILATION && ARDUINO_SELECTIVE_Networking
6 changes: 6 additions & 0 deletions cores/esp32/esp32-hal-periman.c
Original file line number Diff line number Diff line change
@@ -104,6 +104,12 @@ const char* perimanGetTypeName(peripheral_bus_type_t type) {
case ESP32_BUS_TYPE_ETHERNET_MCD: return "ETHERNET_MCD";
case ESP32_BUS_TYPE_ETHERNET_MDIO: return "ETHERNET_MDIO";
case ESP32_BUS_TYPE_ETHERNET_PWR: return "ETHERNET_PWR";
#endif
#if CONFIG_LWIP_PPP_SUPPORT
case ESP32_BUS_TYPE_PPP_TX: return "PPP_MODEM_TX";
case ESP32_BUS_TYPE_PPP_RX: return "PPP_MODEM_RX";
case ESP32_BUS_TYPE_PPP_RTS: return "PPP_MODEM_RTS";
case ESP32_BUS_TYPE_PPP_CTS: return "PPP_MODEM_CTS";
#endif
default: return "UNKNOWN";
}
6 changes: 6 additions & 0 deletions cores/esp32/esp32-hal-periman.h
Original file line number Diff line number Diff line change
@@ -102,6 +102,12 @@ extern "C" {
ESP32_BUS_TYPE_ETHERNET_MCD, // IO is used as ETHERNET MCD pin
ESP32_BUS_TYPE_ETHERNET_MDIO, // IO is used as ETHERNET MDIO pin
ESP32_BUS_TYPE_ETHERNET_PWR, // IO is used as ETHERNET PWR pin
#endif
#if CONFIG_LWIP_PPP_SUPPORT
ESP32_BUS_TYPE_PPP_TX, // IO is used as PPP Modem TX pin
ESP32_BUS_TYPE_PPP_RX, // IO is used as PPP Modem RX pin
ESP32_BUS_TYPE_PPP_RTS, // IO is used as PPP Modem RTS pin
ESP32_BUS_TYPE_PPP_CTS, // IO is used as PPP Modem CTS pin
#endif
ESP32_BUS_TYPE_MAX
} peripheral_bus_type_t;
1 change: 1 addition & 0 deletions idf_component.yml
Original file line number Diff line number Diff line change
@@ -45,6 +45,7 @@ dependencies:
idf: ">=5.1"
# mdns 1.2.1 is necessary to build H2 with no WiFi
mdns: "^1.2.3"
espressif/esp_modem: "^1.1.0"
chmorgan/esp-libhelix-mp3:
version: "1.0.3"
require: public
18 changes: 8 additions & 10 deletions libraries/Network/src/NetworkEvents.cpp
Original file line number Diff line number Diff line change
@@ -319,16 +319,14 @@ const char *NetworkEvents::eventName(arduino_event_id_t id) {
case ARDUINO_EVENT_ETH_DISCONNECTED: return "ETH_DISCONNECTED";
case ARDUINO_EVENT_ETH_GOT_IP: return "ETH_GOT_IP";
case ARDUINO_EVENT_ETH_LOST_IP: return "ETH_LOST_IP";
case ARDUINO_EVENT_ETH_GOT_IP6:
return "ETH_GOT_IP6";

// case ARDUINO_EVENT_PPP_START: return "PPP_START";
// case ARDUINO_EVENT_PPP_STOP: return "PPP_STOP";
// case ARDUINO_EVENT_PPP_CONNECTED: return "PPP_CONNECTED";
// case ARDUINO_EVENT_PPP_DISCONNECTED: return "PPP_DISCONNECTED";
// case ARDUINO_EVENT_PPP_GOT_IP: return "PPP_GOT_IP";
// case ARDUINO_EVENT_PPP_LOST_IP: return "PPP_LOST_IP";
// case ARDUINO_EVENT_PPP_GOT_IP6: return "PPP_GOT_IP6";
case ARDUINO_EVENT_ETH_GOT_IP6: return "ETH_GOT_IP6";
case ARDUINO_EVENT_PPP_START: return "PPP_START";
case ARDUINO_EVENT_PPP_STOP: return "PPP_STOP";
case ARDUINO_EVENT_PPP_CONNECTED: return "PPP_CONNECTED";
case ARDUINO_EVENT_PPP_DISCONNECTED: return "PPP_DISCONNECTED";
case ARDUINO_EVENT_PPP_GOT_IP: return "PPP_GOT_IP";
case ARDUINO_EVENT_PPP_LOST_IP: return "PPP_LOST_IP";
case ARDUINO_EVENT_PPP_GOT_IP6: return "PPP_GOT_IP6";
#if SOC_WIFI_SUPPORTED
case ARDUINO_EVENT_WIFI_OFF: return "WIFI_OFF";
case ARDUINO_EVENT_WIFI_READY: return "WIFI_READY";
15 changes: 8 additions & 7 deletions libraries/Network/src/NetworkEvents.h
Original file line number Diff line number Diff line change
@@ -78,13 +78,13 @@ typedef enum {
ARDUINO_EVENT_PROV_CRED_FAIL,
ARDUINO_EVENT_PROV_CRED_SUCCESS,
#endif
// ARDUINO_EVENT_PPP_START,
// ARDUINO_EVENT_PPP_STOP,
// ARDUINO_EVENT_PPP_CONNECTED,
// ARDUINO_EVENT_PPP_DISCONNECTED,
// ARDUINO_EVENT_PPP_GOT_IP,
// ARDUINO_EVENT_PPP_LOST_IP,
// ARDUINO_EVENT_PPP_GOT_IP6,
ARDUINO_EVENT_PPP_START,
ARDUINO_EVENT_PPP_STOP,
ARDUINO_EVENT_PPP_CONNECTED,
ARDUINO_EVENT_PPP_DISCONNECTED,
ARDUINO_EVENT_PPP_GOT_IP,
ARDUINO_EVENT_PPP_LOST_IP,
ARDUINO_EVENT_PPP_GOT_IP6,
ARDUINO_EVENT_MAX
} arduino_event_id_t;

@@ -146,6 +146,7 @@ class NetworkEvents {

friend class ESP_NetworkInterface;
friend class ETHClass;
friend class PPPClass;
#if SOC_WIFI_SUPPORTED
friend class STAClass;
friend class APClass;
42 changes: 19 additions & 23 deletions libraries/Network/src/NetworkInterface.cpp
Original file line number Diff line number Diff line change
@@ -71,12 +71,11 @@ void NetworkInterface::_onIpEvent(int32_t event_id, void* event_data) {
arduino_event.event_id = ARDUINO_EVENT_WIFI_STA_GOT_IP;
} else
#endif
// if(_interface_id == ESP_NETIF_ID_PPP){
// arduino_event.event_id = ARDUINO_EVENT_PPP_GOT_IP;
// } else
if (_interface_id >= ESP_NETIF_ID_ETH && _interface_id < ESP_NETIF_ID_MAX) {
arduino_event.event_id = ARDUINO_EVENT_ETH_GOT_IP;
}
if (_interface_id == ESP_NETIF_ID_PPP) {
arduino_event.event_id = ARDUINO_EVENT_PPP_GOT_IP;
} else if (_interface_id >= ESP_NETIF_ID_ETH && _interface_id < ESP_NETIF_ID_MAX) {
arduino_event.event_id = ARDUINO_EVENT_ETH_GOT_IP;
}
} else if (event_id == _lost_ip_event_id) {
clearStatusBits(ESP_NETIF_HAS_IP_BIT);
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_VERBOSE
@@ -87,12 +86,11 @@ void NetworkInterface::_onIpEvent(int32_t event_id, void* event_data) {
arduino_event.event_id = ARDUINO_EVENT_WIFI_STA_LOST_IP;
} else
#endif
// if(_interface_id == ESP_NETIF_ID_PPP){
// arduino_event.event_id = ARDUINO_EVENT_PPP_LOST_IP;
// } else
if (_interface_id >= ESP_NETIF_ID_ETH && _interface_id < ESP_NETIF_ID_MAX) {
arduino_event.event_id = ARDUINO_EVENT_ETH_LOST_IP;
}
if (_interface_id == ESP_NETIF_ID_PPP) {
arduino_event.event_id = ARDUINO_EVENT_PPP_LOST_IP;
} else if (_interface_id >= ESP_NETIF_ID_ETH && _interface_id < ESP_NETIF_ID_MAX) {
arduino_event.event_id = ARDUINO_EVENT_ETH_LOST_IP;
}
} else if (event_id == IP_EVENT_GOT_IP6) {
ip_event_got_ip6_t* event = (ip_event_got_ip6_t*)event_data;
esp_ip6_addr_type_t addr_type = esp_netif_ip6_get_addr_type(&event->ip6_info.ip);
@@ -117,12 +115,11 @@ void NetworkInterface::_onIpEvent(int32_t event_id, void* event_data) {
arduino_event.event_id = ARDUINO_EVENT_WIFI_AP_GOT_IP6;
} else
#endif
// if(_interface_id == ESP_NETIF_ID_PPP){
// arduino_event.event_id = ARDUINO_EVENT_PPP_GOT_IP6;
// } else
if (_interface_id >= ESP_NETIF_ID_ETH && _interface_id < ESP_NETIF_ID_MAX) {
arduino_event.event_id = ARDUINO_EVENT_ETH_GOT_IP6;
}
if (_interface_id == ESP_NETIF_ID_PPP) {
arduino_event.event_id = ARDUINO_EVENT_PPP_GOT_IP6;
} else if (_interface_id >= ESP_NETIF_ID_ETH && _interface_id < ESP_NETIF_ID_MAX) {
arduino_event.event_id = ARDUINO_EVENT_ETH_GOT_IP6;
}
#if SOC_WIFI_SUPPORTED
} else if (event_id == IP_EVENT_AP_STAIPASSIGNED && _interface_id == ESP_NETIF_ID_AP) {
setStatusBits(ESP_NETIF_HAS_IP_BIT);
@@ -536,7 +533,7 @@ String NetworkInterface::impl_name(void) const {
char netif_name[8];
esp_err_t err = esp_netif_get_netif_impl_name(_esp_netif, netif_name);
if (err != ESP_OK) {
log_e("Failed to get netif impl_name: %d", err);
log_e("Failed to get netif impl_name: 0x%04x %s", err, esp_err_to_name(err));
return String("");
}
return String(netif_name);
@@ -562,7 +559,7 @@ bool NetworkInterface::setDefault() {
}
esp_err_t err = esp_netif_set_default_netif(_esp_netif);
if (err != ESP_OK) {
log_e("Failed to set default netif: %d", err);
log_e("Failed to set default netif: 0x%04x %s", err, esp_err_to_name(err));
return false;
}
return true;
@@ -576,15 +573,14 @@ bool NetworkInterface::isDefault() const {
}

uint8_t* NetworkInterface::macAddress(uint8_t* mac) const {
if (!mac || _esp_netif == NULL) {
if (!mac || _esp_netif == NULL || _interface_id == ESP_NETIF_ID_PPP) {
return NULL;
}
esp_err_t err = esp_netif_get_mac(_esp_netif, mac);
if (err != ESP_OK) {
log_e("Failed to get netif mac: %d", err);
log_e("Failed to get netif mac: 0x%04x %s", err, esp_err_to_name(err));
return NULL;
}
// getMac(mac);
return mac;
}

141 changes: 141 additions & 0 deletions libraries/PPP/examples/PPP_Basic/PPP_Basic.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
#include <PPP.h>

#define PPP_MODEM_APN "internet"
#define PPP_MODEM_PIN "0000" // or NULL

// WaveShare SIM7600 HW Flow Control
#define PPP_MODEM_RST 25
#define PPP_MODEM_RST_LOW false //active HIGH
#define PPP_MODEM_TX 21
#define PPP_MODEM_RX 22
#define PPP_MODEM_RTS 26
#define PPP_MODEM_CTS 27
#define PPP_MODEM_FC ESP_MODEM_FLOW_CONTROL_HW
#define PPP_MODEM_MODEL PPP_MODEM_SIM7600

// SIM800 basic module with just TX,RX and RST
// #define PPP_MODEM_RST 0
// #define PPP_MODEM_RST_LOW true //active LOW
// #define PPP_MODEM_TX 2
// #define PPP_MODEM_RX 19
// #define PPP_MODEM_RTS -1
// #define PPP_MODEM_CTS -1
// #define PPP_MODEM_FC ESP_MODEM_FLOW_CONTROL_NONE
// #define PPP_MODEM_MODEL PPP_MODEM_SIM800

void onEvent(arduino_event_id_t event, arduino_event_info_t info) {
switch (event) {
case ARDUINO_EVENT_PPP_START:
Serial.println("PPP Started");
break;
case ARDUINO_EVENT_PPP_CONNECTED:
Serial.println("PPP Connected");
break;
case ARDUINO_EVENT_PPP_GOT_IP:
Serial.println("PPP Got IP");
break;
case ARDUINO_EVENT_PPP_LOST_IP:
Serial.println("PPP Lost IP");
break;
case ARDUINO_EVENT_PPP_DISCONNECTED:
Serial.println("PPP Disconnected");
break;
case ARDUINO_EVENT_PPP_STOP:
Serial.println("PPP Stopped");
break;
default:
break;
}
}

void testClient(const char* host, uint16_t port) {
NetworkClient client;
if (!client.connect(host, port)) {
Serial.println("Connection Failed");
return;
}
client.printf("GET / HTTP/1.1\r\nHost: %s\r\n\r\n", host);
while (client.connected() && !client.available())
;
while (client.available()) {
client.read(); //Serial.write(client.read());
}

Serial.println("Connection Success");
client.stop();
}

void setup() {
Serial.begin(115200);

// Listen for modem events
Network.onEvent(onEvent);

// Configure the modem
PPP.setApn(PPP_MODEM_APN);
PPP.setPin(PPP_MODEM_PIN);
PPP.setResetPin(PPP_MODEM_RST, PPP_MODEM_RST_LOW);
PPP.setPins(PPP_MODEM_TX, PPP_MODEM_RX, PPP_MODEM_RTS, PPP_MODEM_CTS, PPP_MODEM_FC);

Serial.println("Starting the modem. It might take a while!");
PPP.begin(PPP_MODEM_MODEL);

Serial.print("Manufacturer: ");
Serial.println(PPP.cmd("AT+CGMI", 10000));
Serial.print("Model: ");
Serial.println(PPP.moduleName());
Serial.print("IMEI: ");
Serial.println(PPP.IMEI());

bool attached = PPP.attached();
if (!attached) {
int i = 0;
unsigned int s = millis();
Serial.print("Waiting to connect to network");
while (!attached && ((++i) < 600)) {
Serial.print(".");
delay(100);
attached = PPP.attached();
}
Serial.print((millis() - s) / 1000.0, 1);
Serial.println("s");
attached = PPP.attached();
}

Serial.print("Attached: ");
Serial.println(attached);
Serial.print("State: ");
Serial.println(PPP.radioState());
if (attached) {
Serial.print("Operator: ");
Serial.println(PPP.operatorName());
Serial.print("IMSI: ");
Serial.println(PPP.IMSI());
Serial.print("RSSI: ");
Serial.println(PPP.RSSI());
int ber = PPP.BER();
if (ber > 0) {
Serial.print("BER: ");
Serial.println(ber);
Serial.print("NetMode: ");
Serial.println(PPP.networkMode());
}

Serial.println("Switching to data mode...");
PPP.mode(ESP_MODEM_MODE_CMUX); // Data and Command mixed mode
if (!PPP.waitStatusBits(ESP_NETIF_CONNECTED_BIT, 1000)) {
Serial.println("Failed to connect to internet!");
} else {
Serial.println("Connected to internet!");
}
} else {
Serial.println("Failed to connect to network!");
}
}

void loop() {
if (PPP.connected()) {
testClient("google.com", 80);
}
delay(20000);
}
9 changes: 9 additions & 0 deletions libraries/PPP/library.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
name=PPP
version=1.0.0
author=Hristo Gochkov
maintainer=Hristo Gochkov <hristo@espressif.com>
sentence=Enables network connection using GSM Modem.
paragraph=With this library you can instantiate Servers, Clients and send/receive UDP packets through GSM Modem.
category=Communication
url=
architectures=esp32
792 changes: 792 additions & 0 deletions libraries/PPP/src/PPP.cpp

Large diffs are not rendered by default.

109 changes: 109 additions & 0 deletions libraries/PPP/src/PPP.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
#pragma once

#include "sdkconfig.h"
#if CONFIG_LWIP_PPP_SUPPORT
#include "Network.h"
#include "esp_modem_c_api_types.h"

typedef enum {
PPP_MODEM_GENERIC = ESP_MODEM_DCE_GENETIC,
PPP_MODEM_SIM7600 = ESP_MODEM_DCE_SIM7600,
PPP_MODEM_SIM7070 = ESP_MODEM_DCE_SIM7070,
PPP_MODEM_SIM7000 = ESP_MODEM_DCE_SIM7000,
PPP_MODEM_BG96 = ESP_MODEM_DCE_BG96,
PPP_MODEM_SIM800 = ESP_MODEM_DCE_SIM800,
#if CONFIG_ESP_MODEM_ADD_CUSTOM_MODULE
PPP_MODEM_CUSTOM = ESP_MODEM_DCE_CUSTOM,
#endif
PPP_MODEM_MAX
} ppp_modem_model_t;

class PPPClass : public NetworkInterface {
public:
PPPClass();
~PPPClass();

bool begin(ppp_modem_model_t model, uint8_t uart_num = 1, int baud_rate = 115200);
void end();

// Required for connecting to internet
bool setApn(const char* apn);

// Required only if the SIM card is protected by PIN
bool setPin(const char* pin);

// If the modem supports hardware flow control, it's best to use it
bool setPins(int8_t tx, int8_t rx, int8_t rts = -1, int8_t cts = -1, esp_modem_flow_ctrl_t flow_ctrl = ESP_MODEM_FLOW_CONTROL_NONE);

// Using the reset pin of the module ensures that proper communication can be achieved
void setResetPin(int8_t rst, bool active_low = true);

// Modem DCE APIs
int RSSI() const;
int BER() const;
String IMSI() const;
String IMEI() const;
String moduleName() const; // modem module name
String operatorName() const; // network operator name
int networkMode() const; // network type (GSM, LTE, etc.)
int radioState() const; // 0:minimal, 1:full
bool attached() const; // true is attached to network
bool sync() const; // true if responds to 'AT'

// Switch the communication mode
bool mode(esp_modem_dce_mode_t m);
esp_modem_dce_mode_t mode() const {
return _mode;
}

// Change temporary the baud rate of communication
bool setBaudrate(int baudrate);

// Sens SMS message to a number
bool sms(const char* num, const char* message);
bool sms(String num, String message) {
return sms(num.c_str(), message.c_str());
}

// Send AT command with timeout in milliseconds
String cmd(const char* at_command, int timeout);
String cmd(String at_command, int timeout) {
return cmd(at_command.c_str(), timeout);
}

// untested
bool powerDown();
bool reset();
bool storeProfile();

esp_modem_dce_t* handle() const;

protected:
size_t printDriverInfo(Print& out) const;

public:
void _onPppEvent(int32_t event_id, void* event_data);
void _onPppArduinoEvent(arduino_event_id_t event, arduino_event_info_t info);

private:
esp_modem_dce_t* _dce;
int8_t _pin_tx;
int8_t _pin_rx;
int8_t _pin_rts;
int8_t _pin_cts;
esp_modem_flow_ctrl_t _flow_ctrl;
int8_t _pin_rst;
bool _pin_rst_act_low;
const char* _pin;
const char* _apn;
int _rx_buffer_size;
int _tx_buffer_size;
esp_modem_dce_mode_t _mode;
uint8_t _uart_num;

static bool pppDetachBus(void* bus_pointer);
};

extern PPPClass PPP;

#endif /* CONFIG_LWIP_PPP_SUPPORT */
28 changes: 28 additions & 0 deletions libraries/PPP/src/ppp.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#include "sdkconfig.h"
#if CONFIG_LWIP_PPP_SUPPORT
#include "esp_modem_api.h"

esp_err_t _esp_modem_at(esp_modem_dce_t *dce_wrap, const char *at, char *p_out, int timeout) {
return esp_modem_at(dce_wrap, at, p_out, timeout);
}

esp_err_t _esp_modem_send_sms(esp_modem_dce_t *dce_wrap, const char *number, const char *message) {
return esp_modem_send_sms(dce_wrap, number, message);
}

esp_err_t _esp_modem_set_pin(esp_modem_dce_t *dce_wrap, const char *pin) {
return esp_modem_set_pin(dce_wrap, pin);
}

esp_err_t _esp_modem_at_raw(esp_modem_dce_t *dce_wrap, const char *cmd, char *p_out, const char *pass, const char *fail, int timeout) {
return esp_modem_at_raw(dce_wrap, cmd, p_out, pass, fail, timeout);
}

esp_err_t _esp_modem_set_operator(esp_modem_dce_t *dce_wrap, int mode, int format, const char *oper) {
return esp_modem_set_operator(dce_wrap, mode, format, oper);
}

esp_err_t _esp_modem_set_network_bands(esp_modem_dce_t *dce_wrap, const char *mode, const int *bands, int size) {
return esp_modem_set_network_bands(dce_wrap, mode, bands, size);
}
#endif // CONFIG_LWIP_PPP_SUPPORT
68 changes: 34 additions & 34 deletions package/package_esp32_index.template.json
Original file line number Diff line number Diff line change
@@ -42,7 +42,7 @@
{
"packager": "esp32",
"name": "esp32-arduino-libs",
"version": "idf-release_v5.1-c432c692fa"
"version": "idf--c432c692fa"
},
{
"packager": "esp32",
@@ -105,63 +105,63 @@
"tools": [
{
"name": "esp32-arduino-libs",
"version": "idf-release_v5.1-c432c692fa",
"version": "idf--c432c692fa",
"systems": [
{
"host": "i686-mingw32",
"url": "https://codeload.github.com/espressif/esp32-arduino-libs/zip/ad1f97a1623c5c41a0db40a1def6d3fb8548a37d",
"archiveFileName": "esp32-arduino-libs-ad1f97a1623c5c41a0db40a1def6d3fb8548a37d.zip",
"checksum": "SHA-256:08790776b0351d9ef820777b6630514fd96b9ee28e894af527b3bbb8141f38de",
"size": "358586091"
"url": "https://codeload.github.com/espressif/esp32-arduino-libs/zip/fbc464148f35fbcc0e93b17a7a21e25b035efedb",
"archiveFileName": "esp32-arduino-libs-fbc464148f35fbcc0e93b17a7a21e25b035efedb.zip",
"checksum": "SHA-256:bbf2d324c310e8a80e0a4c0c6b2464a7d0ffb2509ae2cc2d06e65a260f3d8bae",
"size": "371625301"
},
{
"host": "x86_64-mingw32",
"url": "https://codeload.github.com/espressif/esp32-arduino-libs/zip/ad1f97a1623c5c41a0db40a1def6d3fb8548a37d",
"archiveFileName": "esp32-arduino-libs-ad1f97a1623c5c41a0db40a1def6d3fb8548a37d.zip",
"checksum": "SHA-256:08790776b0351d9ef820777b6630514fd96b9ee28e894af527b3bbb8141f38de",
"size": "358586091"
"url": "https://codeload.github.com/espressif/esp32-arduino-libs/zip/fbc464148f35fbcc0e93b17a7a21e25b035efedb",
"archiveFileName": "esp32-arduino-libs-fbc464148f35fbcc0e93b17a7a21e25b035efedb.zip",
"checksum": "SHA-256:bbf2d324c310e8a80e0a4c0c6b2464a7d0ffb2509ae2cc2d06e65a260f3d8bae",
"size": "371625301"
},
{
"host": "arm64-apple-darwin",
"url": "https://codeload.github.com/espressif/esp32-arduino-libs/zip/ad1f97a1623c5c41a0db40a1def6d3fb8548a37d",
"archiveFileName": "esp32-arduino-libs-ad1f97a1623c5c41a0db40a1def6d3fb8548a37d.zip",
"checksum": "SHA-256:08790776b0351d9ef820777b6630514fd96b9ee28e894af527b3bbb8141f38de",
"size": "358586091"
"url": "https://codeload.github.com/espressif/esp32-arduino-libs/zip/fbc464148f35fbcc0e93b17a7a21e25b035efedb",
"archiveFileName": "esp32-arduino-libs-fbc464148f35fbcc0e93b17a7a21e25b035efedb.zip",
"checksum": "SHA-256:bbf2d324c310e8a80e0a4c0c6b2464a7d0ffb2509ae2cc2d06e65a260f3d8bae",
"size": "371625301"
},
{
"host": "x86_64-apple-darwin",
"url": "https://codeload.github.com/espressif/esp32-arduino-libs/zip/ad1f97a1623c5c41a0db40a1def6d3fb8548a37d",
"archiveFileName": "esp32-arduino-libs-ad1f97a1623c5c41a0db40a1def6d3fb8548a37d.zip",
"checksum": "SHA-256:08790776b0351d9ef820777b6630514fd96b9ee28e894af527b3bbb8141f38de",
"size": "358586091"
"url": "https://codeload.github.com/espressif/esp32-arduino-libs/zip/fbc464148f35fbcc0e93b17a7a21e25b035efedb",
"archiveFileName": "esp32-arduino-libs-fbc464148f35fbcc0e93b17a7a21e25b035efedb.zip",
"checksum": "SHA-256:bbf2d324c310e8a80e0a4c0c6b2464a7d0ffb2509ae2cc2d06e65a260f3d8bae",
"size": "371625301"
},
{
"host": "x86_64-pc-linux-gnu",
"url": "https://codeload.github.com/espressif/esp32-arduino-libs/zip/ad1f97a1623c5c41a0db40a1def6d3fb8548a37d",
"archiveFileName": "esp32-arduino-libs-ad1f97a1623c5c41a0db40a1def6d3fb8548a37d.zip",
"checksum": "SHA-256:08790776b0351d9ef820777b6630514fd96b9ee28e894af527b3bbb8141f38de",
"size": "358586091"
"url": "https://codeload.github.com/espressif/esp32-arduino-libs/zip/fbc464148f35fbcc0e93b17a7a21e25b035efedb",
"archiveFileName": "esp32-arduino-libs-fbc464148f35fbcc0e93b17a7a21e25b035efedb.zip",
"checksum": "SHA-256:bbf2d324c310e8a80e0a4c0c6b2464a7d0ffb2509ae2cc2d06e65a260f3d8bae",
"size": "371625301"
},
{
"host": "i686-pc-linux-gnu",
"url": "https://codeload.github.com/espressif/esp32-arduino-libs/zip/ad1f97a1623c5c41a0db40a1def6d3fb8548a37d",
"archiveFileName": "esp32-arduino-libs-ad1f97a1623c5c41a0db40a1def6d3fb8548a37d.zip",
"checksum": "SHA-256:08790776b0351d9ef820777b6630514fd96b9ee28e894af527b3bbb8141f38de",
"size": "358586091"
"url": "https://codeload.github.com/espressif/esp32-arduino-libs/zip/fbc464148f35fbcc0e93b17a7a21e25b035efedb",
"archiveFileName": "esp32-arduino-libs-fbc464148f35fbcc0e93b17a7a21e25b035efedb.zip",
"checksum": "SHA-256:bbf2d324c310e8a80e0a4c0c6b2464a7d0ffb2509ae2cc2d06e65a260f3d8bae",
"size": "371625301"
},
{
"host": "aarch64-linux-gnu",
"url": "https://codeload.github.com/espressif/esp32-arduino-libs/zip/ad1f97a1623c5c41a0db40a1def6d3fb8548a37d",
"archiveFileName": "esp32-arduino-libs-ad1f97a1623c5c41a0db40a1def6d3fb8548a37d.zip",
"checksum": "SHA-256:08790776b0351d9ef820777b6630514fd96b9ee28e894af527b3bbb8141f38de",
"size": "358586091"
"url": "https://codeload.github.com/espressif/esp32-arduino-libs/zip/fbc464148f35fbcc0e93b17a7a21e25b035efedb",
"archiveFileName": "esp32-arduino-libs-fbc464148f35fbcc0e93b17a7a21e25b035efedb.zip",
"checksum": "SHA-256:bbf2d324c310e8a80e0a4c0c6b2464a7d0ffb2509ae2cc2d06e65a260f3d8bae",
"size": "371625301"
},
{
"host": "arm-linux-gnueabihf",
"url": "https://codeload.github.com/espressif/esp32-arduino-libs/zip/ad1f97a1623c5c41a0db40a1def6d3fb8548a37d",
"archiveFileName": "esp32-arduino-libs-ad1f97a1623c5c41a0db40a1def6d3fb8548a37d.zip",
"checksum": "SHA-256:08790776b0351d9ef820777b6630514fd96b9ee28e894af527b3bbb8141f38de",
"size": "358586091"
"url": "https://codeload.github.com/espressif/esp32-arduino-libs/zip/fbc464148f35fbcc0e93b17a7a21e25b035efedb",
"archiveFileName": "esp32-arduino-libs-fbc464148f35fbcc0e93b17a7a21e25b035efedb.zip",
"checksum": "SHA-256:bbf2d324c310e8a80e0a4c0c6b2464a7d0ffb2509ae2cc2d06e65a260f3d8bae",
"size": "371625301"
}
]
},