NEW
This commit is contained in:
1 parent
953536a032
commit
7db6c57b63
2021 files changed
+779840
No files matched your search
Vendored
BIN
Binary file not shown.
@@ -0,0 +1,80 @@
|
||||
#include <lvgl.h>
|
||||
#include <WiFi.h>
|
||||
#include <time.h>
|
||||
#include "config.h"
|
||||
#include "gfx.h"
|
||||
#include "ui.h"
|
||||
#include "openwrt.h"
|
||||
|
||||
unsigned long last = 0;
|
||||
unsigned long last_wifi_try = 0;
|
||||
unsigned long last_clock = 0;
|
||||
bool time_started = false;
|
||||
|
||||
static void service_ui(uint32_t wait_ms) {
|
||||
lv_task_handler();
|
||||
delay(wait_ms);
|
||||
}
|
||||
|
||||
static void start_wifi() {
|
||||
WiFi.mode(WIFI_STA);
|
||||
WiFi.begin(WIFI_SSID, WIFI_PASS);
|
||||
last_wifi_try = millis();
|
||||
}
|
||||
|
||||
static void start_time_sync() {
|
||||
if (time_started) return;
|
||||
configTime(8 * 3600, 0, "pool.ntp.org", "ntp.aliyun.com", "time.windows.com");
|
||||
time_started = true;
|
||||
}
|
||||
|
||||
void setup() {
|
||||
|
||||
Serial.begin(115200);
|
||||
|
||||
gfx_init();
|
||||
ui_init();
|
||||
|
||||
ui_set_status("Connecting WiFi...");
|
||||
start_wifi();
|
||||
|
||||
unsigned long start = millis();
|
||||
while (WiFi.status() != WL_CONNECTED && millis() - start < 15000) {
|
||||
service_ui(5);
|
||||
}
|
||||
|
||||
if (WiFi.status() == WL_CONNECTED) {
|
||||
start_time_sync();
|
||||
}
|
||||
ui_update_clock();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
|
||||
service_ui(5);
|
||||
|
||||
if (millis() - last_clock > 1000) {
|
||||
last_clock = millis();
|
||||
ui_update_clock();
|
||||
}
|
||||
|
||||
if (WiFi.status() != WL_CONNECTED) {
|
||||
if (millis() - last_wifi_try > 5000) {
|
||||
ui_set_status("Connecting WiFi...");
|
||||
start_wifi();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
start_time_sync();
|
||||
|
||||
if (millis() - last > 2000) {
|
||||
last = millis();
|
||||
|
||||
if (fetchOpenWrtData()) {
|
||||
ui_update();
|
||||
} else {
|
||||
ui_set_status("OpenWrt fetch failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,570 @@
|
||||
# OpenWrt Monitor
|
||||
|
||||
这是一个基于 ESP32 + LCD 屏幕的 OpenWrt 状态监控小屏项目。ESP32 会通过 Wi-Fi 定时访问 OpenWrt 路由器上的 CGI 接口,获取 CPU 负载、内存占用、温度、运行时间、实时上下行速率、内网 IP、公网 IP 和路由器时间,并显示在 LCD 上。
|
||||
|
||||
当前代码默认适配:
|
||||
|
||||
- 开发板:Waveshare ESP32-C6-LCD-1.47
|
||||
- 屏幕驱动:ST7789
|
||||
- 分辨率:172 x 320
|
||||
- 开发环境:Arduino IDE
|
||||
- 显示库:GFX Library for Arduino
|
||||
- UI 库:LVGL 8.x
|
||||
|
||||
## 功能
|
||||
|
||||
- 显示设备名称:`C2000 Max`
|
||||
- 显示 OpenWrt 系统状态:
|
||||
- CPU Load
|
||||
- RAM 使用率
|
||||
- CPU 温度
|
||||
- OpenWrt uptime
|
||||
- 显示网络状态:
|
||||
- UP 上传速率
|
||||
- DOWN 下载速率
|
||||
- LAN IP
|
||||
- Public IP
|
||||
- 底部显示 OpenWrt 后台 `date` 获取的当前时间
|
||||
- OpenWrt 后端脚本无固定 `sleep` 阻塞,响应更快
|
||||
- 网络速度单位自动切换 `Kb/s` 和 `Mb/s`
|
||||
- 英文和数字使用 LVGL 内置 Montserrat 字体
|
||||
|
||||
## 项目文件
|
||||
|
||||
```text
|
||||
OpenWrt_Monitor.ino Arduino 主程序
|
||||
config.h Wi-Fi 和 OpenWrt 接口配置
|
||||
gfx.cpp / gfx.h 屏幕驱动配置
|
||||
ui.cpp / ui.h LVGL 界面
|
||||
openwrt.cpp / .h HTTP 请求与 JSON 解析
|
||||
lcd.cpp / lcd.h 备用底层 LCD 驱动,目前主程序未使用
|
||||
openwrt_status.sh OpenWrt 后台 CGI 脚本
|
||||
```
|
||||
|
||||
## 一、Arduino IDE 准备
|
||||
|
||||
### 1. 安装 ESP32 开发板支持
|
||||
|
||||
打开 Arduino IDE,进入:
|
||||
|
||||
```text
|
||||
文件 -> 首选项 -> 其他开发板管理器地址
|
||||
```
|
||||
|
||||
加入 Espressif ESP32 地址:
|
||||
|
||||
```text
|
||||
https://espressif.github.io/arduino-esp32/package_esp32_index.json
|
||||
```
|
||||
|
||||
然后进入:
|
||||
|
||||
```text
|
||||
工具 -> 开发板 -> 开发板管理器
|
||||
```
|
||||
|
||||
搜索并安装:
|
||||
|
||||
```text
|
||||
esp32 by Espressif Systems
|
||||
```
|
||||
|
||||
建议使用较新的 3.x 版本。如果某些旧库不兼容,也可以尝试 2.0.x 版本。
|
||||
|
||||
### 2. 安装依赖库
|
||||
|
||||
进入 Arduino IDE:
|
||||
|
||||
```text
|
||||
工具 -> 管理库
|
||||
```
|
||||
|
||||
安装以下库:
|
||||
|
||||
```text
|
||||
GFX Library for Arduino
|
||||
lvgl
|
||||
ArduinoJson
|
||||
```
|
||||
|
||||
建议:
|
||||
|
||||
- LVGL 使用 8.x 版本
|
||||
- ArduinoJson 使用 6.x 或兼容版本
|
||||
|
||||
## 二、配置 ESP32 端
|
||||
|
||||
打开 [config.h](config.h),修改 Wi-Fi 和 OpenWrt 接口地址:
|
||||
|
||||
```cpp
|
||||
#define WIFI_SSID "你的WiFi名称"
|
||||
#define WIFI_PASS "你的WiFi密码"
|
||||
|
||||
#define OPENWRT_URL "http://192.168.7.1/cgi-bin/status.json"
|
||||
```
|
||||
|
||||
注意:
|
||||
|
||||
- ESP32 必须能访问 OpenWrt 的这个 IP。
|
||||
- 如果你的路由器 LAN IP 不是 `192.168.7.1`,请改成实际地址。
|
||||
- 如果脚本文件名不是 `status.json`,这里也要同步修改。
|
||||
|
||||
## 三、部署 OpenWrt 后台脚本
|
||||
|
||||
项目里的 [openwrt_status.sh](openwrt_status.sh) 是运行在 OpenWrt 上的 CGI 脚本。
|
||||
|
||||
### 1. 上传脚本到路由器
|
||||
|
||||
可以用 `scp` 上传:
|
||||
|
||||
```sh
|
||||
scp openwrt_status.sh root@192.168.7.1:/www/cgi-bin/status.json
|
||||
```
|
||||
|
||||
如果你的路由器 IP 不是 `192.168.7.1`,请替换成实际 IP。
|
||||
|
||||
### 2. 添加执行权限
|
||||
|
||||
SSH 登录 OpenWrt:
|
||||
|
||||
```sh
|
||||
ssh root@192.168.7.1
|
||||
```
|
||||
|
||||
执行:
|
||||
|
||||
```sh
|
||||
chmod +x /www/cgi-bin/status.json
|
||||
```
|
||||
|
||||
### 3. 浏览器测试接口
|
||||
|
||||
在浏览器打开:
|
||||
|
||||
```text
|
||||
http://192.168.7.1/cgi-bin/status.json
|
||||
```
|
||||
|
||||
正常情况下会看到类似:
|
||||
|
||||
```json
|
||||
{
|
||||
"load": 0.08,
|
||||
"cpu_load": 0.08,
|
||||
"mem": 42,
|
||||
"mem_percent": 42,
|
||||
"temp": 48,
|
||||
"cpu_temp": 48,
|
||||
"uptime": 123456,
|
||||
"time": "14:30:08",
|
||||
"rx": 123456789,
|
||||
"tx": 987654321,
|
||||
"rx_speed": 2048,
|
||||
"tx_speed": 1024,
|
||||
"lan_ip": "192.168.7.1",
|
||||
"wan_ip": "10.0.0.2",
|
||||
"public_ip": "1.2.3.4"
|
||||
}
|
||||
```
|
||||
|
||||
说明:
|
||||
|
||||
- `rx_speed` 和 `tx_speed` 单位是 Byte/s。
|
||||
- ESP32 会转换成 bit/s 后显示为 `Kb/s` 或 `Mb/s`。
|
||||
- 第一次请求时速度可能为 0,因为脚本需要先建立一次采样缓存。
|
||||
- `public_ip` 默认通过 `api.ipify.org` 获取,并缓存 5 分钟,避免频繁访问外网。
|
||||
|
||||
## 四、上传 ESP32 程序
|
||||
|
||||
### Waveshare ESP32-C6-LCD-1.47 推荐设置
|
||||
|
||||
Arduino IDE 中选择:
|
||||
|
||||
```text
|
||||
工具 -> 开发板 -> ESP32 Arduino -> ESP32C6 Dev Module
|
||||
```
|
||||
|
||||
常见设置:
|
||||
|
||||
```text
|
||||
USB CDC On Boot: Enabled
|
||||
Upload Speed: 460800 或 921600
|
||||
Flash Size: 4MB
|
||||
Partition Scheme: Default
|
||||
```
|
||||
|
||||
不同 Arduino ESP32 Core 版本的菜单项可能略有不同,能正常编译上传即可。
|
||||
|
||||
### 上传步骤
|
||||
|
||||
1. 用 USB-C 连接开发板。
|
||||
2. 在 Arduino IDE 选择正确串口。
|
||||
3. 点击上传。
|
||||
4. 如果上传失败,按住 `BOOT`,点一下 `RESET`,松开 `BOOT`,再上传。
|
||||
5. 上传完成后,按一下 `RESET` 运行程序。
|
||||
|
||||
## 五、默认屏幕参数
|
||||
|
||||
当前 [gfx.cpp](gfx.cpp) 默认使用 Waveshare ESP32-C6-LCD-1.47 参数:
|
||||
|
||||
```cpp
|
||||
constexpr int LCD_MOSI = 6;
|
||||
constexpr int LCD_SCLK = 7;
|
||||
constexpr int LCD_CS = 14;
|
||||
constexpr int LCD_DC = 15;
|
||||
constexpr int LCD_RST = 21;
|
||||
constexpr int LCD_BL = 22;
|
||||
constexpr int LCD_WIDTH = 172;
|
||||
constexpr int LCD_HEIGHT = 320;
|
||||
constexpr int LCD_X_OFFSET = 34;
|
||||
constexpr int LCD_Y_OFFSET = 0;
|
||||
```
|
||||
|
||||
对应官方参数:
|
||||
|
||||
```text
|
||||
MOSI GPIO6
|
||||
SCLK GPIO7
|
||||
CS GPIO14
|
||||
DC GPIO15
|
||||
RST GPIO21
|
||||
BL GPIO22
|
||||
LCD ST7789
|
||||
Size 172 x 320
|
||||
Offset X = 34
|
||||
```
|
||||
|
||||
## 六、适配不同 ESP32 型号或不同屏幕
|
||||
|
||||
适配其他 ESP32 板子时,主要改 4 类东西:
|
||||
|
||||
1. 开发板型号
|
||||
2. LCD 引脚
|
||||
3. LCD 驱动型号
|
||||
4. 分辨率、偏移和旋转方向
|
||||
|
||||
### 1. 修改开发板型号
|
||||
|
||||
在 Arduino IDE 选择与你硬件匹配的板型,例如:
|
||||
|
||||
```text
|
||||
ESP32 Dev Module
|
||||
ESP32-S3 Dev Module
|
||||
ESP32-C3 Dev Module
|
||||
ESP32-C6 Dev Module
|
||||
ESP32C6 Dev Module
|
||||
```
|
||||
|
||||
如果屏幕驱动和引脚都正确,但一直黑屏,优先确认板型是否选错。
|
||||
|
||||
### 2. 修改 LCD 引脚
|
||||
|
||||
打开 [gfx.cpp](gfx.cpp),修改:
|
||||
|
||||
```cpp
|
||||
constexpr int LCD_MOSI = 6;
|
||||
constexpr int LCD_SCLK = 7;
|
||||
constexpr int LCD_CS = 14;
|
||||
constexpr int LCD_DC = 15;
|
||||
constexpr int LCD_RST = 21;
|
||||
constexpr int LCD_BL = 22;
|
||||
```
|
||||
|
||||
不同开发板的屏幕接线不同,必须按实际原理图或商家 Wiki 修改。
|
||||
|
||||
如果你的屏幕没有背光控制脚,可以把:
|
||||
|
||||
```cpp
|
||||
constexpr int LCD_BL = 22;
|
||||
```
|
||||
|
||||
改成实际背光脚,或者在 `gfx_init()` 中去掉:
|
||||
|
||||
```cpp
|
||||
pinMode(LCD_BL, OUTPUT);
|
||||
digitalWrite(LCD_BL, HIGH);
|
||||
```
|
||||
|
||||
### 3. 修改屏幕分辨率和偏移
|
||||
|
||||
仍然在 [gfx.cpp](gfx.cpp) 修改:
|
||||
|
||||
```cpp
|
||||
constexpr int LCD_WIDTH = 172;
|
||||
constexpr int LCD_HEIGHT = 320;
|
||||
constexpr int LCD_X_OFFSET = 34;
|
||||
constexpr int LCD_Y_OFFSET = 0;
|
||||
```
|
||||
|
||||
常见 ST7789 屏幕参数示例:
|
||||
|
||||
```text
|
||||
240 x 240: offset 0, 0 或 0, 80
|
||||
240 x 320: offset 0, 0
|
||||
172 x 320: offset 34, 0
|
||||
170 x 320: offset 35, 0
|
||||
```
|
||||
|
||||
偏移不对时,常见现象:
|
||||
|
||||
- 画面偏移
|
||||
- 画面只显示一部分
|
||||
- 边缘有彩条
|
||||
- 屏幕亮但内容不在可见区域
|
||||
|
||||
### 4. 修改 LCD 驱动类型
|
||||
|
||||
当前使用:
|
||||
|
||||
```cpp
|
||||
Arduino_GFX *gfx = new Arduino_ST7789(...);
|
||||
```
|
||||
|
||||
如果你的屏幕不是 ST7789,需要换成对应驱动。例如:
|
||||
|
||||
```cpp
|
||||
Arduino_GFX *gfx = new Arduino_ILI9341(...);
|
||||
Arduino_GFX *gfx = new Arduino_GC9A01(...);
|
||||
Arduino_GFX *gfx = new Arduino_ST7735(...);
|
||||
```
|
||||
|
||||
具体支持哪些驱动,请查看 `GFX Library for Arduino` 文档或示例。
|
||||
|
||||
### 5. 修改 SPI 总线
|
||||
|
||||
当前使用:
|
||||
|
||||
```cpp
|
||||
Arduino_DataBus *bus = new Arduino_ESP32SPI(
|
||||
LCD_DC, LCD_CS, LCD_SCLK, LCD_MOSI, GFX_NOT_DEFINED
|
||||
);
|
||||
```
|
||||
|
||||
大多数 ESP32 SPI 屏幕都可以这样使用。
|
||||
|
||||
如果你的屏幕需要 MISO,可以把最后一个参数改成实际 MISO 引脚:
|
||||
|
||||
```cpp
|
||||
Arduino_DataBus *bus = new Arduino_ESP32SPI(
|
||||
LCD_DC, LCD_CS, LCD_SCLK, LCD_MOSI, LCD_MISO
|
||||
);
|
||||
```
|
||||
|
||||
### 6. 修改 UI 分辨率
|
||||
|
||||
当前 UI 按 `172 x 320` 竖屏设计:
|
||||
|
||||
```cpp
|
||||
disp_drv.hor_res = 172;
|
||||
disp_drv.ver_res = 320;
|
||||
```
|
||||
|
||||
如果屏幕分辨率不同,需要在 [ui.cpp](ui.cpp) 里同步修改:
|
||||
|
||||
```cpp
|
||||
static lv_color_t buf[172 * 40];
|
||||
disp_drv.hor_res = 172;
|
||||
disp_drv.ver_res = 320;
|
||||
```
|
||||
|
||||
例如 240 x 320 竖屏:
|
||||
|
||||
```cpp
|
||||
static lv_color_t buf[240 * 40];
|
||||
disp_drv.hor_res = 240;
|
||||
disp_drv.ver_res = 320;
|
||||
```
|
||||
|
||||
如果改成横屏,还需要重新调整 `ui.cpp` 里的控件坐标和宽高。
|
||||
|
||||
## 七、OpenWrt 接口字段说明
|
||||
|
||||
ESP32 当前支持以下字段:
|
||||
|
||||
```json
|
||||
{
|
||||
"load": 0.08,
|
||||
"mem": 42,
|
||||
"temp": 48,
|
||||
"uptime": 123456,
|
||||
"time": "14:30:08",
|
||||
"rx": 123456789,
|
||||
"tx": 987654321,
|
||||
"rx_speed": 2048,
|
||||
"tx_speed": 1024,
|
||||
"lan_ip": "192.168.7.1",
|
||||
"public_ip": "1.2.3.4"
|
||||
}
|
||||
```
|
||||
|
||||
也兼容这些旧字段:
|
||||
|
||||
```json
|
||||
{
|
||||
"cpu_load": 0.08,
|
||||
"mem_percent": 42,
|
||||
"cpu_temp": 48
|
||||
}
|
||||
```
|
||||
|
||||
字段说明:
|
||||
|
||||
```text
|
||||
load CPU load,浮点数
|
||||
mem 内存占用百分比,0-100
|
||||
temp CPU 温度,摄氏度
|
||||
uptime OpenWrt 运行时间,单位秒
|
||||
time OpenWrt 当前时间,建议 HH:MM:SS
|
||||
rx 网卡累计接收字节数
|
||||
tx 网卡累计发送字节数
|
||||
rx_speed 接收速度,Byte/s
|
||||
tx_speed 发送速度,Byte/s
|
||||
lan_ip 内网 IP
|
||||
public_ip 公网 IP
|
||||
```
|
||||
|
||||
## 八、修改监控网卡
|
||||
|
||||
OpenWrt 脚本默认监控:
|
||||
|
||||
```sh
|
||||
IFACE="${IFACE:-br-lan}"
|
||||
```
|
||||
|
||||
如果你要监控 WAN 口、PPPoE 或其他接口,可以改成实际网卡名,例如:
|
||||
|
||||
```sh
|
||||
IFACE="${IFACE:-pppoe-wan}"
|
||||
```
|
||||
|
||||
查看网卡:
|
||||
|
||||
```sh
|
||||
ip link
|
||||
```
|
||||
|
||||
也可以临时用环境变量运行:
|
||||
|
||||
```sh
|
||||
IFACE=pppoe-wan /www/cgi-bin/status.json
|
||||
```
|
||||
|
||||
## 九、常见问题
|
||||
|
||||
### 1. 屏幕完全不亮
|
||||
|
||||
优先检查:
|
||||
|
||||
- `LCD_BL` 背光引脚是否正确
|
||||
- `LCD_CS`、`LCD_DC`、`LCD_RST` 是否正确
|
||||
- 开发板型号是否选对
|
||||
- USB 供电是否稳定
|
||||
|
||||
当前默认背光是:
|
||||
|
||||
```cpp
|
||||
pinMode(LCD_BL, OUTPUT);
|
||||
digitalWrite(LCD_BL, HIGH);
|
||||
```
|
||||
|
||||
如果你的屏幕背光是低电平点亮,需要改成:
|
||||
|
||||
```cpp
|
||||
digitalWrite(LCD_BL, LOW);
|
||||
```
|
||||
|
||||
### 2. 屏幕亮,但没有内容
|
||||
|
||||
可能原因:
|
||||
|
||||
- ST7789 偏移参数不对
|
||||
- 分辨率不对
|
||||
- SPI 引脚不对
|
||||
- 屏幕驱动型号不对
|
||||
|
||||
重点检查 [gfx.cpp](gfx.cpp) 中的:
|
||||
|
||||
```cpp
|
||||
LCD_WIDTH
|
||||
LCD_HEIGHT
|
||||
LCD_X_OFFSET
|
||||
LCD_Y_OFFSET
|
||||
Arduino_ST7789
|
||||
```
|
||||
|
||||
### 3. 一直显示空数据或网速为 0
|
||||
|
||||
先在浏览器打开:
|
||||
|
||||
```text
|
||||
http://你的路由器IP/cgi-bin/status.json
|
||||
```
|
||||
|
||||
确认 JSON 是否正常返回。
|
||||
|
||||
如果网页打不开:
|
||||
|
||||
- CGI 脚本没有执行权限
|
||||
- 路径不对
|
||||
- OpenWrt 没启用 uhttpd CGI
|
||||
- ESP32 和 OpenWrt 不在同一网络
|
||||
|
||||
### 4. 公网 IP 显示为空
|
||||
|
||||
脚本会访问:
|
||||
|
||||
```text
|
||||
http://api.ipify.org
|
||||
```
|
||||
|
||||
如果路由器不能访问外网,公网 IP 会回退为 WAN IP。某些内网、多级 NAT、旁路由环境下,公网 IP 和 WAN IP 可能不同。
|
||||
|
||||
### 5. 时间显示不对
|
||||
|
||||
底部时间优先显示 OpenWrt 的:
|
||||
|
||||
```sh
|
||||
date '+%H:%M:%S'
|
||||
```
|
||||
|
||||
如果时间不对,请先修正 OpenWrt 时间同步:
|
||||
|
||||
```sh
|
||||
date
|
||||
```
|
||||
|
||||
或者检查 OpenWrt 的 NTP 设置。
|
||||
|
||||
### 6. 上传失败
|
||||
|
||||
ESP32-C6 有时需要手动进入下载模式:
|
||||
|
||||
1. 按住 `BOOT`
|
||||
2. 点一下 `RESET`
|
||||
3. 松开 `BOOT`
|
||||
4. 点击 Arduino IDE 上传
|
||||
5. 上传完成后再按一下 `RESET`
|
||||
|
||||
## 十、交付客户前建议
|
||||
|
||||
交付给客户前,建议确认:
|
||||
|
||||
- [ ] Wi-Fi 名称和密码已经改成客户环境
|
||||
- [ ] `OPENWRT_URL` 是客户路由器地址
|
||||
- [ ] OpenWrt 脚本已经部署并能浏览器访问
|
||||
- [ ] 屏幕能正常点亮
|
||||
- [ ] CPU/RAM/TEMP/UP 有数据
|
||||
- [ ] UP/DOWN 网速会变化
|
||||
- [ ] LAN/PUB IP 正常
|
||||
- [ ] 底部时间与 OpenWrt 时间一致
|
||||
|
||||
## 十一、安全提醒
|
||||
|
||||
当前 [config.h](config.h) 中会明文保存 Wi-Fi 密码。公开代码或交付第三方前,建议删除真实密码,改成占位内容:
|
||||
|
||||
```cpp
|
||||
#define WIFI_SSID "YOUR_WIFI"
|
||||
#define WIFI_PASS "YOUR_PASSWORD"
|
||||
```
|
||||
|
||||
OpenWrt 的 `status.json` 接口默认没有鉴权,建议只在内网使用,不要暴露到公网。
|
||||
@@ -0,0 +1,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#define WIFI_SSID "92FA-2.4G"
|
||||
#define WIFI_PASS "HdJd-2020"
|
||||
|
||||
#define OPENWRT_URL "http://192.168.7.1/cgi-bin/status.json"
|
||||
@@ -0,0 +1,38 @@
|
||||
#include "gfx.h"
|
||||
#include <Arduino_GFX_Library.h>
|
||||
|
||||
constexpr int LCD_MOSI = 6;
|
||||
constexpr int LCD_SCLK = 7;
|
||||
constexpr int LCD_CS = 14;
|
||||
constexpr int LCD_DC = 15;
|
||||
constexpr int LCD_RST = 21;
|
||||
constexpr int LCD_BL = 22;
|
||||
constexpr int LCD_WIDTH = 172;
|
||||
constexpr int LCD_HEIGHT = 320;
|
||||
constexpr int LCD_X_OFFSET = 34;
|
||||
constexpr int LCD_Y_OFFSET = 0;
|
||||
|
||||
Arduino_DataBus *bus = new Arduino_ESP32SPI(
|
||||
LCD_DC, LCD_CS, LCD_SCLK, LCD_MOSI, GFX_NOT_DEFINED
|
||||
);
|
||||
|
||||
Arduino_GFX *gfx = new Arduino_ST7789(
|
||||
bus,
|
||||
LCD_RST,
|
||||
0,
|
||||
false,
|
||||
LCD_WIDTH,
|
||||
LCD_HEIGHT,
|
||||
LCD_X_OFFSET,
|
||||
LCD_Y_OFFSET,
|
||||
LCD_X_OFFSET,
|
||||
LCD_Y_OFFSET
|
||||
);
|
||||
|
||||
void gfx_init() {
|
||||
pinMode(LCD_BL, OUTPUT);
|
||||
digitalWrite(LCD_BL, HIGH);
|
||||
gfx->begin();
|
||||
gfx->setRotation(2);
|
||||
gfx->fillScreen(0x0000);
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
#include <Arduino_GFX_Library.h>
|
||||
|
||||
extern Arduino_GFX *gfx;
|
||||
|
||||
void gfx_init();
|
||||
@@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
#include <Arduino.h>
|
||||
#include <SPI.h>
|
||||
#define LCD_WIDTH 172 //LCD width
|
||||
#define LCD_HEIGHT 320 //LCD height
|
||||
|
||||
#define SPIFreq 80000000
|
||||
#define EXAMPLE_PIN_NUM_MISO 5
|
||||
#define EXAMPLE_PIN_NUM_MOSI 6
|
||||
#define EXAMPLE_PIN_NUM_SCLK 7
|
||||
#define EXAMPLE_PIN_NUM_LCD_CS 14
|
||||
#define EXAMPLE_PIN_NUM_LCD_DC 15
|
||||
#define EXAMPLE_PIN_NUM_LCD_RST 21
|
||||
#define EXAMPLE_PIN_NUM_BK_LIGHT 22
|
||||
#define Frequency 1000
|
||||
#define Resolution 10
|
||||
|
||||
#define VERTICAL 0
|
||||
#define HORIZONTAL 1
|
||||
|
||||
#define Offset_X 34
|
||||
#define Offset_Y 0
|
||||
|
||||
|
||||
void LCD_SetCursor(uint16_t x1, uint16_t y1, uint16_t x2,uint16_t y2);
|
||||
|
||||
void LCD_Init(void);
|
||||
void LCD_SetCursor(uint16_t Xstart, uint16_t Ystart, uint16_t Xend, uint16_t Yend);
|
||||
void LCD_addWindow(uint16_t Xstart, uint16_t Ystart, uint16_t Xend, uint16_t Yend,uint16_t* color);
|
||||
|
||||
void Backlight_Init(void);
|
||||
void Set_Backlight(uint8_t Light);
|
||||
@@ -0,0 +1,58 @@
|
||||
#include "config.h"
|
||||
#include "openwrt.h"
|
||||
#include <WiFi.h>
|
||||
#include <HTTPClient.h>
|
||||
#include <ArduinoJson.h>
|
||||
#include <string.h>
|
||||
|
||||
OpenWrtData data;
|
||||
|
||||
bool fetchOpenWrtData() {
|
||||
|
||||
if (WiFi.status() != WL_CONNECTED) return false;
|
||||
|
||||
HTTPClient http;
|
||||
http.setTimeout(5000);
|
||||
if (!http.begin(OPENWRT_URL)) return false;
|
||||
|
||||
int code = http.GET();
|
||||
if (code != 200) {
|
||||
http.end();
|
||||
return false;
|
||||
}
|
||||
|
||||
String payload = http.getString();
|
||||
http.end();
|
||||
|
||||
StaticJsonDocument<1024> doc;
|
||||
if (deserializeJson(doc, payload)) return false;
|
||||
|
||||
JsonVariant cpu = doc["load"];
|
||||
if (cpu.isNull()) cpu = doc["cpu_load"];
|
||||
JsonVariant mem = doc["mem"];
|
||||
if (mem.isNull()) mem = doc["mem_percent"];
|
||||
JsonVariant temp = doc["temp"];
|
||||
if (temp.isNull()) temp = doc["cpu_temp"];
|
||||
|
||||
data.cpu = cpu.isNull() ? 0.0f : cpu.as<float>();
|
||||
data.mem = mem.isNull() ? 0 : mem.as<int>();
|
||||
data.temp = temp.isNull() ? 0 : temp.as<int>();
|
||||
data.uptime = doc["uptime"].as<uint64_t>();
|
||||
data.rx = doc["rx"].as<uint64_t>();
|
||||
data.tx = doc["tx"].as<uint64_t>();
|
||||
data.rx_speed = doc["rx_speed"].as<uint64_t>();
|
||||
data.tx_speed = doc["tx_speed"].as<uint64_t>();
|
||||
data.has_speed = !doc["rx_speed"].isNull() && !doc["tx_speed"].isNull();
|
||||
|
||||
const char *lan_ip = doc["lan_ip"] | "";
|
||||
const char *public_ip = doc["public_ip"] | "";
|
||||
const char *time_text = doc["time"] | "";
|
||||
strncpy(data.lan_ip, lan_ip, sizeof(data.lan_ip) - 1);
|
||||
data.lan_ip[sizeof(data.lan_ip) - 1] = '\0';
|
||||
strncpy(data.public_ip, public_ip, sizeof(data.public_ip) - 1);
|
||||
data.public_ip[sizeof(data.public_ip) - 1] = '\0';
|
||||
strncpy(data.time_text, time_text, sizeof(data.time_text) - 1);
|
||||
data.time_text[sizeof(data.time_text) - 1] = '\0';
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
|
||||
struct OpenWrtData {
|
||||
float cpu;
|
||||
int mem;
|
||||
int temp;
|
||||
uint64_t uptime;
|
||||
uint64_t rx;
|
||||
uint64_t tx;
|
||||
uint64_t rx_speed;
|
||||
uint64_t tx_speed;
|
||||
bool has_speed;
|
||||
char lan_ip[16];
|
||||
char public_ip[16];
|
||||
char time_text[16];
|
||||
};
|
||||
|
||||
extern OpenWrtData data;
|
||||
|
||||
bool fetchOpenWrtData();
|
||||
Executable
+127
@@ -0,0 +1,127 @@
|
||||
#!/bin/sh
|
||||
|
||||
echo "Content-Type: application/json"
|
||||
echo ""
|
||||
|
||||
IFACE="${IFACE:-br-lan}"
|
||||
STATE_FILE="/tmp/openwrt_monitor_${IFACE}.state"
|
||||
PUBLIC_IP_CACHE="/tmp/openwrt_monitor_public_ip"
|
||||
PUBLIC_IP_TTL=300
|
||||
|
||||
read_first_line() {
|
||||
[ -r "$1" ] && sed -n '1p' "$1" 2>/dev/null
|
||||
}
|
||||
|
||||
json_escape() {
|
||||
printf '%s' "$1" | sed 's/\\/\\\\/g; s/"/\\"/g'
|
||||
}
|
||||
|
||||
get_ip_from_ubus() {
|
||||
ubus call "network.interface.$1" status 2>/dev/null |
|
||||
jsonfilter -e '@["ipv4-address"][0].address' 2>/dev/null
|
||||
}
|
||||
|
||||
get_lan_ip() {
|
||||
local ip
|
||||
ip="$(get_ip_from_ubus lan)"
|
||||
[ -n "$ip" ] || ip="$(ip -4 addr show br-lan 2>/dev/null | awk '/inet / {sub(/\/.*/, "", $2); print $2; exit}')"
|
||||
printf '%s' "${ip:-0.0.0.0}"
|
||||
}
|
||||
|
||||
get_wan_ip() {
|
||||
local ip
|
||||
ip="$(get_ip_from_ubus wan)"
|
||||
[ -n "$ip" ] || ip="$(get_ip_from_ubus wan6)"
|
||||
[ -n "$ip" ] || ip="$(ip -4 route get 1.1.1.1 2>/dev/null | awk '{for (i=1; i<=NF; i++) if ($i=="src") {print $(i+1); exit}}')"
|
||||
printf '%s' "$ip"
|
||||
}
|
||||
|
||||
get_public_ip() {
|
||||
local now cache_mtime cache_age ip
|
||||
now="$(date +%s)"
|
||||
|
||||
if [ -s "$PUBLIC_IP_CACHE" ]; then
|
||||
cache_mtime="$(stat -c %Y "$PUBLIC_IP_CACHE" 2>/dev/null)"
|
||||
cache_age=$((now - ${cache_mtime:-0}))
|
||||
if [ "$cache_age" -lt "$PUBLIC_IP_TTL" ]; then
|
||||
read_first_line "$PUBLIC_IP_CACHE"
|
||||
return
|
||||
fi
|
||||
fi
|
||||
|
||||
ip="$(wget -qO- -T 2 http://api.ipify.org 2>/dev/null)"
|
||||
case "$ip" in
|
||||
*.*.*.*)
|
||||
printf '%s\n' "$ip" > "$PUBLIC_IP_CACHE"
|
||||
printf '%s' "$ip"
|
||||
;;
|
||||
*)
|
||||
get_wan_ip
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
LOAD="$(awk '{print $1}' /proc/loadavg 2>/dev/null)"
|
||||
MEM_TOTAL="$(awk '/MemTotal/ {print $2}' /proc/meminfo 2>/dev/null)"
|
||||
MEM_AVAILABLE="$(awk '/MemAvailable/ {print $2}' /proc/meminfo 2>/dev/null)"
|
||||
MEM_TOTAL="${MEM_TOTAL:-0}"
|
||||
MEM_AVAILABLE="${MEM_AVAILABLE:-0}"
|
||||
if [ "$MEM_TOTAL" -gt 0 ]; then
|
||||
MEM_PERCENT=$(((MEM_TOTAL - MEM_AVAILABLE) * 100 / MEM_TOTAL))
|
||||
else
|
||||
MEM_PERCENT=0
|
||||
fi
|
||||
|
||||
CPU_TEMP="$(read_first_line /sys/class/thermal/thermal_zone0/temp)"
|
||||
CPU_TEMP="${CPU_TEMP:-0}"
|
||||
[ "$CPU_TEMP" -gt 1000 ] 2>/dev/null && CPU_TEMP=$((CPU_TEMP / 1000))
|
||||
|
||||
NOW="$(date +%s)"
|
||||
TIME_TEXT="$(date '+%H:%M:%S' 2>/dev/null)"
|
||||
UPTIME="$(cut -d. -f1 /proc/uptime 2>/dev/null)"
|
||||
RX="$(read_first_line "/sys/class/net/$IFACE/statistics/rx_bytes")"
|
||||
TX="$(read_first_line "/sys/class/net/$IFACE/statistics/tx_bytes")"
|
||||
RX="${RX:-0}"
|
||||
TX="${TX:-0}"
|
||||
|
||||
RX_SPEED=0
|
||||
TX_SPEED=0
|
||||
if [ -r "$STATE_FILE" ]; then
|
||||
read LAST_NOW LAST_RX LAST_TX < "$STATE_FILE"
|
||||
DELTA_TIME=$((NOW - ${LAST_NOW:-0}))
|
||||
if [ "$DELTA_TIME" -gt 0 ] && [ "$RX" -ge "${LAST_RX:-0}" ] && [ "$TX" -ge "${LAST_TX:-0}" ]; then
|
||||
RX_SPEED=$(((RX - LAST_RX) / DELTA_TIME))
|
||||
TX_SPEED=$(((TX - LAST_TX) / DELTA_TIME))
|
||||
fi
|
||||
fi
|
||||
printf '%s %s %s\n' "$NOW" "$RX" "$TX" > "$STATE_FILE"
|
||||
|
||||
LAN_IP="$(get_lan_ip)"
|
||||
WAN_IP="$(get_wan_ip)"
|
||||
PUBLIC_IP="$(get_public_ip)"
|
||||
[ -n "$PUBLIC_IP" ] || PUBLIC_IP="$WAN_IP"
|
||||
|
||||
LAN_IP_ESC="$(json_escape "$LAN_IP")"
|
||||
WAN_IP_ESC="$(json_escape "$WAN_IP")"
|
||||
PUBLIC_IP_ESC="$(json_escape "$PUBLIC_IP")"
|
||||
TIME_TEXT_ESC="$(json_escape "$TIME_TEXT")"
|
||||
|
||||
cat <<EOF
|
||||
{
|
||||
"load": ${LOAD:-0},
|
||||
"cpu_load": ${LOAD:-0},
|
||||
"mem": ${MEM_PERCENT:-0},
|
||||
"mem_percent": ${MEM_PERCENT:-0},
|
||||
"temp": ${CPU_TEMP:-0},
|
||||
"cpu_temp": ${CPU_TEMP:-0},
|
||||
"uptime": ${UPTIME:-0},
|
||||
"time": "$TIME_TEXT_ESC",
|
||||
"rx": ${RX:-0},
|
||||
"tx": ${TX:-0},
|
||||
"rx_speed": ${RX_SPEED:-0},
|
||||
"tx_speed": ${TX_SPEED:-0},
|
||||
"lan_ip": "$LAN_IP_ESC",
|
||||
"wan_ip": "$WAN_IP_ESC",
|
||||
"public_ip": "$PUBLIC_IP_ESC"
|
||||
}
|
||||
EOF
|
||||
@@ -0,0 +1,280 @@
|
||||
#include "ui.h"
|
||||
#include "openwrt.h"
|
||||
#include "gfx.h"
|
||||
#include <lvgl.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
static lv_disp_draw_buf_t draw_buf;
|
||||
static lv_color_t buf[172 * 40];
|
||||
|
||||
static lv_obj_t *cpu_value;
|
||||
static lv_obj_t *mem_value;
|
||||
static lv_obj_t *temp_value;
|
||||
static lv_obj_t *uptime_value;
|
||||
static lv_obj_t *up_value;
|
||||
static lv_obj_t *down_value;
|
||||
static lv_obj_t *lan_value;
|
||||
static lv_obj_t *pub_value;
|
||||
static lv_obj_t *clock_label;
|
||||
static lv_obj_t *cpu_bar;
|
||||
static lv_obj_t *mem_bar;
|
||||
|
||||
static uint64_t last_rx = 0;
|
||||
static uint64_t last_tx = 0;
|
||||
static unsigned long last_net_ms = 0;
|
||||
static bool has_net_sample = false;
|
||||
|
||||
static const lv_color_t COLOR_SKY = lv_color_hex(0x264653);
|
||||
static const lv_color_t COLOR_WAVE = lv_color_hex(0x2A9D8F);
|
||||
static const lv_color_t COLOR_SAND = lv_color_hex(0xE9C46A);
|
||||
static const lv_color_t COLOR_CORAL = lv_color_hex(0xE76F51);
|
||||
static const lv_color_t COLOR_PANEL = lv_color_hex(0x203D49);
|
||||
static const lv_color_t COLOR_BAR_BG = lv_color_hex(0x345866);
|
||||
static const lv_color_t COLOR_DIM = lv_color_hex(0xB8D5D2);
|
||||
static const lv_color_t COLOR_TEXT = lv_color_hex(0xF7FBF8);
|
||||
|
||||
static const lv_font_t *FONT_EN = &lv_font_montserrat_14;
|
||||
static const lv_font_t *FONT_TITLE = &lv_font_montserrat_16;
|
||||
|
||||
static void format_rate(char *out, size_t out_size, double bits_per_sec) {
|
||||
double kbits = bits_per_sec / 1000.0;
|
||||
|
||||
if (kbits >= 1000.0) {
|
||||
snprintf(out, out_size, "%.2fMb/s", kbits / 1000.0);
|
||||
} else {
|
||||
snprintf(out, out_size, "%.0fKb/s", kbits);
|
||||
}
|
||||
}
|
||||
|
||||
static int clamp_percent(int value) {
|
||||
if (value < 0) return 0;
|
||||
if (value > 100) return 100;
|
||||
return value;
|
||||
}
|
||||
|
||||
static void format_uptime(char *out, size_t out_size, uint64_t seconds) {
|
||||
uint32_t days = seconds / 86400ULL;
|
||||
uint8_t hours = (seconds % 86400ULL) / 3600ULL;
|
||||
uint8_t minutes = (seconds % 3600ULL) / 60ULL;
|
||||
uint8_t secs = seconds % 60ULL;
|
||||
|
||||
if (days > 0) {
|
||||
snprintf(out, out_size, "%lud %02u:%02u:%02u",
|
||||
(unsigned long)days,
|
||||
(unsigned int)hours,
|
||||
(unsigned int)minutes,
|
||||
(unsigned int)secs);
|
||||
} else {
|
||||
snprintf(out, out_size, "%02u:%02u:%02u",
|
||||
(unsigned int)hours,
|
||||
(unsigned int)minutes,
|
||||
(unsigned int)secs);
|
||||
}
|
||||
}
|
||||
|
||||
static lv_obj_t *make_panel(lv_obj_t *parent, int16_t x, int16_t y, int16_t w, int16_t h) {
|
||||
lv_obj_t *panel = lv_obj_create(parent);
|
||||
lv_obj_set_pos(panel, x, y);
|
||||
lv_obj_set_size(panel, w, h);
|
||||
lv_obj_clear_flag(panel, LV_OBJ_FLAG_SCROLLABLE);
|
||||
lv_obj_set_style_bg_color(panel, COLOR_PANEL, LV_PART_MAIN);
|
||||
lv_obj_set_style_bg_opa(panel, LV_OPA_COVER, LV_PART_MAIN);
|
||||
lv_obj_set_style_border_color(panel, COLOR_WAVE, LV_PART_MAIN);
|
||||
lv_obj_set_style_border_opa(panel, LV_OPA_50, LV_PART_MAIN);
|
||||
lv_obj_set_style_border_width(panel, 1, LV_PART_MAIN);
|
||||
lv_obj_set_style_radius(panel, 4, LV_PART_MAIN);
|
||||
lv_obj_set_style_pad_all(panel, 5, LV_PART_MAIN);
|
||||
return panel;
|
||||
}
|
||||
|
||||
static lv_obj_t *make_text(lv_obj_t *parent, const char *text, int16_t x, int16_t y,
|
||||
int16_t w, lv_color_t color, lv_text_align_t align) {
|
||||
lv_obj_t *label = lv_label_create(parent);
|
||||
lv_label_set_text(label, text);
|
||||
lv_obj_set_width(label, w);
|
||||
lv_obj_set_style_text_color(label, color, LV_PART_MAIN);
|
||||
lv_obj_set_style_text_font(label, FONT_EN, LV_PART_MAIN);
|
||||
lv_obj_set_style_text_align(label, align, LV_PART_MAIN);
|
||||
lv_label_set_long_mode(label, LV_LABEL_LONG_CLIP);
|
||||
lv_obj_align(label, LV_ALIGN_TOP_LEFT, x, y);
|
||||
return label;
|
||||
}
|
||||
|
||||
static lv_obj_t *make_section_title(lv_obj_t *parent, const char *text, lv_color_t color) {
|
||||
return make_text(parent, text, 0, 0, 144, color, LV_TEXT_ALIGN_LEFT);
|
||||
}
|
||||
|
||||
static lv_obj_t *make_row(lv_obj_t *parent, const char *name, int16_t y, lv_color_t value_color) {
|
||||
make_text(parent, name, 0, y, 58, COLOR_DIM, LV_TEXT_ALIGN_LEFT);
|
||||
return make_text(parent, "--", 58, y, 86, value_color, LV_TEXT_ALIGN_RIGHT);
|
||||
}
|
||||
|
||||
static lv_obj_t *make_ip_row(lv_obj_t *parent, const char *name, int16_t y) {
|
||||
make_text(parent, name, 0, y, 30, COLOR_DIM, LV_TEXT_ALIGN_LEFT);
|
||||
return make_text(parent, "--", 30, y, 114, COLOR_DIM, LV_TEXT_ALIGN_RIGHT);
|
||||
}
|
||||
|
||||
static lv_obj_t *make_bar(lv_obj_t *parent, int16_t y, lv_color_t color) {
|
||||
lv_obj_t *bar = lv_bar_create(parent);
|
||||
lv_obj_set_size(bar, 142, 6);
|
||||
lv_obj_align(bar, LV_ALIGN_TOP_LEFT, 0, y);
|
||||
lv_bar_set_range(bar, 0, 100);
|
||||
lv_obj_set_style_bg_color(bar, COLOR_BAR_BG, LV_PART_MAIN);
|
||||
lv_obj_set_style_bg_opa(bar, LV_OPA_COVER, LV_PART_MAIN);
|
||||
lv_obj_set_style_bg_color(bar, color, LV_PART_INDICATOR);
|
||||
lv_obj_set_style_radius(bar, 1, LV_PART_MAIN);
|
||||
lv_obj_set_style_radius(bar, 1, LV_PART_INDICATOR);
|
||||
return bar;
|
||||
}
|
||||
|
||||
static lv_obj_t *make_hline(lv_obj_t *parent, int16_t x, int16_t y, int16_t w, lv_color_t color) {
|
||||
lv_obj_t *line = lv_obj_create(parent);
|
||||
lv_obj_set_pos(line, x, y);
|
||||
lv_obj_set_size(line, w, 2);
|
||||
lv_obj_clear_flag(line, LV_OBJ_FLAG_SCROLLABLE);
|
||||
lv_obj_set_style_bg_color(line, color, LV_PART_MAIN);
|
||||
lv_obj_set_style_bg_opa(line, LV_OPA_COVER, LV_PART_MAIN);
|
||||
lv_obj_set_style_border_width(line, 0, LV_PART_MAIN);
|
||||
lv_obj_set_style_radius(line, 0, LV_PART_MAIN);
|
||||
lv_obj_set_style_pad_all(line, 0, LV_PART_MAIN);
|
||||
return line;
|
||||
}
|
||||
|
||||
void my_flush(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p) {
|
||||
gfx->draw16bitRGBBitmap(
|
||||
area->x1,
|
||||
area->y1,
|
||||
(uint16_t *)color_p,
|
||||
area->x2 - area->x1 + 1,
|
||||
area->y2 - area->y1 + 1
|
||||
);
|
||||
|
||||
lv_disp_flush_ready(disp);
|
||||
}
|
||||
|
||||
void ui_init() {
|
||||
lv_init();
|
||||
lv_disp_draw_buf_init(&draw_buf, buf, NULL, 172 * 40);
|
||||
|
||||
static lv_disp_drv_t disp_drv;
|
||||
lv_disp_drv_init(&disp_drv);
|
||||
disp_drv.hor_res = 172;
|
||||
disp_drv.ver_res = 320;
|
||||
disp_drv.flush_cb = my_flush;
|
||||
disp_drv.draw_buf = &draw_buf;
|
||||
lv_disp_drv_register(&disp_drv);
|
||||
|
||||
lv_obj_t *screen = lv_scr_act();
|
||||
lv_obj_set_style_bg_color(screen, COLOR_SKY, LV_PART_MAIN);
|
||||
lv_obj_set_style_text_color(screen, COLOR_TEXT, LV_PART_MAIN);
|
||||
lv_obj_clear_flag(screen, LV_OBJ_FLAG_SCROLLABLE);
|
||||
|
||||
lv_obj_t *title = lv_label_create(screen);
|
||||
lv_label_set_text(title, "C2000 MAX");
|
||||
lv_obj_set_style_text_color(title, COLOR_SAND, LV_PART_MAIN);
|
||||
lv_obj_set_style_text_font(title, FONT_TITLE, LV_PART_MAIN);
|
||||
lv_obj_align(title, LV_ALIGN_TOP_MID, 0, 8);
|
||||
make_hline(screen, 8, 32, 156, COLOR_WAVE);
|
||||
|
||||
lv_obj_t *sys_panel = make_panel(screen, 8, 38, 156, 124);
|
||||
make_section_title(sys_panel, "SYSTEM", COLOR_SAND);
|
||||
cpu_value = make_row(sys_panel, "CPU", 18, COLOR_TEXT);
|
||||
cpu_bar = make_bar(sys_panel, 37, COLOR_WAVE);
|
||||
mem_value = make_row(sys_panel, "RAM", 51, COLOR_TEXT);
|
||||
mem_bar = make_bar(sys_panel, 70, COLOR_SAND);
|
||||
temp_value = make_row(sys_panel, "TEMP", 83, COLOR_TEXT);
|
||||
uptime_value = make_row(sys_panel, "UPTIME", 103, COLOR_DIM);
|
||||
|
||||
lv_obj_t *net_panel = make_panel(screen, 8, 170, 156, 106);
|
||||
make_section_title(net_panel, "NETWORK", COLOR_WAVE);
|
||||
up_value = make_row(net_panel, "UP", 20, COLOR_TEXT);
|
||||
down_value = make_row(net_panel, "DOWN", 39, COLOR_TEXT);
|
||||
lan_value = make_ip_row(net_panel, "LAN", 63);
|
||||
pub_value = make_ip_row(net_panel, "PUB", 82);
|
||||
|
||||
make_hline(screen, 8, 286, 156, COLOR_WAVE);
|
||||
clock_label = make_text(screen, "--:--:--", 8, 296, 156, COLOR_SAND, LV_TEXT_ALIGN_CENTER);
|
||||
}
|
||||
|
||||
void ui_update() {
|
||||
char buf[64];
|
||||
|
||||
snprintf(buf, sizeof(buf), "%.2f", data.cpu);
|
||||
lv_label_set_text(cpu_value, buf);
|
||||
lv_bar_set_value(cpu_bar, clamp_percent((int)(data.cpu * 25.0f)), LV_ANIM_OFF);
|
||||
|
||||
int mem_percent = clamp_percent(data.mem);
|
||||
snprintf(buf, sizeof(buf), "%d%%", mem_percent);
|
||||
lv_label_set_text(mem_value, buf);
|
||||
lv_bar_set_value(mem_bar, mem_percent, LV_ANIM_OFF);
|
||||
|
||||
snprintf(buf, sizeof(buf), "%d C", data.temp);
|
||||
lv_label_set_text(temp_value, buf);
|
||||
lv_obj_set_style_text_color(temp_value, data.temp >= 70 ? COLOR_CORAL : COLOR_TEXT, LV_PART_MAIN);
|
||||
|
||||
uint64_t uptime_seconds = data.uptime;
|
||||
if (uptime_seconds == 0) {
|
||||
uptime_seconds = millis() / 1000UL;
|
||||
}
|
||||
format_uptime(buf, sizeof(buf), uptime_seconds);
|
||||
lv_label_set_text(uptime_value, buf);
|
||||
|
||||
unsigned long now = millis();
|
||||
if (data.has_speed) {
|
||||
char rx_buf[16];
|
||||
char tx_buf[16];
|
||||
format_rate(rx_buf, sizeof(rx_buf), data.rx_speed * 8.0);
|
||||
format_rate(tx_buf, sizeof(tx_buf), data.tx_speed * 8.0);
|
||||
lv_label_set_text(up_value, tx_buf);
|
||||
lv_label_set_text(down_value, rx_buf);
|
||||
} else if (has_net_sample && now > last_net_ms && data.rx >= last_rx && data.tx >= last_tx) {
|
||||
double seconds = (now - last_net_ms) / 1000.0;
|
||||
char rx_buf[16];
|
||||
char tx_buf[16];
|
||||
format_rate(rx_buf, sizeof(rx_buf), (data.rx - last_rx) * 8.0 / seconds);
|
||||
format_rate(tx_buf, sizeof(tx_buf), (data.tx - last_tx) * 8.0 / seconds);
|
||||
lv_label_set_text(up_value, tx_buf);
|
||||
lv_label_set_text(down_value, rx_buf);
|
||||
} else {
|
||||
lv_label_set_text(up_value, "--");
|
||||
lv_label_set_text(down_value, "--");
|
||||
}
|
||||
|
||||
lv_label_set_text(lan_value, data.lan_ip[0] ? data.lan_ip : "--");
|
||||
lv_label_set_text(pub_value, data.public_ip[0] ? data.public_ip : "--");
|
||||
|
||||
last_rx = data.rx;
|
||||
last_tx = data.tx;
|
||||
last_net_ms = now;
|
||||
has_net_sample = true;
|
||||
ui_update_clock();
|
||||
}
|
||||
|
||||
void ui_update_clock() {
|
||||
if (clock_label == NULL) return;
|
||||
|
||||
if (data.time_text[0] != '\0') {
|
||||
lv_label_set_text(clock_label, data.time_text);
|
||||
return;
|
||||
}
|
||||
|
||||
time_t now = time(NULL);
|
||||
struct tm time_info;
|
||||
if (now < 1700000000 || localtime_r(&now, &time_info) == NULL) {
|
||||
lv_label_set_text(clock_label, "--:--:--");
|
||||
return;
|
||||
}
|
||||
|
||||
char buf[24];
|
||||
snprintf(buf, sizeof(buf), "%02d:%02d:%02d",
|
||||
time_info.tm_hour,
|
||||
time_info.tm_min,
|
||||
time_info.tm_sec);
|
||||
lv_label_set_text(clock_label, buf);
|
||||
}
|
||||
|
||||
void ui_set_status(const char *text) {
|
||||
(void)text;
|
||||
ui_update_clock();
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
void ui_init();
|
||||
void ui_update();
|
||||
void ui_update_clock();
|
||||
void ui_set_status(const char *text);
|
||||
@@ -0,0 +1,569 @@
|
||||
# OpenWrt Monitor
|
||||
|
||||
这是一个基于 ESP32 + LCD 屏幕的 OpenWrt 状态监控小屏项目。ESP32 会通过 Wi-Fi 定时访问 OpenWrt 路由器上的 CGI 接口,获取 CPU 负载、内存占用、温度、运行时间、实时上下行速率、内网 IP、公网 IP 和路由器时间,并显示在 LCD 上。
|
||||
|
||||
当前代码默认适配:
|
||||
|
||||
- 开发板:Waveshare ESP32-C6-LCD-1.47
|
||||
- 屏幕驱动:ST7789
|
||||
- 分辨率:172 x 320
|
||||
- 开发环境:Arduino IDE
|
||||
- 显示库:GFX Library for Arduino
|
||||
- UI 库:LVGL 8.x
|
||||
|
||||
## 功能
|
||||
|
||||
- 显示设备名称:`C2000 Max`
|
||||
- 显示 OpenWrt 系统状态:
|
||||
- CPU Load
|
||||
- RAM 使用率
|
||||
- CPU 温度
|
||||
- OpenWrt uptime
|
||||
- 显示网络状态:
|
||||
- RX 实时下载速率
|
||||
- TX 实时上传速率
|
||||
- LAN IP
|
||||
- Public IP
|
||||
- 底部显示 OpenWrt 后台 `date` 获取的当前时间
|
||||
- OpenWrt 后端脚本无固定 `sleep` 阻塞,响应更快
|
||||
- 网络速度单位自动切换 `Kb/s` 和 `Mb/s`
|
||||
|
||||
## 项目文件
|
||||
|
||||
```text
|
||||
OpenWrt_Monitor.ino Arduino 主程序
|
||||
config.h Wi-Fi 和 OpenWrt 接口配置
|
||||
gfx.cpp / gfx.h 屏幕驱动配置
|
||||
ui.cpp / ui.h LVGL 界面
|
||||
openwrt.cpp / .h HTTP 请求与 JSON 解析
|
||||
lcd.cpp / lcd.h 备用底层 LCD 驱动,目前主程序未使用
|
||||
openwrt_status.sh OpenWrt 后台 CGI 脚本
|
||||
```
|
||||
|
||||
## 一、Arduino IDE 准备
|
||||
|
||||
### 1. 安装 ESP32 开发板支持
|
||||
|
||||
打开 Arduino IDE,进入:
|
||||
|
||||
```text
|
||||
文件 -> 首选项 -> 其他开发板管理器地址
|
||||
```
|
||||
|
||||
加入 Espressif ESP32 地址:
|
||||
|
||||
```text
|
||||
https://espressif.github.io/arduino-esp32/package_esp32_index.json
|
||||
```
|
||||
|
||||
然后进入:
|
||||
|
||||
```text
|
||||
工具 -> 开发板 -> 开发板管理器
|
||||
```
|
||||
|
||||
搜索并安装:
|
||||
|
||||
```text
|
||||
esp32 by Espressif Systems
|
||||
```
|
||||
|
||||
建议使用较新的 3.x 版本。如果某些旧库不兼容,也可以尝试 2.0.x 版本。
|
||||
|
||||
### 2. 安装依赖库
|
||||
|
||||
进入 Arduino IDE:
|
||||
|
||||
```text
|
||||
工具 -> 管理库
|
||||
```
|
||||
|
||||
安装以下库:
|
||||
|
||||
```text
|
||||
GFX Library for Arduino
|
||||
lvgl
|
||||
ArduinoJson
|
||||
```
|
||||
|
||||
建议:
|
||||
|
||||
- LVGL 使用 8.x 版本
|
||||
- ArduinoJson 使用 6.x 或兼容版本
|
||||
|
||||
## 二、配置 ESP32 端
|
||||
|
||||
打开 [config.h](config.h),修改 Wi-Fi 和 OpenWrt 接口地址:
|
||||
|
||||
```cpp
|
||||
#define WIFI_SSID "你的WiFi名称"
|
||||
#define WIFI_PASS "你的WiFi密码"
|
||||
|
||||
#define OPENWRT_URL "http://192.168.7.1/cgi-bin/status.json"
|
||||
```
|
||||
|
||||
注意:
|
||||
|
||||
- ESP32 必须能访问 OpenWrt 的这个 IP。
|
||||
- 如果你的路由器 LAN IP 不是 `192.168.7.1`,请改成实际地址。
|
||||
- 如果脚本文件名不是 `status.json`,这里也要同步修改。
|
||||
|
||||
## 三、部署 OpenWrt 后台脚本
|
||||
|
||||
项目里的 [openwrt_status.sh](openwrt_status.sh) 是运行在 OpenWrt 上的 CGI 脚本。
|
||||
|
||||
### 1. 上传脚本到路由器
|
||||
|
||||
可以用 `scp` 上传:
|
||||
|
||||
```sh
|
||||
scp openwrt_status.sh root@192.168.7.1:/www/cgi-bin/status.json
|
||||
```
|
||||
|
||||
如果你的路由器 IP 不是 `192.168.7.1`,请替换成实际 IP。
|
||||
|
||||
### 2. 添加执行权限
|
||||
|
||||
SSH 登录 OpenWrt:
|
||||
|
||||
```sh
|
||||
ssh root@192.168.7.1
|
||||
```
|
||||
|
||||
执行:
|
||||
|
||||
```sh
|
||||
chmod +x /www/cgi-bin/status.json
|
||||
```
|
||||
|
||||
### 3. 浏览器测试接口
|
||||
|
||||
在浏览器打开:
|
||||
|
||||
```text
|
||||
http://192.168.7.1/cgi-bin/status.json
|
||||
```
|
||||
|
||||
正常情况下会看到类似:
|
||||
|
||||
```json
|
||||
{
|
||||
"load": 0.08,
|
||||
"cpu_load": 0.08,
|
||||
"mem": 42,
|
||||
"mem_percent": 42,
|
||||
"temp": 48,
|
||||
"cpu_temp": 48,
|
||||
"uptime": 123456,
|
||||
"time": "14:30:08",
|
||||
"rx": 123456789,
|
||||
"tx": 987654321,
|
||||
"rx_speed": 2048,
|
||||
"tx_speed": 1024,
|
||||
"lan_ip": "192.168.7.1",
|
||||
"wan_ip": "10.0.0.2",
|
||||
"public_ip": "1.2.3.4"
|
||||
}
|
||||
```
|
||||
|
||||
说明:
|
||||
|
||||
- `rx_speed` 和 `tx_speed` 单位是 Byte/s。
|
||||
- ESP32 会转换成 bit/s 后显示为 `Kb/s` 或 `Mb/s`。
|
||||
- 第一次请求时速度可能为 0,因为脚本需要先建立一次采样缓存。
|
||||
- `public_ip` 默认通过 `api.ipify.org` 获取,并缓存 5 分钟,避免频繁访问外网。
|
||||
|
||||
## 四、上传 ESP32 程序
|
||||
|
||||
### Waveshare ESP32-C6-LCD-1.47 推荐设置
|
||||
|
||||
Arduino IDE 中选择:
|
||||
|
||||
```text
|
||||
工具 -> 开发板 -> ESP32 Arduino -> ESP32C6 Dev Module
|
||||
```
|
||||
|
||||
常见设置:
|
||||
|
||||
```text
|
||||
USB CDC On Boot: Enabled
|
||||
Upload Speed: 460800 或 921600
|
||||
Flash Size: 4MB
|
||||
Partition Scheme: Default
|
||||
```
|
||||
|
||||
不同 Arduino ESP32 Core 版本的菜单项可能略有不同,能正常编译上传即可。
|
||||
|
||||
### 上传步骤
|
||||
|
||||
1. 用 USB-C 连接开发板。
|
||||
2. 在 Arduino IDE 选择正确串口。
|
||||
3. 点击上传。
|
||||
4. 如果上传失败,按住 `BOOT`,点一下 `RESET`,松开 `BOOT`,再上传。
|
||||
5. 上传完成后,按一下 `RESET` 运行程序。
|
||||
|
||||
## 五、默认屏幕参数
|
||||
|
||||
当前 [gfx.cpp](gfx.cpp) 默认使用 Waveshare ESP32-C6-LCD-1.47 参数:
|
||||
|
||||
```cpp
|
||||
constexpr int LCD_MOSI = 6;
|
||||
constexpr int LCD_SCLK = 7;
|
||||
constexpr int LCD_CS = 14;
|
||||
constexpr int LCD_DC = 15;
|
||||
constexpr int LCD_RST = 21;
|
||||
constexpr int LCD_BL = 22;
|
||||
constexpr int LCD_WIDTH = 172;
|
||||
constexpr int LCD_HEIGHT = 320;
|
||||
constexpr int LCD_X_OFFSET = 34;
|
||||
constexpr int LCD_Y_OFFSET = 0;
|
||||
```
|
||||
|
||||
对应官方参数:
|
||||
|
||||
```text
|
||||
MOSI GPIO6
|
||||
SCLK GPIO7
|
||||
CS GPIO14
|
||||
DC GPIO15
|
||||
RST GPIO21
|
||||
BL GPIO22
|
||||
LCD ST7789
|
||||
Size 172 x 320
|
||||
Offset X = 34
|
||||
```
|
||||
|
||||
## 六、适配不同 ESP32 型号或不同屏幕
|
||||
|
||||
适配其他 ESP32 板子时,主要改 4 类东西:
|
||||
|
||||
1. 开发板型号
|
||||
2. LCD 引脚
|
||||
3. LCD 驱动型号
|
||||
4. 分辨率、偏移和旋转方向
|
||||
|
||||
### 1. 修改开发板型号
|
||||
|
||||
在 Arduino IDE 选择与你硬件匹配的板型,例如:
|
||||
|
||||
```text
|
||||
ESP32 Dev Module
|
||||
ESP32-S3 Dev Module
|
||||
ESP32-C3 Dev Module
|
||||
ESP32-C6 Dev Module
|
||||
ESP32C6 Dev Module
|
||||
```
|
||||
|
||||
如果屏幕驱动和引脚都正确,但一直黑屏,优先确认板型是否选错。
|
||||
|
||||
### 2. 修改 LCD 引脚
|
||||
|
||||
打开 [gfx.cpp](gfx.cpp),修改:
|
||||
|
||||
```cpp
|
||||
constexpr int LCD_MOSI = 6;
|
||||
constexpr int LCD_SCLK = 7;
|
||||
constexpr int LCD_CS = 14;
|
||||
constexpr int LCD_DC = 15;
|
||||
constexpr int LCD_RST = 21;
|
||||
constexpr int LCD_BL = 22;
|
||||
```
|
||||
|
||||
不同开发板的屏幕接线不同,必须按实际原理图或商家 Wiki 修改。
|
||||
|
||||
如果你的屏幕没有背光控制脚,可以把:
|
||||
|
||||
```cpp
|
||||
constexpr int LCD_BL = 22;
|
||||
```
|
||||
|
||||
改成实际背光脚,或者在 `gfx_init()` 中去掉:
|
||||
|
||||
```cpp
|
||||
pinMode(LCD_BL, OUTPUT);
|
||||
digitalWrite(LCD_BL, HIGH);
|
||||
```
|
||||
|
||||
### 3. 修改屏幕分辨率和偏移
|
||||
|
||||
仍然在 [gfx.cpp](gfx.cpp) 修改:
|
||||
|
||||
```cpp
|
||||
constexpr int LCD_WIDTH = 172;
|
||||
constexpr int LCD_HEIGHT = 320;
|
||||
constexpr int LCD_X_OFFSET = 34;
|
||||
constexpr int LCD_Y_OFFSET = 0;
|
||||
```
|
||||
|
||||
常见 ST7789 屏幕参数示例:
|
||||
|
||||
```text
|
||||
240 x 240: offset 0, 0 或 0, 80
|
||||
240 x 320: offset 0, 0
|
||||
172 x 320: offset 34, 0
|
||||
170 x 320: offset 35, 0
|
||||
```
|
||||
|
||||
偏移不对时,常见现象:
|
||||
|
||||
- 画面偏移
|
||||
- 画面只显示一部分
|
||||
- 边缘有彩条
|
||||
- 屏幕亮但内容不在可见区域
|
||||
|
||||
### 4. 修改 LCD 驱动类型
|
||||
|
||||
当前使用:
|
||||
|
||||
```cpp
|
||||
Arduino_GFX *gfx = new Arduino_ST7789(...);
|
||||
```
|
||||
|
||||
如果你的屏幕不是 ST7789,需要换成对应驱动。例如:
|
||||
|
||||
```cpp
|
||||
Arduino_GFX *gfx = new Arduino_ILI9341(...);
|
||||
Arduino_GFX *gfx = new Arduino_GC9A01(...);
|
||||
Arduino_GFX *gfx = new Arduino_ST7735(...);
|
||||
```
|
||||
|
||||
具体支持哪些驱动,请查看 `GFX Library for Arduino` 文档或示例。
|
||||
|
||||
### 5. 修改 SPI 总线
|
||||
|
||||
当前使用:
|
||||
|
||||
```cpp
|
||||
Arduino_DataBus *bus = new Arduino_ESP32SPI(
|
||||
LCD_DC, LCD_CS, LCD_SCLK, LCD_MOSI, GFX_NOT_DEFINED
|
||||
);
|
||||
```
|
||||
|
||||
大多数 ESP32 SPI 屏幕都可以这样使用。
|
||||
|
||||
如果你的屏幕需要 MISO,可以把最后一个参数改成实际 MISO 引脚:
|
||||
|
||||
```cpp
|
||||
Arduino_DataBus *bus = new Arduino_ESP32SPI(
|
||||
LCD_DC, LCD_CS, LCD_SCLK, LCD_MOSI, LCD_MISO
|
||||
);
|
||||
```
|
||||
|
||||
### 6. 修改 UI 分辨率
|
||||
|
||||
当前 UI 按 `172 x 320` 竖屏设计:
|
||||
|
||||
```cpp
|
||||
disp_drv.hor_res = 172;
|
||||
disp_drv.ver_res = 320;
|
||||
```
|
||||
|
||||
如果屏幕分辨率不同,需要在 [ui.cpp](ui.cpp) 里同步修改:
|
||||
|
||||
```cpp
|
||||
static lv_color_t buf[172 * 40];
|
||||
disp_drv.hor_res = 172;
|
||||
disp_drv.ver_res = 320;
|
||||
```
|
||||
|
||||
例如 240 x 320 竖屏:
|
||||
|
||||
```cpp
|
||||
static lv_color_t buf[240 * 40];
|
||||
disp_drv.hor_res = 240;
|
||||
disp_drv.ver_res = 320;
|
||||
```
|
||||
|
||||
如果改成横屏,还需要重新调整 `ui.cpp` 里的控件坐标和宽高。
|
||||
|
||||
## 七、OpenWrt 接口字段说明
|
||||
|
||||
ESP32 当前支持以下字段:
|
||||
|
||||
```json
|
||||
{
|
||||
"load": 0.08,
|
||||
"mem": 42,
|
||||
"temp": 48,
|
||||
"uptime": 123456,
|
||||
"time": "14:30:08",
|
||||
"rx": 123456789,
|
||||
"tx": 987654321,
|
||||
"rx_speed": 2048,
|
||||
"tx_speed": 1024,
|
||||
"lan_ip": "192.168.7.1",
|
||||
"public_ip": "1.2.3.4"
|
||||
}
|
||||
```
|
||||
|
||||
也兼容这些旧字段:
|
||||
|
||||
```json
|
||||
{
|
||||
"cpu_load": 0.08,
|
||||
"mem_percent": 42,
|
||||
"cpu_temp": 48
|
||||
}
|
||||
```
|
||||
|
||||
字段说明:
|
||||
|
||||
```text
|
||||
load CPU load,浮点数
|
||||
mem 内存占用百分比,0-100
|
||||
temp CPU 温度,摄氏度
|
||||
uptime OpenWrt 运行时间,单位秒
|
||||
time OpenWrt 当前时间,建议 HH:MM:SS
|
||||
rx 网卡累计接收字节数
|
||||
tx 网卡累计发送字节数
|
||||
rx_speed 接收速度,Byte/s
|
||||
tx_speed 发送速度,Byte/s
|
||||
lan_ip 内网 IP
|
||||
public_ip 公网 IP
|
||||
```
|
||||
|
||||
## 八、修改监控网卡
|
||||
|
||||
OpenWrt 脚本默认监控:
|
||||
|
||||
```sh
|
||||
IFACE="${IFACE:-br-lan}"
|
||||
```
|
||||
|
||||
如果你要监控 WAN 口、PPPoE 或其他接口,可以改成实际网卡名,例如:
|
||||
|
||||
```sh
|
||||
IFACE="${IFACE:-pppoe-wan}"
|
||||
```
|
||||
|
||||
查看网卡:
|
||||
|
||||
```sh
|
||||
ip link
|
||||
```
|
||||
|
||||
也可以临时用环境变量运行:
|
||||
|
||||
```sh
|
||||
IFACE=pppoe-wan /www/cgi-bin/status.json
|
||||
```
|
||||
|
||||
## 九、常见问题
|
||||
|
||||
### 1. 屏幕完全不亮
|
||||
|
||||
优先检查:
|
||||
|
||||
- `LCD_BL` 背光引脚是否正确
|
||||
- `LCD_CS`、`LCD_DC`、`LCD_RST` 是否正确
|
||||
- 开发板型号是否选对
|
||||
- USB 供电是否稳定
|
||||
|
||||
当前默认背光是:
|
||||
|
||||
```cpp
|
||||
pinMode(LCD_BL, OUTPUT);
|
||||
digitalWrite(LCD_BL, HIGH);
|
||||
```
|
||||
|
||||
如果你的屏幕背光是低电平点亮,需要改成:
|
||||
|
||||
```cpp
|
||||
digitalWrite(LCD_BL, LOW);
|
||||
```
|
||||
|
||||
### 2. 屏幕亮,但没有内容
|
||||
|
||||
可能原因:
|
||||
|
||||
- ST7789 偏移参数不对
|
||||
- 分辨率不对
|
||||
- SPI 引脚不对
|
||||
- 屏幕驱动型号不对
|
||||
|
||||
重点检查 [gfx.cpp](gfx.cpp) 中的:
|
||||
|
||||
```cpp
|
||||
LCD_WIDTH
|
||||
LCD_HEIGHT
|
||||
LCD_X_OFFSET
|
||||
LCD_Y_OFFSET
|
||||
Arduino_ST7789
|
||||
```
|
||||
|
||||
### 3. 一直显示空数据或网速为 0
|
||||
|
||||
先在浏览器打开:
|
||||
|
||||
```text
|
||||
http://你的路由器IP/cgi-bin/status.json
|
||||
```
|
||||
|
||||
确认 JSON 是否正常返回。
|
||||
|
||||
如果网页打不开:
|
||||
|
||||
- CGI 脚本没有执行权限
|
||||
- 路径不对
|
||||
- OpenWrt 没启用 uhttpd CGI
|
||||
- ESP32 和 OpenWrt 不在同一网络
|
||||
|
||||
### 4. 公网 IP 显示为空
|
||||
|
||||
脚本会访问:
|
||||
|
||||
```text
|
||||
http://api.ipify.org
|
||||
```
|
||||
|
||||
如果路由器不能访问外网,公网 IP 会回退为 WAN IP。某些内网、多级 NAT、旁路由环境下,公网 IP 和 WAN IP 可能不同。
|
||||
|
||||
### 5. 时间显示不对
|
||||
|
||||
底部时间优先显示 OpenWrt 的:
|
||||
|
||||
```sh
|
||||
date '+%H:%M:%S'
|
||||
```
|
||||
|
||||
如果时间不对,请先修正 OpenWrt 时间同步:
|
||||
|
||||
```sh
|
||||
date
|
||||
```
|
||||
|
||||
或者检查 OpenWrt 的 NTP 设置。
|
||||
|
||||
### 6. 上传失败
|
||||
|
||||
ESP32-C6 有时需要手动进入下载模式:
|
||||
|
||||
1. 按住 `BOOT`
|
||||
2. 点一下 `RESET`
|
||||
3. 松开 `BOOT`
|
||||
4. 点击 Arduino IDE 上传
|
||||
5. 上传完成后再按一下 `RESET`
|
||||
|
||||
## 十、交付客户前建议
|
||||
|
||||
交付给客户前,建议确认:
|
||||
|
||||
- [ ] Wi-Fi 名称和密码已经改成客户环境
|
||||
- [ ] `OPENWRT_URL` 是客户路由器地址
|
||||
- [ ] OpenWrt 脚本已经部署并能浏览器访问
|
||||
- [ ] 屏幕能正常点亮
|
||||
- [ ] CPU/RAM/TEMP/UP 有数据
|
||||
- [ ] RX/TX 网速会变化
|
||||
- [ ] LAN/PUB IP 正常
|
||||
- [ ] 底部时间与 OpenWrt 时间一致
|
||||
|
||||
## 十一、安全提醒
|
||||
|
||||
当前 [config.h](config.h) 中会明文保存 Wi-Fi 密码。公开代码或交付第三方前,建议删除真实密码,改成占位内容:
|
||||
|
||||
```cpp
|
||||
#define WIFI_SSID "YOUR_WIFI"
|
||||
#define WIFI_PASS "YOUR_PASSWORD"
|
||||
```
|
||||
|
||||
OpenWrt 的 `status.json` 接口默认没有鉴权,建议只在内网使用,不要暴露到公网。
|
||||
@@ -0,0 +1,5 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2026, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#include "src/ArduinoJson.h"
|
||||
@@ -0,0 +1,262 @@
|
||||
ArduinoJson: change log
|
||||
=======================
|
||||
|
||||
v7.4.3 (2026-03-02)
|
||||
------
|
||||
|
||||
* Fix a buffer overrun in `as<T>()` when `T` is a numeric type and
|
||||
the variant contains a string representing a floating point number
|
||||
with a large number of digits (issue #2220)
|
||||
|
||||
v7.4.2 (2025-06-20)
|
||||
------
|
||||
|
||||
* Fix truncated strings on Arduino Due (issue #2181)
|
||||
|
||||
v7.4.1 (2025-04-11)
|
||||
------
|
||||
|
||||
* Fix crash with tiny Flash strings (issue #2170)
|
||||
|
||||
v7.4.0 (2025-04-09)
|
||||
------
|
||||
|
||||
* Optimize storage of tiny strings (up to 3 characters)
|
||||
* Fix support for `const char[]` (issue #2166)
|
||||
|
||||
v7.3.1 (2025-02-27)
|
||||
------
|
||||
|
||||
* Fix conversion from static string to number
|
||||
* Slightly reduce code size
|
||||
|
||||
v7.3.0 (2024-12-29)
|
||||
------
|
||||
|
||||
* Fix support for NUL characters in `deserializeJson()`
|
||||
* Make `ElementProxy` and `MemberProxy` non-copyable
|
||||
* Change string copy policy: only string literal are stored by pointer
|
||||
* `JsonString` is now stored by copy, unless specified otherwise
|
||||
* Replace undocumented `JsonString::Ownership` with `bool`
|
||||
* Rename undocumented `JsonString::isLinked()` to `isStatic()`
|
||||
* Move public facing SFINAEs to template declarations
|
||||
|
||||
> ### BREAKING CHANGES
|
||||
>
|
||||
> In previous versions, `MemberProxy` (the class returned by `operator[]`) could lead to dangling pointers when used with a temporary string.
|
||||
> To prevent this issue, `MemberProxy` and `ElementProxy` are now non-copyable.
|
||||
>
|
||||
> Your code is likely to be affected if you use `auto` to store the result of `operator[]`. For example, the following line won't compile anymore:
|
||||
>
|
||||
> ```cpp
|
||||
> auto value = doc["key"];
|
||||
> ```
|
||||
>
|
||||
> To fix the issue, you must append either `.as<T>()` or `.to<T>()`, depending on the situation.
|
||||
>
|
||||
> For example, if you are extracting values from a JSON document, you should update like this:
|
||||
>
|
||||
> ```diff
|
||||
> - auto config = doc["config"];
|
||||
> + auto config = doc["config"].as<JsonObject>();
|
||||
> const char* name = config["name"];
|
||||
> ```
|
||||
>
|
||||
> However, if you are building a JSON document, you should update like this:
|
||||
>
|
||||
> ```diff
|
||||
> - auto config = doc["config"];
|
||||
> + auto config = doc["config"].to<JsonObject>();
|
||||
> config["name"] = "ArduinoJson";
|
||||
> ```
|
||||
|
||||
v7.2.1 (2024-11-15)
|
||||
------
|
||||
|
||||
* Forbid `deserializeJson(JsonArray|JsonObject, ...)` (issue #2135)
|
||||
* Fix VLA support in `JsonDocument::set()`
|
||||
* Fix `operator[](variant)` ignoring NUL characters
|
||||
|
||||
v7.2.0 (2024-09-18)
|
||||
------
|
||||
|
||||
* Store object members with two slots: one for the key and one for the value
|
||||
* Store 64-bit numbers (`double` and `long long`) in an additional slot
|
||||
* Reduce the slot size (see table below)
|
||||
* Improve message when user forgets third arg of `serializeJson()` et al.
|
||||
* Set `ARDUINOJSON_USE_DOUBLE` to `0` by default on 8-bit architectures
|
||||
* Deprecate `containsKey()` in favor of `doc["key"].is<T>()`
|
||||
* Add support for escape sequence `\'` (issue #2124)
|
||||
|
||||
| Architecture | before | after |
|
||||
|--------------|----------|----------|
|
||||
| 8-bit | 8 bytes | 6 bytes |
|
||||
| 32-bit | 16 bytes | 8 bytes |
|
||||
| 64-bit | 24 bytes | 16 bytes |
|
||||
|
||||
> ### BREAKING CHANGES
|
||||
>
|
||||
> After being on the death row for years, the `containsKey()` method has finally been deprecated.
|
||||
> You should replace `doc.containsKey("key")` with `doc["key"].is<T>()`, which not only checks that the key exists but also that the value is of the expected type.
|
||||
>
|
||||
> ```cpp
|
||||
> // Before
|
||||
> if (doc.containsKey("value")) {
|
||||
> int value = doc["value"];
|
||||
> // ...
|
||||
> }
|
||||
>
|
||||
> // After
|
||||
> if (doc["value"].is<int>()) {
|
||||
> int value = doc["value"];
|
||||
> // ...
|
||||
> }
|
||||
> ```
|
||||
|
||||
v7.1.0 (2024-06-27)
|
||||
------
|
||||
|
||||
* Add `ARDUINOJSON_STRING_LENGTH_SIZE` to the namespace name
|
||||
* Add support for MsgPack binary (PR #2078 by @Sanae6)
|
||||
* Add support for MsgPack extension
|
||||
* Make string support even more generic (PR #2084 by @d-a-v)
|
||||
* Optimize `deserializeMsgPack()`
|
||||
* Allow using a `JsonVariant` as a key or index (issue #2080)
|
||||
Note: works only for reading, not for writing
|
||||
* Support `ElementProxy` and `MemberProxy` in `JsonDocument`'s constructor
|
||||
* Don't add partial objects when allocation fails (issue #2081)
|
||||
* Read MsgPack's 64-bit integers even if `ARDUINOJSON_USE_LONG_LONG` is `0`
|
||||
(they are set to `null` if they don't fit in a `long`)
|
||||
|
||||
v7.0.4 (2024-03-12)
|
||||
------
|
||||
|
||||
* Make `JSON_STRING_SIZE(N)` return `N+1` to fix third-party code (issue #2054)
|
||||
|
||||
v7.0.3 (2024-02-05)
|
||||
------
|
||||
|
||||
* Improve error messages when using `char` or `char*` (issue #2043)
|
||||
* Reduce stack consumption (issue #2046)
|
||||
* Fix compatibility with GCC 4.8 (issue #2045)
|
||||
|
||||
v7.0.2 (2024-01-19)
|
||||
------
|
||||
|
||||
* Fix assertion `poolIndex < count_` after `JsonDocument::clear()` (issue #2034)
|
||||
|
||||
v7.0.1 (2024-01-10)
|
||||
------
|
||||
|
||||
* Fix "no matching function" with `JsonObjectConst::operator[]` (issue #2019)
|
||||
* Remove unused files in the PlatformIO package
|
||||
* Fix `volatile bool` serialized as `1` or `0` instead of `true` or `false` (issue #2029)
|
||||
|
||||
v7.0.0 (2024-01-03)
|
||||
------
|
||||
|
||||
* Remove `BasicJsonDocument`
|
||||
* Remove `StaticJsonDocument`
|
||||
* Add abstract `Allocator` class
|
||||
* Merge `DynamicJsonDocument` with `JsonDocument`
|
||||
* Remove `JSON_ARRAY_SIZE()`, `JSON_OBJECT_SIZE()`, and `JSON_STRING_SIZE()`
|
||||
* Remove `ARDUINOJSON_ENABLE_STRING_DEDUPLICATION` (string deduplication cannot be disabled anymore)
|
||||
* Remove `JsonDocument::capacity()`
|
||||
* Store the strings in the heap
|
||||
* Reference-count shared strings
|
||||
* Always store `serialized("string")` by copy (#1915)
|
||||
* Remove the zero-copy mode of `deserializeJson()` and `deserializeMsgPack()`
|
||||
* Fix double lookup in `to<JsonVariant>()`
|
||||
* Fix double call to `size()` in `serializeMsgPack()`
|
||||
* Include `ARDUINOJSON_SLOT_OFFSET_SIZE` in the namespace name
|
||||
* Remove `JsonVariant::shallowCopy()`
|
||||
* `JsonDocument`'s capacity grows as needed, no need to pass it to the constructor anymore
|
||||
* `JsonDocument`'s allocator is not monotonic anymore, removed values get recycled
|
||||
* Show a link to the documentation when user passes an unsupported input type
|
||||
* Remove `JsonDocument::memoryUsage()`
|
||||
* Remove `JsonDocument::garbageCollect()`
|
||||
* Add `deserializeJson(JsonVariant, ...)` and `deserializeMsgPack(JsonVariant, ...)` (#1226)
|
||||
* Call `shrinkToFit()` in `deserializeJson()` and `deserializeMsgPack()`
|
||||
* `serializeJson()` and `serializeMsgPack()` replace the content of `std::string` and `String` instead of appending to it
|
||||
* Replace `add()` with `add<T>()` (`add(T)` is still supported)
|
||||
* Remove `createNestedArray()` and `createNestedObject()` (use `to<JsonArray>()` and `to<JsonObject>()` instead)
|
||||
|
||||
> ### BREAKING CHANGES
|
||||
>
|
||||
> As every major release, ArduinoJson 7 introduces several breaking changes.
|
||||
> I added some stubs so that most existing programs should compile, but I highty recommend you upgrade your code.
|
||||
>
|
||||
> #### `JsonDocument`
|
||||
>
|
||||
> In ArduinoJson 6, you could allocate the memory pool on the stack (with `StaticJsonDocument`) or in the heap (with `DynamicJsonDocument`).
|
||||
> In ArduinoJson 7, the memory pool is always allocated in the heap, so `StaticJsonDocument` and `DynamicJsonDocument` have been merged into `JsonDocument`.
|
||||
>
|
||||
> In ArduinoJson 6, `JsonDocument` had a fixed capacity; in ArduinoJson 7, it has an elastic capacity that grows as needed.
|
||||
> Therefore, you don't need to specify the capacity anymore, so the macros `JSON_ARRAY_SIZE()`, `JSON_OBJECT_SIZE()`, and `JSON_STRING_SIZE()` have been removed.
|
||||
>
|
||||
> ```c++
|
||||
> // ArduinoJson 6
|
||||
> StaticJsonDocument<256> doc;
|
||||
> // or
|
||||
> DynamicJsonDocument doc(256);
|
||||
>
|
||||
> // ArduinoJson 7
|
||||
> JsonDocument doc;
|
||||
> ```
|
||||
>
|
||||
> In ArduinoJson 7, `JsonDocument` reuses released memory, so `garbageCollect()` has been removed.
|
||||
> `shrinkToFit()` is still available and releases the over-allocated memory.
|
||||
>
|
||||
> Due to a change in the implementation, it's not possible to store a pointer to a variant from another `JsonDocument`, so `shallowCopy()` has been removed.
|
||||
>
|
||||
> In ArduinoJson 6, the meaning of `memoryUsage()` was clear: it returned the number of bytes used in the memory pool.
|
||||
> In ArduinoJson 7, the meaning of `memoryUsage()` would be ambiguous, so it has been removed.
|
||||
>
|
||||
> #### Custom allocators
|
||||
>
|
||||
> In ArduinoJson 6, you could specify a custom allocator class as a template parameter of `BasicJsonDocument`.
|
||||
> In ArduinoJson 7, you must inherit from `ArduinoJson::Allocator` and pass a pointer to an instance of your class to the constructor of `JsonDocument`.
|
||||
>
|
||||
> ```c++
|
||||
> // ArduinoJson 6
|
||||
> class MyAllocator {
|
||||
> // ...
|
||||
> };
|
||||
> BasicJsonDocument<MyAllocator> doc(256);
|
||||
>
|
||||
> // ArduinoJson 7
|
||||
> class MyAllocator : public ArduinoJson::Allocator {
|
||||
> // ...
|
||||
> };
|
||||
> MyAllocator myAllocator;
|
||||
> JsonDocument doc(&myAllocator);
|
||||
> ```
|
||||
>
|
||||
> #### `createNestedArray()` and `createNestedObject()`
|
||||
>
|
||||
> In ArduinoJson 6, you could create a nested array or object with `createNestedArray()` and `createNestedObject()`.
|
||||
> In ArduinoJson 7, you must use `add<T>()` or `to<T>()` instead.
|
||||
>
|
||||
> For example, to create `[[],{}]`, you would write:
|
||||
>
|
||||
> ```c++
|
||||
> // ArduinoJson 6
|
||||
> arr.createNestedArray();
|
||||
> arr.createNestedObject();
|
||||
>
|
||||
> // ArduinoJson 7
|
||||
> arr.add<JsonArray>();
|
||||
> arr.add<JsonObject>();
|
||||
> ```
|
||||
>
|
||||
> And to create `{"array":[],"object":{}}`, you would write:
|
||||
>
|
||||
> ```c++
|
||||
> // ArduinoJson 6
|
||||
> obj.createNestedArray("array");
|
||||
> obj.createNestedObject("object");
|
||||
>
|
||||
> // ArduinoJson 7
|
||||
> obj["array"].to<JsonArray>();
|
||||
> obj["object"].to<JsonObject>();
|
||||
> ```
|
||||
@@ -0,0 +1,25 @@
|
||||
# ArduinoJson - https://arduinojson.org
|
||||
# Copyright © 2014-2026, Benoit BLANCHON
|
||||
# MIT License
|
||||
|
||||
cmake_minimum_required(VERSION 3.15)
|
||||
|
||||
if(ESP_PLATFORM)
|
||||
# Build ArduinoJson as an ESP-IDF component
|
||||
idf_component_register(INCLUDE_DIRS src)
|
||||
return()
|
||||
endif()
|
||||
|
||||
project(ArduinoJson VERSION 7.4.3)
|
||||
|
||||
if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME)
|
||||
include(CTest)
|
||||
endif()
|
||||
|
||||
add_subdirectory(src)
|
||||
|
||||
if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME AND BUILD_TESTING)
|
||||
include(extras/CompileOptions.cmake)
|
||||
add_subdirectory(extras/tests)
|
||||
add_subdirectory(extras/fuzzing)
|
||||
endif()
|
||||
@@ -0,0 +1,10 @@
|
||||
# Contribution to ArduinoJson
|
||||
|
||||
First, thank you for taking the time to contribute to this project.
|
||||
|
||||
You can submit changes via GitHub Pull Requests.
|
||||
|
||||
Please:
|
||||
|
||||
1. Update the test suite for any change of behavior
|
||||
2. Use clang-format in "file" mode to format the code
|
||||
@@ -0,0 +1,10 @@
|
||||
The MIT License (MIT)
|
||||
---------------------
|
||||
|
||||
Copyright © 2014-2026, Benoit BLANCHON
|
||||
|
||||
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.
|
||||
|
||||
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
@@ -0,0 +1,153 @@
|
||||
<p align="center">
|
||||
<a href="https://arduinojson.org/"><img alt="ArduinoJson" src="https://arduinojson.org/images/logo.svg" width="200" /></a>
|
||||
</p>
|
||||
|
||||
---
|
||||
|
||||
[](https://github.com/bblanchon/ArduinoJson/actions?query=workflow%3A%22Continuous+Integration%22+branch%3A7.x)
|
||||
[](https://ci.appveyor.com/project/bblanchon/arduinojson/branch/7.x)
|
||||
[](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:arduinojson)
|
||||
[](https://coveralls.io/github/bblanchon/ArduinoJson?branch=7.x)
|
||||
[](https://github.com/bblanchon/ArduinoJson/stargazers)
|
||||
[](https://github.com/sponsors/bblanchon)
|
||||
|
||||
ArduinoJson is a C++ JSON library for Arduino and IoT (Internet Of Things).
|
||||
|
||||
## Features
|
||||
|
||||
* [JSON deserialization](https://arduinojson.org/v7/api/json/deserializejson/)
|
||||
* [Optionally decodes UTF-16 escape sequences to UTF-8](https://arduinojson.org/v7/api/config/decode_unicode/)
|
||||
* [Optionally supports comments in the input](https://arduinojson.org/v7/api/config/enable_comments/)
|
||||
* [Optionally filters the input to keep only desired values](https://arduinojson.org/v7/api/json/deserializejson/#filtering)
|
||||
* Supports single quotes as a string delimiter
|
||||
* Compatible with [NDJSON](http://ndjson.org/) and [JSON Lines](https://jsonlines.org/)
|
||||
* [JSON serialization](https://arduinojson.org/v7/api/json/serializejson/)
|
||||
* [Can write to a buffer or a stream](https://arduinojson.org/v7/api/json/serializejson/)
|
||||
* [Optionally indents the document (prettified JSON)](https://arduinojson.org/v7/api/json/serializejsonpretty/)
|
||||
* [MessagePack serialization](https://arduinojson.org/v7/api/msgpack/serializemsgpack/)
|
||||
* [MessagePack deserialization](https://arduinojson.org/v7/api/msgpack/deserializemsgpack/)
|
||||
* Efficient
|
||||
* [Twice smaller than the "official" Arduino_JSON library](https://arduinojson.org/2019/11/19/arduinojson-vs-arduino_json/)
|
||||
* [Almost 10% faster than the "official" Arduino_JSON library](https://arduinojson.org/2019/11/19/arduinojson-vs-arduino_json/)
|
||||
* [Consumes roughly 10% less RAM than the "official" Arduino_JSON library](https://arduinojson.org/2019/11/19/arduinojson-vs-arduino_json/)
|
||||
* [Deduplicates strings](https://arduinojson.org/news/2020/08/01/version-6-16-0/)
|
||||
* Versatile
|
||||
* Supports [custom allocators (to use external RAM chip, for example)](https://arduinojson.org/v7/how-to/use-external-ram-on-esp32/)
|
||||
* Supports [`String`](https://arduinojson.org/v7/api/config/enable_arduino_string/), [`std::string`](https://arduinojson.org/v7/api/config/enable_std_string/), and [`std::string_view`](https://arduinojson.org/v7/api/config/enable_string_view/)
|
||||
* Supports [`Stream`](https://arduinojson.org/v7/api/config/enable_arduino_stream/) and [`std::istream`/`std::ostream`](https://arduinojson.org/v7/api/config/enable_std_stream/)
|
||||
* Supports [Flash strings](https://arduinojson.org/v7/api/config/enable_progmem/)
|
||||
* Supports [custom readers](https://arduinojson.org/v7/api/json/deserializejson/#custom-reader) and [custom writers](https://arduinojson.org/v7/api/json/serializejson/#custom-writer)
|
||||
* Supports [custom converters](https://arduinojson.org/news/2021/05/04/version-6-18-0/)
|
||||
* Portable
|
||||
* Usable on any C++ project (not limited to Arduino)
|
||||
* Compatible with C++11, C++14 and C++17
|
||||
* Support for C++98/C++03 available on [ArduinoJson 6.20.x](https://github.com/bblanchon/ArduinoJson/tree/6.20.x)
|
||||
* Zero warnings with `-Wall -Wextra -pedantic` and `/W4`
|
||||
* [Header-only library](https://en.wikipedia.org/wiki/Header-only)
|
||||
* Works with virtually any board
|
||||
* Arduino boards: [Uno](https://amzn.to/38aL2ik), [Due](https://amzn.to/36YkWi2), [Micro](https://amzn.to/35WkdwG), [Nano](https://amzn.to/2QTvwRX), [Mega](https://amzn.to/36XWhuf), [Yun](https://amzn.to/30odURc), [Leonardo](https://amzn.to/36XWjlR)...
|
||||
* Espressif chips: [ESP8266](https://amzn.to/36YluV8), [ESP32](https://amzn.to/2G4pRCB)
|
||||
* Lolin (WeMos) boards: [D1 mini](https://amzn.to/2QUpz7q), [D1 Mini Pro](https://amzn.to/36UsGSs)...
|
||||
* Teensy boards: [4.0](https://amzn.to/30ljXGq), [3.2](https://amzn.to/2FT0EuC), [2.0](https://amzn.to/2QXUMXj)
|
||||
* Particle boards: [Argon](https://amzn.to/2FQHa9X), [Boron](https://amzn.to/36WgLUd), [Electron](https://amzn.to/30vEc4k), [Photon](https://amzn.to/387F9Cd)...
|
||||
* Texas Instruments boards: [MSP430](https://amzn.to/30nJWgg)...
|
||||
* Soft cores: [Nios II](https://en.wikipedia.org/wiki/Nios_II)...
|
||||
* Tested on all major development environments
|
||||
* [Arduino IDE](https://www.arduino.cc/en/Main/Software)
|
||||
* [Atmel Studio](http://www.atmel.com/microsite/atmel-studio/)
|
||||
* [Atollic TrueSTUDIO](https://atollic.com/truestudio/)
|
||||
* [Energia](http://energia.nu/)
|
||||
* [IAR Embedded Workbench](https://www.iar.com/iar-embedded-workbench/)
|
||||
* [Keil uVision](http://www.keil.com/)
|
||||
* [MPLAB X IDE](http://www.microchip.com/mplab/mplab-x-ide)
|
||||
* [Particle](https://www.particle.io/)
|
||||
* [PlatformIO](http://platformio.org/)
|
||||
* [Sloeber plugin for Eclipse](https://eclipse.baeyens.it/)
|
||||
* [Visual Micro](http://www.visualmicro.com/)
|
||||
* [Visual Studio](https://www.visualstudio.com/)
|
||||
* [Even works with online compilers like wandbox.org](https://wandbox.org/permlink/RlZSKy17DjJ6HcdN)
|
||||
* [CMake friendly](https://arduinojson.org/v7/how-to/use-arduinojson-with-cmake/)
|
||||
* Well designed
|
||||
* [Elegant API](http://arduinojson.org/v7/example/)
|
||||
* [Thread-safe](https://en.wikipedia.org/wiki/Thread_safety)
|
||||
* Self-contained (no external dependency)
|
||||
* `const` friendly
|
||||
* [`for` friendly](https://arduinojson.org/v7/api/jsonobject/begin_end/)
|
||||
* [TMP friendly](https://en.wikipedia.org/wiki/Template_metaprogramming)
|
||||
* Handles [integer overflows](https://arduinojson.org/v7/api/jsonvariant/as/#integer-overflows)
|
||||
* Well tested
|
||||
* [Unit test coverage close to 100%](https://coveralls.io/github/bblanchon/ArduinoJson?branch=7.x)
|
||||
* Continuously tested on
|
||||
* [Visual Studio 2017, 2019, 2022](https://ci.appveyor.com/project/bblanchon/arduinojson/branch/7.x)
|
||||
* [GCC 4.8, 5, 6, 7, 8, 9, 10, 11, 12](https://github.com/bblanchon/ArduinoJson/actions?query=workflow%3A%22Continuous+Integration%22)
|
||||
* [Clang 7 to 19](https://github.com/bblanchon/ArduinoJson/actions?query=workflow%3A%22Continuous+Integration%22)
|
||||
* [Continuously fuzzed with Google OSS Fuzz](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:arduinojson)
|
||||
* Passes all default checks of [clang-tidy](https://releases.llvm.org/10.0.0/tools/clang/tools/extra/docs/clang-tidy/)
|
||||
* Well documented
|
||||
* [Tutorials](https://arduinojson.org/v7/doc/deserialization/)
|
||||
* [Examples](https://arduinojson.org/v7/example/)
|
||||
* [How-tos](https://arduinojson.org/v7/example/)
|
||||
* [FAQ](https://arduinojson.org/v7/faq/)
|
||||
* [Troubleshooter](https://arduinojson.org/v7/troubleshooter/)
|
||||
* [Book](https://arduinojson.org/book/)
|
||||
* [Changelog](CHANGELOG.md)
|
||||
* Vibrant user community
|
||||
* Most popular of all Arduino libraries on [GitHub](https://github.com/search?o=desc&q=arduino+library&s=stars&type=Repositories)
|
||||
* [Used in hundreds of projects](https://www.hackster.io/search?i=projects&q=arduinojson)
|
||||
* [Responsive support](https://github.com/bblanchon/ArduinoJson/issues?q=is%3Aissue+is%3Aclosed)
|
||||
|
||||
## Quickstart
|
||||
|
||||
### Deserialization
|
||||
|
||||
Here is a program that parses a JSON document with ArduinoJson.
|
||||
|
||||
```c++
|
||||
const char* json = "{\"sensor\":\"gps\",\"time\":1351824120,\"data\":[48.756080,2.302038]}";
|
||||
|
||||
JsonDocument doc;
|
||||
deserializeJson(doc, json);
|
||||
|
||||
const char* sensor = doc["sensor"];
|
||||
long time = doc["time"];
|
||||
double latitude = doc["data"][0];
|
||||
double longitude = doc["data"][1];
|
||||
```
|
||||
|
||||
See the [tutorial on arduinojson.org](https://arduinojson.org/v7/doc/deserialization/)
|
||||
|
||||
### Serialization
|
||||
|
||||
Here is a program that generates a JSON document with ArduinoJson:
|
||||
|
||||
```c++
|
||||
JsonDocument doc;
|
||||
|
||||
doc["sensor"] = "gps";
|
||||
doc["time"] = 1351824120;
|
||||
doc["data"][0] = 48.756080;
|
||||
doc["data"][1] = 2.302038;
|
||||
|
||||
serializeJson(doc, Serial);
|
||||
// This prints:
|
||||
// {"sensor":"gps","time":1351824120,"data":[48.756080,2.302038]}
|
||||
```
|
||||
|
||||
See the [tutorial on arduinojson.org](https://arduinojson.org/v7/doc/serialization/)
|
||||
|
||||
## Sponsors
|
||||
|
||||
ArduinoJson is thankful to its sponsors. Please give them a visit; they deserve it!
|
||||
|
||||
<p>
|
||||
<a href="https://github.com/1technophile" rel="sponsored">
|
||||
<img alt="1technophile" src="https://avatars.githubusercontent.com/u/12672732?s=40&v=4">
|
||||
</a>
|
||||
<a href="https://github.com/LArkema" rel="sponsored">
|
||||
<img alt="LArkema" src="https://avatars.githubusercontent.com/u/38381313?s=40&v=4">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
If you run a commercial project that embeds ArduinoJson, think about [sponsoring the library's development](https://github.com/sponsors/bblanchon): it ensures the code that your products rely on stays actively maintained. It can also give your project some exposure to the makers' community.
|
||||
|
||||
If you are an individual user and want to support the development (or give a sign of appreciation), consider purchasing the book [Mastering ArduinoJson](https://arduinojson.org/book/) ❤, or simply [cast a star](https://github.com/bblanchon/ArduinoJson/stargazers) ⭐.
|
||||
@@ -0,0 +1,27 @@
|
||||
# ArduinoJson Support
|
||||
|
||||
First off, thank you very much for using ArduinoJson.
|
||||
|
||||
We'll be very happy to help you, but first please read the following.
|
||||
|
||||
## Before asking for help
|
||||
|
||||
1. Read the [FAQ](https://arduinojson.org/faq/?utm_source=github&utm_medium=support)
|
||||
2. Search in the [API Reference](https://arduinojson.org/api/?utm_source=github&utm_medium=support)
|
||||
|
||||
If you did not find the answer, please create a [new issue on GitHub](https://github.com/bblanchon/ArduinoJson/issues/new).
|
||||
|
||||
It is OK to add a comment to a currently opened issue, but please avoid adding comments to a closed issue.
|
||||
|
||||
## Before hitting the Submit button
|
||||
|
||||
Please provide all the relevant information:
|
||||
|
||||
* Good title
|
||||
* Short description of the problem
|
||||
* Target platform
|
||||
* Compiler model and version
|
||||
* [MVCE](https://stackoverflow.com/help/mcve)
|
||||
* Compiler output
|
||||
|
||||
Good questions get fast answers!
|
||||
@@ -0,0 +1,28 @@
|
||||
version: 7.4.3.{build}
|
||||
environment:
|
||||
matrix:
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2022
|
||||
CMAKE_GENERATOR: Visual Studio 17 2022
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
|
||||
CMAKE_GENERATOR: Visual Studio 16 2019
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||
CMAKE_GENERATOR: Visual Studio 15 2017
|
||||
- CMAKE_GENERATOR: Ninja
|
||||
MINGW32: i686-6.3.0-posix-dwarf-rt_v5-rev1 # MinGW-w64 6.3.0 i686
|
||||
- CMAKE_GENERATOR: Ninja
|
||||
MINGW64: x86_64-6.3.0-posix-seh-rt_v5-rev1 # MinGW-w64 6.3.0 x86_64
|
||||
- CMAKE_GENERATOR: Ninja
|
||||
MINGW64: x86_64-7.3.0-posix-seh-rt_v5-rev0 # MinGW-w64 7.3.0 x86_64
|
||||
- CMAKE_GENERATOR: Ninja
|
||||
MINGW64: x86_64-8.1.0-posix-seh-rt_v6-rev0 # MinGW-w64 8.1.0 x86_64
|
||||
configuration: Debug
|
||||
before_build:
|
||||
- set PATH=%PATH:C:\Program Files\Git\usr\bin;=% # Workaround for CMake not wanting sh.exe on PATH for MinGW
|
||||
- if defined MINGW set PATH=C:\%MINGW%\bin;%PATH%
|
||||
- if defined MINGW32 set PATH=C:\mingw-w64\%MINGW32%\mingw32\bin;%PATH%
|
||||
- if defined MINGW64 set PATH=C:\mingw-w64\%MINGW64%\mingw64\bin;%PATH%
|
||||
- cmake -DCMAKE_BUILD_TYPE=%CONFIGURATION% -G "%CMAKE_GENERATOR%" .
|
||||
build_script:
|
||||
- cmake --build . --config %CONFIGURATION%
|
||||
test_script:
|
||||
- ctest -C %CONFIGURATION% --output-on-failure .
|
||||
@@ -0,0 +1 @@
|
||||
COMPONENT_ADD_INCLUDEDIRS := src
|
||||
@@ -0,0 +1,152 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2026, Benoit BLANCHON
|
||||
// MIT License
|
||||
//
|
||||
// This example shows how to store your project configuration in a file.
|
||||
// It uses the SD library but can be easily modified for any other file-system.
|
||||
//
|
||||
// The file contains a JSON document with the following content:
|
||||
// {
|
||||
// "hostname": "examples.com",
|
||||
// "port": 2731
|
||||
// }
|
||||
//
|
||||
// To run this program, you need an SD card connected to the SPI bus as follows:
|
||||
// * MOSI <-> pin 11
|
||||
// * MISO <-> pin 12
|
||||
// * CLK <-> pin 13
|
||||
// * CS <-> pin 4
|
||||
//
|
||||
// https://arduinojson.org/v7/example/config/
|
||||
|
||||
#include <ArduinoJson.h>
|
||||
#include <SD.h>
|
||||
#include <SPI.h>
|
||||
|
||||
// Our configuration structure.
|
||||
struct Config {
|
||||
char hostname[64];
|
||||
int port;
|
||||
};
|
||||
|
||||
const char* filename = "/config.txt"; // <- SD library uses 8.3 filenames
|
||||
Config config; // <- global configuration object
|
||||
|
||||
// Loads the configuration from a file
|
||||
void loadConfiguration(const char* filename, Config& config) {
|
||||
// Open file for reading
|
||||
File file = SD.open(filename);
|
||||
|
||||
// Allocate a temporary JsonDocument
|
||||
JsonDocument doc;
|
||||
|
||||
// Deserialize the JSON document
|
||||
DeserializationError error = deserializeJson(doc, file);
|
||||
if (error)
|
||||
Serial.println(F("Failed to read file, using default configuration"));
|
||||
|
||||
// Copy values from the JsonDocument to the Config
|
||||
config.port = doc["port"] | 2731;
|
||||
strlcpy(config.hostname, // <- destination
|
||||
doc["hostname"] | "example.com", // <- source
|
||||
sizeof(config.hostname)); // <- destination's capacity
|
||||
|
||||
// Close the file (Curiously, File's destructor doesn't close the file)
|
||||
file.close();
|
||||
}
|
||||
|
||||
// Saves the configuration to a file
|
||||
void saveConfiguration(const char* filename, const Config& config) {
|
||||
// Delete existing file, otherwise the configuration is appended to the file
|
||||
SD.remove(filename);
|
||||
|
||||
// Open file for writing
|
||||
File file = SD.open(filename, FILE_WRITE);
|
||||
if (!file) {
|
||||
Serial.println(F("Failed to create file"));
|
||||
return;
|
||||
}
|
||||
|
||||
// Allocate a temporary JsonDocument
|
||||
JsonDocument doc;
|
||||
|
||||
// Set the values in the document
|
||||
doc["hostname"] = config.hostname;
|
||||
doc["port"] = config.port;
|
||||
|
||||
// Serialize JSON to file
|
||||
if (serializeJson(doc, file) == 0) {
|
||||
Serial.println(F("Failed to write to file"));
|
||||
}
|
||||
|
||||
// Close the file
|
||||
file.close();
|
||||
}
|
||||
|
||||
// Prints the content of a file to the Serial
|
||||
void printFile(const char* filename) {
|
||||
// Open file for reading
|
||||
File file = SD.open(filename);
|
||||
if (!file) {
|
||||
Serial.println(F("Failed to read file"));
|
||||
return;
|
||||
}
|
||||
|
||||
// Extract each characters by one by one
|
||||
while (file.available()) {
|
||||
Serial.print((char)file.read());
|
||||
}
|
||||
Serial.println();
|
||||
|
||||
// Close the file
|
||||
file.close();
|
||||
}
|
||||
|
||||
void setup() {
|
||||
// Initialize serial port
|
||||
Serial.begin(9600);
|
||||
while (!Serial)
|
||||
continue;
|
||||
|
||||
// Initialize SD library
|
||||
const int chipSelect = 4;
|
||||
while (!SD.begin(chipSelect)) {
|
||||
Serial.println(F("Failed to initialize SD library"));
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
// Should load default config if run for the first time
|
||||
Serial.println(F("Loading configuration..."));
|
||||
loadConfiguration(filename, config);
|
||||
|
||||
// Create configuration file
|
||||
Serial.println(F("Saving configuration..."));
|
||||
saveConfiguration(filename, config);
|
||||
|
||||
// Dump config file
|
||||
Serial.println(F("Print config file..."));
|
||||
printFile(filename);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// not used in this example
|
||||
}
|
||||
|
||||
// Performance issue?
|
||||
// ------------------
|
||||
//
|
||||
// File is an unbuffered stream, which is not optimal for ArduinoJson.
|
||||
// See: https://arduinojson.org/v7/how-to/improve-speed/
|
||||
|
||||
// See also
|
||||
// --------
|
||||
//
|
||||
// https://arduinojson.org/ contains the documentation for all the functions
|
||||
// used above. It also includes an FAQ that will help you solve any
|
||||
// serialization or deserialization problem.
|
||||
//
|
||||
// The book "Mastering ArduinoJson" contains a case study of a project that has
|
||||
// a complex configuration with nested members.
|
||||
// Contrary to this example, the project in the book uses the SPIFFS filesystem.
|
||||
// Learn more at https://arduinojson.org/book/
|
||||
// Use the coupon code TWENTY for a 20% discount ❤❤❤❤❤
|
||||
@@ -0,0 +1,64 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2026, Benoit BLANCHON
|
||||
// MIT License
|
||||
//
|
||||
// This example shows how to use DeserializationOption::Filter
|
||||
//
|
||||
// https://arduinojson.org/v7/example/filter/
|
||||
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
void setup() {
|
||||
// Initialize serial port
|
||||
Serial.begin(9600);
|
||||
while (!Serial)
|
||||
continue;
|
||||
|
||||
// The huge input: an extract from OpenWeatherMap response
|
||||
auto input_json = F(
|
||||
"{\"cod\":\"200\",\"message\":0,\"list\":[{\"dt\":1581498000,\"main\":{"
|
||||
"\"temp\":3.23,\"feels_like\":-3.63,\"temp_min\":3.23,\"temp_max\":4.62,"
|
||||
"\"pressure\":1014,\"sea_level\":1014,\"grnd_level\":1010,\"humidity\":"
|
||||
"58,\"temp_kf\":-1.39},\"weather\":[{\"id\":800,\"main\":\"Clear\","
|
||||
"\"description\":\"clear "
|
||||
"sky\",\"icon\":\"01d\"}],\"clouds\":{\"all\":0},\"wind\":{\"speed\":6."
|
||||
"19,\"deg\":266},\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2020-02-12 "
|
||||
"09:00:00\"},{\"dt\":1581508800,\"main\":{\"temp\":6.09,\"feels_like\":-"
|
||||
"1.07,\"temp_min\":6.09,\"temp_max\":7.13,\"pressure\":1015,\"sea_"
|
||||
"level\":1015,\"grnd_level\":1011,\"humidity\":48,\"temp_kf\":-1.04},"
|
||||
"\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"clear "
|
||||
"sky\",\"icon\":\"01d\"}],\"clouds\":{\"all\":9},\"wind\":{\"speed\":6."
|
||||
"64,\"deg\":268},\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2020-02-12 "
|
||||
"12:00:00\"}],\"city\":{\"id\":2643743,\"name\":\"London\",\"coord\":{"
|
||||
"\"lat\":51.5085,\"lon\":-0.1257},\"country\":\"GB\",\"population\":"
|
||||
"1000000,\"timezone\":0,\"sunrise\":1581492085,\"sunset\":1581527294}}");
|
||||
|
||||
// The filter: it contains "true" for each value we want to keep
|
||||
JsonDocument filter;
|
||||
filter["list"][0]["dt"] = true;
|
||||
filter["list"][0]["main"]["temp"] = true;
|
||||
|
||||
// Deserialize the document
|
||||
JsonDocument doc;
|
||||
deserializeJson(doc, input_json, DeserializationOption::Filter(filter));
|
||||
|
||||
// Print the result
|
||||
serializeJsonPretty(doc, Serial);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// not used in this example
|
||||
}
|
||||
|
||||
// See also
|
||||
// --------
|
||||
//
|
||||
// https://arduinojson.org/ contains the documentation for all the functions
|
||||
// used above. It also includes an FAQ that will help you solve any
|
||||
// deserialization problem.
|
||||
//
|
||||
// The book "Mastering ArduinoJson" contains a tutorial on deserialization.
|
||||
// It begins with a simple example, like the one above, and then adds more
|
||||
// features like deserializing directly from a file or an HTTP request.
|
||||
// Learn more at https://arduinojson.org/book/
|
||||
// Use the coupon code TWENTY for a 20% discount ❤❤❤❤❤
|
||||
@@ -0,0 +1,65 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2026, Benoit BLANCHON
|
||||
// MIT License
|
||||
//
|
||||
// This example shows how to generate a JSON document with ArduinoJson.
|
||||
//
|
||||
// https://arduinojson.org/v7/example/generator/
|
||||
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
void setup() {
|
||||
// Initialize Serial port
|
||||
Serial.begin(9600);
|
||||
while (!Serial)
|
||||
continue;
|
||||
|
||||
// Allocate the JSON document
|
||||
JsonDocument doc;
|
||||
|
||||
// Add values in the document
|
||||
doc["sensor"] = "gps";
|
||||
doc["time"] = 1351824120;
|
||||
|
||||
// Add an array
|
||||
JsonArray data = doc["data"].to<JsonArray>();
|
||||
data.add(48.756080);
|
||||
data.add(2.302038);
|
||||
|
||||
// Generate the minified JSON and send it to the Serial port
|
||||
serializeJson(doc, Serial);
|
||||
// The above line prints:
|
||||
// {"sensor":"gps","time":1351824120,"data":[48.756080,2.302038]}
|
||||
|
||||
// Start a new line
|
||||
Serial.println();
|
||||
|
||||
// Generate the prettified JSON and send it to the Serial port
|
||||
serializeJsonPretty(doc, Serial);
|
||||
// The above line prints:
|
||||
// {
|
||||
// "sensor": "gps",
|
||||
// "time": 1351824120,
|
||||
// "data": [
|
||||
// 48.756080,
|
||||
// 2.302038
|
||||
// ]
|
||||
// }
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// not used in this example
|
||||
}
|
||||
|
||||
// See also
|
||||
// --------
|
||||
//
|
||||
// https://arduinojson.org/ contains the documentation for all the functions
|
||||
// used above. It also includes an FAQ that will help you solve any
|
||||
// serialization problem.
|
||||
//
|
||||
// The book "Mastering ArduinoJson" contains a tutorial on serialization.
|
||||
// It begins with a simple example, like the one above, and then adds more
|
||||
// features like serializing directly to a file or an HTTP request.
|
||||
// Learn more at https://arduinojson.org/book/
|
||||
// Use the coupon code TWENTY for a 20% discount ❤❤❤❤❤
|
||||
@@ -0,0 +1,125 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2026, Benoit BLANCHON
|
||||
// MIT License
|
||||
//
|
||||
// This example shows how to parse a JSON document in an HTTP response.
|
||||
// It uses the Ethernet library, but can be easily adapted for Wifi.
|
||||
//
|
||||
// It performs a GET resquest on https://arduinojson.org/example.json
|
||||
// Here is the expected response:
|
||||
// {
|
||||
// "sensor": "gps",
|
||||
// "time": 1351824120,
|
||||
// "data": [
|
||||
// 48.756080,
|
||||
// 2.302038
|
||||
// ]
|
||||
// }
|
||||
//
|
||||
// https://arduinojson.org/v7/example/http-client/
|
||||
|
||||
#include <ArduinoJson.h>
|
||||
#include <Ethernet.h>
|
||||
#include <SPI.h>
|
||||
|
||||
void setup() {
|
||||
// Initialize Serial port
|
||||
Serial.begin(9600);
|
||||
while (!Serial)
|
||||
continue;
|
||||
|
||||
// Initialize Ethernet library
|
||||
byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
|
||||
if (!Ethernet.begin(mac)) {
|
||||
Serial.println(F("Failed to configure Ethernet"));
|
||||
return;
|
||||
}
|
||||
delay(1000);
|
||||
|
||||
Serial.println(F("Connecting..."));
|
||||
|
||||
// Connect to HTTP server
|
||||
EthernetClient client;
|
||||
client.setTimeout(10000);
|
||||
if (!client.connect("arduinojson.org", 80)) {
|
||||
Serial.println(F("Connection failed"));
|
||||
return;
|
||||
}
|
||||
|
||||
Serial.println(F("Connected!"));
|
||||
|
||||
// Send HTTP request
|
||||
client.println(F("GET /example.json HTTP/1.0"));
|
||||
client.println(F("Host: arduinojson.org"));
|
||||
client.println(F("Connection: close"));
|
||||
if (client.println() == 0) {
|
||||
Serial.println(F("Failed to send request"));
|
||||
client.stop();
|
||||
return;
|
||||
}
|
||||
|
||||
// Check HTTP status
|
||||
char status[32] = {0};
|
||||
client.readBytesUntil('\r', status, sizeof(status));
|
||||
// It should be "HTTP/1.0 200 OK" or "HTTP/1.1 200 OK"
|
||||
if (strcmp(status + 9, "200 OK") != 0) {
|
||||
Serial.print(F("Unexpected response: "));
|
||||
Serial.println(status);
|
||||
client.stop();
|
||||
return;
|
||||
}
|
||||
|
||||
// Skip HTTP headers
|
||||
char endOfHeaders[] = "\r\n\r\n";
|
||||
if (!client.find(endOfHeaders)) {
|
||||
Serial.println(F("Invalid response"));
|
||||
client.stop();
|
||||
return;
|
||||
}
|
||||
|
||||
// Allocate the JSON document
|
||||
JsonDocument doc;
|
||||
|
||||
// Parse JSON object
|
||||
DeserializationError error = deserializeJson(doc, client);
|
||||
if (error) {
|
||||
Serial.print(F("deserializeJson() failed: "));
|
||||
Serial.println(error.f_str());
|
||||
client.stop();
|
||||
return;
|
||||
}
|
||||
|
||||
// Extract values
|
||||
Serial.println(F("Response:"));
|
||||
Serial.println(doc["sensor"].as<const char*>());
|
||||
Serial.println(doc["time"].as<long>());
|
||||
Serial.println(doc["data"][0].as<float>(), 6);
|
||||
Serial.println(doc["data"][1].as<float>(), 6);
|
||||
|
||||
// Disconnect
|
||||
client.stop();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// not used in this example
|
||||
}
|
||||
|
||||
// Performance issue?
|
||||
// ------------------
|
||||
//
|
||||
// EthernetClient is an unbuffered stream, which is not optimal for ArduinoJson.
|
||||
// See: https://arduinojson.org/v7/how-to/improve-speed/
|
||||
|
||||
// See also
|
||||
// --------
|
||||
//
|
||||
// https://arduinojson.org/ contains the documentation for all the functions
|
||||
// used above. It also includes an FAQ that will help you solve any
|
||||
// serialization problem.
|
||||
//
|
||||
// The book "Mastering ArduinoJson" contains a tutorial on deserialization
|
||||
// showing how to parse the response from GitHub's API. In the last chapter,
|
||||
// it shows how to parse the huge documents from OpenWeatherMap
|
||||
// and Reddit.
|
||||
// Learn more at https://arduinojson.org/book/
|
||||
// Use the coupon code TWENTY for a 20% discount ❤❤❤❤❤
|
||||
@@ -0,0 +1,65 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2026, Benoit BLANCHON
|
||||
// MIT License
|
||||
//
|
||||
// This example shows how to deserialize a JSON document with ArduinoJson.
|
||||
//
|
||||
// https://arduinojson.org/v7/example/parser/
|
||||
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
void setup() {
|
||||
// Initialize serial port
|
||||
Serial.begin(9600);
|
||||
while (!Serial)
|
||||
continue;
|
||||
|
||||
// Allocate the JSON document
|
||||
JsonDocument doc;
|
||||
|
||||
// JSON input string.
|
||||
const char* json =
|
||||
"{\"sensor\":\"gps\",\"time\":1351824120,\"data\":[48.756080,2.302038]}";
|
||||
|
||||
// Deserialize the JSON document
|
||||
DeserializationError error = deserializeJson(doc, json);
|
||||
|
||||
// Test if parsing succeeds
|
||||
if (error) {
|
||||
Serial.print(F("deserializeJson() failed: "));
|
||||
Serial.println(error.f_str());
|
||||
return;
|
||||
}
|
||||
|
||||
// Fetch the values
|
||||
//
|
||||
// Most of the time, you can rely on the implicit casts.
|
||||
// In other case, you can do doc["time"].as<long>();
|
||||
const char* sensor = doc["sensor"];
|
||||
long time = doc["time"];
|
||||
double latitude = doc["data"][0];
|
||||
double longitude = doc["data"][1];
|
||||
|
||||
// Print the values
|
||||
Serial.println(sensor);
|
||||
Serial.println(time);
|
||||
Serial.println(latitude, 6);
|
||||
Serial.println(longitude, 6);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// not used in this example
|
||||
}
|
||||
|
||||
// See also
|
||||
// --------
|
||||
//
|
||||
// https://arduinojson.org/ contains the documentation for all the functions
|
||||
// used above. It also includes an FAQ that will help you solve any
|
||||
// deserialization problem.
|
||||
//
|
||||
// The book "Mastering ArduinoJson" contains a tutorial on deserialization.
|
||||
// It begins with a simple example, like the one above, and then adds more
|
||||
// features like deserializing directly from a file or an HTTP request.
|
||||
// Learn more at https://arduinojson.org/book/
|
||||
// Use the coupon code TWENTY for a 20% discount ❤❤❤❤❤
|
||||
@@ -0,0 +1,118 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2026, Benoit BLANCHON
|
||||
// MIT License
|
||||
//
|
||||
// This example shows how to implement an HTTP server that sends a JSON document
|
||||
// in the response.
|
||||
// It uses the Ethernet library but can be easily adapted for Wifi.
|
||||
//
|
||||
// The JSON document contains the values of the analog and digital pins.
|
||||
// It looks like that:
|
||||
// {
|
||||
// "analog": [0, 76, 123, 158, 192, 205],
|
||||
// "digital": [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0]
|
||||
// }
|
||||
//
|
||||
// https://arduinojson.org/v7/example/http-server/
|
||||
|
||||
#include <ArduinoJson.h>
|
||||
#include <Ethernet.h>
|
||||
#include <SPI.h>
|
||||
|
||||
byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
|
||||
EthernetServer server(80);
|
||||
|
||||
void setup() {
|
||||
// Initialize serial port
|
||||
Serial.begin(9600);
|
||||
while (!Serial)
|
||||
continue;
|
||||
|
||||
// Initialize Ethernet libary
|
||||
if (!Ethernet.begin(mac)) {
|
||||
Serial.println(F("Failed to initialize Ethernet library"));
|
||||
return;
|
||||
}
|
||||
|
||||
// Start to listen
|
||||
server.begin();
|
||||
|
||||
Serial.println(F("Server is ready."));
|
||||
Serial.print(F("Please connect to http://"));
|
||||
Serial.println(Ethernet.localIP());
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// Wait for an incomming connection
|
||||
EthernetClient client = server.available();
|
||||
|
||||
// Do we have a client?
|
||||
if (!client)
|
||||
return;
|
||||
|
||||
Serial.println(F("New client"));
|
||||
|
||||
// Read the request (we ignore the content in this example)
|
||||
while (client.available())
|
||||
client.read();
|
||||
|
||||
// Allocate a temporary JsonDocument
|
||||
JsonDocument doc;
|
||||
|
||||
// Create the "analog" array
|
||||
JsonArray analogValues = doc["analog"].to<JsonArray>();
|
||||
for (int pin = 0; pin < 6; pin++) {
|
||||
// Read the analog input
|
||||
int value = analogRead(pin);
|
||||
|
||||
// Add the value at the end of the array
|
||||
analogValues.add(value);
|
||||
}
|
||||
|
||||
// Create the "digital" array
|
||||
JsonArray digitalValues = doc["digital"].to<JsonArray>();
|
||||
for (int pin = 0; pin < 14; pin++) {
|
||||
// Read the digital input
|
||||
int value = digitalRead(pin);
|
||||
|
||||
// Add the value at the end of the array
|
||||
digitalValues.add(value);
|
||||
}
|
||||
|
||||
Serial.print(F("Sending: "));
|
||||
serializeJson(doc, Serial);
|
||||
Serial.println();
|
||||
|
||||
// Write response headers
|
||||
client.println(F("HTTP/1.0 200 OK"));
|
||||
client.println(F("Content-Type: application/json"));
|
||||
client.println(F("Connection: close"));
|
||||
client.print(F("Content-Length: "));
|
||||
client.println(measureJsonPretty(doc));
|
||||
client.println();
|
||||
|
||||
// Write JSON document
|
||||
serializeJsonPretty(doc, client);
|
||||
|
||||
// Disconnect
|
||||
client.stop();
|
||||
}
|
||||
|
||||
// Performance issue?
|
||||
// ------------------
|
||||
//
|
||||
// EthernetClient is an unbuffered stream, which is not optimal for ArduinoJson.
|
||||
// See: https://arduinojson.org/v7/how-to/improve-speed/
|
||||
|
||||
// See also
|
||||
// --------
|
||||
//
|
||||
// https://arduinojson.org/ contains the documentation for all the functions
|
||||
// used above. It also includes an FAQ that will help you solve any
|
||||
// serialization problem.
|
||||
//
|
||||
// The book "Mastering ArduinoJson" contains a tutorial on serialization.
|
||||
// It begins with a simple example, then adds more features like serializing
|
||||
// directly to a file or an HTTP client.
|
||||
// Learn more at https://arduinojson.org/book/
|
||||
// Use the coupon code TWENTY for a 20% discount ❤❤❤❤❤
|
||||
@@ -0,0 +1,106 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2026, Benoit BLANCHON
|
||||
// MIT License
|
||||
//
|
||||
// This example shows how to send a JSON document to a UDP socket.
|
||||
// At regular interval, it sends a UDP packet that contains the status of
|
||||
// analog and digital pins.
|
||||
// It looks like that:
|
||||
// {
|
||||
// "analog": [0, 76, 123, 158, 192, 205],
|
||||
// "digital": [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0]
|
||||
// }
|
||||
//
|
||||
// If you want to test this program, you need to be able to receive the UDP
|
||||
// packets.
|
||||
// For example, you can run netcat on your computer
|
||||
// $ ncat -ulp 8888
|
||||
// See https://nmap.org/ncat/
|
||||
//
|
||||
// https://arduinojson.org/v7/example/udp-beacon/
|
||||
|
||||
#include <ArduinoJson.h>
|
||||
#include <Ethernet.h>
|
||||
#include <SPI.h>
|
||||
|
||||
byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
|
||||
IPAddress remoteIp(192, 168, 0, 108); // <- EDIT!!!!
|
||||
unsigned short remotePort = 8888;
|
||||
unsigned short localPort = 8888;
|
||||
EthernetUDP udp;
|
||||
|
||||
void setup() {
|
||||
// Initialize serial port
|
||||
Serial.begin(9600);
|
||||
while (!Serial)
|
||||
continue;
|
||||
|
||||
// Initialize Ethernet libary
|
||||
if (!Ethernet.begin(mac)) {
|
||||
Serial.println(F("Failed to initialize Ethernet library"));
|
||||
return;
|
||||
}
|
||||
|
||||
// Enable UDP
|
||||
udp.begin(localPort);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// Allocate a temporary JsonDocument
|
||||
JsonDocument doc;
|
||||
|
||||
// Create the "analog" array
|
||||
JsonArray analogValues = doc["analog"].to<JsonArray>();
|
||||
for (int pin = 0; pin < 6; pin++) {
|
||||
// Read the analog input
|
||||
int value = analogRead(pin);
|
||||
|
||||
// Add the value at the end of the array
|
||||
analogValues.add(value);
|
||||
}
|
||||
|
||||
// Create the "digital" array
|
||||
JsonArray digitalValues = doc["digital"].to<JsonArray>();
|
||||
for (int pin = 0; pin < 14; pin++) {
|
||||
// Read the digital input
|
||||
int value = digitalRead(pin);
|
||||
|
||||
// Add the value at the end of the array
|
||||
digitalValues.add(value);
|
||||
}
|
||||
|
||||
// Log
|
||||
Serial.print(F("Sending to "));
|
||||
Serial.print(remoteIp);
|
||||
Serial.print(F(" on port "));
|
||||
Serial.println(remotePort);
|
||||
serializeJson(doc, Serial);
|
||||
|
||||
// Send UDP packet
|
||||
udp.beginPacket(remoteIp, remotePort);
|
||||
serializeJson(doc, udp);
|
||||
udp.println();
|
||||
udp.endPacket();
|
||||
|
||||
// Wait
|
||||
delay(10000);
|
||||
}
|
||||
|
||||
// Performance issue?
|
||||
// ------------------
|
||||
//
|
||||
// EthernetUDP is an unbuffered stream, which is not optimal for ArduinoJson.
|
||||
// See: https://arduinojson.org/v7/how-to/improve-speed/
|
||||
|
||||
// See also
|
||||
// --------
|
||||
//
|
||||
// https://arduinojson.org/ contains the documentation for all the functions
|
||||
// used above. It also includes an FAQ that will help you solve any
|
||||
// serialization problem.
|
||||
//
|
||||
// The book "Mastering ArduinoJson" contains a tutorial on serialization.
|
||||
// It begins with a simple example, then adds more features like serializing
|
||||
// directly to a file or any stream.
|
||||
// Learn more at https://arduinojson.org/book/
|
||||
// Use the coupon code TWENTY for a 20% discount ❤❤❤❤❤
|
||||
@@ -0,0 +1,61 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2026, Benoit BLANCHON
|
||||
// MIT License
|
||||
//
|
||||
// This example shows how to deserialize a MessagePack document with
|
||||
// ArduinoJson.
|
||||
//
|
||||
// https://arduinojson.org/v7/example/msgpack-parser/
|
||||
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
void setup() {
|
||||
// Initialize serial port
|
||||
Serial.begin(9600);
|
||||
while (!Serial)
|
||||
continue;
|
||||
|
||||
// Allocate the JSON document
|
||||
JsonDocument doc;
|
||||
|
||||
// The MessagePack input string
|
||||
uint8_t input[] = {131, 166, 115, 101, 110, 115, 111, 114, 163, 103, 112, 115,
|
||||
164, 116, 105, 109, 101, 206, 80, 147, 50, 248, 164, 100,
|
||||
97, 116, 97, 146, 203, 64, 72, 96, 199, 58, 188, 148,
|
||||
112, 203, 64, 2, 106, 146, 230, 33, 49, 169};
|
||||
// This MessagePack document contains:
|
||||
// {
|
||||
// "sensor": "gps",
|
||||
// "time": 1351824120,
|
||||
// "data": [48.75608, 2.302038]
|
||||
// }
|
||||
|
||||
// Parse the input
|
||||
DeserializationError error = deserializeMsgPack(doc, input);
|
||||
|
||||
// Test if parsing succeeded
|
||||
if (error) {
|
||||
Serial.print("deserializeMsgPack() failed: ");
|
||||
Serial.println(error.f_str());
|
||||
return;
|
||||
}
|
||||
|
||||
// Fetch the values
|
||||
//
|
||||
// Most of the time, you can rely on the implicit casts.
|
||||
// In other case, you can do doc["time"].as<long>();
|
||||
const char* sensor = doc["sensor"];
|
||||
long time = doc["time"];
|
||||
double latitude = doc["data"][0];
|
||||
double longitude = doc["data"][1];
|
||||
|
||||
// Print the values
|
||||
Serial.println(sensor);
|
||||
Serial.println(time);
|
||||
Serial.println(latitude, 6);
|
||||
Serial.println(longitude, 6);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// not used in this example
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2026, Benoit BLANCHON
|
||||
// MIT License
|
||||
//
|
||||
// This example shows the different ways you can use Flash strings with
|
||||
// ArduinoJson.
|
||||
//
|
||||
// Use Flash strings sparingly, because ArduinoJson duplicates them in the
|
||||
// JsonDocument. Prefer plain old char*, as they are more efficient in term of
|
||||
// code size, speed, and memory usage.
|
||||
//
|
||||
// https://arduinojson.org/v7/example/progmem/
|
||||
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
void setup() {
|
||||
JsonDocument doc;
|
||||
|
||||
// You can use a Flash String as your JSON input.
|
||||
// WARNING: the strings in the input will be duplicated in the JsonDocument.
|
||||
deserializeJson(doc, F("{\"sensor\":\"gps\",\"time\":1351824120,"
|
||||
"\"data\":[48.756080,2.302038]}"));
|
||||
|
||||
// You can use a Flash String as a key to get a member from JsonDocument
|
||||
// No duplication is done.
|
||||
long time = doc[F("time")];
|
||||
|
||||
// You can use a Flash String as a key to set a member of a JsonDocument
|
||||
// WARNING: the content of the Flash String will be duplicated in the
|
||||
// JsonDocument.
|
||||
doc[F("time")] = time;
|
||||
|
||||
// You can set a Flash String as the content of a JsonVariant
|
||||
// WARNING: the content of the Flash String will be duplicated in the
|
||||
// JsonDocument.
|
||||
doc["sensor"] = F("gps");
|
||||
|
||||
// It works with serialized() too:
|
||||
doc["sensor"] = serialized(F("\"gps\""));
|
||||
doc["sensor"] = serialized(F("\xA3gps"), 3);
|
||||
|
||||
// You can compare the content of a JsonVariant to a Flash String
|
||||
if (doc["sensor"] == F("gps")) {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// not used in this example
|
||||
}
|
||||
|
||||
// See also
|
||||
// --------
|
||||
//
|
||||
// https://arduinojson.org/ contains the documentation for all the functions
|
||||
// used above. It also includes an FAQ that will help you solve any memory
|
||||
// problem.
|
||||
//
|
||||
// The book "Mastering ArduinoJson" contains a quick C++ course that explains
|
||||
// how your microcontroller stores strings in memory. It also tells why you
|
||||
// should not abuse Flash strings with ArduinoJson.
|
||||
// Learn more at https://arduinojson.org/book/
|
||||
// Use the coupon code TWENTY for a 20% discount ❤❤❤❤❤
|
||||
@@ -0,0 +1,76 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2026, Benoit BLANCHON
|
||||
// MIT License
|
||||
//
|
||||
// This example shows the different ways you can use String with ArduinoJson.
|
||||
//
|
||||
// Use String objects sparingly, because ArduinoJson duplicates them in the
|
||||
// JsonDocument. Prefer plain old char[], as they are more efficient in term of
|
||||
// code size, speed, and memory usage.
|
||||
//
|
||||
// https://arduinojson.org/v7/example/string/
|
||||
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
void setup() {
|
||||
JsonDocument doc;
|
||||
|
||||
// You can use a String as your JSON input.
|
||||
// WARNING: the string in the input will be duplicated in the JsonDocument.
|
||||
String input =
|
||||
"{\"sensor\":\"gps\",\"time\":1351824120,\"data\":[48.756080,2.302038]}";
|
||||
deserializeJson(doc, input);
|
||||
|
||||
// You can use a String as a key to get a member from JsonDocument
|
||||
// No duplication is done.
|
||||
long time = doc[String("time")];
|
||||
|
||||
// You can use a String as a key to set a member of a JsonDocument
|
||||
// WARNING: the content of the String will be duplicated in the JsonDocument.
|
||||
doc[String("time")] = time;
|
||||
|
||||
// You can get the content of a JsonVariant as a String
|
||||
// No duplication is done, at least not in the JsonDocument.
|
||||
String sensor = doc["sensor"];
|
||||
|
||||
// Unfortunately, the following doesn't work (issue #118):
|
||||
// sensor = doc["sensor"]; // <- error "ambiguous overload for 'operator='"
|
||||
// As a workaround, you need to replace by:
|
||||
sensor = doc["sensor"].as<String>();
|
||||
|
||||
// You can set a String as the content of a JsonVariant
|
||||
// WARNING: the content of the String will be duplicated in the JsonDocument.
|
||||
doc["sensor"] = sensor;
|
||||
|
||||
// It works with serialized() too:
|
||||
doc["sensor"] = serialized(sensor);
|
||||
|
||||
// You can also concatenate strings
|
||||
// WARNING: the content of the String will be duplicated in the JsonDocument.
|
||||
doc[String("sen") + "sor"] = String("gp") + "s";
|
||||
|
||||
// You can compare the content of a JsonObject with a String
|
||||
if (doc["sensor"] == sensor) {
|
||||
// ...
|
||||
}
|
||||
|
||||
// Lastly, you can print the resulting JSON to a String
|
||||
String output;
|
||||
serializeJson(doc, output);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// not used in this example
|
||||
}
|
||||
|
||||
// See also
|
||||
// --------
|
||||
//
|
||||
// https://arduinojson.org/ contains the documentation for all the functions
|
||||
// used above. It also includes an FAQ that will help you solve any problem.
|
||||
//
|
||||
// The book "Mastering ArduinoJson" contains a quick C++ course that explains
|
||||
// how your microcontroller stores strings in memory. On several occasions, it
|
||||
// shows how you can avoid String in your program.
|
||||
// Learn more at https://arduinojson.org/book/
|
||||
// Use the coupon code TWENTY for a 20% discount ❤❤❤❤❤
|
||||
@@ -0,0 +1,4 @@
|
||||
@PACKAGE_INIT@
|
||||
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake")
|
||||
check_required_components("@PROJECT_NAME@")
|
||||
@@ -0,0 +1,112 @@
|
||||
if(NOT DEFINED COVERAGE)
|
||||
set(COVERAGE OFF)
|
||||
endif()
|
||||
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "(GNU|Clang)")
|
||||
add_compile_options(
|
||||
-pedantic
|
||||
-Wall
|
||||
-Wcast-align
|
||||
-Wcast-qual
|
||||
-Wconversion
|
||||
-Wctor-dtor-privacy
|
||||
-Wdisabled-optimization
|
||||
-Werror
|
||||
-Wextra
|
||||
-Wformat=2
|
||||
-Winit-self
|
||||
-Wmissing-include-dirs
|
||||
-Wnon-virtual-dtor
|
||||
-Wold-style-cast
|
||||
-Woverloaded-virtual
|
||||
-Wparentheses
|
||||
-Wredundant-decls
|
||||
-Wshadow
|
||||
-Wsign-conversion
|
||||
-Wsign-promo
|
||||
-Wstrict-aliasing
|
||||
-Wundef
|
||||
)
|
||||
|
||||
if(${COVERAGE})
|
||||
set(CMAKE_CXX_FLAGS "-fprofile-arcs -ftest-coverage")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||
if((CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 4.9) AND(NOT ${COVERAGE}))
|
||||
add_compile_options(-g -Og)
|
||||
else() # GCC 4.8
|
||||
add_compile_options(
|
||||
-g
|
||||
-O0 # GCC 4.8 doesn't support -Og
|
||||
-Wno-shadow # allow the same name for a function parameter and a member functions
|
||||
-Wp,-w # Disable preprocessing warnings (see below)
|
||||
)
|
||||
# GCC 4.8 doesn't support __has_include, so we need to help him
|
||||
add_definitions(
|
||||
-DARDUINOJSON_ENABLE_STD_STRING=1
|
||||
-DARDUINOJSON_ENABLE_STD_STREAM=1
|
||||
)
|
||||
endif()
|
||||
|
||||
add_compile_options(
|
||||
-Wstrict-null-sentinel
|
||||
-Wno-vla # Allow VLA in tests
|
||||
)
|
||||
add_definitions(-DHAS_VARIABLE_LENGTH_ARRAY)
|
||||
|
||||
if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 4.5)
|
||||
add_compile_options(-Wlogical-op) # the flag exists in 4.4 but is buggy
|
||||
endif()
|
||||
|
||||
if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 4.6)
|
||||
add_compile_options(-Wnoexcept)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
add_compile_options(
|
||||
-Wc++11-compat
|
||||
-Wdeprecated-register
|
||||
-Wno-vla-extension # Allow VLA in tests
|
||||
)
|
||||
add_definitions(
|
||||
-DHAS_VARIABLE_LENGTH_ARRAY
|
||||
-DSUBSCRIPT_CONFLICTS_WITH_BUILTIN_OPERATOR
|
||||
)
|
||||
endif()
|
||||
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||
add_compile_options(-stdlib=libc++)
|
||||
link_libraries(c++ m)
|
||||
|
||||
if((CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 4.0) AND(NOT ${COVERAGE}))
|
||||
add_compile_options(-g -Og)
|
||||
else()
|
||||
add_compile_options(-g -O0)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
|
||||
if((CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 9.0) AND(NOT ${COVERAGE}))
|
||||
add_compile_options(-g -Og)
|
||||
else()
|
||||
add_compile_options(-g -O0)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(MSVC)
|
||||
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
|
||||
add_compile_options(
|
||||
/W4 # Set warning level
|
||||
/WX # Treats all compiler warnings as errors.
|
||||
/Zc:__cplusplus # Enable updated __cplusplus macro
|
||||
)
|
||||
endif()
|
||||
|
||||
if(MINGW)
|
||||
# Static link on MinGW to avoid linking with the wrong DLLs when multiple
|
||||
# versions are installed.
|
||||
add_link_options(-static)
|
||||
endif()
|
||||
@@ -0,0 +1,8 @@
|
||||
# ArduinoJson - https://arduinojson.org
|
||||
# Copyright © 2014-2026, Benoit BLANCHON
|
||||
# MIT License
|
||||
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(example)
|
||||
@@ -0,0 +1,8 @@
|
||||
# ArduinoJson - https://arduinojson.org
|
||||
# Copyright © 2014-2026, Benoit BLANCHON
|
||||
# MIT License
|
||||
|
||||
idf_component_register(
|
||||
SRCS "main.cpp"
|
||||
INCLUDE_DIRS ""
|
||||
)
|
||||
@@ -0,0 +1,4 @@
|
||||
#
|
||||
# "main" pseudo-component makefile.
|
||||
#
|
||||
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
|
||||
@@ -0,0 +1,16 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2026, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
extern "C" void app_main() {
|
||||
char buffer[256];
|
||||
JsonDocument doc;
|
||||
|
||||
doc["hello"] = "world";
|
||||
serializeJson(doc, buffer);
|
||||
deserializeJson(doc, buffer);
|
||||
serializeMsgPack(doc, buffer);
|
||||
deserializeMsgPack(doc, buffer);
|
||||
}
|
||||
Executable
+10
@@ -0,0 +1,10 @@
|
||||
#!/bin/sh -ex
|
||||
|
||||
BOARD=$1
|
||||
|
||||
cd "$(dirname "$0")/../../"
|
||||
|
||||
cp extras/particle/src/smocktest.ino src/
|
||||
cp extras/particle/project.properties ./
|
||||
|
||||
particle compile "$BOARD"
|
||||
@@ -0,0 +1,18 @@
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
static_assert(ARDUINOJSON_ENABLE_PROGMEM == 1, "ARDUINOJSON_ENABLE_PROGMEM");
|
||||
|
||||
static_assert(ARDUINOJSON_USE_LONG_LONG == 0, "ARDUINOJSON_USE_LONG_LONG");
|
||||
|
||||
static_assert(ARDUINOJSON_SLOT_ID_SIZE == 1, "ARDUINOJSON_SLOT_ID_SIZE");
|
||||
|
||||
static_assert(ARDUINOJSON_POOL_CAPACITY == 16, "ARDUINOJSON_POOL_CAPACITY");
|
||||
|
||||
static_assert(ARDUINOJSON_LITTLE_ENDIAN == 1, "ARDUINOJSON_LITTLE_ENDIAN");
|
||||
|
||||
static_assert(ARDUINOJSON_USE_DOUBLE == 0, "ARDUINOJSON_USE_DOUBLE");
|
||||
|
||||
static_assert(ArduinoJson::detail::ResourceManager::slotSize == 6, "slot size");
|
||||
|
||||
void setup() {}
|
||||
void loop() {}
|
||||
@@ -0,0 +1,16 @@
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
static_assert(ARDUINOJSON_USE_LONG_LONG == 1, "ARDUINOJSON_USE_LONG_LONG");
|
||||
|
||||
static_assert(ARDUINOJSON_SLOT_ID_SIZE == 2, "ARDUINOJSON_SLOT_ID_SIZE");
|
||||
|
||||
static_assert(ARDUINOJSON_POOL_CAPACITY == 128, "ARDUINOJSON_POOL_CAPACITY");
|
||||
|
||||
static_assert(ARDUINOJSON_LITTLE_ENDIAN == 1, "ARDUINOJSON_LITTLE_ENDIAN");
|
||||
|
||||
static_assert(ARDUINOJSON_USE_DOUBLE == 1, "ARDUINOJSON_USE_DOUBLE");
|
||||
|
||||
static_assert(ArduinoJson::detail::ResourceManager::slotSize == 8, "slot size");
|
||||
|
||||
void setup() {}
|
||||
void loop() {}
|
||||
@@ -0,0 +1,16 @@
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
static_assert(ARDUINOJSON_USE_LONG_LONG == 1, "ARDUINOJSON_USE_LONG_LONG");
|
||||
|
||||
static_assert(ARDUINOJSON_SLOT_ID_SIZE == 4, "ARDUINOJSON_SLOT_ID_SIZE");
|
||||
|
||||
static_assert(ARDUINOJSON_POOL_CAPACITY == 256, "ARDUINOJSON_POOL_CAPACITY");
|
||||
|
||||
static_assert(ARDUINOJSON_LITTLE_ENDIAN == 1, "ARDUINOJSON_LITTLE_ENDIAN");
|
||||
|
||||
static_assert(ARDUINOJSON_USE_DOUBLE == 1, "ARDUINOJSON_USE_DOUBLE");
|
||||
|
||||
static_assert(ArduinoJson::detail::ResourceManager::slotSize == 16,
|
||||
"slot size");
|
||||
|
||||
int main() {}
|
||||
@@ -0,0 +1,15 @@
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
static_assert(ARDUINOJSON_USE_LONG_LONG == 1, "ARDUINOJSON_USE_LONG_LONG");
|
||||
|
||||
static_assert(ARDUINOJSON_SLOT_ID_SIZE == 2, "ARDUINOJSON_SLOT_ID_SIZE");
|
||||
|
||||
static_assert(ARDUINOJSON_POOL_CAPACITY == 128, "ARDUINOJSON_POOL_CAPACITY");
|
||||
|
||||
static_assert(ARDUINOJSON_LITTLE_ENDIAN == 1, "ARDUINOJSON_LITTLE_ENDIAN");
|
||||
|
||||
static_assert(ARDUINOJSON_USE_DOUBLE == 1, "ARDUINOJSON_USE_DOUBLE");
|
||||
|
||||
static_assert(ArduinoJson::detail::ResourceManager::slotSize == 8, "slot size");
|
||||
|
||||
int main() {}
|
||||
@@ -0,0 +1,67 @@
|
||||
# ArduinoJson - https://arduinojson.org
|
||||
# Copyright © 2014-2026, Benoit BLANCHON
|
||||
# MIT License
|
||||
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
if(MSVC)
|
||||
add_compile_options(-D_CRT_SECURE_NO_WARNINGS)
|
||||
endif()
|
||||
|
||||
add_executable(msgpack_reproducer
|
||||
msgpack_fuzzer.cpp
|
||||
reproducer.cpp
|
||||
)
|
||||
target_link_libraries(msgpack_reproducer
|
||||
ArduinoJson
|
||||
)
|
||||
|
||||
add_executable(json_reproducer
|
||||
json_fuzzer.cpp
|
||||
reproducer.cpp
|
||||
)
|
||||
target_link_libraries(json_reproducer
|
||||
ArduinoJson
|
||||
)
|
||||
|
||||
macro(add_fuzzer name)
|
||||
set(FUZZER "${name}_fuzzer")
|
||||
set(CORPUS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/${name}_corpus")
|
||||
set(SEED_CORPUS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/${name}_seed_corpus")
|
||||
add_executable("${FUZZER}"
|
||||
"${name}_fuzzer.cpp"
|
||||
)
|
||||
target_link_libraries("${FUZZER}"
|
||||
ArduinoJson
|
||||
)
|
||||
set_target_properties("${FUZZER}"
|
||||
PROPERTIES
|
||||
COMPILE_FLAGS "-fprofile-instr-generate -fcoverage-mapping -fsanitize=fuzzer -fno-sanitize-recover=all"
|
||||
LINK_FLAGS "-fprofile-instr-generate -fcoverage-mapping -fsanitize=fuzzer -fno-sanitize-recover=all"
|
||||
)
|
||||
|
||||
add_test(
|
||||
NAME "${FUZZER}"
|
||||
COMMAND "${FUZZER}" "${CORPUS_DIR}" "${SEED_CORPUS_DIR}" -max_total_time=5 -timeout=1
|
||||
)
|
||||
|
||||
set_tests_properties("${FUZZER}"
|
||||
PROPERTIES
|
||||
LABELS "Fuzzing"
|
||||
)
|
||||
endmacro()
|
||||
|
||||
# Needs Clang 6+ to compile
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 6)
|
||||
if(DEFINED ENV{GITHUB_ACTIONS} AND CMAKE_CXX_COMPILER_VERSION MATCHES "^11\\.")
|
||||
# Clang 11 fails on GitHub Actions with the following error:
|
||||
# > ERROR: UndefinedBehaviorSanitizer failed to allocate 0x0 (0) bytes of SetAlternateSignalStack (error code: 22)
|
||||
# > Sanitizer CHECK failed: /build/llvm-toolchain-11-mnvtwk/llvm-toolchain-11-11.1.0/compiler-rt/lib/sanitizer_common/sanitizer_common.cpp:54 ((0 && "unable to mmap")) != (0) (0, 0)
|
||||
message(WARNING "Fuzzing is disabled on GitHub Actions to workaround a bug in Clang 11")
|
||||
return()
|
||||
endif()
|
||||
|
||||
add_fuzzer(json)
|
||||
add_fuzzer(msgpack)
|
||||
endif()
|
||||
@@ -0,0 +1,22 @@
|
||||
# CAUTION: this file is invoked by https://github.com/google/oss-fuzz
|
||||
|
||||
CXXFLAGS += -I../../src -DARDUINOJSON_DEBUG=1 -std=c++11
|
||||
|
||||
all: \
|
||||
$(OUT)/json_fuzzer \
|
||||
$(OUT)/json_fuzzer_seed_corpus.zip \
|
||||
$(OUT)/json_fuzzer.options \
|
||||
$(OUT)/msgpack_fuzzer \
|
||||
$(OUT)/msgpack_fuzzer_seed_corpus.zip \
|
||||
$(OUT)/msgpack_fuzzer.options
|
||||
|
||||
$(OUT)/%_fuzzer: %_fuzzer.cpp $(shell find ../../src -type f)
|
||||
$(CXX) $(CXXFLAGS) $< -o$@ $(LIB_FUZZING_ENGINE)
|
||||
|
||||
$(OUT)/%_fuzzer_seed_corpus.zip: %_seed_corpus/*
|
||||
zip -j $@ $?
|
||||
|
||||
$(OUT)/%_fuzzer.options:
|
||||
@echo "[libfuzzer]" > $@
|
||||
@echo "max_len = 256" >> $@
|
||||
@echo "timeout = 10" >> $@
|
||||
@@ -0,0 +1,11 @@
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
||||
JsonDocument doc;
|
||||
DeserializationError error = deserializeJson(doc, data, size);
|
||||
if (!error) {
|
||||
std::string json;
|
||||
serializeJson(doc, json);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
//comment
|
||||
/*comment*/
|
||||
[ //comment
|
||||
/*comment*/"comment"/*comment*/,//comment
|
||||
/*comment*/{//comment
|
||||
/* comment*/"key"//comment
|
||||
: //comment
|
||||
"value"//comment
|
||||
}/*comment*/
|
||||
]//comment
|
||||
@@ -0,0 +1 @@
|
||||
[]
|
||||
@@ -0,0 +1 @@
|
||||
{}
|
||||
@@ -0,0 +1 @@
|
||||
[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,[110,[111,[112,[113,[114,[115,[116,[117,[118,[119,[120]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]
|
||||
@@ -0,0 +1 @@
|
||||
9720730739393920739
|
||||
@@ -0,0 +1,24 @@
|
||||
[
|
||||
123,
|
||||
-123,
|
||||
123.456,
|
||||
-123.456,
|
||||
12e34,
|
||||
12e-34,
|
||||
12e+34,
|
||||
12E34,
|
||||
12E-34,
|
||||
12E+34,
|
||||
12.34e56,
|
||||
12.34e-56,
|
||||
12.34e+56,
|
||||
12.34E56,
|
||||
12.34E-56,
|
||||
12.34E+56,
|
||||
NaN,
|
||||
-NaN,
|
||||
+NaN,
|
||||
Infinity,
|
||||
+Infinity,
|
||||
-Infinity
|
||||
]
|
||||
@@ -0,0 +1,53 @@
|
||||
{
|
||||
"coord": {
|
||||
"lon": -0.13,
|
||||
"lat": 51.51
|
||||
},
|
||||
"weather": [
|
||||
{
|
||||
"id": 301,
|
||||
"main": "Drizzle",
|
||||
"description": "drizzle",
|
||||
"icon": "09n"
|
||||
},
|
||||
{
|
||||
"id": 701,
|
||||
"main": "Mist",
|
||||
"description": "mist",
|
||||
"icon": "50n"
|
||||
},
|
||||
{
|
||||
"id": 741,
|
||||
"main": "Fog",
|
||||
"description": "fog",
|
||||
"icon": "50n"
|
||||
}
|
||||
],
|
||||
"base": "stations",
|
||||
"main": {
|
||||
"temp": 281.87,
|
||||
"pressure": 1032,
|
||||
"humidity": 100,
|
||||
"temp_min": 281.15,
|
||||
"temp_max": 283.15
|
||||
},
|
||||
"visibility": 2900,
|
||||
"wind": {
|
||||
"speed": 1.5
|
||||
},
|
||||
"clouds": {
|
||||
"all": 90
|
||||
},
|
||||
"dt": 1483820400,
|
||||
"sys": {
|
||||
"type": 1,
|
||||
"id": 5091,
|
||||
"message": 0.0226,
|
||||
"country": "GB",
|
||||
"sunrise": 1483776245,
|
||||
"sunset": 1483805443
|
||||
},
|
||||
"id": 2643743,
|
||||
"name": "London",
|
||||
"cod": 200
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
[
|
||||
"hello",
|
||||
'hello',
|
||||
hello,
|
||||
{"hello":"world"},
|
||||
{'hello':'world'},
|
||||
{hello:world}
|
||||
]
|
||||
@@ -0,0 +1,90 @@
|
||||
{
|
||||
"response": {
|
||||
"version": "0.1",
|
||||
"termsofService": "http://www.wunderground.com/weather/api/d/terms.html",
|
||||
"features": {
|
||||
"conditions": 1
|
||||
}
|
||||
},
|
||||
"current_observation": {
|
||||
"image": {
|
||||
"url": "http://icons-ak.wxug.com/graphics/wu2/logo_130x80.png",
|
||||
"title": "Weather Underground",
|
||||
"link": "http://www.wunderground.com"
|
||||
},
|
||||
"display_location": {
|
||||
"full": "San Francisco, CA",
|
||||
"city": "San Francisco",
|
||||
"state": "CA",
|
||||
"state_name": "California",
|
||||
"country": "US",
|
||||
"country_iso3166": "US",
|
||||
"zip": "94101",
|
||||
"latitude": "37.77500916",
|
||||
"longitude": "-122.41825867",
|
||||
"elevation": "47.00000000"
|
||||
},
|
||||
"observation_location": {
|
||||
"full": "SOMA - Near Van Ness, San Francisco, California",
|
||||
"city": "SOMA - Near Van Ness, San Francisco",
|
||||
"state": "California",
|
||||
"country": "US",
|
||||
"country_iso3166": "US",
|
||||
"latitude": "37.773285",
|
||||
"longitude": "-122.417725",
|
||||
"elevation": "49 ft"
|
||||
},
|
||||
"estimated": {},
|
||||
"station_id": "KCASANFR58",
|
||||
"observation_time": "Last Updated on June 27, 5:27 PM PDT",
|
||||
"observation_time_rfc822": "Wed, 27 Jun 2012 17:27:13 -0700",
|
||||
"observation_epoch": "1340843233",
|
||||
"local_time_rfc822": "Wed, 27 Jun 2012 17:27:14 -0700",
|
||||
"local_epoch": "1340843234",
|
||||
"local_tz_short": "PDT",
|
||||
"local_tz_long": "America/Los_Angeles",
|
||||
"local_tz_offset": "-0700",
|
||||
"weather": "Partly Cloudy",
|
||||
"temperature_string": "66.3 F (19.1 C)",
|
||||
"temp_f": 66.3,
|
||||
"temp_c": 19.1,
|
||||
"relative_humidity": "65%",
|
||||
"wind_string": "From the NNW at 22.0 MPH Gusting to 28.0 MPH",
|
||||
"wind_dir": "NNW",
|
||||
"wind_degrees": 346,
|
||||
"wind_mph": 22,
|
||||
"wind_gust_mph": "28.0",
|
||||
"wind_kph": 35.4,
|
||||
"wind_gust_kph": "45.1",
|
||||
"pressure_mb": "1013",
|
||||
"pressure_in": "29.93",
|
||||
"pressure_trend": "+",
|
||||
"dewpoint_string": "54 F (12 C)",
|
||||
"dewpoint_f": 54,
|
||||
"dewpoint_c": 12,
|
||||
"heat_index_string": "NA",
|
||||
"heat_index_f": "NA",
|
||||
"heat_index_c": "NA",
|
||||
"windchill_string": "NA",
|
||||
"windchill_f": "NA",
|
||||
"windchill_c": "NA",
|
||||
"feelslike_string": "66.3 F (19.1 C)",
|
||||
"feelslike_f": "66.3",
|
||||
"feelslike_c": "19.1",
|
||||
"visibility_mi": "10.0",
|
||||
"visibility_km": "16.1",
|
||||
"solarradiation": "",
|
||||
"UV": "5",
|
||||
"precip_1hr_string": "0.00 in ( 0 mm)",
|
||||
"precip_1hr_in": "0.00",
|
||||
"precip_1hr_metric": " 0",
|
||||
"precip_today_string": "0.00 in (0 mm)",
|
||||
"precip_today_in": "0.00",
|
||||
"precip_today_metric": "0",
|
||||
"icon": "partlycloudy",
|
||||
"icon_url": "http://icons-ak.wxug.com/i/c/k/partlycloudy.gif",
|
||||
"forecast_url": "http://www.wunderground.com/US/CA/San_Francisco.html",
|
||||
"history_url": "http://www.wunderground.com/history/airport/KCASANFR58/2012/6/27/DailyHistory.html",
|
||||
"ob_url": "http://www.wunderground.com/cgi-bin/findweather/getForecast?query=37.773285,-122.417725"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
||||
JsonDocument doc;
|
||||
DeserializationError error = deserializeMsgPack(doc, data, size);
|
||||
if (!error) {
|
||||
std::string json;
|
||||
serializeMsgPack(doc, json);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1 @@
|
||||
�
|
||||
@@ -0,0 +1 @@
|
||||
’¥hello¥world
|
||||
@@ -0,0 +1 @@
|
||||
�
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
‚£one£two
|
||||
@@ -0,0 +1 @@
|
||||
«hello world
|
||||
@@ -0,0 +1 @@
|
||||
ハ@H�
|
||||
@@ -0,0 +1 @@
|
||||
Л@ !КАѓo
|
||||
@@ -0,0 +1 @@
|
||||
拮�
|
||||
@@ -0,0 +1 @@
|
||||
Ҷi.
|
||||
@@ -0,0 +1 @@
|
||||
モ4Vx埔゙�
|
||||
@@ -0,0 +1 @@
|
||||
��
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1 @@
|
||||
�
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1 @@
|
||||
Ùhello
|
||||
@@ -0,0 +1 @@
|
||||
�
|
||||
@@ -0,0 +1 @@
|
||||
09
|
||||
@@ -0,0 +1 @@
|
||||
4Vx
|
||||
@@ -0,0 +1 @@
|
||||
マ4Vx埔゙�
|
||||
@@ -0,0 +1 @@
|
||||
��
|
||||
@@ -0,0 +1,50 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2026, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
// This file is NOT use by Google's OSS fuzz
|
||||
// I only use it to reproduce the bugs found
|
||||
|
||||
#include <stdint.h> // size_t
|
||||
#include <stdio.h> // fopen et al.
|
||||
#include <stdlib.h> // exit
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size);
|
||||
|
||||
std::vector<uint8_t> read(const char* path) {
|
||||
FILE* f = fopen(path, "rb");
|
||||
if (!f) {
|
||||
std::cerr << "Failed to open " << path << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
fseek(f, 0, SEEK_END);
|
||||
size_t size = static_cast<size_t>(ftell(f));
|
||||
fseek(f, 0, SEEK_SET);
|
||||
|
||||
std::vector<uint8_t> buffer(size);
|
||||
if (fread(buffer.data(), 1, size, f) != size) {
|
||||
fclose(f);
|
||||
std::cerr << "Failed to read " << path << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
int main(int argc, const char* argv[]) {
|
||||
if (argc < 2) {
|
||||
std::cerr << "Usage: msgpack_fuzzer files" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (int i = 1; i < argc; i++) {
|
||||
std::cout << "Loading " << argv[i] << std::endl;
|
||||
std::vector<uint8_t> buffer = read(argv[i]);
|
||||
LLVMFuzzerTestOneInput(buffer.data(), buffer.size());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
name=ArduinoJsonCI
|
||||
@@ -0,0 +1,5 @@
|
||||
#include "ArduinoJson.h"
|
||||
|
||||
void setup() {}
|
||||
|
||||
void loop() {}
|
||||
@@ -0,0 +1,65 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
RE_RELATIVE_INCLUDE='^#[[:space:]]*include[[:space:]]*"(.*)"'
|
||||
RE_ABSOLUTE_INCLUDE='^#[[:space:]]*include[[:space:]]*<(ArduinoJson/.*)>'
|
||||
RE_SYSTEM_INCLUDE='^#[[:space:]]*include[[:space:]]*<(.*)>'
|
||||
RE_EMPTY='^(#[[:space:]]*pragma[[:space:]]+once)?[[:space:]]*(//.*)?$'
|
||||
SRC_DIRECTORY="$(realpath "$(dirname $0)/../../src")"
|
||||
|
||||
|
||||
declare -A INCLUDED
|
||||
|
||||
process()
|
||||
{
|
||||
local PARENT=$1
|
||||
local FOLDER=$(dirname $1)
|
||||
local SHOW_COMMENT=$2
|
||||
while IFS= read -r LINE; do
|
||||
if [[ $LINE =~ $RE_ABSOLUTE_INCLUDE ]]; then
|
||||
local CHILD=${BASH_REMATCH[1]}
|
||||
local CHILD_PATH
|
||||
CHILD_PATH=$(realpath "$SRC_DIRECTORY/$CHILD")
|
||||
echo "$PARENT -> $CHILD" >&2
|
||||
if [[ ! ${INCLUDED[$CHILD_PATH]} ]]; then
|
||||
INCLUDED[$CHILD_PATH]=true
|
||||
process "$CHILD" false
|
||||
fi
|
||||
elif [[ $LINE =~ $RE_RELATIVE_INCLUDE ]]; then
|
||||
local CHILD=${BASH_REMATCH[1]}
|
||||
pushd "$FOLDER" > /dev/null
|
||||
local CHILD_PATH
|
||||
CHILD_PATH=$(realpath "$CHILD")
|
||||
echo "$PARENT -> $CHILD" >&2
|
||||
if [[ ! ${INCLUDED[$CHILD_PATH]} ]]; then
|
||||
INCLUDED[$CHILD_PATH]=true
|
||||
process "$CHILD" false
|
||||
fi
|
||||
popd > /dev/null
|
||||
elif [[ $LINE =~ $RE_SYSTEM_INCLUDE ]]; then
|
||||
local CHILD=${BASH_REMATCH[1]}
|
||||
echo "$PARENT -> <$CHILD>" >&2
|
||||
if [[ ! ${INCLUDED[$CHILD]} ]]; then
|
||||
echo "#include <$CHILD>"
|
||||
INCLUDED[$CHILD]=true
|
||||
fi
|
||||
elif [[ "${SHOW_COMMENT}" = "true" ]] ; then
|
||||
echo "$LINE"
|
||||
elif [[ ! $LINE =~ $RE_EMPTY ]]; then
|
||||
echo "$LINE"
|
||||
fi
|
||||
done < $PARENT
|
||||
}
|
||||
|
||||
simplify_namespaces() {
|
||||
perl -p0i -e 's|ARDUINOJSON_END_PUBLIC_NAMESPACE\r?\nARDUINOJSON_BEGIN_PUBLIC_NAMESPACE\r?\n||igs' "$1"
|
||||
perl -p0i -e 's|ARDUINOJSON_END_PRIVATE_NAMESPACE\r?\nARDUINOJSON_BEGIN_PRIVATE_NAMESPACE\r?\n||igs' "$1"
|
||||
rm -f "$1.bak"
|
||||
}
|
||||
|
||||
INCLUDED=()
|
||||
INPUT=$1
|
||||
OUTPUT=$2
|
||||
process "$INPUT" true > "$OUTPUT"
|
||||
simplify_namespaces "$OUTPUT"
|
||||
@@ -0,0 +1,29 @@
|
||||
#!/usr/bin/awk -f
|
||||
|
||||
# Start echoing after the first list item
|
||||
/\* / {
|
||||
STARTED=1
|
||||
EMPTY_LINE=0
|
||||
}
|
||||
|
||||
# Remember if we have seen an empty line
|
||||
/^[[:space:]]*$/ {
|
||||
EMPTY_LINE=1
|
||||
}
|
||||
|
||||
# Exit when seeing a new version number
|
||||
/^v[[:digit:]]/ {
|
||||
if (STARTED) exit
|
||||
}
|
||||
|
||||
# Print if the line is not empty
|
||||
# and restore the empty line we have skipped
|
||||
!/^[[:space:]]*$/ {
|
||||
if (STARTED) {
|
||||
if (EMPTY_LINE) {
|
||||
print ""
|
||||
EMPTY_LINE=0
|
||||
}
|
||||
print
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -eu
|
||||
|
||||
VERSION="$1"
|
||||
CHANGELOG="$2"
|
||||
ARDUINOJSON_H="$3"
|
||||
|
||||
cat << END
|
||||
---
|
||||
branch: v7
|
||||
version: $VERSION
|
||||
date: '$(date +'%Y-%m-%d')'
|
||||
$(extras/scripts/wandbox/publish.sh "$ARDUINOJSON_H")
|
||||
---
|
||||
|
||||
$(extras/scripts/extract_changes.awk "$CHANGELOG")
|
||||
END
|
||||
@@ -0,0 +1,18 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -eu
|
||||
|
||||
SOURCE_DIR="$(dirname "$0")/../.."
|
||||
WORK_DIR=$(mktemp -d)
|
||||
trap 'rm -rf "$WORK_DIR"' EXIT
|
||||
|
||||
cp "$SOURCE_DIR/README.md" "$WORK_DIR/README.md"
|
||||
cp "$SOURCE_DIR/CHANGELOG.md" "$WORK_DIR/CHANGELOG.md"
|
||||
cp "$SOURCE_DIR/library.properties" "$WORK_DIR/library.properties"
|
||||
cp "$SOURCE_DIR/LICENSE.txt" "$WORK_DIR/LICENSE.txt"
|
||||
cp -r "$SOURCE_DIR/src" "$WORK_DIR/"
|
||||
cp -r "$SOURCE_DIR/examples" "$WORK_DIR/"
|
||||
|
||||
cd "$WORK_DIR"
|
||||
particle library upload
|
||||
particle library publish
|
||||
+87
@@ -0,0 +1,87 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -eu
|
||||
|
||||
which awk sed jq curl perl >/dev/null
|
||||
|
||||
cd "$(dirname "$0")/../.."
|
||||
|
||||
if ! git diff --quiet --exit-code; then
|
||||
echo "Repository contains uncommitted changes"
|
||||
exit
|
||||
fi
|
||||
|
||||
VERSION="$1"
|
||||
DATE=$(date +%F)
|
||||
TAG="v$VERSION"
|
||||
VERSION_REGEX='[0-9]+\.[0-9]+\.[0-9]+(-[a-z0-9]+)?'
|
||||
STARS=$(curl -s https://api.github.com/repos/bblanchon/ArduinoJson | jq '.stargazers_count')
|
||||
|
||||
update_version_in_source () {
|
||||
IFS=".-" read MAJOR MINOR REVISION EXTRA < <(echo "$VERSION")
|
||||
UNDERLINE=$(printf -- '-%.0s' $(seq 1 ${#TAG}))
|
||||
|
||||
sed -i~ -bE "1,20{s/$VERSION_REGEX/$VERSION/g}" README.md
|
||||
rm README.md~
|
||||
|
||||
sed -i~ -bE "4s/HEAD/$TAG ($DATE)/; 5s/-+/$UNDERLINE/" CHANGELOG.md
|
||||
rm CHANGELOG.md~
|
||||
|
||||
sed -i~ -bE "s/(project\\s*\\(ArduinoJson\\s+VERSION\\s+).*?\\)/\\1$MAJOR.$MINOR.$REVISION)/" CMakeLists.txt
|
||||
rm CMakeLists.txt~
|
||||
|
||||
sed -i~ -bE \
|
||||
-e "s/\"version\":.*$/\"version\": \"$VERSION\",/" \
|
||||
-e "s/[0-9]+ stars/$STARS stars/" \
|
||||
library.json
|
||||
rm library.json~
|
||||
|
||||
sed -i~ -bE \
|
||||
-e "s/version=.*$/version=$VERSION/" \
|
||||
-e "s/[0-9]+ stars/$STARS stars/" \
|
||||
library.properties
|
||||
rm library.properties~
|
||||
|
||||
sed -i~ -bE "s/version: .*$/version: $VERSION.{build}/" appveyor.yml
|
||||
rm appveyor.yml~
|
||||
|
||||
sed -i~ -bE \
|
||||
-e "s/^version: .*$/version: \"$VERSION\"/" \
|
||||
-e "s/[0-9]+ stars/$STARS stars/" \
|
||||
idf_component.yml
|
||||
rm idf_component.yml~
|
||||
|
||||
sed -i~ -bE \
|
||||
-e "s/ARDUINOJSON_VERSION .*$/ARDUINOJSON_VERSION \"$VERSION\"/" \
|
||||
-e "s/ARDUINOJSON_VERSION_MAJOR .*$/ARDUINOJSON_VERSION_MAJOR $MAJOR/" \
|
||||
-e "s/ARDUINOJSON_VERSION_MINOR .*$/ARDUINOJSON_VERSION_MINOR $MINOR/" \
|
||||
-e "s/ARDUINOJSON_VERSION_REVISION .*$/ARDUINOJSON_VERSION_REVISION $REVISION/" \
|
||||
-e "s/ARDUINOJSON_VERSION_MACRO .*$/ARDUINOJSON_VERSION_MACRO V$MAJOR$MINOR$REVISION/" \
|
||||
src/ArduinoJson/version.hpp
|
||||
rm src/ArduinoJson/version.hpp*~
|
||||
}
|
||||
|
||||
commit_new_version () {
|
||||
git add src/ArduinoJson/version.hpp README.md CHANGELOG.md library.json library.properties appveyor.yml CMakeLists.txt idf_component.yml
|
||||
git commit -m "Set version to $VERSION"
|
||||
}
|
||||
|
||||
add_tag () {
|
||||
CHANGES=$(awk '/\* /{ FOUND=1; print; next } { if (FOUND) exit}' CHANGELOG.md)
|
||||
git tag -m "ArduinoJson $VERSION"$'\n'"$CHANGES" "$TAG"
|
||||
}
|
||||
|
||||
push () {
|
||||
git push --follow-tags
|
||||
}
|
||||
|
||||
update_version_in_source
|
||||
commit_new_version
|
||||
add_tag
|
||||
push
|
||||
|
||||
extras/scripts/build-single-header.sh "src/ArduinoJson.h" "../ArduinoJson-$TAG.h"
|
||||
extras/scripts/build-single-header.sh "src/ArduinoJson.hpp" "../ArduinoJson-$TAG.hpp"
|
||||
extras/scripts/get-release-page.sh "$VERSION" "CHANGELOG.md" "../ArduinoJson-$TAG.h" > "../ArduinoJson-$TAG.md"
|
||||
|
||||
echo "You can now copy ../ArduinoJson-$TAG.md into arduinojson.org/collections/_versions/$VERSION.md"
|
||||
@@ -0,0 +1,42 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2026, Benoit BLANCHON
|
||||
// MIT License
|
||||
//
|
||||
// This example shows how to generate a JSON document with ArduinoJson.
|
||||
|
||||
#include <iostream>
|
||||
#include "ArduinoJson.h"
|
||||
|
||||
int main() {
|
||||
// Allocate the JSON document
|
||||
JsonDocument doc;
|
||||
|
||||
// Add values in the document.
|
||||
doc["sensor"] = "gps";
|
||||
doc["time"] = 1351824120;
|
||||
|
||||
// Add an array
|
||||
JsonArray data = doc["data"].to<JsonArray>();
|
||||
data.add(48.756080);
|
||||
data.add(2.302038);
|
||||
|
||||
// Generate the minified JSON and send it to STDOUT
|
||||
serializeJson(doc, std::cout);
|
||||
// The above line prints:
|
||||
// {"sensor":"gps","time":1351824120,"data":[48.756080,2.302038]}
|
||||
|
||||
// Start a new line
|
||||
std::cout << std::endl;
|
||||
|
||||
// Generate the prettified JSON and send it to STDOUT
|
||||
serializeJsonPretty(doc, std::cout);
|
||||
// The above line prints:
|
||||
// {
|
||||
// "sensor": "gps",
|
||||
// "time": 1351824120,
|
||||
// "data": [
|
||||
// 48.756080,
|
||||
// 2.302038
|
||||
// ]
|
||||
// }
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2026, Benoit BLANCHON
|
||||
// MIT License
|
||||
//
|
||||
// This example shows how to deserialize a JSON document with ArduinoJson.
|
||||
|
||||
#include <iostream>
|
||||
#include "ArduinoJson.h"
|
||||
|
||||
int main() {
|
||||
// Allocate the JSON document
|
||||
JsonDocument doc;
|
||||
|
||||
// JSON input string
|
||||
const char* json =
|
||||
"{\"sensor\":\"gps\",\"time\":1351824120,\"data\":[48.756080,2.302038]}";
|
||||
|
||||
// Deserialize the JSON document
|
||||
DeserializationError error = deserializeJson(doc, json);
|
||||
|
||||
// Test if parsing succeeds
|
||||
if (error) {
|
||||
std::cerr << "deserializeJson() failed: " << error.c_str() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Fetch the values
|
||||
//
|
||||
// Most of the time, you can rely on the implicit casts.
|
||||
// In other case, you can do doc["time"].as<long>();
|
||||
const char* sensor = doc["sensor"];
|
||||
long time = doc["time"];
|
||||
double latitude = doc["data"][0];
|
||||
double longitude = doc["data"][1];
|
||||
|
||||
// Print the values
|
||||
std::cout << sensor << std::endl;
|
||||
std::cout << time << std::endl;
|
||||
std::cout << latitude << std::endl;
|
||||
std::cout << longitude << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2026, Benoit BLANCHON
|
||||
// MIT License
|
||||
//
|
||||
// This example shows how to generate a JSON document with ArduinoJson.
|
||||
|
||||
#include <iostream>
|
||||
#include "ArduinoJson.h"
|
||||
|
||||
int main() {
|
||||
// Allocate the JSON document
|
||||
JsonDocument doc;
|
||||
|
||||
// The MessagePack input string
|
||||
uint8_t input[] = {131, 166, 115, 101, 110, 115, 111, 114, 163, 103, 112, 115,
|
||||
164, 116, 105, 109, 101, 206, 80, 147, 50, 248, 164, 100,
|
||||
97, 116, 97, 146, 203, 64, 72, 96, 199, 58, 188, 148,
|
||||
112, 203, 64, 2, 106, 146, 230, 33, 49, 169};
|
||||
// This MessagePack document contains:
|
||||
// {
|
||||
// "sensor": "gps",
|
||||
// "time": 1351824120,
|
||||
// "data": [48.75608, 2.302038]
|
||||
// }
|
||||
|
||||
// Parse the input
|
||||
DeserializationError error = deserializeMsgPack(doc, input);
|
||||
|
||||
// Test if parsing succeeds
|
||||
if (error) {
|
||||
std::cerr << "deserializeMsgPack() failed: " << error.c_str() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Fetch the values
|
||||
//
|
||||
// Most of the time, you can rely on the implicit casts.
|
||||
// In other case, you can do doc["time"].as<long>();
|
||||
const char* sensor = doc["sensor"];
|
||||
long time = doc["time"];
|
||||
double latitude = doc["data"][0];
|
||||
double longitude = doc["data"][1];
|
||||
|
||||
// Print the values
|
||||
std::cout << sensor << std::endl;
|
||||
std::cout << time << std::endl;
|
||||
std::cout << latitude << std::endl;
|
||||
std::cout << longitude << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -eu
|
||||
|
||||
ARDUINOJSON_H="$1"
|
||||
|
||||
read_string() {
|
||||
jq --slurp --raw-input '.' "$1"
|
||||
}
|
||||
|
||||
compile() {
|
||||
FILE_PATH="$(dirname $0)/$1.cpp"
|
||||
cat >parameters.json <<END
|
||||
{
|
||||
"code":$(read_string "$FILE_PATH"),
|
||||
"codes": [{"file":"ArduinoJson.h","code":$(read_string "$ARDUINOJSON_H")}],
|
||||
"options": "warning,c++11",
|
||||
"compiler": "gcc-head",
|
||||
"save": true
|
||||
}
|
||||
END
|
||||
URL=$(curl -sS -H "Content-type: application/json" -d @parameters.json https://wandbox.org/api/compile.json | jq --raw-output .url)
|
||||
rm parameters.json
|
||||
[ -n "$URL" ] && echo "$1: $URL"
|
||||
}
|
||||
|
||||
compile "JsonGeneratorExample"
|
||||
compile "JsonParserExample"
|
||||
compile "MsgPackParserExample"
|
||||
@@ -0,0 +1,36 @@
|
||||
# ArduinoJson - https://arduinojson.org
|
||||
# Copyright © 2014-2026, Benoit BLANCHON
|
||||
# MIT License
|
||||
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
link_libraries(ArduinoJson)
|
||||
|
||||
# Failing builds should only link with ArduinoJson, not catch
|
||||
add_subdirectory(FailingBuilds)
|
||||
|
||||
add_subdirectory(catch)
|
||||
link_libraries(catch)
|
||||
|
||||
include_directories(Helpers)
|
||||
add_subdirectory(Cpp17)
|
||||
add_subdirectory(Cpp20)
|
||||
add_subdirectory(Deprecated)
|
||||
add_subdirectory(IntegrationTests)
|
||||
add_subdirectory(JsonArray)
|
||||
add_subdirectory(JsonArrayConst)
|
||||
add_subdirectory(JsonDeserializer)
|
||||
add_subdirectory(JsonDocument)
|
||||
add_subdirectory(JsonObject)
|
||||
add_subdirectory(JsonObjectConst)
|
||||
add_subdirectory(JsonSerializer)
|
||||
add_subdirectory(JsonVariant)
|
||||
add_subdirectory(JsonVariantConst)
|
||||
add_subdirectory(ResourceManager)
|
||||
add_subdirectory(Misc)
|
||||
add_subdirectory(MixedConfiguration)
|
||||
add_subdirectory(MsgPackDeserializer)
|
||||
add_subdirectory(MsgPackSerializer)
|
||||
add_subdirectory(Numbers)
|
||||
add_subdirectory(TextFormatter)
|
||||
@@ -0,0 +1,29 @@
|
||||
# ArduinoJson - https://arduinojson.org
|
||||
# Copyright © 2014-2026, Benoit BLANCHON
|
||||
# MIT License
|
||||
|
||||
if(MSVC_VERSION LESS 1910)
|
||||
return()
|
||||
endif()
|
||||
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5)
|
||||
return()
|
||||
endif()
|
||||
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 7)
|
||||
return()
|
||||
endif()
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
add_executable(Cpp17Tests
|
||||
string_view.cpp
|
||||
)
|
||||
|
||||
add_test(Cpp17 Cpp17Tests)
|
||||
|
||||
set_tests_properties(Cpp17
|
||||
PROPERTIES
|
||||
LABELS "Catch"
|
||||
)
|
||||
@@ -0,0 +1,113 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2026, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
// we expect ArduinoJson.h to include <string_view>
|
||||
// but we don't want it to included accidentally
|
||||
#undef ARDUINO
|
||||
#define ARDUINOJSON_ENABLE_STD_STREAM 0
|
||||
#define ARDUINOJSON_ENABLE_STD_STRING 0
|
||||
|
||||
#include <ArduinoJson.h>
|
||||
#include <catch.hpp>
|
||||
|
||||
#include "Allocators.hpp"
|
||||
#include "Literals.hpp"
|
||||
|
||||
#if !ARDUINOJSON_ENABLE_STRING_VIEW
|
||||
# error ARDUINOJSON_ENABLE_STRING_VIEW must be set to 1
|
||||
#endif
|
||||
|
||||
using ArduinoJson::detail::sizeofArray;
|
||||
|
||||
TEST_CASE("string_view") {
|
||||
SpyingAllocator spy;
|
||||
JsonDocument doc(&spy);
|
||||
JsonVariant variant = doc.to<JsonVariant>();
|
||||
|
||||
SECTION("deserializeJson()") {
|
||||
auto err = deserializeJson(doc, std::string_view("123", 2));
|
||||
REQUIRE(err == DeserializationError::Ok);
|
||||
REQUIRE(doc.as<int>() == 12);
|
||||
}
|
||||
|
||||
SECTION("JsonDocument::set()") {
|
||||
doc.set(std::string_view("123", 2));
|
||||
REQUIRE(doc.as<std::string_view>() == "12");
|
||||
}
|
||||
|
||||
SECTION("JsonDocument::operator[]() const") {
|
||||
doc["ab"] = "Yes";
|
||||
doc["abc"] = "No";
|
||||
REQUIRE(doc[std::string_view("abc", 2)] == "Yes");
|
||||
}
|
||||
|
||||
SECTION("JsonDocument::operator[]()") {
|
||||
doc[std::string_view("abc", 2)] = "Yes";
|
||||
REQUIRE(doc["ab"] == "Yes");
|
||||
}
|
||||
|
||||
SECTION("JsonVariant::operator==()") {
|
||||
variant.set("A");
|
||||
REQUIRE(variant == std::string_view("AX", 1));
|
||||
REQUIRE_FALSE(variant == std::string_view("BX", 1));
|
||||
}
|
||||
|
||||
SECTION("JsonVariant::operator>()") {
|
||||
variant.set("B");
|
||||
REQUIRE(variant > std::string_view("AX", 1));
|
||||
REQUIRE_FALSE(variant > std::string_view("CX", 1));
|
||||
}
|
||||
|
||||
SECTION("JsonVariant::operator<()") {
|
||||
variant.set("B");
|
||||
REQUIRE(variant < std::string_view("CX", 1));
|
||||
REQUIRE_FALSE(variant < std::string_view("AX", 1));
|
||||
}
|
||||
|
||||
SECTION("String deduplication") {
|
||||
doc.add(std::string_view("example one", 7));
|
||||
doc.add(std::string_view("example two", 7));
|
||||
doc.add(std::string_view("example\0tree", 12));
|
||||
doc.add(std::string_view("example\0tree and a half", 12));
|
||||
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
Allocate(sizeofString("example")),
|
||||
Allocate(sizeofString("example tree")),
|
||||
});
|
||||
}
|
||||
|
||||
SECTION("as<std::string_view>()") {
|
||||
doc["s"] = "Hello World";
|
||||
doc["i"] = 42;
|
||||
REQUIRE(doc["s"].as<std::string_view>() == std::string_view("Hello World"));
|
||||
REQUIRE(doc["i"].as<std::string_view>() == std::string_view());
|
||||
}
|
||||
|
||||
SECTION("is<std::string_view>()") {
|
||||
doc["s"] = "Hello World";
|
||||
doc["i"] = 42;
|
||||
REQUIRE(doc["s"].is<std::string_view>() == true);
|
||||
REQUIRE(doc["i"].is<std::string_view>() == false);
|
||||
}
|
||||
|
||||
SECTION("String containing NUL") {
|
||||
doc.set("hello\0world"_s);
|
||||
REQUIRE(doc.as<std::string_view>().size() == 11);
|
||||
REQUIRE(doc.as<std::string_view>() == std::string_view("hello\0world", 11));
|
||||
}
|
||||
}
|
||||
|
||||
using ArduinoJson::detail::adaptString;
|
||||
|
||||
TEST_CASE("StringViewAdapter") {
|
||||
std::string_view str("bravoXXX", 5);
|
||||
auto adapter = adaptString(str);
|
||||
|
||||
CHECK(stringCompare(adapter, adaptString("alpha", 5)) > 0);
|
||||
CHECK(stringCompare(adapter, adaptString("bravo", 5)) == 0);
|
||||
CHECK(stringCompare(adapter, adaptString("charlie", 7)) < 0);
|
||||
|
||||
CHECK(adapter.size() == 5);
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
# ArduinoJson - https://arduinojson.org
|
||||
# Copyright © 2014-2026, Benoit BLANCHON
|
||||
# MIT License
|
||||
|
||||
if(MSVC_VERSION LESS 1910)
|
||||
return()
|
||||
endif()
|
||||
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 10)
|
||||
return()
|
||||
endif()
|
||||
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 10)
|
||||
return()
|
||||
endif()
|
||||
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
add_executable(Cpp20Tests
|
||||
smoke_test.cpp
|
||||
)
|
||||
|
||||
add_test(Cpp20 Cpp20Tests)
|
||||
|
||||
set_tests_properties(Cpp20
|
||||
PROPERTIES
|
||||
LABELS "Catch"
|
||||
)
|
||||
@@ -0,0 +1,15 @@
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
#include <catch.hpp>
|
||||
#include <string>
|
||||
|
||||
TEST_CASE("C++20 smoke test") {
|
||||
JsonDocument doc;
|
||||
|
||||
deserializeJson(doc, "{\"hello\":\"world\"}");
|
||||
REQUIRE(doc["hello"] == "world");
|
||||
|
||||
std::string json;
|
||||
serializeJson(doc, json);
|
||||
REQUIRE(json == "{\"hello\":\"world\"}");
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2026, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#include <ArduinoJson.h>
|
||||
#include <catch.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
using ArduinoJson::detail::is_base_of;
|
||||
|
||||
static std::string allocatorLog;
|
||||
|
||||
struct CustomAllocator {
|
||||
CustomAllocator() {
|
||||
allocatorLog = "";
|
||||
}
|
||||
|
||||
void* allocate(size_t n) {
|
||||
allocatorLog += "A";
|
||||
return malloc(n);
|
||||
}
|
||||
|
||||
void deallocate(void* p) {
|
||||
free(p);
|
||||
allocatorLog += "D";
|
||||
}
|
||||
|
||||
void* reallocate(void* p, size_t n) {
|
||||
allocatorLog += "R";
|
||||
return realloc(p, n);
|
||||
}
|
||||
};
|
||||
|
||||
TEST_CASE("BasicJsonDocument") {
|
||||
allocatorLog.clear();
|
||||
|
||||
SECTION("is a JsonDocument") {
|
||||
REQUIRE(
|
||||
is_base_of<JsonDocument, BasicJsonDocument<CustomAllocator>>::value ==
|
||||
true);
|
||||
}
|
||||
|
||||
SECTION("deserialize / serialize") {
|
||||
BasicJsonDocument<CustomAllocator> doc(256);
|
||||
deserializeJson(doc, "{\"hello\":\"world\"}");
|
||||
REQUIRE(doc.as<std::string>() == "{\"hello\":\"world\"}");
|
||||
doc.clear();
|
||||
REQUIRE(allocatorLog == "AARARDDD");
|
||||
}
|
||||
|
||||
SECTION("copy") {
|
||||
BasicJsonDocument<CustomAllocator> doc(256);
|
||||
doc["hello"] = "world";
|
||||
auto copy = doc;
|
||||
REQUIRE(copy.as<std::string>() == "{\"hello\":\"world\"}");
|
||||
REQUIRE(allocatorLog == "AA");
|
||||
}
|
||||
|
||||
SECTION("capacity") {
|
||||
BasicJsonDocument<CustomAllocator> doc(256);
|
||||
REQUIRE(doc.capacity() == 256);
|
||||
}
|
||||
|
||||
SECTION("garbageCollect()") {
|
||||
BasicJsonDocument<CustomAllocator> doc(256);
|
||||
doc.garbageCollect();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
# ArduinoJson - https://arduinojson.org
|
||||
# Copyright © 2014-2026, Benoit BLANCHON
|
||||
# MIT License
|
||||
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "(GNU|Clang)")
|
||||
add_compile_options(
|
||||
-w
|
||||
)
|
||||
endif()
|
||||
|
||||
if(MSVC)
|
||||
add_compile_options(
|
||||
/wd4996
|
||||
)
|
||||
endif()
|
||||
|
||||
add_executable(DeprecatedTests
|
||||
add.cpp
|
||||
BasicJsonDocument.cpp
|
||||
containsKey.cpp
|
||||
createNestedArray.cpp
|
||||
createNestedObject.cpp
|
||||
DynamicJsonDocument.cpp
|
||||
macros.cpp
|
||||
memoryUsage.cpp
|
||||
shallowCopy.cpp
|
||||
StaticJsonDocument.cpp
|
||||
)
|
||||
|
||||
add_test(Deprecated DeprecatedTests)
|
||||
|
||||
set_tests_properties(Deprecated
|
||||
PROPERTIES
|
||||
LABELS "Catch"
|
||||
)
|
||||
Loaded 100 of 2021 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user