├── .htmlHash.txt
├── ChangeLog.md
├── LICENSE
├── OTASettings.bat
├── OTASettings.command
├── OTASettings.js
├── README.md
├── README_CN.md
├── ap
├── README.md
├── ab.js
├── apIndex.html
├── hash.js
├── hash.min.js
├── main.js
├── main.min.js
├── out.txt
└── tools.js
├── app
├── README.md
└── empty_example
│ ├── README.md
│ └── app
│ ├── app.cpp
│ └── app.h
├── build.bat
├── build.command
├── build.js
├── directory_structure.md
├── doc
├── README.md
├── extented_command_specification.txt
└── get_method.js
├── examples
├── README.md
├── aes_256_cbc_example
│ ├── README.md
│ └── app
│ │ ├── app.cpp
│ │ └── app.h
├── arraybuffer_example
│ ├── README.md
│ └── app
│ │ ├── app.cpp
│ │ └── app.h
├── blink_example
│ ├── README.md
│ └── app
│ │ ├── app.cpp
│ │ └── app.h
├── database_example
│ ├── README.md
│ └── app
│ │ ├── app.cpp
│ │ └── app.h
├── element_example
│ ├── README.md
│ └── app
│ │ ├── app.cpp
│ │ └── app.h
├── empty_example
│ ├── README.md
│ └── app
│ │ ├── app.cpp
│ │ └── app.h
├── ota_example
│ ├── README.md
│ └── app
│ │ ├── app.cpp
│ │ └── app.h
├── provider_example
│ ├── README.md
│ └── app
│ │ ├── app.cpp
│ │ └── app.h
├── sha_digest_example
│ ├── README.md
│ └── app
│ │ ├── app.cpp
│ │ └── app.h
└── web_serial_example
│ ├── README.md
│ └── app
│ ├── app.cpp
│ └── app.h
├── firmware
└── README.md
├── lib
├── arraybuffer
│ ├── README.md
│ └── arraybuffer.hpp
├── config
│ ├── README.md
│ └── config.h
├── esp32time
│ ├── esp32time.cpp
│ └── esp32time.h
├── globalmanager
│ ├── globalmanager.cpp
│ └── globalmanager.h
├── languages
│ └── languages.h
├── mycrypto
│ ├── README.md
│ ├── mycrypto.cpp
│ └── mycrypto.h
├── mydb
│ ├── README.md
│ ├── mydb.cpp
│ └── mydb.h
├── myfs
│ ├── myfs.cpp
│ └── myfs.h
├── mynet
│ ├── mynet.cpp
│ └── mynet.h
├── mywebsocket
│ ├── README.md
│ ├── mywebsocket.cpp
│ └── mywebsocket.h
├── ota
│ ├── README.md
│ ├── ota.cpp
│ └── ota.h
├── provider
│ ├── provider.cpp
│ └── provider.h
└── softtimer
│ ├── softtimer.h
│ └── softtimr.cpp
├── partition
├── README.md
└── partition.csv
├── platformio.ini
├── scripts
├── .htmlHash.txt
├── ab.js
├── autoOTA.js
├── copyFirmware.js
├── hash.js
├── littlefsbuilder.py
└── replaceHtml.js
├── server
├── README.md
├── ab.js
├── ab.min.js
├── aes.js
├── aes.min.js
├── blacklist.json
├── create.js
├── device.js
├── device.min.js
├── globalConfig.json
├── hash.js
├── hash.min.js
├── index.html
├── index.js
├── index.min.js
├── iot.js
├── pro
│ └── index.html
├── source
│ └── index.html
├── start.bat
├── start.command
├── tools.bat
├── tools.command
└── tools.js
├── src
└── app
│ ├── README.md
│ ├── app.cpp
│ └── app.h
├── test
└── test.cpp
├── todo_list.txt
└── tools
├── mklittlefs
└── mklittlefs.exe
/.htmlHash.txt:
--------------------------------------------------------------------------------
1 | 7864b065b5153d14460ffe001a2eea69e30412ca1013f6bc830a79289f51683e
--------------------------------------------------------------------------------
/ChangeLog.md:
--------------------------------------------------------------------------------
1 | 2024/05/01
2 |
3 | English:
4 | 1. Fix bug of build tool.
5 | 2. Now support ESP32-C3.
6 |
7 | 中文:
8 |
9 | 1. 修复了构建工具的bug。
10 | 2. 现在支持ESP32-C3。
11 |
12 |
13 | 2023/09/03
14 |
15 | English:
16 | 1. Bug fixed: path indexing error for S3.
17 |
18 | 中文:
19 | 1. 错误已修复: S3的路径索引错误。
20 |
21 | 2023/09/03
22 |
23 | English:
24 | 1. An auotomatic function added to the codes, it could help you to convert old file format to new.
25 | Check tail of "config.h".
26 | (Better backup database and files before you do this)
27 | 2. ESP32-S3 support added, the default ESP32-S3 env added to the "platformio.ini".
28 | 3. A bug fixed. This bug could make app loop won't run.
29 |
30 | 中文:
31 | 1. 向代码中添加了一个函数可以自动转换旧版本的数据,查看"config.h"的尾部。(最好在转换前先备份数据库和文件)
32 | 2. 现已支持ESP32-S3,默认的ESP32-S3环境参数已添加到 "platformio.ini"。
33 | 3. 修复了一个错误,此错误可能会导致esp32的app loop不会运行。
34 |
35 |
36 | 2023/04/02
37 |
38 | English:
39 |
40 | 1. Unify mark for transfer and type of class Element.
41 | 2. Change function name from "webSerial" to "sendMessageToClient" of class GlobalManager.
42 | 3. Change argument type of "sendMessageToClient" to Element&, which is more convenient to use. New usage: "global->sendMessageToClient(100); global->sendMessageToClient(3.14); global->sendMessageToClient("Hello world!"); ...".
43 | 4. Change bytes format of Element from custom to little endian, attenation, this is NOT compatible with former version, MyDB will be interacted.
44 | 5. Because of bytes format changed, there will be a function added after, it could update former version.
45 |
46 | 中文:
47 |
48 | 1. 统一了用于传输的标志和类 Element 的类型。
49 | 2. 类 GlobalManager 的成员函数 "webSerial" 的名称修改为 "sendMessageToClient"。
50 | 3. "sendMessageToClient" 参数类型修改为 Element& , 这可以让使用更加方便。
51 | 4. 更改了类 Element 存储数据的字节序,由自定义字节序修改为小段存储,注意,这个修改不兼容以前的版本,内置的数据库组件将受到影响。
52 | 5. 由于更改了字节序,之后会添加一个函数用于更新已存储的数据到新的版本。
53 |
54 | 2023/03/30
55 |
56 | English:
57 |
58 | 1. Change data format to standard little endian.
59 | 2. ETYPE_STRING will copy last '\0'.
60 | 3. Move part of processes of create buffer and decode buffer to class Element.
61 | 4. Data processing of JS had been synchronized with cpp.
62 |
63 | 中文:
64 |
65 | 1. 修改数据格式为标准小端存储。
66 | 2. 字符串类型现在会拷贝末尾的 '\0'。
67 | 3. 编解码 Elements 的一部分处理过程移动到类 Element。
68 | 4. JS的数据处理过程现已与C++同步。
69 |
70 | 2023/03/28
71 |
72 | English:
73 |
74 | 1. Bug fixed:
75 | * Non-copy mode of class Element for buffer.
76 |
77 | 2023/03/26
78 |
79 | English:
80 |
81 | 1. Remove redundant function "getU8ALen" and "getBufferLength" of class Element, use "getRawBufferLength" to instead.
82 | 2. Replace data type from uint64_t to uint32_t of static functions in class ArrayBuffer.
83 |
84 | 中文:
85 |
86 | 1. 移除了冗余的成员函数 "getU8ALen" 和 "getBufferLength",使用 "getRawBufferLength" 来代替。
87 | 2. 类 ArrayBuffer 中的静态函数的数据类型由 uint64_t 改为 uint32_t。
88 |
89 | 2023/03/24
90 |
91 | English:
92 |
93 | 1. Reduce RAM cost from 24 bytes to 16 bytes of class Element by reorder member sequence.
94 | 2. Remove member "bufferLength", use union data member to hold length of buffer.
95 |
96 | 中文:
97 |
98 | 1. 通过重新对成员排序,使类 Element 的栈内存消耗由24字节缩小为16字节。
99 | 2. 移除了数据成员 bufferLength,改为使用联合体成员实现同样的功能。
100 |
101 | 2023/03/24
102 |
103 | English:
104 |
105 | 1. Bug fixed:
106 | * Remove "\r\n" in /scripts/replaceHtml.js to avoid too many empty lines in globalmmanager.h following compile time.
107 | * Fix SHA logical error in class Element.
108 |
109 | 2. Add convenient functions of Base64, SHA256 and AES to class Element.
110 | 3. Add more unit test to /test/test.cpp.
111 |
112 |
113 | 中文:
114 |
115 | 1. 错误修复:
116 | * 移除了 /scripts/replaceHtml.js 中多余的 "\r\n" 来避免文件 globalmanager.h 中编译时间后多余的空行。
117 | * 修复了 类 Element 中 SHA 的逻辑错误。
118 |
119 | 2. 给 类 Element 增加了方便的Base64、SHA256、AES 相关函数。
120 | 3. 添加了更多的单元测试到 /test/test.cpp。
121 |
122 | 2023/03/22
123 |
124 | English:
125 |
126 | 1. Add all types supported to class Element, u8, i8, u16, i16, u32, i32, u64, i64, float, double, string, buffer. Some name of enum were changed. Reference to arraybuffer.hpp.
127 | 2. Add convenient method to support Android WebView to get custom ID, Android Studio example project will release later.
128 |
129 |
130 | 中文:
131 |
132 | 1. 给类 Element 添加了所有数据类型的支持,单字节、双字节、四字节的有符号和无符号整数,单精度浮点、双精度浮点,字符串和二进制数组。 修改了某些枚举的名称。
133 | 2. 添加了方便的方法来给安卓WebView快速获取自定义ID,Android Studio 示例工程后续会上传。
134 |
135 | 2023/02/07
136 |
137 | English:
138 |
139 | 1. Fix bug that AP won't start on new device after firmware uploaded.
140 |
141 | 中文:
142 |
143 | 1. 修复了bug: 新设备在烧录固件后AP不会开启。
144 |
145 | 2023/02/05
146 |
147 | English:
148 |
149 | 1. Add auto sync function, which means you could modify source file in /app/appName, it will be copied to /src/app automatically.
150 | 2. Fix bug of web client and add cr, lf, crlf or none to serial mode. The cr, lf, crlf will be appended to content automatically.
151 | 3. Add timeout check process to auto OTA update, the auto OTA update process will be restart when error detected.
152 | 4. Fix bug of tools "replaceHtml.js".
153 | 5. Update version of main system to 42.1.0. Refer to /lib/config/config.h.
154 | 6. Add quick interface to global manager to set RX buffer size of serial0.
155 | 7. Remove a repeat function of global manager "inline uint16_t getRemoteServerOfflineDetectedTimes()". Use "inline bool serverOnline(uint8_t serverStatus = 0)" to instead.
156 | 8. Add feature to let user manually force system won't start AP in any situations. Be careful to use this function, or the system will NOT enable AP when sta connection failed or other status, this will reduce heat from SoC which help to other sensor that sensitive to temperature.
157 | 9. The time of firmware compiled will be copied to /lib/globalmanager/globalmanager.h automatically, it will shows in web client to let user can get time info.
158 | 10. Fix bug that AP won't close automatically.
159 | 11. Fix bug that transfer data from hardware serial to web client. It will use stack to hold data when size of data less than 128 bytes, or it will use heap to hold data. The maximum size of data defined as 81916 bytes, which is large enough.
160 |
161 | Conclusion: Currently the whold system running with no error, it is stable.
162 |
163 | 中文:
164 |
165 | 1. 增加了源代码自动同步辅助功能,在/app/app名称下修改源代码会自动同步到/src/app下。
166 | 2. 修复了前端的bug,给serial数据转发增加了在末尾自动添加特殊字符的功能,可以选择cr、lf、crlf或无特殊字符。
167 | 3. 给自动OTA升级功能增加了超时检测功能,自动OTA在发生错误超时 时会自动重新对设备发起升级请求。
168 | 4. 修复了工具"replaceHtml.js"中的路径引用错误。
169 | 5. 更新系统版本号到 "42.1.0",在头文件/lib/config/config.h中。
170 | 6. 增加了快速设置硬件串口RX缓冲区大小的功能。
171 | 7. 移除了一个globalmanager冗余的函数"inline uint16_t getRemoteServerOfflineDetectedTimes()",现在使用"inline bool serverOnline(uint8_t serverStatus = 0)"代替。
172 | 8. 增加了功能可以让用户手动执行强制禁止开启AP,使用此功能系统在**任何状态下**都**不会**开启AP,这会减少SoC的热量,以减少对周围距离较近的对温度敏感的传感器的影响。
173 | 9. 固件的编译时间会被自动填充到头文件/lib/globalmanager/globalmanager.h中,这个时间可以在前端看到,方便确定固件的具体编译时间。
174 | 10. 修复了AP不会自动关闭的bug。
175 | 11. 修复了串口数据转发的bug,当转发的数据大小小于128字节时,将使用栈空间存放数据,否则将使用堆空间存储数据,最大数据量被定义为81916字节,这足够大了。
176 |
177 | 结论: 当前系统运行无任何错误,非常稳定。
178 |
--------------------------------------------------------------------------------
/OTASettings.bat:
--------------------------------------------------------------------------------
1 | node OTASettings.js
--------------------------------------------------------------------------------
/OTASettings.command:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | cd $(dirname $0)
3 | node OTASettings.js
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Abc
2 |
3 | [中文](https://github.com/vidalouiswang/Abc/blob/main/README_CN.md)
4 |
5 | ## A basic ESP32 library for beginners
6 |
7 | ## Support ESP32/ESP32-S3/ESP32-C3
8 |
9 | ### At present, the ESP32 firmware built with this library has been running stably for several months and can be used officially.
10 |
11 | ### Note: Clone the code from main branch.
12 |
13 | ## Brief
14 |
15 | This library work with Espressif offical framework esp32-arduino 2.0.3.
16 |
17 | This library is for beginners who want to write their own code, but don't have much foundation. This library can be your starting point for learning esp32, you can use not only all the functions of esp32-arduino, but also esp-idf function, you can learn how to develop ESP32 from simple to further.
18 |
19 | ### Features
20 |
21 | * Built-in convenient, **fast and stable OTA update feature without even one line extra code**.
22 | * Rollback firmware when new frimware error at boot state automatically(esp32-arduino library closed this function from esp-idf, **this library implemented this feature without modify SDK that downloaded by Platform IO**).
23 | * Easy method to store or transfer integer, string, binary data without other format(like json), it will save more space or bandwidth when you storing those data into storage or transfer with internet.
24 | * Built-in convenient RAM database could store key-value typed data, based on LittleFS(esp-idf has this function but it don't has wear-leveling, according to offical document).
25 | * Stable and fast Websocket implement, **transfer a great many of data with high stability**.
26 | * One line code to get SHA1 and SHA256 using ESP32 hardware acceleration with variant types of input data.
27 | * One line code to encrypt or decrypt data with AES-256-CBC.
28 | * Develop **without connect your board to computer**, only provide power supply, use built-in fully automatic OTA update, this allows you could continue developing when you use light laptop or your computer doesn't support more USB port at that time, directly connect your develop board into any power. This feature also fits in those ESP32 had embedded into another devices, cooperate with auto rollback feature, this allows you to do more things with less works.
29 | * Transfer data from web page to serial or transfer data from serial to web page without coding, default settings use the first group of serial port, you can modify it if you like to, or transfer data from(to) more serial port simultaneously.
30 | * More features are in development...
31 |
32 | These features especially designed for beginners, easy to use and have strong scalability. For experts, please ignore.
33 |
34 | # How to use
35 |
36 | IDE requirement: Visual studio code with Platform IO installed.
37 |
38 | First you need to have a VPS, node.js 16 required.
39 | Or you could use your PC or NAS as a server.
40 |
41 | ### Step 1: Clone
42 |
43 | ```console
44 | git clone https://github.com/vidalouiswang/Abc.git
45 | ```
46 |
47 | ### Step 2: Setup Server
48 |
49 | 1. Use SSH connect to your VPS or NAS
50 |
51 | 2. Install package manager , suppose your OS is Ubuntu
52 |
53 | ```console
54 | sudo apt-get install npm
55 | ```
56 |
57 | 3. Install n module
58 | ```console
59 | sudo npm install -g n
60 | ```
61 |
62 | 4. Install Node.js
63 | ```console
64 | sudo n stable
65 | ```
66 |
67 | 5. Install pm2
68 | ```console
69 | sudo npm install -g pm2
70 | ```
71 |
72 | Now the version of node.js is lastest stable version, you could use the following command to check
73 |
74 | ```console
75 | node -v
76 | ```
77 |
78 | If shows "v16.x" means Node.js installed correctly, if it show old version, like "v8.x", you should input command
79 |
80 | ```console
81 | hash -r
82 | ```
83 |
84 | 6. If you clone the code into your personal computer, you should upload
85 | /server/
86 | - index.html
87 | - ab.js
88 | - hash.js
89 | - create.js
90 | - iot.js
91 |
92 | These five files to your server
93 |
94 | ```console
95 | cd ~/
96 | ```
97 | ```console
98 | mkdir server
99 | ```
100 | ```console
101 | cd server
102 | ```
103 |
104 | Then upload five files by any method you like to the folder "server"
105 |
106 | This step could be omit if you clone the code directly to your server, do this:
107 |
108 | ```console
109 | cd Abc/server
110 | ```
111 |
112 | 7. Install components
113 | ```console
114 | sudo npm install ws
115 | ```
116 |
117 | 8. Start server
118 | ```console
119 | sudo pm2 start iot.js
120 | ```
121 |
122 | Now the server configuration is finished, the default port is 12345 , you could modify it if you like,
123 |
124 | in file "globalConfig.json".
125 |
126 | Or, modify it at the bottom in file "iot.js".
127 |
128 | Remember restart server if you modified the port.
129 |
130 | ```console
131 | sudo pm2 restart iot.js
132 | ```
133 |
134 | Don't forget add rule to let new port could pass through in firewall.
135 |
136 | ### Step 3: Local Use
137 |
138 | 1. Use Platform IO open root folder.
139 | 2. Locate to /src/app/ .
140 | 3. Edit app.h and app.cpp as Arduino way.
141 | 4. Compile and upload(better erase flash first).
142 | 5. Use PC or phone connect to esp32 access point.
143 | 6. Open browser,locate to http://192.168.8.1.
144 | 7. Set arguments by tips and click reboot.
145 | 8. Locate to http://your_domain_or_ip_of_your_server:port/.
146 | 9. Login in with user name and password set in step 7.
147 | 10. Now you could see your device online, click "@" could access built-in providers.
148 |
149 | More information and examples refer to /examples/ , full comments in it.
150 |
151 | ### Check header files for basic information, configs locate to /lib/config/config.h
152 |
153 | ### The LittleFS extra component auto-selection feature has not been tested on Windows, but it should work and currently works fine on macOS 12.5.
154 |
155 | ### More tutorials and documentation are in the works.
156 |
157 | ### If you still don't know how to use, I will make a video and upload to YouTube, the link will be put right here.
158 |
159 | ### Code comments status(full and detailed comments):
160 |
161 | * Local:
162 |
163 | * Header file:
164 |
165 | * Almost all header files
166 | * /examples/*.h
167 |
168 | * Source File:
169 |
170 | * /lib/arraybuffer/arraybuffer.cpp
171 | * /examples/*.cpp
172 |
173 | * Server:
174 |
175 | * /server/iot.js
176 | * /server/create.js
177 |
178 | # Thanks to
179 |
180 | Thanks to the entire staff of Espressif, we have a cheap and easy-to-use ESP32 and other chips.
181 | Thanks to all the developers of Node.js, we have a convenient and easy-to-use JavaScript runtime.
182 | Thanks to all the developers of VSCode and Platform IO, we have an easy-to-use integrated development environment.
183 |
184 | [Espressif](https://github.com/espressif)
185 |
186 | [Node.js](https://github.com/nodejs)
187 |
188 | [Visual Studio Code](https://github.com/microsoft/vscode)
189 |
190 | [Platform IO](https://github.com/platformio)
191 |
192 | [ws](https://github.com/websockets/ws)
193 |
194 | [Brix](https://github.com/brix/crypto-js)
195 |
196 | [Felix Biego](https://github.com/fbiego/ESP32Time)
197 |
198 | # License
199 |
200 | (GNU General Public License v3.0 License)
201 |
202 | Copyright 2022, Vida Wang
203 |
204 | Children are the future of mankind, but there are still many children who are enduring hunger all over the world at this moment. If you are a good person and you like this lib, please donate to UNICEF.
205 | https://unicef.org
206 |
--------------------------------------------------------------------------------
/README_CN.md:
--------------------------------------------------------------------------------
1 | # Abc
2 |
3 | ## 一个为新手打造的 esp32 基础库
4 |
5 | ## 支持ESP32/ESP32-S3/ESP32-C3
6 |
7 | ### 目前,使用该库构建的 ESP32 固件已经稳定运行了数月,可以正式使用了。
8 |
9 | ### 备注: 从主分支克隆代码。
10 |
11 | ## 简介
12 |
13 | 这个库和乐鑫官方 esp32-arduino 2.0.3 库一起使用。
14 | 这个库是为了那些想要自己编写代码,但是却又没有太多基础的新手打造的,这个库可以成为你学习 esp32 的起点,你不仅可以使用 esp32-arduino 的所有功能,也能使用 esp-idf 的功能,可以由浅入深的学习如何开发 ESP32。
15 |
16 | ### 功能
17 |
18 | * 内置了方便、快速且稳定的 OTA 升级功能,**无需任何一行额外代码即可使用**。
19 | * 存在故障的固件可以自动回滚,再也不用担心与安装到电饭锅里的 ESP32 失联( esp-idf 有这个功能,但是 esp32-arduino 库把这个功能关闭了,**本库无需修改自动下载的 SDK 即可实现这个功能**),这可以让你在不同开发机器之间快速的同步代码而无需担心出错。
20 | * 非常简单的方法就可以存储和传输整数、字符串、二进制数据而无需再使用其他格式( 比如 json ),这可以让你在存储数据和在网络上进行传输时节省许多空间和带宽。
21 | * 内置了便于使用的内存数据库,使用 LittleFS 进行存储( esp-idf 有这个功能,但是根据官方文档没有磨损均衡)。
22 | * 稳定且快速的 Websocket 实现,**可以非常方便的传输大量数据且具备高稳定性**。
23 | * 一行代码就能用的 SHA1,SHA256 数字摘要功能,基于 ESP32 硬件加速实现,可使用多种不同种类的数据作为输入。
24 | * 一行代码就能用的 AES-256-CBC 加密与解密功能,基于 ESP32 硬件加速实现。
25 | * **无需连接到电脑**,只需要给开发板供电,即可快速开发烧录,使用内置的全自动 OTA 升级功能,当使用轻薄笔记本开发或电脑 USB 接口不够用,暂时又没有拓展坞时,可以直接把开发板插到其他电源上(比如移动电源),这可以让你从容的继续进行开发。此功能同样适用于已部署到设备内的 ESP32,配合故障自动回滚功能开发效率事半功倍。
26 | * 无需一行代码即可把数据从串口转发到前端,或从前端把数据转发到串口,开箱即用,默认使用第一组串口,即串口0,可以根据自己的需要修改到其他串口,或同时转发多个串口。
27 | * 更多功能正在开发中...
28 |
29 | 以上功能均是为新手开发的,使用方便扩展性强,高手请忽略。
30 |
31 | # 如何使用
32 |
33 | ### 各种配置以及教学系列视频: https://space.bilibili.com/4733242
34 |
35 | 开发环境: 安装了 Platform IO 的 Visual studio code.
36 |
37 | 首先你需要有一台 VPS,安装了 node.js 16。
38 | 或者你也可以用你的电脑或 NAS 当做服务器。
39 |
40 | ### 第一步:克隆代码
41 |
42 | ```console
43 | git clone https://github.com/vidalouiswang/Abc.git
44 | ```
45 |
46 | ### 第二步:配置服务器
47 |
48 | 1. 使用SSH连接你的VPS
49 |
50 | 2. 安装 包管理器 , 假设你的系统是 Ubuntu
51 |
52 | ```console
53 | sudo apt-get install npm
54 | ```
55 |
56 | 3. 安装n模块
57 | ```console
58 | sudo npm install -g n
59 | ```
60 |
61 | 4. 安装 Node.js
62 | ```console
63 | sudo n stable
64 | ```
65 |
66 | 5. 安装 pm2
67 | ```console
68 | sudo npm install -g pm2
69 | ```
70 |
71 | 现在你的node.js应该已经处于最新稳定版了,可以输入如下命令查看
72 |
73 | ```console
74 | node -v
75 | ```
76 |
77 | 如果出现 "v16.x" 证明安装已经完成了,如果依然显示旧版本,比如 "v8.x",你可以输入如下命令
78 |
79 | ```console
80 | hash -r
81 | ```
82 |
83 | 6. 如果你的代码克隆到你的个人电脑,你需要上传
84 | /server/
85 | - index.html
86 | - ab.js
87 | - hash.js
88 | - create.js
89 | - iot.js
90 |
91 | 这五个文件到你的服务器,在SSH中按如下步骤操作
92 |
93 | ```console
94 | cd ~/
95 | ```
96 | ```console
97 | mkdir server
98 | ```
99 | ```console
100 | cd server
101 | ```
102 |
103 | 然后把上面的五个文件使用你喜欢的方式上传到server文件夹下
104 |
105 | 如果你直接将代码克隆到服务器则这一步可以省略,直接
106 | ```console
107 | cd Abc/server
108 | ```
109 |
110 | 7. 安装基础组件
111 | ```console
112 | sudo npm install ws
113 | ```
114 |
115 | 8. 开启服务器
116 | ```console
117 | sudo pm2 start iot.js
118 | ```
119 |
120 | 服务器已经配置完毕,默认端口为 12345, 可以自己修改,配置在 "globalConfig.json" 中
121 |
122 | 也可以直接在代码文件 iot.js 最底部修改
123 |
124 | 如果修改了端口记得重新启动服务器
125 | ```console
126 | sudo pm2 restart iot.js
127 | ```
128 |
129 | 请注意在防火墙放行相应端口
130 |
131 | ### 第三步:本地使用
132 |
133 | 1. 使用 Platform IO 打开根目录。
134 | 2. 定位到路径 /src/app。
135 | 3. 然后编辑 app.h 和 app.cpp,编程方式和 arduino 一样,在函数 setup 和 loop 中添加代码即可。
136 | 4. 编译上传固件(首次使用最好先擦除flash)。
137 | 5. 使用电脑或手机搜索esp32热点,然后连接。
138 | 6. 打开浏览器,进入 http://192.168.8.1。
139 | 7. 根据提示设置参数然后点击重启。
140 | 8. 打开 http://你的服务器ip或域名:端口/。
141 | 9. 使用在第7步中设置的用户明和密码登录。
142 | 10. 你可以看到在线的设备,点击 "@" 可以访问内置Provider。
143 |
144 | 其他功能请参考示例,所有示例均有详细的中英双语注释,也可关注本人B站账号,会不定期发布新的视频。
145 |
146 | ### 参考头文件查看基础信息与各种配置,在 /lib/config/config.h。
147 |
148 | ### LittleFS 额外组件自动选择功能还未在Windows环境测试过,但是它应该可以工作,目前在macOS 12.5工作正常。
149 |
150 | ### 更多教程和文档正在编写中。
151 |
152 | ### 代码注释状态(全部的、详细的双语注释,其他文件也有注释,一般都是开发时用的简单英文注释):
153 |
154 | * 本地:
155 |
156 | * 头文件:
157 |
158 | * 几乎所有的头文件
159 | * 示例的所有头文件
160 |
161 | * 源文件:
162 |
163 | * /lib/arraybuffer/arraybuffer.cpp
164 | * 示例的所有源文件
165 |
166 | * 服务器
167 |
168 | * /server/iot.js
169 | * /server/create.js
170 |
171 | # 感谢
172 |
173 | 感谢乐鑫的全体工作人员,让我们拥有了便宜好用的ESP32以及其他芯片。
174 | 感谢Node.js的全体开发者,让我们拥有了便捷好用的JavaScript运行时。
175 | 感谢VSCode和Platform IO的全体开发者,让我们拥有了好用的集成开发环境。
176 |
177 | [Espressif](https://github.com/espressif)
178 |
179 | [Node.js](https://github.com/nodejs)
180 |
181 | [Visual Studio Code](https://github.com/microsoft/vscode)
182 |
183 | [Platform IO](https://github.com/platformio)
184 |
185 | [ws](https://github.com/websockets/ws)
186 |
187 | [Brix](https://github.com/brix/crypto-js)
188 |
189 | [Felix Biego](https://github.com/fbiego/ESP32Time)
190 |
191 | # 协议
192 |
193 | (GNU General Public License v3.0 License)
194 |
195 | Copyright 2022, Vida Wang
196 |
197 | 孩子是人类的未来,但是现在全世界仍然有许多孩子饱受饥饿,如果你是个善良的人、认可我的代码,请捐助联合国儿童基金会,谢谢。
198 | https://unicef.cn
199 |
--------------------------------------------------------------------------------
/ap/README.md:
--------------------------------------------------------------------------------
1 | This folder contains files for AP mode web server.
2 | You can modify apIndex.html and main.js, and then minify them into xxx.min.js.
3 | Before you build firmware, the script will combine js and html into out.html and out.txt, and replace it to globalmanager.h.
4 |
5 | 这个文件夹包含了AP模式前端使用的文件。
6 | 你可以修改apIndex.html和main.js,然后把它们精简到 xxx.min.js。
7 | 在你构建固件的时候脚本会合成 js 和 html 到 out.html 和 out.txt,然后替换globalmanager.h中的内容。
--------------------------------------------------------------------------------
/ap/ab.js:
--------------------------------------------------------------------------------
1 | (function(){function e(e){for(let t=0;t=0?n<256?(o.push(r),o=e({arr:o,byteLength:1,number:n,type:"8"})):n>255&&n<65536?(o.push(a),o=e({arr:o,byteLength:2,number:n,type:"16"})):n>65535&&n<4294967296?(o.push(g),o=e({arr:o,byteLength:4,number:n,type:"32"})):(o.push(h),o=e({arr:o,byteLength:8,number:n,type:"64"})):n>=-128?(o.push(b),o=e({arr:o,byteLength:1,number:n,type:"8"})):n<-128&&n>=-32768?(o.push(f),o=e({arr:o,byteLength:2,number:n,type:"16"})):n<-32768&&n>=-2147483648?(o.push(i),o=e({arr:o,byteLength:4,number:n,type:"32"})):(o.push(y),o=e({arr:o,byteLength:8,number:n,type:"64"}));else{let t=n.toString().length-1;t>5?(o.push(l),o=e({arr:o,byteLength:8,number:n,type:"d"})):(o.push(p),o=e({arr:o,byteLength:4,number:n,type:"f"}))}}else if(0<=typeName.indexOf("bigint"))o.push(h),o=e({arr:o,byteLength:8,number:t[L],type:"64"});else if(0<=typeName.indexOf("uint8array")){o.push(u),o=e({arr:o,byteLength:4,number:t[L].length,type:"32"});for(let e of t[L])o.push(e)}else if(0<=typeName.indexOf("string")){o.push(s);let n=(new TextEncoder).encode(t[L]);o=e({arr:o,byteLength:4,number:n.length+1,type:"32"});for(let e of n)o.push(e);o.push(0)}return new Uint8Array(o).buffer}function n(e,t,n,o,L){if(!e)return;if(!e.byteLength)return;let c,m=[],d=e=>n?{}:[];try{c=new DataView(e)}catch(e){return d()}let U=0;for(;U247&&(t-=256),m.length&&o)break;switch(t){case r:case b:if(++U,e.byteLength-U<1)return d();if(L?m.push({data:t==r?c.getUint8(U):c.getInt8(U),offset:U,length:1}):m.push(t==r?c.getUint8(U):c.getInt8(U)),++U,o)break;break;case a:case f:if(++U,e.byteLength-U<2)return d();L?m.push({data:t==a?c.getUint16(U,!0):c.getInt16(U,!0),offset:U,length:2}):m.push(t==a?c.getUint16(U,!0):c.getInt16(U,!0)),U+=2;break;case g:case i:if(++U,e.byteLength-U<4)return d();L?m.push({data:t==g?c.getUint32(U,!0):c.getInt32(U,!0),offset:U,length:4}):m.push(t==g?c.getUint32(U,!0):c.getInt32(U,!0)),U+=4;break;case h:case y:if(++U,e.byteLength-U<8)return d();L?m.push({data:t==h?c.getBigUint64(U,!0):c.getBigInt64(U,!0),offset:U,length:8}):m.push(t==h?c.getBigUint64(U,!0):c.getBigInt64(U,!0)),U+=8;break;case p:case l:if(++U,e.byteLength-U<(t==p?4:8))return d();L?m.push({data:m.push(t==p?c.getFloat32(U,!0):c.getFloat64(U,!0)),offset:U,length:t==p?4:8}):m.push(t==p?c.getFloat32(U,!0):c.getFloat64(U,!0)),U+=t==p?4:8;break;case u:if(++U,e.byteLength-U<4)return d();let n=c.getUint32(U,!0);if(U+=4,e.byteLength-Ue.byteLength){m.push({offset:U,length:n});break}let w=new Uint8Array(n);for(let e=0;em.length-1?w[n[e]]=null:w[n[e]]=m[e];return w}const r=1,a=2,g=4,h=8,u=10,s=9,b=-1,f=-2,i=-4,y=-8,p=6,l=7;"object"==typeof window?(window.createArrayBuffer=t,window.decodeArrayBuffer=n):module.exports={createArrayBuffer:t,decodeArrayBuffer:n}})();
--------------------------------------------------------------------------------
/ap/apIndex.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Abc
6 |
7 |
8 |
57 |
58 |
59 |
60 |
61 |
62 |
70 |
78 |
89 |
97 |
98 |
101 |
104 |
107 |
110 |
113 |
114 |
115 |
118 |
121 |
124 |
125 |
126 |
--------------------------------------------------------------------------------
/ap/hash.js:
--------------------------------------------------------------------------------
1 | (function(){let e,r,t,l=(e,r)=>r>>>e|r<<32-e,o=(e,r,t)=>e&r^~e&t,n=(e,r,t)=>e&r^e&t^r&t,f=e=>l(2,e)^l(13,e)^l(22,e),a=e=>l(6,e)^l(11,e)^l(25,e),w=e=>l(7,e)^l(18,e)^e>>>3,A=e=>l(17,e)^l(19,e)^e>>>10,y=(e,r)=>e[15&r]+=A(e[r+14&15])+e[r+9&15]+w(e[r+1&15]),c=new Array(1116352408,1899447441,3049323471,3921009573,961987163,1508970993,2453635748,2870763221,3624381080,310598401,607225278,1426881987,1925078388,2162078206,2614888103,3248222580,3835390401,4022224774,264347078,604807628,770255983,1249150122,1555081692,1996064986,2554220882,2821834349,2952996808,3210313671,3336571891,3584528711,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,2177026350,2456956037,2730485921,2820302411,3259730800,3345764771,3516065817,3600352804,4094571909,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,2227730452,2361852424,2428436474,2756734187,3204031479,3329325298),d="0123456789abcdef",u=(e,r)=>{let t=(65535&e)+(65535&r),l=(e>>16)+(r>>16)+(t>>16);return l<<16|65535&t},h=()=>{e=new Array(8);r=new Array(2);t=new Array(64);r[0]=r[1]=0;e[0]=1779033703;e[1]=3144134277;e[2]=1013904242;e[3]=2773480762;e[4]=1359893119;e[5]=2600822924;e[6]=528734635;e[7]=1541459225},i=()=>{let r,l,w,A,d,h,i,g,s,b,p=new Array(16);r=e[0];l=e[1];w=e[2];A=e[3];d=e[4];h=e[5];i=e[6];g=e[7];for(let e=0;e<16;e++)p[e]=t[3+(e<<2)]|t[2+(e<<2)]<<8|t[1+(e<<2)]<<16|t[e<<2]<<24;for(let e=0;e<64;e++){s=g+a(d)+o(d,h,i)+c[e];s+=e<16?p[e]:y(p,e);b=f(r)+n(r,l,w);g=i;i=h;h=d;d=u(A,s);A=w;w=l;l=r;r=u(s,b)}e[0]+=r;e[1]+=l;e[2]+=w;e[3]+=A;e[4]+=d;e[5]+=h;e[6]+=i;e[7]+=g},g=(e,l)=>{let o,n,f=0;n=r[0]>>3&63;let a=63&l;(r[0]+=l<<3)>29;for(o=0;o+63{let e=r[0]>>3&63;t[e++]=128;if(e<=56)for(let r=e;r<56;r++)t[r]=0;else{for(let r=e;r<64;r++)t[r]=0;i();for(let e=0;e<56;e++)t[e]=0}t[56]=r[1]>>>24&255;t[57]=r[1]>>>16&255;t[58]=r[1]>>>8&255;t[59]=255&r[1];t[60]=r[0]>>>24&255;t[61]=r[0]>>>16&255;t[62]=r[0]>>>8&255;t[63]=255&r[0];i()},b=()=>{let r=0,t=new Array(32);for(let l=0;l<8;l++){t[r++]=e[l]>>>24&255;t[r++]=e[l]>>>16&255;t[r++]=e[l]>>>8&255;t[r++]=255&e[l]}return t},p=()=>{let r=new String;for(let t=0;t<8;t++)for(let l=28;l>=0;l-=4)r+=d.charAt(e[t]>>>l&15);return r},C=(e,r,t)=>{h();g(e,e.length);s();return r?b():p()};"object"==typeof window?window.getHash=C:module.exports=C})();
--------------------------------------------------------------------------------
/ap/hash.min.js:
--------------------------------------------------------------------------------
1 | (function(){let e,r,t,l=(e,r)=>r>>>e|r<<32-e,o=(e,r,t)=>e&r^~e&t,f=(e,r,t)=>e&r^e&t^r&t,n=e=>l(2,e)^l(13,e)^l(22,e),a=e=>l(6,e)^l(11,e)^l(25,e),w=e=>l(7,e)^l(18,e)^e>>>3,A=e=>l(17,e)^l(19,e)^e>>>10,y=(e,r)=>e[15&r]+=A(e[r+14&15])+e[r+9&15]+w(e[r+1&15]),i=new Array(1116352408,1899447441,3049323471,3921009573,961987163,1508970993,2453635748,2870763221,3624381080,310598401,607225278,1426881987,1925078388,2162078206,2614888103,3248222580,3835390401,4022224774,264347078,604807628,770255983,1249150122,1555081692,1996064986,2554220882,2821834349,2952996808,3210313671,3336571891,3584528711,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,2177026350,2456956037,2730485921,2820302411,3259730800,3345764771,3516065817,3600352804,4094571909,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,2227730452,2361852424,2428436474,2756734187,3204031479,3329325298),c="0123456789abcdef",d=(e,r)=>{let t=(65535&e)+(65535&r),l=(e>>16)+(r>>16)+(t>>16);return l<<16|65535&t},h=()=>{e=new Array(8),r=new Array(2),t=new Array(64),r[0]=r[1]=0,e[0]=1779033703,e[1]=3144134277,e[2]=1013904242,e[3]=2773480762,e[4]=1359893119,e[5]=2600822924,e[6]=528734635,e[7]=1541459225},s=()=>{let r,l,w,A,c,h,s,u,g,p,b=new Array(16);r=e[0],l=e[1],w=e[2],A=e[3],c=e[4],h=e[5],s=e[6],u=e[7];for(let e=0;e<16;e++)b[e]=t[3+(e<<2)]|t[2+(e<<2)]<<8|t[1+(e<<2)]<<16|t[e<<2]<<24;for(let e=0;e<64;e++)g=u+a(c)+o(c,h,s)+i[e],g+=e<16?b[e]:y(b,e),p=n(r)+f(r,l,w),u=s,s=h,h=c,c=d(A,g),A=w,w=l,l=r,r=d(g,p);e[0]+=r,e[1]+=l,e[2]+=w,e[3]+=A,e[4]+=c,e[5]+=h,e[6]+=s,e[7]+=u},u=(e,l)=>{let o,f,n=0;f=r[0]>>3&63;let a=63&l;if((r[0]+=l<<3)>29,"string"==typeof e){for(o=0;o+63{let e=r[0]>>3&63;if(t[e++]=128,e<=56)for(let r=e;r<56;r++)t[r]=0;else{for(let r=e;r<64;r++)t[r]=0;s();for(let e=0;e<56;e++)t[e]=0}t[56]=r[1]>>>24&255,t[57]=r[1]>>>16&255,t[58]=r[1]>>>8&255,t[59]=255&r[1],t[60]=r[0]>>>24&255,t[61]=r[0]>>>16&255,t[62]=r[0]>>>8&255,t[63]=255&r[0],s()},p=()=>{let r=0,t=new Array(32);for(let l=0;l<8;l++)t[r++]=e[l]>>>24&255,t[r++]=e[l]>>>16&255,t[r++]=e[l]>>>8&255,t[r++]=255&e[l];return t},b=()=>{let r=new String;for(let t=0;t<8;t++)for(let l=28;l>=0;l-=4)r+=c.charAt(e[t]>>>l&15);return r},C=(e,r,t)=>(h(),u(e,e.length),g(),r?p():b());"object"==typeof window?window.getHash=C:module.exports=C})();
--------------------------------------------------------------------------------
/ap/main.min.js:
--------------------------------------------------------------------------------
1 | (e=>{let t=window,o=e=>document.getElementById(e),n=t.showMsg=((e,t)=>{t=t||3e3;let n=o("msg");try{clearTimeout(n.t)}catch(e){}n.innerHTML=e,n.className+=" msgShow",n.t=setTimeout(()=>{n.className="msg"},t)}),c=!0,r={cn:{ssid:"WiFi名称",wifiPwd:"WiFi密码",user:"用户名",userPwd:"密码",websocketDomain:"WebSocket主机",websocketPort:"WebSocket端口",websocketPath:"WebSocket路径",nickname:"昵称",token:"令牌",setArguments:"设置参数",reboot:"重启",rebootNow:"立即重启",rollback:"回滚固件",deepSleep:"睡眠10分钟",txtError:"错误",txtSet:"设置参数成功",txtDelayReboot:"设备将会在3秒后重启",txtRollback:"回滚操作成功",txtDeepSleep:"设备即将睡眠",txtConnected:"已连接",txtDisconnected:"已断开",txtInvalid:"不合法"},en:{ssid:"WiFi SSID",wifiPwd:"WiFi password",user:"User name",userPwd:"password",websocketDomain:"WebSocket host",websocketPort:"WebSocket port",websocketPath:"WebSocket path",nickname:"Nickname",token:"Token",setArguments:"Submit",reboot:"Reboot",rebootNow:"Reboot immediately",rollback:"Rollback firmware",deepSleep:"Deep sleep 10 minutes",txtError:"Error",txtSet:"Arguments set",txtDelayReboot:"Will reboot in 3 seconds",txtRollback:"Rollback OK",txtDeepSleep:"Will into deep sleep in 3 seconds",txtConnected:"Connected",txtDisconnected:"Disconnected",txtInvalid:" Invalid"}};(e=>{let t=navigator.language;t.length&&(t=t.substring(0,2).toLowerCase(),t.startsWith("en")&&(c=!1));let o=document.getElementsByTagName("a");for(let e of o)e.href&&""!=e.href||(e.href="javascript:void(0);"),e.innerText=c?r.cn[e.id]:r.en[e.id];o=document.getElementsByTagName("input");for(let e of o)"text"!=e.type&&"password"!=e.type||(e.placeholder=c?r.cn[e.id]:r.en[e.id])})();let l=t.connectWebsocket=(e=>{try{t.webSocket=new WebSocket("ws://"+t.location.host+":80"),t.webSocket.binaryType="arraybuffer",t.webSocket.onerror=(e=>{n((c?r.cn.txtError:r.en.txtError)+": "+JSON.stringify(e)),setTimeout(()=>{l()},1e3)}),t.webSocket.onmessage=(e=>{if(e.data&&e.data.byteLength>=2){let t=decodeArrayBuffer(e.data);t&&t.length&&(0==t[0]?n(c?r.cn.txtSet:r.en.txtSet):1==t[0]?n(c?r.cn.txtDelayReboot:r.en.txtDelayReboot):136==t[0]?n(c?r.cn.txtRollback:r.en.rollback):137==t[0]?n(c?r.cn.txtDeepSleep:r.en.deepSleep):t[0])}}),t.webSocket.onopen=function(){n(c?r.cn.txtConnected:r.en.txtConnected)},t.webSocket.onclose=(e=>{n(c?r.cn.txtDisconnected:r.en.txtDisconnected),setTimeout(()=>{l()},1e3)})}catch(e){setTimeout(()=>{l()},1e3)}});t.connectWebsocket();let i=t.launch=function(e){t.webSocket.send(createArrayBuffer(e))};o("setArguments").onclick=(e=>{let t=e=>{n(e+(c?r.cn.txtInvalid:r.en.txtInvalid))},l=o("nickname").value,a=o("ssid").value;if(!a.trim().length)return void t(c?r.cn.ssid:r.en.ssid);let s=o("wifiPwd").value;if(!s.trim().length)return void t(c?r.cn.wifiPwd:r.en.wifiPwd);let d=o("user").value;if(!d.trim().length)return void t(c?r.cn.user:r.en.user);let b=o("userPwd").value;if(!b.trim().length)return void t(c?r.cn.userPwd:r.en.userPwd);let u=o("websocketDomain").value;if(!u.trim().length)return void t(c?r.cn.websocketDomain:r.en.websocketDomain);let k=o("websocketPort").value;k=k.replace(/\s/g,""),k=k.length?k:"80",k=parseInt(k);let w=o("websocketPath").value;w=w.replace(/\s/g,""),w=w.length?w:"/";let m=o("token").value;i([0,l,a,s,new Uint8Array(getHash(d,!0)),new Uint8Array(getHash(b,!0)),u,k,w,m])}),o("reboot").onclick=(e=>{i([1])}),o("rebootNow").onclick=(e=>{i([2])}),o("rollback").onclick=(e=>{i([136])}),o("deepSleep").onclick=(e=>{i([137])}),(e=>{let t=document.getElementsByTagName("input");for(let e of t)"text"!=e.type&&"password"!=e.type||(e.onkeyup=function(e){localStorage[this.id]=this.value});for(let e in localStorage){let t=o(e);t&&(t.value=localStorage[e])}})()})();
--------------------------------------------------------------------------------
/ap/tools.js:
--------------------------------------------------------------------------------
1 | let fs = require("fs");
2 |
3 | let rootPath = process.argv[process.argv.length - 1];
4 |
5 | rootPath += "ap/";
6 |
7 | let html = fs.readFileSync(rootPath + "apIndex.html").toString();
8 | let js = fs.readFileSync(rootPath + "main.min.js").toString();
9 | let ab = fs.readFileSync(rootPath + "ab.js").toString();
10 | let hash = fs.readFileSync(rootPath + "hash.js").toString();
11 | html = html.replace("main_js", js);
12 | html = html.replace("ab_js", ab);
13 | html = html.replace("hash_js", hash);
14 | html = html.replace(/"/g, "'");
15 | html = html.replace(/[\r\n]/g, "");
16 | html = html.replace(/[\s]{2,}/g, " ")
17 |
18 | fs.writeFileSync(rootPath + "out.txt", html);
19 | //fs.writeFileSync(rootPath + "out.html", html);
20 |
21 | console.log("ap index built");
--------------------------------------------------------------------------------
/app/README.md:
--------------------------------------------------------------------------------
1 | This folder stored all single apps.
2 |
3 | 这个文件夹存储了所有单独的app。
--------------------------------------------------------------------------------
/app/empty_example/README.md:
--------------------------------------------------------------------------------
1 | This is an empty example, only show code structure.
2 |
3 | 这是个空工程,仅用于展示代码结构。
--------------------------------------------------------------------------------
/app/empty_example/app/app.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * @file app.cpp
3 | * @brief
4 | *
5 | * Code this file just like Arduino way
6 | *
7 | * 就像使用Arduino框架一样在这个文件中写代码就可以了
8 | *
9 | */
10 |
11 | #include "app.h"
12 |
13 | void App::setup()
14 | {
15 | /**
16 | * ===English:
17 | * put your code in this function to run it once
18 | *
19 | * ===中文:
20 | * 把你的代码放在这个函数里,代码会被运行一次
21 | */
22 |
23 | /**
24 | * ===English:
25 | * if you just did an OTA update
26 | * you could do anything here, don't worry any code bugs
27 | * if any error happened, and reboot times reach maximum valve
28 | * firmware will rollback to former version automatically
29 | *
30 | * you could modify the valve yourself
31 | * in file /lib/config/config.h
32 | *
33 | * ! Attention: ONLY when firmware updated by built-in OTA function
34 | * has this feature, not included update through serial lines
35 | *
36 | * ===中文:
37 | * 如果你刚才使用了OTA升级了这个固件
38 | * 你可以在这里写任何代码
39 | * 无须担心任何错误引起无限复位
40 | * 当复位次数超过设定阈值时
41 | * 固件会自动回滚上一个版本
42 | *
43 | * 阈值可以根据自己的需求调整
44 | * 在 /lib/config/config.h
45 | *
46 | * ! 注意: [ 仅 ] 当固件通过内置的OTA升级功能升级后才有此功能
47 | * 直接从串口升级的固件没有此功能
48 | */
49 | }
50 |
51 | void App::loop()
52 | {
53 | // put your code in this function
54 | // it will run repeatedly, attention attached
55 |
56 | // 把你的代码放在这个函数里,代码会重复的运行,请阅读注意事项
57 | }
58 |
59 | /**
60 | * @brief App instance defined here
61 | *
62 | * 类App实例在此实例化
63 | *
64 | */
65 | App *app = new App();
--------------------------------------------------------------------------------
/app/empty_example/app/app.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include "../src/globalmanager/globalmanager.h"
3 |
4 | /**
5 | * @brief name of app
6 | *
7 | * app名称
8 | *
9 | */
10 | #define APP_NAME "Abc"
11 |
12 | /**
13 | * @brief version of app
14 | *
15 | * app版本
16 | *
17 | */
18 | #define APP_VERSION 0
19 |
20 | /**
21 | * @brief default cpu frequency of current app
22 | *
23 | * 这个app默认的cpu频率
24 | *
25 | */
26 | #define DEFAULT_CPU_FREQ 240
27 |
28 | /**
29 | * @brief indicate app has setup function
30 | * or not
31 | *
32 | * 指示app是否有初始化函数
33 | *
34 | */
35 | #define APP_HAS_SETUP
36 |
37 | /**
38 | * @brief indicate app has main loop function
39 | *
40 | * 指示app是否有主循环函数
41 | *
42 | */
43 | #define APP_HAS_LOOP
44 |
45 | /**
46 | * @brief the stack size of current app loop
47 | *
48 | * 当前app循环任务的栈大小
49 | *
50 | */
51 | #define APP_LOOP_STACK_SIZE 8 * 1024
52 |
53 | /**
54 | * @brief indicate app has custom extra callback
55 | * for local websocket server
56 | *
57 | * 指示app是否有自定义的用于本地websocket服务器的回调函数
58 | *
59 | *
60 | * @note the function declared and defined as C pattern
61 | * not included in class App
62 | *
63 | * 函数以C语言风格声明和定义,不包含在类App内
64 | *
65 | */
66 | //#define APP_HAS_EXTRA_LOCAL_WEBSOCKET_CALLBACK
67 |
68 | /**
69 | * @brief indicate app has custom extra callback
70 | * for remote websocket client
71 | *
72 | * 指示app是否有自定义的用于远程websocket客户端的回调函数
73 | *
74 | *
75 | * @note the function declared and defined as C pattern
76 | * not included in class App
77 | *
78 | * 函数以C语言风格声明和定义,不包含在类App内
79 | *
80 | */
81 | //#define APP_HAS_EXTRA_REMOTE_WEBSOCKET_CALLBACK
82 |
83 | /**
84 | * @brief default app class
85 | * you could modify class name, attention attached
86 | *
87 | * 默认的app类
88 | * 你可以修改这个类的名字,请阅读注意事项
89 | *
90 | * @attention the name of instance must be "app"
91 | * refer to the tail of the file "app.cpp"
92 | *
93 | * 类实例的名称必须为 "app",查看 "app.app" 的尾部
94 | *
95 | * @note if you modified the name of he instance,
96 | * you should also modify the name in the file "main.cpp"
97 | * not recommended for beginner
98 | *
99 | * 如果你修改了类实例的名字,你也应该一同修改文件 "main.cpp"
100 | * 里的名字
101 | * 不推荐新手做此操作
102 | *
103 | */
104 | class App
105 | {
106 | private:
107 | public:
108 | /**
109 | * @brief default constructor, attention attached!
110 | * 默认构造函数,请阅读注意事项!
111 | *
112 | * @attention if you declared and define other constructors
113 | * you should NOT do any actions except set default value
114 | * for variables.
115 | * Because the instance of class App will be define in the tail
116 | * of the app.cpp, and that is NOT included in the system
117 | * GlobalManager::makeSureNewFirmwareValid() measurement scope,
118 | * if any action in constructor cause ESP32 panic reset,
119 | * you will lost connection of this ESP32, then you have to
120 | * use hardware serial to upload new firmware.
121 | *
122 | * 如果你定义了其他构造函数,请确保在构造函数内 [不要] 做 除了给变量赋值
123 | * 以外的其他操作,因为类App的实例在 app.cpp 文件的尾部被实例化,
124 | * 而这不在系统 GlobalManager::makeSureNewFirmwareValid() 的
125 | * 监测范围内,如果构造函数内有任何操作导致ESP32复位,你会丢失与这个
126 | * ESP32的连接,此时你只能再次用硬件串口重新上传固件。
127 | *
128 | */
129 | inline App(){};
130 | inline ~App(){};
131 |
132 | /**
133 | * @brief put your code in this function to run it once
134 | *
135 | * 把你的代码放在这个函数里,代码会被运行一次
136 | *
137 | */
138 | void setup();
139 |
140 | /**
141 | * @brief put your code in this function
142 | * it will run repeatedly, attention attached
143 | *
144 | * 把你的代码放在这个函数里,代码会重复的运行,请阅读注意事项
145 | *
146 | * @attention loop function will NOT run when OTA update
147 | * process running
148 | *
149 | * 在OTA升级期间,loop函数不会被运行
150 | *
151 | */
152 | void loop();
153 | };
154 |
155 | extern App *app;
--------------------------------------------------------------------------------
/build.bat:
--------------------------------------------------------------------------------
1 | node build.js
--------------------------------------------------------------------------------
/build.command:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | cd $(dirname $0)
3 | node build.js
--------------------------------------------------------------------------------
/build.js:
--------------------------------------------------------------------------------
1 | let child_process = require("child_process"), fs = require("fs");
2 |
3 | (e => {
4 |
5 | let config = {};
6 |
7 | let autoSync = false;
8 |
9 | let language = {
10 | en: {
11 | input: "Input: ",
12 | buildingApp: " Building app: ",
13 | allBuilt: "All firmwares have been built",
14 | errorInput: "Wrong selection, input again\n",
15 | selectBuildApp: "Select one app to build:\n",
16 | selectCopyApp: "Select one app to copy:\n",
17 | copied: "copied\n",
18 | opType: "1: Build single app\n2: Build all\n3: Copy only\n4: Enable auto sync\n5: exit\n:"
19 | },
20 | cn: {
21 | input: "请输入: ",
22 | buildingApp: "正在构建固件: ",
23 | allBuilt: "所有固件已构建完成",
24 | errorInput: "输入错误,请重新输入\n",
25 | selectBuildApp: "构建哪一个固件:\n",
26 | selectCopyApp: "拷贝哪个固件:\n",
27 | copied: "已拷贝\n",
28 | opType: "1: 单独构建\n2: 全部构建\n3: 仅拷贝\n4: 启用自动同步\n5: 退出\n:"
29 | }
30 | };
31 |
32 | // build firmware
33 | let buildFirmware = e => {
34 | let stdout = child_process.execSync("export PATH=$PATH:~/.platformio/penv/bin && pio run --target clean");
35 | console.log(stdout.toString());
36 | stdout = child_process.execSync("export PATH=$PATH:~/.platformio/penv/bin && pio run");
37 | console.log(stdout.toString());
38 | };
39 |
40 | // create directory
41 | if (!fs.existsSync("./app/")) {
42 | fs.mkdirSync("./app/");
43 | }
44 |
45 | let apps = fs.readdirSync("./app");
46 | let appsRoot = "./app/";
47 |
48 | // load names of app
49 | let refresh = function () {
50 | //load all files and directories
51 | apps = fs.readdirSync("./app");
52 | for (let i = 0; i < apps.length; i++) {
53 | if (
54 | !fs.statSync(appsRoot + apps[i]).isDirectory() //remove other files
55 | ||
56 | apps[i].trim().endsWith(".md") //remove readme
57 | ) {
58 | apps.splice(i, 1);
59 | i = i >= 0 ? i - 1 : i;
60 | }
61 | }
62 |
63 | let appString = "";
64 |
65 | for (let i = 0; i < apps.length; i++) {
66 | let json = {
67 | index: i + 1,
68 | name: apps[i]
69 | };
70 | arrMete.push(json);
71 | appString += json.index.toString() + ": " + json.name + "\n";
72 | }
73 |
74 | appString += language[config.language].input;
75 | return appString;
76 | };
77 |
78 | // build all firmware
79 | let buildAll = function () {
80 | for (let i of apps) {
81 | if (fs.statSync(appsRoot + i).isDirectory()) {
82 | console.log(language[config.language].buildingApp + i);
83 | fs.cpSync(appsRoot + i + "/app/", "./src/app/", { recursive: true });
84 | buildFirmware();
85 | }
86 | }
87 | console.log(language[config.language].allBuilt);
88 | };
89 |
90 | let readline = require('readline');
91 | let rl = readline.createInterface({
92 | input: process.stdin,
93 | output: process.stdout
94 | });
95 |
96 | let query = function () {
97 | rl.question(language[config.language].opType, buildType);
98 | };
99 |
100 | let arrMete = [];
101 |
102 | let buildSingle = function (data) {
103 | data = parseInt(data);
104 | let json = arrMete.find(e => { return e.index == data; });
105 | if (!json) {
106 | query();
107 | return;
108 | }
109 | console.log(language[config.language].buildingApp + json.name)
110 | fs.cpSync(appsRoot + json.name + "/app/", "./src/app/", { recursive: true });
111 | buildFirmware();
112 | query();
113 | };
114 |
115 | let copyOnly = function (data) {
116 | data = parseInt(data);
117 | let json = arrMete.find(e => { return e.index == data; });
118 | if (!json) {
119 | query();
120 | return;
121 | }
122 | fs.cpSync(appsRoot + json.name + "/app/", "./src/app/", { recursive: true });
123 | console.log(json.name + " " + language[config.language].copied);
124 | query();
125 | };
126 |
127 | let buildType = function (data) {
128 | data = parseInt(data);
129 | if (data == 1) {
130 | let q = refresh();
131 | rl.question(language[config.language].selectBuildApp + q, buildSingle);
132 | } else if (data == 2) {
133 | buildAll();
134 | query();
135 | } else if (data == 3) {
136 | let q = refresh();
137 | rl.question(language[config.language].selectCopyApp + q, copyOnly);
138 | } else if (data == 4) {
139 | if (!autoSync) {
140 | autoSync = true;
141 | fs.watch("./", {
142 | recursive: true
143 | }, function (e, fileName) {
144 | if (fileName.startsWith("app/")) {
145 | let m = /app\/(?[^\/]+)\/.+/i.exec(fileName);
146 | if (m) {
147 | m = m.groups.appName;
148 | fs.cpSync(appsRoot + m + "/app/", "./src/app/", { recursive: true });
149 | }
150 | }
151 | });
152 | }
153 |
154 | query();
155 | } else if (data == 5) {
156 | process.exit();
157 | } else {
158 | rl.question(language[config.language].errorInput +
159 | language[config.language].opType, buildType);
160 | }
161 | };
162 | config.language = Intl.DateTimeFormat().resolvedOptions().locale.toLowerCase();
163 | if (config.language == "zh-cn") {
164 | config.language = "cn";
165 | } else {
166 | config.language = "en";
167 | }
168 |
169 | query();
170 |
171 | })();
--------------------------------------------------------------------------------
/doc/README.md:
--------------------------------------------------------------------------------
1 | ### English
2 |
3 | You could use http get to execute provider, example refer to /doc/get_method.js
4 |
5 | ### 中文
6 |
7 | 你可以使用http get 方法执行provider,例子参考 /doc/get_method.js
--------------------------------------------------------------------------------
/doc/extented_command_specification.txt:
--------------------------------------------------------------------------------
1 | Extented command has 8 bytes, the format are following:
2 | 扩展命令为8字节,格式如下:
3 |
4 | byte offset:
5 | 字节偏移量:
6 | | 0 | | 1 2 3 4 5 6 7
7 | -----------|--------------------------------|-------------------|-------------------------------------------------------------------------------------------
8 | comments: | mask | | message ID reserved basic command
9 | 注释: | | | 4 bytes 2 bytes 1 byte
10 | -----------|--------------------------------|-------------------|-------------------------------------------------------------------------------------------
11 | bit offset:| | |
12 | 0 | 1 | 2 | 3 4
13 | -----------|--------------------------------|-------------------|-------------------------------------------------------------------------------------------
14 | 1 fixed | 0 delivery once | 0 nothing | targetID position
15 | -----------|--------------------------------|-------------------|-------------------------------------------------------------------------------------------
16 | | 1 delivery should be confirmed | 1 confirm message |
17 | -----------|--------------------------------|-------------------|-------------------------------------------------------------------------------------------
18 | comments: | server will push same message | receiver will set | only show to server
19 | | repeatedly until got confirm | this bit to 1 if |
20 | | if this bit set to 1 by sender | it had received |
21 | | 如果这个bit设置为1,服务器会在收到 | a message which |
22 | | 响应数据之前持续重复发送消息 | should be |
23 | | | confirmed |
24 |
25 |
--------------------------------------------------------------------------------
/examples/README.md:
--------------------------------------------------------------------------------
1 | ### English
2 |
3 | How to use: select one example, and copy its inner "app" folder to /src/ , cover original folder.
4 |
5 | ### 中文
6 |
7 | 如何使用: 选择一个例子,然后拷贝其中的 "app" 文件夹到 /src/ ,覆盖里面的文件。
--------------------------------------------------------------------------------
/examples/aes_256_cbc_example/README.md:
--------------------------------------------------------------------------------
1 | This example show you how to encrypt and decrypt AES-256-CBC with one line code.
2 |
3 | 这个例子演示如何使用一行代码加密或解密AES-256-CBC。
--------------------------------------------------------------------------------
/examples/aes_256_cbc_example/app/app.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * @file app.cpp
3 | * @brief
4 | *
5 | * Code this file just like Arduino way
6 | *
7 | * 就像使用Arduino框架一样在这个文件中写代码就可以了
8 | *
9 | */
10 |
11 | #include "app.h"
12 |
13 | void App::setup()
14 | {
15 | // plain text
16 | // 明文
17 | String plain = "12345678";
18 |
19 | Serial.printf("Plain text: %s\n", plain.c_str());
20 | Serial.printf("明文: %s\n", plain.c_str());
21 |
22 | // key, 32 bytes
23 | // 密匙, 32字节
24 | String key = "abcdefghijklmnopqrstuvwxyz012345";
25 |
26 | // iv, 16 bytes
27 | // 初始化向量, 16字节
28 | String iv = "0123456789abcdef";
29 |
30 | // encrypt
31 | // 加密
32 | String cipher = mycrypto::AES::aes256CBCEncrypt(
33 | key,
34 | iv,
35 | plain);
36 |
37 | // the cipher is hex format, lower case
38 | // 密文是16进制字符串,小写
39 | Serial.printf("Encrypted data: 0x%s\n", cipher.c_str());
40 | Serial.printf("加密后的数据: 0x%s\n", cipher.c_str());
41 |
42 | // decrypt
43 | // 解密
44 | String decrypted = mycrypto::AES::aes256CBCDecrypt(
45 | key,
46 | iv,
47 | cipher);
48 |
49 | Serial.printf("Decrypted data: %s\n", decrypted.c_str());
50 | Serial.printf("解密后的数据: %s\n", decrypted.c_str());
51 |
52 | // ==========
53 | // you could also use traditional method
54 | // 你也可以使用传统方法
55 |
56 | const char *plain2 = "abc";
57 |
58 | uint32_t encryptOutLen = 0;
59 |
60 | uint8_t *encryptedBuffer = mycrypto::AES::aes256CBCEncrypt(
61 | (uint8_t *)key.c_str(), // key 密匙
62 | (uint8_t *)iv.c_str(), // iv 初始化向量
63 | (uint8_t *)plain2, // plain 明文
64 | strlen(plain2), // length of plain 明文长度
65 | &encryptOutLen // length of output 输出长度
66 | );
67 |
68 | // output buffer will be set to nullptr
69 | // and output length will be set to 0
70 | // if error occured
71 |
72 | // 如果发生错误,buffer会返回空指针
73 | // 输出长度会返回0
74 |
75 | if (encryptedBuffer && encryptOutLen)
76 | {
77 | // do your thing with buffer and length
78 | // 你可以使用 buffer 和 长度做你想做的事
79 |
80 | // here BTW, for example, decrypt it
81 | // 这里顺便演示解密
82 |
83 | // decrypting part
84 | // 解密部分
85 | uint32_t decryptedOutLen = 0;
86 |
87 | uint8_t *decryptedBuffer = mycrypto::AES::aes256CBCDecrypt(
88 | (uint8_t *)key.c_str(), // key 密匙
89 | (uint8_t *)iv.c_str(), // iv 初始化向量
90 | encryptedBuffer, // cipher 密文
91 | encryptOutLen, // length of cipher 密文的长度
92 | &decryptedOutLen // length of output 输出的长度
93 | );
94 |
95 | if (decryptedBuffer && decryptedOutLen)
96 | {
97 | // do your thing with buffer and length
98 | // 你可以使用 buffer 和 长度做你想做的事
99 |
100 | delete decryptedBuffer;
101 | decryptedOutLen = 0;
102 | }
103 | else
104 | {
105 | Serial.println("Error occured when decrypting\n");
106 | Serial.println("解密时发生错误\n");
107 | }
108 |
109 | // decryption end
110 | // 解密部分结束
111 |
112 | // don't forget release memory
113 | // 别忘记释放内存
114 | delete encryptedBuffer;
115 |
116 | // reset outLen to 0 is more better
117 | // 最好连输出长度也重置
118 | encryptOutLen = 0;
119 | }
120 | else
121 | {
122 | Serial.println("Error occured when encrypting\n");
123 | Serial.println("加密时发生错误\n");
124 | }
125 | }
126 |
127 | void App::loop()
128 | {
129 | // put your code in this function
130 | // it will run repeatedly, attention attached
131 |
132 | // 把你的代码放在这个函数里,代码会重复的运行,请阅读注意事项
133 | }
134 |
135 | /**
136 | * @brief App instance defined here
137 | *
138 | * 类App实例在此实例化
139 | *
140 | */
141 | App *app = new App();
--------------------------------------------------------------------------------
/examples/aes_256_cbc_example/app/app.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 |
4 | /**
5 | * @brief name of app
6 | *
7 | * app名称
8 | *
9 | */
10 | #define APP_NAME "AES"
11 |
12 | /**
13 | * @brief version of app
14 | *
15 | * app版本
16 | *
17 | */
18 | #define APP_VERSION 0
19 |
20 | /**
21 | * @brief default cpu frequency of current app
22 | *
23 | * 这个app默认的cpu频率
24 | *
25 | */
26 | #define DEFAULT_CPU_FREQ 240
27 |
28 |
29 | /**
30 | * @brief indicate app has custom extra callback
31 | * for local websocket server
32 | *
33 | * 指示app是否有自定义的用于本地websocket服务器的回调函数
34 | *
35 | *
36 | * @note the function declared and defined as C pattern
37 | * not included in class App
38 | *
39 | * 函数以C语言风格声明和定义,不包含在类App内
40 | *
41 | */
42 | //#define APP_HAS_EXTRA_LOCAL_WEBSOCKET_CALLBACK
43 |
44 | /**
45 | * @brief indicate app has custom extra callback
46 | * for remote websocket client
47 | *
48 | * 指示app是否有自定义的用于远程websocket客户端的回调函数
49 | *
50 | *
51 | * @note the function declared and defined as C pattern
52 | * not included in class App
53 | *
54 | * 函数以C语言风格声明和定义,不包含在类App内
55 | *
56 | */
57 | //#define APP_HAS_EXTRA_REMOTE_WEBSOCKET_CALLBACK
58 |
59 | /**
60 | * @brief default app class
61 | * you could modify class name, attention attached
62 | *
63 | * 默认的app类
64 | * 你可以修改这个类的名字,请阅读注意事项
65 | *
66 | * @attention the name of instance must be "app"
67 | * refer to the tail of the file "app.cpp"
68 | *
69 | * 类实例的名称必须为 "app",查看 "app.app" 的尾部
70 | *
71 | * @note if you modified the name of he instance,
72 | * you should also modify the name in the file "main.cpp"
73 | * not recommended for beginner
74 | *
75 | * 如果你修改了类实例的名字,你也应该一同修改文件 "main.cpp"
76 | * 里的名字
77 | * 不推荐新手做此操作
78 | *
79 | */
80 | class App
81 | {
82 | private:
83 | public:
84 | /**
85 | * @brief default constructor, attention attached!
86 | * 默认构造函数,请阅读注意事项!
87 | *
88 | * @attention if you declared and define other constructors
89 | * you should NOT do any actions except set default value
90 | * for variables.
91 | * Because the instance of class App will be define in the tail
92 | * of the app.cpp, and that is NOT included in the system
93 | * GlobalManager::makeSureNewFirmwareValid() measurement scope,
94 | * if any action in constructor cause ESP32 panic reset,
95 | * you will lost connection of this ESP32, then you have to
96 | * use hardware serial to upload new firmware.
97 | *
98 | * 如果你定义了其他构造函数,请确保在构造函数内 [不要] 做 除了给变量赋值
99 | * 以外的其他操作,因为类App的实例在 app.cpp 文件的尾部被实例化,
100 | * 而这不在系统 GlobalManager::makeSureNewFirmwareValid() 的
101 | * 监测范围内,如果构造函数内有任何操作导致ESP32复位,你会丢失与这个
102 | * ESP32的连接,此时你只能再次用硬件串口重新上传固件。
103 | *
104 | */
105 | inline App(){};
106 | inline ~App(){};
107 |
108 | /**
109 | * @brief put your code in this function to run it once
110 | *
111 | * 把你的代码放在这个函数里,代码会被运行一次
112 | *
113 | */
114 | void setup();
115 |
116 | /**
117 | * @brief put your code in this function
118 | * it will run repeatedly, attention attached
119 | *
120 | * 把你的代码放在这个函数里,代码会重复的运行,请阅读注意事项
121 | *
122 | * @attention loop function will NOT run when OTA update
123 | * process running
124 | *
125 | * 在OTA升级期间,loop函数不会被运行
126 | *
127 | */
128 | void loop();
129 | };
130 |
131 | extern App *app;
--------------------------------------------------------------------------------
/examples/arraybuffer_example/README.md:
--------------------------------------------------------------------------------
1 | This example show how to use class ArrayBuffer.
2 |
3 | 这个例子演示如何使用类ArrayBuffer。
--------------------------------------------------------------------------------
/examples/arraybuffer_example/app/app.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * @file app.cpp
3 | * @brief
4 | *
5 | * Code this file just like Arduino way
6 | *
7 | * 就像使用Arduino框架一样在这个文件中写代码就可以了
8 | *
9 | */
10 |
11 | #include "app.h"
12 |
13 | void App::setup()
14 | {
15 | // a temporary array
16 | // 一个临时数组
17 | uint8_t buffer[128] = {0};
18 |
19 | // set some ramdom value
20 | // 设置点随机数
21 | for (uint32_t i = 0; i < 128; ++i)
22 | {
23 | buffer[i] = random(0, 0xff);
24 | }
25 |
26 | // container
27 | // 容器
28 | Elements container =
29 | {
30 | new Element(0x01),
31 | new Element(0x80),
32 | new Element(0xffff),
33 | new Element(0xffffffff),
34 | new Element("Hello world!"),
35 | new Element(buffer, 1024)};
36 |
37 | // method A
38 | // 方法A
39 | ArrayBuffer::createArrayBuffer(
40 | &container,
41 | [](uint8_t *outputBuffer, uint64_t length, bool *isBufferDeleted)
42 | {
43 | // this buffer could be send through socket of store to flash
44 | // 这个数组可以被通过网络发送或存储到flash
45 |
46 | // this buffer will be freed automatically
47 | // 这个数组会被自动删除
48 |
49 | // or you could delete it manually
50 | // 或者你也可以手动删除
51 | delete outputBuffer;
52 | (*isBufferDeleted) = true;
53 | });
54 |
55 | // method B
56 | // 方法B
57 | uint64_t outLen = 0;
58 | uint8_t *outputBuffer = ArrayBuffer::createArrayBuffer(&container, &outLen);
59 |
60 | if (outputBuffer && outLen)
61 | {
62 | // buffer OK
63 |
64 | ArrayBuffer::decodeArrayBuffer(
65 | [](Elements *outputVector)
66 | {
67 | if (outputVector)
68 | {
69 | if (outputVector->size())
70 | {
71 | for (
72 | Elements::iterator it = outputVector->begin();
73 | it != outputVector->end();
74 | ++it)
75 | {
76 | auto type = (*it)->getType(true);
77 | if (type == NUMBER)
78 | {
79 | Serial.printf("number: %llu\n", (*it)->getNumber());
80 | }
81 | else if (type == ETYPE_STRING)
82 | {
83 | //Serial.printf("string: %s\n", (*it)->getString().c_str());
84 | // or 或者
85 | Serial.printf("string: %s\n", (*it)->c_str());
86 | }
87 | else if (type == U8A)
88 | {
89 | Serial.printf("uint8 array:\n 0x%s\n", (*it)->getHex());
90 | }
91 | else
92 | {
93 | Serial.println("error");
94 | }
95 | }
96 | }
97 | }
98 | },
99 | outputBuffer,
100 | outLen);
101 | }
102 | }
103 |
104 | void App::loop()
105 | {
106 | // put your code in this function
107 | // it will run repeatedly, attention attached
108 |
109 | // 把你的代码放在这个函数里,代码会重复的运行,请阅读注意事项
110 | }
111 |
112 | /**
113 | * @brief App instance defined here
114 | *
115 | * 类App实例在此实例化
116 | *
117 | */
118 | App *app = new App();
--------------------------------------------------------------------------------
/examples/arraybuffer_example/app/app.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 |
4 | /**
5 | * @brief name of app
6 | *
7 | * app名称
8 | *
9 | */
10 | #define APP_NAME "Class ArrayBuffer"
11 |
12 | /**
13 | * @brief version of app
14 | *
15 | * app版本
16 | *
17 | */
18 | #define APP_VERSION 0
19 |
20 | /**
21 | * @brief default cpu frequency of current app
22 | *
23 | * 这个app默认的cpu频率
24 | *
25 | */
26 | #define DEFAULT_CPU_FREQ 240
27 |
28 |
29 | /**
30 | * @brief indicate app has custom extra callback
31 | * for local websocket server
32 | *
33 | * 指示app是否有自定义的用于本地websocket服务器的回调函数
34 | *
35 | *
36 | * @note the function declared and defined as C pattern
37 | * not included in class App
38 | *
39 | * 函数以C语言风格声明和定义,不包含在类App内
40 | *
41 | */
42 | //#define APP_HAS_EXTRA_LOCAL_WEBSOCKET_CALLBACK
43 |
44 | /**
45 | * @brief indicate app has custom extra callback
46 | * for remote websocket client
47 | *
48 | * 指示app是否有自定义的用于远程websocket客户端的回调函数
49 | *
50 | *
51 | * @note the function declared and defined as C pattern
52 | * not included in class App
53 | *
54 | * 函数以C语言风格声明和定义,不包含在类App内
55 | *
56 | */
57 | //#define APP_HAS_EXTRA_REMOTE_WEBSOCKET_CALLBACK
58 |
59 | /**
60 | * @brief default app class
61 | * you could modify class name, attention attached
62 | *
63 | * 默认的app类
64 | * 你可以修改这个类的名字,请阅读注意事项
65 | *
66 | * @attention the name of instance must be "app"
67 | * refer to the tail of the file "app.cpp"
68 | *
69 | * 类实例的名称必须为 "app",查看 "app.app" 的尾部
70 | *
71 | * @note if you modified the name of he instance,
72 | * you should also modify the name in the file "main.cpp"
73 | * not recommended for beginner
74 | *
75 | * 如果你修改了类实例的名字,你也应该一同修改文件 "main.cpp"
76 | * 里的名字
77 | * 不推荐新手做此操作
78 | *
79 | */
80 | class App
81 | {
82 | private:
83 | public:
84 | /**
85 | * @brief default constructor, attention attached!
86 | * 默认构造函数,请阅读注意事项!
87 | *
88 | * @attention if you declared and define other constructors
89 | * you should NOT do any actions except set default value
90 | * for variables.
91 | * Because the instance of class App will be define in the tail
92 | * of the app.cpp, and that is NOT included in the system
93 | * GlobalManager::makeSureNewFirmwareValid() measurement scope,
94 | * if any action in constructor cause ESP32 panic reset,
95 | * you will lost connection of this ESP32, then you have to
96 | * use hardware serial to upload new firmware.
97 | *
98 | * 如果你定义了其他构造函数,请确保在构造函数内 [不要] 做 除了给变量赋值
99 | * 以外的其他操作,因为类App的实例在 app.cpp 文件的尾部被实例化,
100 | * 而这不在系统 GlobalManager::makeSureNewFirmwareValid() 的
101 | * 监测范围内,如果构造函数内有任何操作导致ESP32复位,你会丢失与这个
102 | * ESP32的连接,此时你只能再次用硬件串口重新上传固件。
103 | *
104 | */
105 | inline App(){};
106 | inline ~App(){};
107 |
108 | /**
109 | * @brief put your code in this function to run it once
110 | *
111 | * 把你的代码放在这个函数里,代码会被运行一次
112 | *
113 | */
114 | void setup();
115 |
116 | /**
117 | * @brief put your code in this function
118 | * it will run repeatedly, attention attached
119 | *
120 | * 把你的代码放在这个函数里,代码会重复的运行,请阅读注意事项
121 | *
122 | * @attention loop function will NOT run when OTA update
123 | * process running
124 | *
125 | * 在OTA升级期间,loop函数不会被运行
126 | *
127 | */
128 | void loop();
129 | };
130 |
131 | extern App *app;
--------------------------------------------------------------------------------
/examples/blink_example/README.md:
--------------------------------------------------------------------------------
1 | This example blink LED.
2 |
3 | 这个例子闪烁LED。
--------------------------------------------------------------------------------
/examples/blink_example/app/app.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * @file app.cpp
3 | * @brief
4 | *
5 | * Code this file just like Arduino way
6 | *
7 | * 就像使用Arduino框架一样在这个文件中写代码就可以了
8 | *
9 | */
10 |
11 | #include "app.h"
12 |
13 | void App::setup()
14 | {
15 | // set GPIO mode
16 | // 设置GPIO模式
17 | pinMode(this->pinLED, OUTPUT);
18 | digitalWrite(this->pinLED, LOW);
19 |
20 | // check delay timeout valid
21 | // 检查延时是否被误设置成其他值
22 | if (!this->delayTimeout || this->delayTimeout > 100000)
23 | this->delayTimeout = 1000U;
24 | }
25 |
26 | void App::loop()
27 | {
28 | // method A
29 | // 方法A
30 | // digitalWrite(this->pinLED, HIGH);
31 | // delay(this->delayTimeout);
32 | // digitalWrite(this->pinLED, LOW);
33 | // delay(this->delayTimeout);
34 |
35 | // method B
36 | // 方法B
37 | uint64_t t = millis();
38 | if (t - this->lastActionTime > this->delayTimeout)
39 | {
40 | this->lastActionTime = t;
41 | if (this->isLightOn)
42 | {
43 | digitalWrite(this->pinLED, LOW);
44 | }
45 | else
46 | {
47 | digitalWrite(this->pinLED, HIGH);
48 | }
49 | this->isLightOn = !(this->isLightOn);
50 | }
51 | }
52 |
53 | /**
54 | * @brief App instance defined here
55 | *
56 | * 类App实例在此实例化
57 | *
58 | */
59 | App *app = new App();
--------------------------------------------------------------------------------
/examples/blink_example/app/app.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 |
4 | /**
5 | * @brief name of app
6 | *
7 | * app名称
8 | *
9 | */
10 | #define APP_NAME "Blink"
11 |
12 | /**
13 | * @brief version of app
14 | *
15 | * app版本
16 | *
17 | */
18 | #define APP_VERSION 0
19 |
20 | /**
21 | * @brief default cpu frequency of current app
22 | *
23 | * 这个app默认的cpu频率
24 | *
25 | */
26 | #define DEFAULT_CPU_FREQ 240
27 |
28 |
29 | /**
30 | * @brief indicate app has custom extra callback
31 | * for local websocket server
32 | *
33 | * 指示app是否有自定义的用于本地websocket服务器的回调函数
34 | *
35 | *
36 | * @note the function declared and defined as C pattern
37 | * not included in class App
38 | *
39 | * 函数以C语言风格声明和定义,不包含在类App内
40 | *
41 | */
42 | //#define APP_HAS_EXTRA_LOCAL_WEBSOCKET_CALLBACK
43 |
44 | /**
45 | * @brief indicate app has custom extra callback
46 | * for remote websocket client
47 | *
48 | * 指示app是否有自定义的用于远程websocket客户端的回调函数
49 | *
50 | *
51 | * @note the function declared and defined as C pattern
52 | * not included in class App
53 | *
54 | * 函数以C语言风格声明和定义,不包含在类App内
55 | *
56 | */
57 | //#define APP_HAS_EXTRA_REMOTE_WEBSOCKET_CALLBACK
58 |
59 | /**
60 | * @brief default app class
61 | * you could modify class name, attention attached
62 | *
63 | * 默认的app类
64 | * 你可以修改这个类的名字,请阅读注意事项
65 | *
66 | * @attention the name of instance must be "app"
67 | * refer to the tail of the file "app.cpp"
68 | *
69 | * 类实例的名称必须为 "app",查看 "app.app" 的尾部
70 | *
71 | * @note if you modified the name of he instance,
72 | * you should also modify the name in the file "main.cpp"
73 | * not recommended for beginner
74 | *
75 | * 如果你修改了类实例的名字,你也应该一同修改文件 "main.cpp"
76 | * 里的名字
77 | * 不推荐新手做此操作
78 | *
79 | */
80 | class App
81 | {
82 | private:
83 | /**
84 | * @brief GPIO number
85 | * GPIO 引脚
86 | */
87 | uint8_t pinLED = 18U;
88 |
89 | /**
90 | * @brief indicate LED state
91 | * 指示LED状态
92 | */
93 | bool isLightOn = false;
94 |
95 | /**
96 | * @brief last action time
97 | * 上次动作时间
98 | */
99 | uint64_t lastActionTime = 0;
100 |
101 | /**
102 | * @brief delay timeout
103 | * 延时时间
104 | */
105 | uint32_t delayTimeout = 1000U;
106 |
107 | public:
108 | /**
109 | * @brief default constructor, attention attached!
110 | * 默认构造函数,请阅读注意事项!
111 | *
112 | * @attention if you declared and define other constructors
113 | * you should NOT do any actions except set default value
114 | * for variables.
115 | * Because the instance of class App will be define in the tail
116 | * of the app.cpp, and that is NOT included in the system
117 | * GlobalManager::makeSureNewFirmwareValid() measurement scope,
118 | * if any action in constructor cause ESP32 panic reset,
119 | * you will lost connection of this ESP32, then you have to
120 | * use hardware serial to upload new firmware.
121 | *
122 | * 如果你定义了其他构造函数,请确保在构造函数内 [不要] 做 除了给变量赋值
123 | * 以外的其他操作,因为类App的实例在 app.cpp 文件的尾部被实例化,
124 | * 而这不在系统 GlobalManager::makeSureNewFirmwareValid() 的
125 | * 监测范围内,如果构造函数内有任何操作导致ESP32复位,你会丢失与这个
126 | * ESP32的连接,此时你只能再次用硬件串口重新上传固件。
127 | *
128 | */
129 | inline App(){};
130 |
131 | inline App(uint8_t pinLED, uint32_t delayTimeout = 1000U)
132 | : pinLED(pinLED), delayTimeout(delayTimeout) {}
133 |
134 | inline ~App(){};
135 |
136 | /**
137 | * @brief put your code in this function to run it once
138 | *
139 | * 把你的代码放在这个函数里,代码会被运行一次
140 | *
141 | */
142 | void setup();
143 |
144 | /**
145 | * @brief put your code in this function
146 | * it will run repeatedly, attention attached
147 | *
148 | * 把你的代码放在这个函数里,代码会重复的运行,请阅读注意事项
149 | *
150 | * @attention loop function will NOT run when OTA update
151 | * process running
152 | *
153 | * 在OTA升级期间,loop函数不会被运行
154 | *
155 | */
156 | void loop();
157 | };
158 |
159 | extern App *app;
--------------------------------------------------------------------------------
/examples/database_example/README.md:
--------------------------------------------------------------------------------
1 | This example show how to use class MyDB.
2 |
3 | 这个例子演示如何使用类MyDB。
--------------------------------------------------------------------------------
/examples/database_example/app/app.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * @file app.cpp
3 | * @brief
4 | *
5 | * Code this file just like Arduino way
6 | *
7 | * 就像使用Arduino框架一样在这个文件中写代码就可以了
8 | *
9 | */
10 |
11 | #include "app.h"
12 |
13 | void App::setup()
14 | {
15 | MyDB dbExample("example");
16 | dbExample.begin();
17 |
18 | if (!dbExample.loaded)
19 | {
20 | Serial.println("Database load failed 数据库加载失败");
21 | return;
22 | }
23 |
24 | auto value = dbExample("key");
25 | if (!value->available())
26 | {
27 | Serial.println("key does not exists or value unavailable\n键不存在或值不可用");
28 | }
29 |
30 | // set value
31 | // 设置值
32 | (*value) = "value";
33 |
34 | // or set it directly
35 | // 或者直接设置
36 |
37 | *dbExample("number_A") = 0;
38 |
39 | // force type
40 | // 强制类型
41 | *dbExample("number_B") = (uint64_t)0xffU;
42 |
43 | *dbExample("number_C") = (uint64_t)millis();
44 |
45 | (*dbExample("number_A"))++;
46 |
47 | // clear a key/value
48 | // 清除键/值
49 | *dbExample("number_C") = "";
50 |
51 | // don't forget write it to flash
52 | // 别忘了写入flash
53 | if (!dbExample.flush())
54 | {
55 | Serial.println("database flush failed\n数据库写入失败");
56 | }
57 | }
58 |
59 | void App::loop()
60 | {
61 | // put your code in this function
62 | // it will run repeatedly, attention attached
63 |
64 | // 把你的代码放在这个函数里,代码会重复的运行,请阅读注意事项
65 | }
66 |
67 | /**
68 | * @brief App instance defined here
69 | *
70 | * 类App实例在此实例化
71 | *
72 | */
73 | App *app = new App();
--------------------------------------------------------------------------------
/examples/database_example/app/app.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 |
4 | /**
5 | * @brief name of app
6 | *
7 | * app名称
8 | *
9 | */
10 | #define APP_NAME "Class ArrayBuffer"
11 |
12 | /**
13 | * @brief version of app
14 | *
15 | * app版本
16 | *
17 | */
18 | #define APP_VERSION 0
19 |
20 | /**
21 | * @brief default cpu frequency of current app
22 | *
23 | * 这个app默认的cpu频率
24 | *
25 | */
26 | #define DEFAULT_CPU_FREQ 240
27 |
28 |
29 | /**
30 | * @brief indicate app has custom extra callback
31 | * for local websocket server
32 | *
33 | * 指示app是否有自定义的用于本地websocket服务器的回调函数
34 | *
35 | *
36 | * @note the function declared and defined as C pattern
37 | * not included in class App
38 | *
39 | * 函数以C语言风格声明和定义,不包含在类App内
40 | *
41 | */
42 | //#define APP_HAS_EXTRA_LOCAL_WEBSOCKET_CALLBACK
43 |
44 | /**
45 | * @brief indicate app has custom extra callback
46 | * for remote websocket client
47 | *
48 | * 指示app是否有自定义的用于远程websocket客户端的回调函数
49 | *
50 | *
51 | * @note the function declared and defined as C pattern
52 | * not included in class App
53 | *
54 | * 函数以C语言风格声明和定义,不包含在类App内
55 | *
56 | */
57 | //#define APP_HAS_EXTRA_REMOTE_WEBSOCKET_CALLBACK
58 |
59 | /**
60 | * @brief default app class
61 | * you could modify class name, attention attached
62 | *
63 | * 默认的app类
64 | * 你可以修改这个类的名字,请阅读注意事项
65 | *
66 | * @attention the name of instance must be "app"
67 | * refer to the tail of the file "app.cpp"
68 | *
69 | * 类实例的名称必须为 "app",查看 "app.app" 的尾部
70 | *
71 | * @note if you modified the name of he instance,
72 | * you should also modify the name in the file "main.cpp"
73 | * not recommended for beginner
74 | *
75 | * 如果你修改了类实例的名字,你也应该一同修改文件 "main.cpp"
76 | * 里的名字
77 | * 不推荐新手做此操作
78 | *
79 | */
80 | class App
81 | {
82 | private:
83 | public:
84 | /**
85 | * @brief default constructor, attention attached!
86 | * 默认构造函数,请阅读注意事项!
87 | *
88 | * @attention if you declared and define other constructors
89 | * you should NOT do any actions except set default value
90 | * for variables.
91 | * Because the instance of class App will be define in the tail
92 | * of the app.cpp, and that is NOT included in the system
93 | * GlobalManager::makeSureNewFirmwareValid() measurement scope,
94 | * if any action in constructor cause ESP32 panic reset,
95 | * you will lost connection of this ESP32, then you have to
96 | * use hardware serial to upload new firmware.
97 | *
98 | * 如果你定义了其他构造函数,请确保在构造函数内 [不要] 做 除了给变量赋值
99 | * 以外的其他操作,因为类App的实例在 app.cpp 文件的尾部被实例化,
100 | * 而这不在系统 GlobalManager::makeSureNewFirmwareValid() 的
101 | * 监测范围内,如果构造函数内有任何操作导致ESP32复位,你会丢失与这个
102 | * ESP32的连接,此时你只能再次用硬件串口重新上传固件。
103 | *
104 | */
105 | inline App(){};
106 | inline ~App(){};
107 |
108 | /**
109 | * @brief put your code in this function to run it once
110 | *
111 | * 把你的代码放在这个函数里,代码会被运行一次
112 | *
113 | */
114 | void setup();
115 |
116 | /**
117 | * @brief put your code in this function
118 | * it will run repeatedly, attention attached
119 | *
120 | * 把你的代码放在这个函数里,代码会重复的运行,请阅读注意事项
121 | *
122 | * @attention loop function will NOT run when OTA update
123 | * process running
124 | *
125 | * 在OTA升级期间,loop函数不会被运行
126 | *
127 | */
128 | void loop();
129 | };
130 |
131 | extern App *app;
--------------------------------------------------------------------------------
/examples/element_example/README.md:
--------------------------------------------------------------------------------
1 | This example show how to use class Element.
2 |
3 | 这个例子演示如何使用类Element。
--------------------------------------------------------------------------------
/examples/element_example/app/app.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * @file app.cpp
3 | * @brief
4 | *
5 | * Code this file just like Arduino way
6 | *
7 | * 就像使用Arduino框架一样在这个文件中写代码就可以了
8 | *
9 | */
10 |
11 | #include "app.h"
12 |
13 | void App::setup()
14 | {
15 | Element x;
16 | Element y = 100;
17 | uint8_t buf[] = {97, 98, 99};
18 | String hello = "Hello world!";
19 |
20 | // set value
21 | // 设置值
22 |
23 | // set number
24 | // 设置数字
25 | x = 10;
26 |
27 | x.setNumber(100);
28 |
29 | // set number with given type
30 | // 用指定的类型设置数字
31 | x = (uint16_t)65535;
32 |
33 | // set string
34 | // 设置字符串
35 | x = "Hello world!";
36 | x = hello;
37 | x = &hello;
38 | x.setString("Hello world");
39 | x.setString(hello);
40 | x.setString(&hello);
41 |
42 | // set buffer
43 | // 设置二进制数组
44 | x(buf, 3);
45 | x.setUint8Array(buf, 3);
46 |
47 | // set with another element
48 | // 用另一个元素来设置值
49 | x = y;
50 | x = &y;
51 | x.copyFrom(y);
52 | x.copyFrom(&y);
53 |
54 | // operators
55 | // 操作符
56 |
57 | // math operators
58 | // 数学符号
59 |
60 | // reset value
61 | // 重置值
62 | x = 10000;
63 |
64 | x++;
65 | x--;
66 |
67 | ++x;
68 | --x;
69 |
70 | uint64_t a = 0;
71 |
72 | a = x + y;
73 | a = x - y;
74 | a = x * y;
75 | a = x / y;
76 | a = x % y;
77 |
78 | a = x + 100;
79 | a = x - 100;
80 | a = x * 100;
81 | a = x / 100;
82 | a = x % 100;
83 |
84 | x = "Hello ";
85 | String b = x + String("world!");
86 | String c = "o";
87 | x += "world!";
88 |
89 | // will remove all char 'o'
90 | // 会去除掉所有的'o'
91 | String c = x - c;
92 |
93 | x -= c;
94 |
95 | // reset value
96 | // 重置值
97 | x = 10000;
98 |
99 | x += 100;
100 | x -= 100;
101 | x *= 100;
102 | x /= 100;
103 | x %= 100;
104 |
105 | // reset value
106 | // 重置值
107 | x = 10000;
108 |
109 | // bit operators
110 | // 位符号
111 | a = ~x;
112 |
113 | a = x << 2;
114 | a = x >> 2;
115 |
116 | x <<= 2;
117 | x >>= 2;
118 |
119 | a = x & 0xffU;
120 | a = x | 0xffU;
121 |
122 | x &= 0xffU;
123 | x |= 0xffU;
124 |
125 | a = x ^ 0xffU;
126 | x ^= 0xffU;
127 |
128 | // reset value
129 | // 重置值
130 | x = 10000;
131 |
132 | // logical
133 | // 逻辑值
134 | Element z = 2;
135 | bool d = x && 100;
136 | int e = 100;
137 |
138 | d = x || 100;
139 | d = !x;
140 |
141 | d = x > z;
142 | d = x < z;
143 |
144 | d = x >= z;
145 | d = x <= z;
146 |
147 | d = x == z;
148 |
149 | d = x > e;
150 | d = x < e;
151 |
152 | d = x <= e;
153 | d = x >= e;
154 |
155 | x = "abc";
156 | z = "cde";
157 |
158 | d = x < z;
159 | d = x > z;
160 | //...
161 |
162 | // reset value
163 | // 重置值
164 | x(buf, 3);
165 | z = 2;
166 |
167 | // index
168 | // 索引
169 | uint8_t f = x[2];
170 | f = x[z];
171 |
172 | x = "abc";
173 | char g = x[2];
174 |
175 | // others functions
176 | // 其他功能
177 | x = "Hello world!";
178 | const char *h = x.c_str();
179 | f = x.indexOf("w");
180 | f = x.lastIndexOf("o");
181 |
182 | ElementType type = x.getType();
183 | type = x.getType(true);
184 |
185 | // reset value
186 | // 重置值
187 | x = 10000;
188 |
189 | uint64_t i = x.getUint8();
190 | i = x.getUint16();
191 | i = x.getUint32();
192 | i = x.getUint64();
193 | i = x.getNumber();
194 |
195 | x = "abc";
196 | String j = x.getString();
197 |
198 | // reset value
199 | // 重置值
200 | x(buf, 3);
201 | String k = x.getHex();
202 |
203 | x = "0f3ab86d19f98891";
204 | x.convertHexStringIntoUint8Array();
205 |
206 | uint32_t m = 0;
207 | uint8_t *l = x.getUint8Array(&m);
208 | m = x.getRawBufferLength();
209 |
210 | }
211 |
212 | void App::loop()
213 | {
214 | // put your code in this function
215 | // it will run repeatedly, attention attached
216 |
217 | // 把你的代码放在这个函数里,代码会重复的运行,请阅读注意事项
218 | }
219 |
220 | /**
221 | * @brief App instance defined here
222 | *
223 | * 类App实例在此实例化
224 | *
225 | */
226 | App *app = new App();
--------------------------------------------------------------------------------
/examples/element_example/app/app.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 |
4 | /**
5 | * @brief name of app
6 | *
7 | * app名称
8 | *
9 | */
10 | #define APP_NAME "Class Element"
11 |
12 | /**
13 | * @brief version of app
14 | *
15 | * app版本
16 | *
17 | */
18 | #define APP_VERSION 0
19 |
20 | /**
21 | * @brief default cpu frequency of current app
22 | *
23 | * 这个app默认的cpu频率
24 | *
25 | */
26 | #define DEFAULT_CPU_FREQ 240
27 |
28 |
29 | /**
30 | * @brief indicate app has custom extra callback
31 | * for local websocket server
32 | *
33 | * 指示app是否有自定义的用于本地websocket服务器的回调函数
34 | *
35 | *
36 | * @note the function declared and defined as C pattern
37 | * not included in class App
38 | *
39 | * 函数以C语言风格声明和定义,不包含在类App内
40 | *
41 | */
42 | //#define APP_HAS_EXTRA_LOCAL_WEBSOCKET_CALLBACK
43 |
44 | /**
45 | * @brief indicate app has custom extra callback
46 | * for remote websocket client
47 | *
48 | * 指示app是否有自定义的用于远程websocket客户端的回调函数
49 | *
50 | *
51 | * @note the function declared and defined as C pattern
52 | * not included in class App
53 | *
54 | * 函数以C语言风格声明和定义,不包含在类App内
55 | *
56 | */
57 | //#define APP_HAS_EXTRA_REMOTE_WEBSOCKET_CALLBACK
58 |
59 | /**
60 | * @brief default app class
61 | * you could modify class name, attention attached
62 | *
63 | * 默认的app类
64 | * 你可以修改这个类的名字,请阅读注意事项
65 | *
66 | * @attention the name of instance must be "app"
67 | * refer to the tail of the file "app.cpp"
68 | *
69 | * 类实例的名称必须为 "app",查看 "app.app" 的尾部
70 | *
71 | * @note if you modified the name of he instance,
72 | * you should also modify the name in the file "main.cpp"
73 | * not recommended for beginner
74 | *
75 | * 如果你修改了类实例的名字,你也应该一同修改文件 "main.cpp"
76 | * 里的名字
77 | * 不推荐新手做此操作
78 | *
79 | */
80 | class App
81 | {
82 | private:
83 | public:
84 | /**
85 | * @brief default constructor, attention attached!
86 | * 默认构造函数,请阅读注意事项!
87 | *
88 | * @attention if you declared and define other constructors
89 | * you should NOT do any actions except set default value
90 | * for variables.
91 | * Because the instance of class App will be define in the tail
92 | * of the app.cpp, and that is NOT included in the system
93 | * GlobalManager::makeSureNewFirmwareValid() measurement scope,
94 | * if any action in constructor cause ESP32 panic reset,
95 | * you will lost connection of this ESP32, then you have to
96 | * use hardware serial to upload new firmware.
97 | *
98 | * 如果你定义了其他构造函数,请确保在构造函数内 [不要] 做 除了给变量赋值
99 | * 以外的其他操作,因为类App的实例在 app.cpp 文件的尾部被实例化,
100 | * 而这不在系统 GlobalManager::makeSureNewFirmwareValid() 的
101 | * 监测范围内,如果构造函数内有任何操作导致ESP32复位,你会丢失与这个
102 | * ESP32的连接,此时你只能再次用硬件串口重新上传固件。
103 | *
104 | */
105 | inline App(){};
106 | inline ~App(){};
107 |
108 | /**
109 | * @brief put your code in this function to run it once
110 | *
111 | * 把你的代码放在这个函数里,代码会被运行一次
112 | *
113 | */
114 | void setup();
115 |
116 | /**
117 | * @brief put your code in this function
118 | * it will run repeatedly, attention attached
119 | *
120 | * 把你的代码放在这个函数里,代码会重复的运行,请阅读注意事项
121 | *
122 | * @attention loop function will NOT run when OTA update
123 | * process running
124 | *
125 | * 在OTA升级期间,loop函数不会被运行
126 | *
127 | */
128 | void loop();
129 | };
130 |
131 | extern App *app;
--------------------------------------------------------------------------------
/examples/empty_example/README.md:
--------------------------------------------------------------------------------
1 | This is an empty example, only show code structure.
2 |
3 | 这是个空工程,仅用于展示代码结构。
--------------------------------------------------------------------------------
/examples/empty_example/app/app.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * @file app.cpp
3 | * @brief
4 | *
5 | * Code this file just like Arduino way
6 | *
7 | * 就像使用Arduino框架一样在这个文件中写代码就可以了
8 | *
9 | */
10 |
11 | #include "app.h"
12 |
13 | void App::setup()
14 | {
15 | /**
16 | * ===English:
17 | * put your code in this function to run it once
18 | *
19 | * ===中文:
20 | * 把你的代码放在这个函数里,代码会被运行一次
21 | */
22 |
23 | /**
24 | * ===English:
25 | * if you just did an OTA update
26 | * you could do anything here, don't worry any code bugs
27 | * if any error happened, and reboot times reach maximum valve
28 | * firmware will rollback to former version automatically
29 | *
30 | * you could modify the valve yourself
31 | * in file /lib/config/config.h
32 | *
33 | * ! Attention: ONLY when firmware updated by built-in OTA function
34 | * has this feature, not included update through serial lines
35 | *
36 | * ===中文:
37 | * 如果你刚才使用了OTA升级了这个固件
38 | * 你可以在这里写任何代码
39 | * 无须担心任何错误引起无限复位
40 | * 当复位次数超过设定阈值时
41 | * 固件会自动回滚上一个版本
42 | *
43 | * 阈值可以根据自己的需求调整
44 | * 在 /lib/config/config.h
45 | *
46 | * ! 注意: [ 仅 ] 当固件通过内置的OTA升级功能升级后才有此功能
47 | * 直接从串口升级的固件没有此功能
48 | */
49 | }
50 |
51 | void App::loop()
52 | {
53 | // put your code in this function
54 | // it will run repeatedly, attention attached
55 |
56 | // 把你的代码放在这个函数里,代码会重复的运行,请阅读注意事项
57 | }
58 |
59 | /**
60 | * @brief App instance defined here
61 | *
62 | * 类App实例在此实例化
63 | *
64 | */
65 | App *app = new App();
--------------------------------------------------------------------------------
/examples/empty_example/app/app.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 |
4 | /**
5 | * @brief name of app
6 | *
7 | * app名称
8 | *
9 | */
10 | #define APP_NAME "Abc"
11 |
12 | /**
13 | * @brief version of app
14 | *
15 | * app版本
16 | *
17 | */
18 | #define APP_VERSION 0
19 |
20 | /**
21 | * @brief default cpu frequency of current app
22 | *
23 | * 这个app默认的cpu频率
24 | *
25 | */
26 | #define DEFAULT_CPU_FREQ 240
27 |
28 |
29 | /**
30 | * @brief indicate app has custom extra callback
31 | * for local websocket server
32 | *
33 | * 指示app是否有自定义的用于本地websocket服务器的回调函数
34 | *
35 | *
36 | * @note the function declared and defined as C pattern
37 | * not included in class App
38 | *
39 | * 函数以C语言风格声明和定义,不包含在类App内
40 | *
41 | */
42 | //#define APP_HAS_EXTRA_LOCAL_WEBSOCKET_CALLBACK
43 |
44 | /**
45 | * @brief indicate app has custom extra callback
46 | * for remote websocket client
47 | *
48 | * 指示app是否有自定义的用于远程websocket客户端的回调函数
49 | *
50 | *
51 | * @note the function declared and defined as C pattern
52 | * not included in class App
53 | *
54 | * 函数以C语言风格声明和定义,不包含在类App内
55 | *
56 | */
57 | //#define APP_HAS_EXTRA_REMOTE_WEBSOCKET_CALLBACK
58 |
59 | /**
60 | * @brief default app class
61 | * you could modify class name, attention attached
62 | *
63 | * 默认的app类
64 | * 你可以修改这个类的名字,请阅读注意事项
65 | *
66 | * @attention the name of instance must be "app"
67 | * refer to the tail of the file "app.cpp"
68 | *
69 | * 类实例的名称必须为 "app",查看 "app.app" 的尾部
70 | *
71 | * @note if you modified the name of he instance,
72 | * you should also modify the name in the file "main.cpp"
73 | * not recommended for beginner
74 | *
75 | * 如果你修改了类实例的名字,你也应该一同修改文件 "main.cpp"
76 | * 里的名字
77 | * 不推荐新手做此操作
78 | *
79 | */
80 | class App
81 | {
82 | private:
83 | public:
84 | /**
85 | * @brief default constructor, attention attached!
86 | * 默认构造函数,请阅读注意事项!
87 | *
88 | * @attention if you declared and define other constructors
89 | * you should NOT do any actions except set default value
90 | * for variables.
91 | * Because the instance of class App will be define in the tail
92 | * of the app.cpp, and that is NOT included in the system
93 | * GlobalManager::makeSureNewFirmwareValid() measurement scope,
94 | * if any action in constructor cause ESP32 panic reset,
95 | * you will lost connection of this ESP32, then you have to
96 | * use hardware serial to upload new firmware.
97 | *
98 | * 如果你定义了其他构造函数,请确保在构造函数内 [不要] 做 除了给变量赋值
99 | * 以外的其他操作,因为类App的实例在 app.cpp 文件的尾部被实例化,
100 | * 而这不在系统 GlobalManager::makeSureNewFirmwareValid() 的
101 | * 监测范围内,如果构造函数内有任何操作导致ESP32复位,你会丢失与这个
102 | * ESP32的连接,此时你只能再次用硬件串口重新上传固件。
103 | *
104 | */
105 | inline App(){};
106 | inline ~App(){};
107 |
108 | /**
109 | * @brief put your code in this function to run it once
110 | *
111 | * 把你的代码放在这个函数里,代码会被运行一次
112 | *
113 | */
114 | void setup();
115 |
116 | /**
117 | * @brief put your code in this function
118 | * it will run repeatedly, attention attached
119 | *
120 | * 把你的代码放在这个函数里,代码会重复的运行,请阅读注意事项
121 | *
122 | * @attention loop function will NOT run when OTA update
123 | * process running
124 | *
125 | * 在OTA升级期间,loop函数不会被运行
126 | *
127 | */
128 | void loop();
129 | };
130 |
131 | extern App *app;
--------------------------------------------------------------------------------
/examples/ota_example/README.md:
--------------------------------------------------------------------------------
1 | ### English
2 |
3 | This example show OTA update function.
4 |
5 | Before you use this example, you need to do a little bit prepare:
6 |
7 | * 1. Install Node.js 16 on your PC, offical download address:
8 |
9 | ```console
10 | https://nodejs.org/
11 | ```
12 |
13 | * 2. Use cmd or terminal open the path /server/
14 |
15 | * 3. Run
16 |
17 | ```console
18 | node iot.js
19 | ```
20 |
21 | Or
22 |
23 | ```console
24 | sudo node iot.js
25 | ```
26 |
27 | To start a local server.
28 |
29 | Don't forget let port pass in firewall.
30 |
31 | * 4. Modify the IP address in "app.h" to your PC IP address(Local Area Network IP), line 131.
32 |
33 | * 5. Compile and upload firmware
34 |
35 | * 6. Open your serial monitor, follow the guide in serial monitor
36 |
37 | (If you didn't see anything output from monitor, press reset button on your ESP32 dev board.)
38 |
39 |
40 | ### 中文
41 |
42 | 这个例子展示OTA升级功能。
43 |
44 | 在你使用这个例子之前,你需要做一点点准备工作:
45 |
46 | * 1. 在你的电脑上安装 Node.js, 官方下载地址:
47 |
48 | ```console
49 | https://nodejs.org/
50 | ```
51 |
52 | ```console
53 | http://nodejs.cn/
54 | ```
55 |
56 | * 2. 使用 cmd 或终端打开路径 /server/
57 |
58 | * 3. 运行
59 |
60 | ```console
61 | node iot.js
62 | ```
63 |
64 | 或者
65 |
66 | ```console
67 | sudo node iot.js
68 | ```
69 |
70 | 来开启一个本地服务器。
71 |
72 | 别忘了在防火墙中放行相应端口.
73 |
74 | * 4. 修改文件 "app.h" 中的IP地址为你电脑所在的内网IP地址,131行
75 |
76 | * 5. 编译上传固件
77 |
78 | * 6. 打开你的串口监视器, 跟随串口监视器中的指引操作
79 |
80 | (如果你没有在串口监视器中看到任何信息,按复位按钮。)
81 |
82 |
--------------------------------------------------------------------------------
/examples/ota_example/app/app.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * @file app.cpp
3 | * @brief
4 | *
5 | * Code this file just like Arduino way
6 | *
7 | * 就像使用Arduino框架一样在这个文件中写代码就可以了
8 | *
9 | */
10 |
11 | #include "app.h"
12 |
13 | void App::setup()
14 | {
15 | Serial.println("1. Open your browser 打开你的浏览器\n");
16 |
17 | Serial.println("2. Redirect to \"http://127.0.0.1:12345/\" or \"http://localhost:12345/\"");
18 | Serial.println("转到\"http://127.0.0.1:12345/\" 或者 \"http://localhost:12345/\"");
19 |
20 | Serial.println("3. Use \"abc12345678\" as user name and password");
21 | Serial.println("使用 \"abc12345678\" 作为用户名和密码\n");
22 |
23 | Serial.println("4. Login 登录\n");
24 |
25 | Serial.println("5. You can see esp32 is online 你可以看见esp32在线\n");
26 |
27 | Serial.println("6. Click \"@\" 点击 \"@\"\n");
28 |
29 | Serial.println("7. Click \"Upload firmware\" 点击 \"上传固件\"\n");
30 |
31 | Serial.println("8. Choose a firmware 选择一个固件\n");
32 |
33 | Serial.println("9. Click OK 点击确定\n");
34 |
35 | Serial.println("10. Click \"OTA Update\" 点击 \"更新固件\"\n");
36 |
37 | Serial.println("Then you will see esp32 is updating firmware, it will reboot after finished");
38 | Serial.println("然后你就可以看到esp32正在更新固件了, 更新完成后会自动重启");
39 | }
40 |
41 | void App::loop()
42 | {
43 | // put your code in this function
44 | // it will run repeatedly, attention attached
45 |
46 | // 把你的代码放在这个函数里,代码会重复的运行,请阅读注意事项
47 | }
48 |
49 | /**
50 | * @brief App instance defined here
51 | *
52 | * 类App实例在此实例化
53 | *
54 | */
55 | App *app = new App();
--------------------------------------------------------------------------------
/examples/ota_example/app/app.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 |
4 | /**
5 | * @brief name of app
6 | *
7 | * app名称
8 | *
9 | */
10 | #define APP_NAME "OTA Update"
11 |
12 | /**
13 | * @brief version of app
14 | *
15 | * app版本
16 | *
17 | */
18 | #define APP_VERSION 0
19 |
20 | /**
21 | * @brief default cpu frequency of current app
22 | *
23 | * 这个app默认的cpu频率
24 | *
25 | */
26 | #define DEFAULT_CPU_FREQ 240
27 |
28 |
29 | /**
30 | * @brief indicate app has custom extra callback
31 | * for local websocket server
32 | *
33 | * 指示app是否有自定义的用于本地websocket服务器的回调函数
34 | *
35 | *
36 | * @note the function declared and defined as C pattern
37 | * not included in class App
38 | *
39 | * 函数以C语言风格声明和定义,不包含在类App内
40 | *
41 | */
42 | //#define APP_HAS_EXTRA_LOCAL_WEBSOCKET_CALLBACK
43 |
44 | /**
45 | * @brief indicate app has custom extra callback
46 | * for remote websocket client
47 | *
48 | * 指示app是否有自定义的用于远程websocket客户端的回调函数
49 | *
50 | *
51 | * @note the function declared and defined as C pattern
52 | * not included in class App
53 | *
54 | * 函数以C语言风格声明和定义,不包含在类App内
55 | *
56 | */
57 | //#define APP_HAS_EXTRA_REMOTE_WEBSOCKET_CALLBACK
58 |
59 | #ifdef PRESET_WIFI_SSID
60 | #undef PRESET_WIFI_SSID
61 | #endif
62 |
63 | #ifdef PRESET_WIFI_PASSWORD
64 | #undef PRESET_WIFI_PASSWORD
65 | #endif
66 |
67 | #ifdef PRESET_ADMIN_USERNAME
68 | #undef PRESET_ADMIN_USERNAME
69 | #endif
70 |
71 | #ifdef PRESET_ADMIN_PASSWORD
72 | #undef PRESET_ADMIN_PASSWORD
73 | #endif
74 |
75 | #ifndef ENABLE_USE_PRESET_WEBSOCKET_INFORMATION
76 | #define ENABLE_USE_PRESET_WEBSOCKET_INFORMATION
77 | #endif
78 |
79 | #ifdef PRESET_WEBSOCKET_DOMAIN
80 | #undef PRESET_WEBSOCKET_DOMAIN
81 | #endif
82 |
83 | #ifdef PRESET_WEBSOCKET_PORT
84 | #undef PRESET_WEBSOCKET_PORT
85 | #endif
86 |
87 | #ifdef PRESET_WEBSOCKET_PATH
88 | #undef PRESET_WEBSOCKET_PATH
89 | #endif
90 |
91 | /**
92 | * @brief replace the strings
93 | * following 2 lines with
94 | * your wifi name and password
95 | *
96 | * 把下面两行里面的字符串替换成你的wifi名称
97 | * 和密码
98 | *
99 | */
100 | #define PRESET_WIFI_SSID "Your WiFi Name"
101 | #define PRESET_WIFI_PASSWORD "Your WiFi password"
102 |
103 | /**
104 | * @brief replace IP with your local ip
105 | * of your computer, and run /server/start.(bat/command)
106 | * make sure you didn't change the default port
107 | * of the local server
108 | *
109 | * 把 IP 替换为你电脑的局域网IP地址
110 | * 然后运行 /server/start.(bat/command)
111 | * 确保你没有修改本地服务器的默认端口
112 | *
113 | */
114 | #define PRESET_WEBSOCKET_DOMAIN "IP"
115 | #define PRESET_WEBSOCKET_PORT 12345
116 | #define PRESET_WEBSOCKET_PATH "/"
117 |
118 | #define PRESET_ADMIN_USERNAME "e06787aebebb1ce726260447b036fd36289a7e7133f61b1def05f18734300b1a"
119 | #define PRESET_ADMIN_PASSWORD "e06787aebebb1ce726260447b036fd36289a7e7133f61b1def05f18734300b1a"
120 |
121 | /**
122 | * @brief default app class
123 | * you could modify class name, attention attached
124 | *
125 | * 默认的app类
126 | * 你可以修改这个类的名字,请阅读注意事项
127 | *
128 | * @attention the name of instance must be "app"
129 | * refer to the tail of the file "app.cpp"
130 | *
131 | * 类实例的名称必须为 "app",查看 "app.app" 的尾部
132 | *
133 | * @note if you modified the name of he instance,
134 | * you should also modify the name in the file "main.cpp"
135 | * not recommended for beginner
136 | *
137 | * 如果你修改了类实例的名字,你也应该一同修改文件 "main.cpp"
138 | * 里的名字
139 | * 不推荐新手做此操作
140 | *
141 | */
142 | class App
143 | {
144 | private:
145 | public:
146 | /**
147 | * @brief default constructor, attention attached!
148 | * 默认构造函数,请阅读注意事项!
149 | *
150 | * @attention if you declared and define other constructors
151 | * you should NOT do any actions except set default value
152 | * for variables.
153 | * Because the instance of class App will be define in the tail
154 | * of the app.cpp, and that is NOT included in the system
155 | * GlobalManager::makeSureNewFirmwareValid() measurement scope,
156 | * if any action in constructor cause ESP32 panic reset,
157 | * you will lost connection of this ESP32, then you have to
158 | * use hardware serial to upload new firmware.
159 | *
160 | * 如果你定义了其他构造函数,请确保在构造函数内 [不要] 做 除了给变量赋值
161 | * 以外的其他操作,因为类App的实例在 app.cpp 文件的尾部被实例化,
162 | * 而这不在系统 GlobalManager::makeSureNewFirmwareValid() 的
163 | * 监测范围内,如果构造函数内有任何操作导致ESP32复位,你会丢失与这个
164 | * ESP32的连接,此时你只能再次用硬件串口重新上传固件。
165 | *
166 | */
167 | inline App(){};
168 | inline ~App(){};
169 |
170 | /**
171 | * @brief put your code in this function to run it once
172 | *
173 | * 把你的代码放在这个函数里,代码会被运行一次
174 | *
175 | */
176 | void setup();
177 |
178 | /**
179 | * @brief put your code in this function
180 | * it will run repeatedly, attention attached
181 | *
182 | * 把你的代码放在这个函数里,代码会重复的运行,请阅读注意事项
183 | *
184 | * @attention loop function will NOT run when OTA update
185 | * process running
186 | *
187 | * 在OTA升级期间,loop函数不会被运行
188 | *
189 | */
190 | void loop();
191 | };
192 |
193 | extern App *app;
--------------------------------------------------------------------------------
/examples/provider_example/README.md:
--------------------------------------------------------------------------------
1 | This is example shows you how to create unique provider for single app.
2 |
3 | 这个例子展示如何给 app 添加 单独的 provider。
--------------------------------------------------------------------------------
/examples/provider_example/app/app.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * @file app.cpp
3 | * @brief
4 | *
5 | * Code this file just like Arduino way
6 | *
7 | * 就像使用Arduino框架一样在这个文件中写代码就可以了
8 | *
9 | */
10 |
11 | #include "app.h"
12 |
13 | void App::setup()
14 | {
15 |
16 | // callback for provider
17 | // you could return information or null pointer
18 | // provider 的回调函数
19 | // 你可以返回信息或空指针
20 | auto fnCallback = [](
21 | // arguments 参数
22 | ProviderArguments arguments) -> Element *
23 | {
24 | // do your things here with arguments
25 | // you could convert every argument to supported types
26 | // in web page, js file
27 | // or use string directly
28 | // 你可以在这用参数执行你的操作
29 | // 你可以提前在前端把参数转换为支持的类型
30 | // 或者直接使用字符串
31 | if (arguments->size())
32 | {
33 | auto argument0 = arguments->at(0);
34 |
35 | if (argument0->available())
36 | {
37 | // ...
38 | }
39 | }
40 |
41 | // return information, no need to delete object
42 | // 返回信息, 不需要手动释放对象
43 | return new Element("Hello world!");
44 | // return new Element(0x10);
45 |
46 | /*
47 | * char buf[24] = {0};
48 | * sprintf(buf, "Time: %llu", globalTime->getTime() );
49 | * return new Element(buf);
50 | */
51 |
52 | // ...
53 |
54 | // or return null pointer
55 | // 或者返回空指针
56 | // return nullptr;
57 | };
58 |
59 | // create new provider
60 | // this provider only belongs to this app
61 | // 创建新的provider
62 | // 这个provider只属于当前app
63 | global->createProvider(
64 |
65 | // callback 回调函数
66 | fnCallback,
67 |
68 | // provider name, provider 名称
69 | "Provider 0",
70 |
71 | // provider settings, provider 选项
72 | (PROVIDER_ADMIN | PROVIDER_COMMON),
73 |
74 | // how many arguments this provider needs, for web page use, default is 0
75 | // 这个provider 需要多少个参数, 给前端用的, 默认为0
76 | 0,
77 |
78 | // custom id, for other purpose, optional
79 | // 其他用途的自定义id,可省略
80 | 12345ULL);
81 |
82 | /*
83 | if you added "PROVIDER_USER" in settings
84 | this provider will show it to any users
85 | this is especially for web page js using
86 | if you added "PROVIDER_QUESTION" in settings
87 | means this provider should question user
88 | to confirm action
89 | though anyone could send request to
90 | execute those providers only
91 | administrator can execute
92 | don't worry, the request will be confirmed
93 | at local, provider will NOT be executed
94 | if user role isn't administrator
95 |
96 | 如果你在选项中添加了 "PROVIDER_USER"
97 | 那么这个 provider 会显示给所有用户
98 | 这个是为了前端用的
99 | 如果你在选项添加了 "PROVIDER_QUESTION"
100 | 代表这个操作需要确认,典型的,比如双击或者
101 | 弹窗询问
102 | 尽管所有人都可以通过直接发送请求
103 | 比如直接使用控制台企图用普通用户执行
104 | 管理员才能执行的provider
105 | 但是无须担心
106 | 请求会在本地被确认
107 | 如果用户角色不是管理员
108 | 则请求会被丢弃
109 | */
110 | global->createProvider(
111 | [](ProviderArguments arguments) -> Element *
112 | {
113 | // ...
114 | return new Element("OK");
115 | },
116 | "Provider 1",
117 | (PROVIDER_USER | PROVIDER_QUESTION),
118 | 2);
119 |
120 | /*
121 | if you added "PROVIDER_ENCRYPT" in settings
122 | both arguments and return value will be encrypted
123 | with AES-256-CBC before transfer to target
124 | I think this is safer than https
125 |
126 | 如果你在选项添加了 "PROVIDER_ENCRYPT"
127 | 那么参数和返回值都会使用 AES-256-CBC 加密后
128 | 再传输给对方
129 | 我认为这比https更安全
130 | */
131 | global->createProvider(
132 | [](ProviderArguments arguments) -> Element *
133 | {
134 | // arguments had been decrypted before callback
135 | // so just use it is fine
136 | // 参数在回调函数执行前已经被解密
137 | // 直接使用就可以了
138 | // ...
139 | return new Element("OK");
140 | },
141 | "Provider 2",
142 | (PROVIDER_ADMIN | PROVIDER_COMMON | PROVIDER_ENCRYPT),
143 | 2);
144 |
145 | global->createProvider(
146 | [](ProviderArguments arguments) -> Element *
147 | {
148 | // ...
149 | return new Element("OK");
150 | },
151 | "Provider 3",
152 | PROVIDER_USER,
153 | 0,
154 |
155 | // custom id could use as many purpose
156 | // like execute provider by http get method
157 | // other purposes depend on your design
158 | // 自定义 id 可以用作许多用途
159 | // 比如通过 http get 方法执行provider
160 | // 其他用途取决于你的设计
161 | 8888ULL);
162 | }
163 |
164 | void App::loop()
165 | {
166 | // put your code in this function
167 | // it will run repeatedly, attention attached
168 |
169 | // 把你的代码放在这个函数里,代码会重复的运行,请阅读注意事项
170 | }
171 |
172 | /**
173 | * @brief App instance defined here
174 | *
175 | * 类App实例在此实例化
176 | *
177 | */
178 | App *app = new App();
--------------------------------------------------------------------------------
/examples/provider_example/app/app.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 |
4 | /**
5 | * @brief name of app
6 | *
7 | * app名称
8 | *
9 | */
10 | #define APP_NAME "Provider"
11 |
12 | /**
13 | * @brief version of app
14 | *
15 | * app版本
16 | *
17 | */
18 | #define APP_VERSION 0
19 |
20 | /**
21 | * @brief default cpu frequency of current app
22 | *
23 | * 这个app默认的cpu频率
24 | *
25 | */
26 | #define DEFAULT_CPU_FREQ 240
27 |
28 |
29 | /**
30 | * @brief indicate app has custom extra callback
31 | * for local websocket server
32 | *
33 | * 指示app是否有自定义的用于本地websocket服务器的回调函数
34 | *
35 | *
36 | * @note the function declared and defined as C pattern
37 | * not included in class App
38 | *
39 | * 函数以C语言风格声明和定义,不包含在类App内
40 | *
41 | */
42 | //#define APP_HAS_EXTRA_LOCAL_WEBSOCKET_CALLBACK
43 |
44 | /**
45 | * @brief indicate app has custom extra callback
46 | * for remote websocket client
47 | *
48 | * 指示app是否有自定义的用于远程websocket客户端的回调函数
49 | *
50 | *
51 | * @note the function declared and defined as C pattern
52 | * not included in class App
53 | *
54 | * 函数以C语言风格声明和定义,不包含在类App内
55 | *
56 | */
57 | //#define APP_HAS_EXTRA_REMOTE_WEBSOCKET_CALLBACK
58 |
59 | /**
60 | * @brief default app class
61 | * you could modify class name, attention attached
62 | *
63 | * 默认的app类
64 | * 你可以修改这个类的名字,请阅读注意事项
65 | *
66 | * @attention the name of instance must be "app"
67 | * refer to the tail of the file "app.cpp"
68 | *
69 | * 类实例的名称必须为 "app",查看 "app.app" 的尾部
70 | *
71 | * @note if you modified the name of he instance,
72 | * you should also modify the name in the file "main.cpp"
73 | * not recommended for beginner
74 | *
75 | * 如果你修改了类实例的名字,你也应该一同修改文件 "main.cpp"
76 | * 里的名字
77 | * 不推荐新手做此操作
78 | *
79 | */
80 | class App
81 | {
82 | private:
83 | public:
84 | /**
85 | * @brief default constructor, attention attached!
86 | * 默认构造函数,请阅读注意事项!
87 | *
88 | * @attention if you declared and define other constructors
89 | * you should NOT do any actions except set default value
90 | * for variables.
91 | * Because the instance of class App will be define in the tail
92 | * of the app.cpp, and that is NOT included in the system
93 | * GlobalManager::makeSureNewFirmwareValid() measurement scope,
94 | * if any action in constructor cause ESP32 panic reset,
95 | * you will lost connection of this ESP32, then you have to
96 | * use hardware serial to upload new firmware.
97 | *
98 | * 如果你定义了其他构造函数,请确保在构造函数内 [不要] 做 除了给变量赋值
99 | * 以外的其他操作,因为类App的实例在 app.cpp 文件的尾部被实例化,
100 | * 而这不在系统 GlobalManager::makeSureNewFirmwareValid() 的
101 | * 监测范围内,如果构造函数内有任何操作导致ESP32复位,你会丢失与这个
102 | * ESP32的连接,此时你只能再次用硬件串口重新上传固件。
103 | *
104 | */
105 | inline App(){};
106 | inline ~App(){};
107 |
108 | /**
109 | * @brief put your code in this function to run it once
110 | *
111 | * 把你的代码放在这个函数里,代码会被运行一次
112 | *
113 | */
114 | void setup();
115 |
116 | /**
117 | * @brief put your code in this function
118 | * it will run repeatedly, attention attached
119 | *
120 | * 把你的代码放在这个函数里,代码会重复的运行,请阅读注意事项
121 | *
122 | * @attention loop function will NOT run when OTA update
123 | * process running
124 | *
125 | * 在OTA升级期间,loop函数不会被运行
126 | *
127 | */
128 | void loop();
129 | };
130 |
131 | extern App *app;
--------------------------------------------------------------------------------
/examples/sha_digest_example/README.md:
--------------------------------------------------------------------------------
1 | This example show you how to get SHA digest with one line code.
2 |
3 | 这个例子演示如何使用一行代码获取SHA数字摘要。
--------------------------------------------------------------------------------
/examples/sha_digest_example/app/app.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * @file app.cpp
3 | * @brief
4 | *
5 | * Code this file just like Arduino way
6 | *
7 | * 就像使用Arduino框架一样在这个文件中写代码就可以了
8 | *
9 | */
10 |
11 | #include "app.h"
12 |
13 | void App::setup()
14 | {
15 | // SHA1
16 | String sha1Result = mycrypto::SHA::sha1("1234567890");
17 |
18 | // SHA256
19 | String sha256Result = mycrypto::SHA::sha256("1234567890");
20 |
21 | // print
22 | // 打印
23 | Serial.printf("SHA1 of \"1234567890\": %s\n", sha1Result.c_str());
24 | Serial.printf("SHA256 of \"1234567890\": %s\n", sha256Result.c_str());
25 |
26 | //and there are more way to get digest, refer to /lib/mycrypto/mycrypto.h
27 | //还有更多方法获取数字摘要,访问 /lib/mycrypto/mycrypto.h
28 | }
29 |
30 | void App::loop()
31 | {
32 | // put your code in this function
33 | // it will run repeatedly, attention attached
34 |
35 | // 把你的代码放在这个函数里,代码会重复的运行,请阅读注意事项
36 | }
37 |
38 | /**
39 | * @brief App instance defined here
40 | *
41 | * 类App实例在此实例化
42 | *
43 | */
44 | App *app = new App();
--------------------------------------------------------------------------------
/examples/sha_digest_example/app/app.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 |
4 | /**
5 | * @brief name of app
6 | *
7 | * app名称
8 | *
9 | */
10 | #define APP_NAME "SHA Digest"
11 |
12 | /**
13 | * @brief version of app
14 | *
15 | * app版本
16 | *
17 | */
18 | #define APP_VERSION 0
19 |
20 | /**
21 | * @brief default cpu frequency of current app
22 | *
23 | * 这个app默认的cpu频率
24 | *
25 | */
26 | #define DEFAULT_CPU_FREQ 240
27 |
28 |
29 | /**
30 | * @brief indicate app has custom extra callback
31 | * for local websocket server
32 | *
33 | * 指示app是否有自定义的用于本地websocket服务器的回调函数
34 | *
35 | *
36 | * @note the function declared and defined as C pattern
37 | * not included in class App
38 | *
39 | * 函数以C语言风格声明和定义,不包含在类App内
40 | *
41 | */
42 | //#define APP_HAS_EXTRA_LOCAL_WEBSOCKET_CALLBACK
43 |
44 | /**
45 | * @brief indicate app has custom extra callback
46 | * for remote websocket client
47 | *
48 | * 指示app是否有自定义的用于远程websocket客户端的回调函数
49 | *
50 | *
51 | * @note the function declared and defined as C pattern
52 | * not included in class App
53 | *
54 | * 函数以C语言风格声明和定义,不包含在类App内
55 | *
56 | */
57 | //#define APP_HAS_EXTRA_REMOTE_WEBSOCKET_CALLBACK
58 |
59 | /**
60 | * @brief default app class
61 | * you could modify class name, attention attached
62 | *
63 | * 默认的app类
64 | * 你可以修改这个类的名字,请阅读注意事项
65 | *
66 | * @attention the name of instance must be "app"
67 | * refer to the tail of the file "app.cpp"
68 | *
69 | * 类实例的名称必须为 "app",查看 "app.app" 的尾部
70 | *
71 | * @note if you modified the name of he instance,
72 | * you should also modify the name in the file "main.cpp"
73 | * not recommended for beginner
74 | *
75 | * 如果你修改了类实例的名字,你也应该一同修改文件 "main.cpp"
76 | * 里的名字
77 | * 不推荐新手做此操作
78 | *
79 | */
80 | class App
81 | {
82 | private:
83 | public:
84 | /**
85 | * @brief default constructor, attention attached!
86 | * 默认构造函数,请阅读注意事项!
87 | *
88 | * @attention if you declared and define other constructors
89 | * you should NOT do any actions except set default value
90 | * for variables.
91 | * Because the instance of class App will be define in the tail
92 | * of the app.cpp, and that is NOT included in the system
93 | * GlobalManager::makeSureNewFirmwareValid() measurement scope,
94 | * if any action in constructor cause ESP32 panic reset,
95 | * you will lost connection of this ESP32, then you have to
96 | * use hardware serial to upload new firmware.
97 | *
98 | * 如果你定义了其他构造函数,请确保在构造函数内 [不要] 做 除了给变量赋值
99 | * 以外的其他操作,因为类App的实例在 app.cpp 文件的尾部被实例化,
100 | * 而这不在系统 GlobalManager::makeSureNewFirmwareValid() 的
101 | * 监测范围内,如果构造函数内有任何操作导致ESP32复位,你会丢失与这个
102 | * ESP32的连接,此时你只能再次用硬件串口重新上传固件。
103 | *
104 | */
105 | inline App(){};
106 | inline ~App(){};
107 |
108 | /**
109 | * @brief put your code in this function to run it once
110 | *
111 | * 把你的代码放在这个函数里,代码会被运行一次
112 | *
113 | */
114 | void setup();
115 |
116 | /**
117 | * @brief put your code in this function
118 | * it will run repeatedly, attention attached
119 | *
120 | * 把你的代码放在这个函数里,代码会重复的运行,请阅读注意事项
121 | *
122 | * @attention loop function will NOT run when OTA update
123 | * process running
124 | *
125 | * 在OTA升级期间,loop函数不会被运行
126 | *
127 | */
128 | void loop();
129 | };
130 |
131 | extern App *app;
--------------------------------------------------------------------------------
/examples/web_serial_example/README.md:
--------------------------------------------------------------------------------
1 | This is example shows you how to push message to administrator.
2 |
3 | 这个例子展示如何推送消息给管理员。
--------------------------------------------------------------------------------
/examples/web_serial_example/app/app.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * @file app.cpp
3 | * @brief
4 | *
5 | * Code this file just like Arduino way
6 | *
7 | * 就像使用Arduino框架一样在这个文件中写代码就可以了
8 | *
9 | */
10 |
11 | #include "app.h"
12 |
13 | void App::setup()
14 | {
15 |
16 | app->push = dbApp("push")->getUint8() ? true : false;
17 |
18 | // create a provider for toggle message push
19 | // 创建一个 provider 用于切换消息推送
20 | global->createProvider(
21 | [](ProviderArguments arguments) -> Element *
22 | {
23 | app->push = !app->push;
24 |
25 | // you could store it with database
26 | // 你可以顺便把设置保存一下
27 |
28 | *dbApp("push") = app->push ? 1 : 0;
29 | dbApp.flush();
30 |
31 | return new Element("OK");
32 | },
33 | "Toggle 开关", PROVIDER_USER);
34 | }
35 |
36 | void App::loop()
37 | {
38 | if (this->push)
39 | {
40 | uint64_t t = millis();
41 |
42 | if (t - this->lastPushTime > 1000)
43 | {
44 | this->lastPushTime = t;
45 | global->sendMessageToClient(globalTime->getTime());
46 | }
47 | }
48 | }
49 |
50 | /**
51 | * @brief App instance defined here
52 | *
53 | * 类App实例在此实例化
54 | *
55 | */
56 | App *app = new App();
--------------------------------------------------------------------------------
/examples/web_serial_example/app/app.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 |
4 | /**
5 | * @brief name of app
6 | *
7 | * app名称
8 | *
9 | */
10 | #define APP_NAME "Web Serial"
11 |
12 | /**
13 | * @brief version of app
14 | *
15 | * app版本
16 | *
17 | */
18 | #define APP_VERSION 0
19 |
20 | /**
21 | * @brief default cpu frequency of current app
22 | *
23 | * 这个app默认的cpu频率
24 | *
25 | */
26 | #define DEFAULT_CPU_FREQ 240
27 |
28 |
29 | /**
30 | * @brief indicate app has custom extra callback
31 | * for local websocket server
32 | *
33 | * 指示app是否有自定义的用于本地websocket服务器的回调函数
34 | *
35 | *
36 | * @note the function declared and defined as C pattern
37 | * not included in class App
38 | *
39 | * 函数以C语言风格声明和定义,不包含在类App内
40 | *
41 | */
42 | //#define APP_HAS_EXTRA_LOCAL_WEBSOCKET_CALLBACK
43 |
44 | /**
45 | * @brief indicate app has custom extra callback
46 | * for remote websocket client
47 | *
48 | * 指示app是否有自定义的用于远程websocket客户端的回调函数
49 | *
50 | *
51 | * @note the function declared and defined as C pattern
52 | * not included in class App
53 | *
54 | * 函数以C语言风格声明和定义,不包含在类App内
55 | *
56 | */
57 | //#define APP_HAS_EXTRA_REMOTE_WEBSOCKET_CALLBACK
58 |
59 | /**
60 | * @brief default app class
61 | * you could modify class name, attention attached
62 | *
63 | * 默认的app类
64 | * 你可以修改这个类的名字,请阅读注意事项
65 | *
66 | * @attention the name of instance must be "app"
67 | * refer to the tail of the file "app.cpp"
68 | *
69 | * 类实例的名称必须为 "app",查看 "app.app" 的尾部
70 | *
71 | * @note if you modified the name of he instance,
72 | * you should also modify the name in the file "main.cpp"
73 | * not recommended for beginner
74 | *
75 | * 如果你修改了类实例的名字,你也应该一同修改文件 "main.cpp"
76 | * 里的名字
77 | * 不推荐新手做此操作
78 | *
79 | */
80 | class App
81 | {
82 | private:
83 | public:
84 | bool push = false;
85 | uint64_t lastPushTime = 0;
86 | /**
87 | * @brief default constructor, attention attached!
88 | * 默认构造函数,请阅读注意事项!
89 | *
90 | * @attention if you declared and define other constructors
91 | * you should NOT do any actions except set default value
92 | * for variables.
93 | * Because the instance of class App will be define in the tail
94 | * of the app.cpp, and that is NOT included in the system
95 | * GlobalManager::makeSureNewFirmwareValid() measurement scope,
96 | * if any action in constructor cause ESP32 panic reset,
97 | * you will lost connection of this ESP32, then you have to
98 | * use hardware serial to upload new firmware.
99 | *
100 | * 如果你定义了其他构造函数,请确保在构造函数内 [不要] 做 除了给变量赋值
101 | * 以外的其他操作,因为类App的实例在 app.cpp 文件的尾部被实例化,
102 | * 而这不在系统 GlobalManager::makeSureNewFirmwareValid() 的
103 | * 监测范围内,如果构造函数内有任何操作导致ESP32复位,你会丢失与这个
104 | * ESP32的连接,此时你只能再次用硬件串口重新上传固件。
105 | *
106 | */
107 | inline App(){};
108 | inline ~App(){};
109 |
110 | /**
111 | * @brief put your code in this function to run it once
112 | *
113 | * 把你的代码放在这个函数里,代码会被运行一次
114 | *
115 | */
116 | void setup();
117 |
118 | /**
119 | * @brief put your code in this function
120 | * it will run repeatedly, attention attached
121 | *
122 | * 把你的代码放在这个函数里,代码会重复的运行,请阅读注意事项
123 | *
124 | * @attention loop function will NOT run when OTA update
125 | * process running
126 | *
127 | * 在OTA升级期间,loop函数不会被运行
128 | *
129 | */
130 | void loop();
131 | };
132 |
133 | extern App *app;
--------------------------------------------------------------------------------
/firmware/README.md:
--------------------------------------------------------------------------------
1 | Complied firmware will be copied to here.
2 |
3 | 编译好的固件会被拷贝到这里。
--------------------------------------------------------------------------------
/lib/arraybuffer/README.md:
--------------------------------------------------------------------------------
1 | The class Element is the core of class MyDB and whole system, it allows you to store data in it. And you could use it for manu purpose.
2 | The class ArrayBuffer is a tool that generate buffer using Element vector, or decode buffer to Element vector.
3 | If you are a beginner, do not modify any codes. If you are master-hand of C++ and you have enhancement method, please submit issue or send email, thanks.
4 | There are full comments in header file, check arraybuffer.h for more information.
5 |
6 | 类Element是数据库和整个系统的核心,他可以用来存储数据。你可以把它用作许多用途。
7 | 类ArrayBuffer是一个可以将Element容器转换为buffer的工具,或者可以用来将buffer转换为Element容器。
8 | 如果你是新手,请不要改动任何代码。如果你是C++高手觉得某些地方可以改进,可以提交issue或发邮件,谢谢。
9 | 头文件中有完整的注释,更多信息请参阅arraybuffer.h。
10 |
11 | 2023/03/23
12 | Rebuilt class Element, now it supports all types of data.
13 | Change file structure from .h and .cpp to single .hpp.
14 | Almost all operators had been overloaded, it's very useful.
15 | More usage refer to /test/test.cpp.
16 |
17 |
18 | 重构了类Element,现在它支持所有数据类型。
19 | 修改了文件结构,由.hpp替代.h和.cpp。
20 | 几乎所有的符号都已被重载,这很实用。
21 | 更多用法参见/test/test.cpp。
--------------------------------------------------------------------------------
/lib/config/README.md:
--------------------------------------------------------------------------------
1 | Almost all configs in the config.h, you could change it yourself.
2 |
3 | 几乎所有的设置都在config.h中,你可以自己修改。
--------------------------------------------------------------------------------
/lib/esp32time/esp32time.cpp:
--------------------------------------------------------------------------------
1 | #include "esp32time.h"
2 |
3 | String Esp32Time::getTimeFormat(bool longFormat)
4 | {
5 | struct tm time = this->getStructure();
6 | char s[61];
7 | if (longFormat)
8 | {
9 | strftime(s, 60, "%H:%M:%S %A, %B %d %Y", &time);
10 | }
11 | else
12 | {
13 | strftime(s, 60, "%H:%M:%S %a, %b %d %Y", &time);
14 | }
15 | return String(s);
16 | }
17 |
18 | struct tm Esp32Time::getStructure()
19 | {
20 | time_t now;
21 | struct tm tms;
22 | time(&now);
23 | localtime_r(&now, &tms);
24 | return tms;
25 | }
26 |
27 | void Esp32Time::setTime(uint64_t time, uint16_t timeZone)
28 | {
29 | long second = time / 1000;
30 | int ms = time % 1000;
31 |
32 | struct timeval tv;
33 | tv.tv_sec = second;
34 | tv.tv_usec = ms;
35 |
36 | setenv("TZ", String(String("GMT-") + String(timeZone)).c_str(), 1);
37 | tzset();
38 |
39 | settimeofday(&tv, NULL);
40 | }
41 |
42 | void Esp32Time::setTime(uint16_t year, uint8_t month, uint8_t date, uint8_t hour, uint8_t minute, uint8_t second, uint16_t ms)
43 | {
44 | struct tm time = {0};
45 | time.tm_year = year - 1900;
46 | time.tm_mon = month - 1;
47 | time.tm_mday = date;
48 | time.tm_hour = hour;
49 | time.tm_min = minute;
50 | time.tm_sec = second;
51 | time_t t = mktime(&time);
52 | setTime((t * 1000) + ms);
53 | }
54 |
55 | String Esp32Time::getDate(bool longFormat)
56 | {
57 | struct tm time = this->getStructure();
58 |
59 | char buf[61];
60 | buf[60] = 0;
61 |
62 | if (longFormat)
63 | {
64 | strftime(buf, 60, "%A, %B %d %Y", &time);
65 | }
66 | else
67 | {
68 | strftime(buf, 60, "%a, %b %d %Y", &time);
69 | }
70 |
71 | return String(buf);
72 | }
73 |
74 | uint64_t Esp32Time::getSeconds()
75 | {
76 | struct timeval tv;
77 | gettimeofday(&tv, NULL);
78 | return tv.tv_sec;
79 | }
80 |
81 | uint16_t Esp32Time::getMilli()
82 | {
83 | return this->getMicro() / 1000;
84 | }
85 |
86 | uint32_t Esp32Time::getMicro()
87 | {
88 | struct timeval tv;
89 | gettimeofday(&tv, NULL);
90 | return tv.tv_usec;
91 | }
92 |
93 | Esp32Time *globalTime = new Esp32Time();
--------------------------------------------------------------------------------
/lib/esp32time/esp32time.h:
--------------------------------------------------------------------------------
1 | /**
2 | * @file esp32time.h
3 | * @author Vida Wang (support@vida.wang)
4 | * @brief This file provided functions related to time, reduced and modified
5 | * some functions from https://github.com/fbiego/ESP32Time, thanks to Felix Biego
6 | *
7 | * 这个文件提供了时间相关的功能,从 https://github.com/fbiego/ESP32Time 去掉了一些
8 | * 不常用功能,对有些功能做出了一些修改,感谢 Felix Biego
9 | *
10 | * @version 1.0.0
11 | * @date 2022-08-01
12 | *
13 | * @copyright Copyright (c) 2022
14 | *
15 | */
16 |
17 | /*
18 | MIT License
19 | Copyright (c) 2021 Felix Biego
20 | Permission is hereby granted, free of charge, to any person obtaining a copy
21 | of this software and associated documentation files (the "Software"), to deal
22 | in the Software without restriction, including without limitation the rights
23 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
24 | copies of the Software, and to permit persons to whom the Software is
25 | furnished to do so, subject to the following conditions:
26 | The above copyright notice and this permission notice shall be included in all
27 | copies or substantial portions of the Software.
28 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
29 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
30 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
31 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
32 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
33 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
34 | SOFTWARE.
35 | */
36 |
37 | #ifndef ESP32_TIME_H_
38 | #define ESP32_TIME_H_
39 |
40 | #include
41 | #include "time.h"
42 | #include
43 |
44 | class Esp32Time
45 | {
46 | private:
47 | struct tm getStructure();
48 |
49 | public:
50 | /**
51 | * @brief set system time(unix epoch timestamp)
52 | * 设置系统时间(unix时间戳)
53 | *
54 | * @param time unix epoch timestamp, unix时间戳
55 | * @param timeZone time zone 时区
56 | */
57 | void setTime(uint64_t time, uint16_t timeZone = 8);
58 |
59 | /**
60 | * @brief set system time
61 | * 设置系统时间
62 | *
63 | * @param year year 年
64 | * @param month month 月
65 | * @param date date 日
66 | * @param hour hour 时
67 | * @param minute minute 分
68 | * @param second second 秒
69 | * @param ms millisecond 毫秒
70 | */
71 | void setTime(uint16_t year, uint8_t month, uint8_t date, uint8_t hour, uint8_t minute, uint8_t second, uint16_t ms = 0);
72 |
73 | /**
74 | * @brief get formatted time string
75 | * 获取格式化的时间
76 | *
77 | * @param longFormat use full name or not 是否使用完整名称
78 | * @return String formatted time 格式化的时间
79 | */
80 | String getTimeFormat(bool longFormat = true);
81 |
82 | /**
83 | * @brief get day number in year
84 | * 获取在一年中的天数
85 | *
86 | * @return uint16_t number of day 天数
87 | */
88 | inline uint16_t getDayInYear()
89 | {
90 | return this->getStructure().tm_yday;
91 | }
92 |
93 | /**
94 | * @brief get milliseconds from unix epoch
95 | * 获取unix时间戳
96 | *
97 | * @return uint64_t unix epoch timestamp, unix时间戳
98 | */
99 | inline uint64_t getTime()
100 | {
101 | return ((uint64_t)((this->getSeconds() * 1000) + this->getMilli()));
102 | }
103 |
104 | /**
105 | * @brief get year
106 | * 获取年份
107 | *
108 | * @return uint16_t year 年份
109 | */
110 | inline uint16_t getYear()
111 | {
112 | return this->getStructure().tm_year + 1900;
113 | }
114 |
115 | /**
116 | * @brief get month
117 | * 获取月份
118 | *
119 | * @return uint8_t month 月份
120 | */
121 | inline uint8_t getMonth()
122 | {
123 | return this->getStructure().tm_mon;
124 | }
125 |
126 | /**
127 | * @brief get date(not included time)
128 | * 获取日期(不包括时间)
129 | *
130 | * @param longFormat use full name 是否使用完整名称
131 | * @return String formatted date 格式化的日期
132 | */
133 | String getDate(bool longFormat = true);
134 |
135 | /**
136 | * @brief get hour
137 | * 获取小时
138 | *
139 | * @param a24hour use a24-hour or not 是否使用24小时制
140 | * @return uint8_t hour 小时
141 | */
142 | inline uint8_t getHour(bool a24hour = true)
143 | {
144 | uint8_t hour = this->getStructure().tm_hour;
145 | return a24hour ? hour : (hour > 12 ? hour - 12 : hour);
146 | }
147 |
148 | /**
149 | * @brief get minute
150 | * 获取分钟
151 | *
152 | * @return uint8_t minute 分钟
153 | */
154 | inline uint8_t getMinute()
155 | {
156 | return this->getStructure().tm_min;
157 | }
158 |
159 | /**
160 | * @brief get second
161 | * 获取秒数
162 | *
163 | * @return uint8_t second 秒数
164 | */
165 | uint8_t getSecond()
166 | {
167 | return this->getStructure().tm_sec;
168 | }
169 |
170 | /**
171 | * @brief get seconds from unix epoch timestamp
172 | * 获取unix时间戳的秒数
173 | *
174 | * @return uint64_t seconds from unix epoch timestamp, unix时间戳的秒数
175 | */
176 | uint64_t getSeconds();
177 |
178 | /**
179 | * @brief get milliseconds
180 | * 获取毫秒数
181 | *
182 | * @return uint16_t milliseconds 毫秒数
183 | */
184 | uint16_t getMilli();
185 |
186 | /**
187 | * @brief get microseconds
188 | * 获取微秒数
189 | *
190 | * @return uint32_t microseconds 微秒数
191 | */
192 | uint32_t getMicro();
193 |
194 | /**
195 | * @brief get day in week
196 | * 获取在星期内的天数
197 | *
198 | * @return uint8_t day 天数
199 | */
200 | inline uint8_t getDay()
201 | {
202 | return this->getStructure().tm_wday;
203 | }
204 |
205 | /**
206 | * @brief get formatted time string
207 | * 获取格式化的时间
208 | *
209 | * @param longFormat use full name or not 是否使用完整名称
210 | * @return String formatted time 格式化的时间
211 | */
212 | inline String getDateTime(bool longFormat = true)
213 | {
214 | return this->getTimeFormat(longFormat);
215 | }
216 |
217 | inline Esp32Time() {}
218 | inline ~Esp32Time() {}
219 | };
220 |
221 | extern Esp32Time *globalTime;
222 |
223 | #endif
--------------------------------------------------------------------------------
/lib/languages/languages.h:
--------------------------------------------------------------------------------
1 | /**
2 | * @file languages.h
3 | * @author Vida Wang (support@vida.wang)
4 | * @brief This file include languages informations
5 | * 这个文件包含了语言信息
6 | * @version 1.0.0
7 | * @date 2022-08-16
8 | *
9 | * @copyright Copyright (c) 2022
10 | *
11 | */
12 |
13 | #ifndef LANGUAGES_H_
14 | #define LANGUAGES_H_
15 | #include "config.h"
16 |
17 | #ifdef CHINESE_VERSION
18 | // PROVIDER_INFO
19 |
20 | #define PI_UNKNOWN "未知"
21 | #define PI_BOOT "开机"
22 | #define PI_ESP_RST_INT_WDT "中断看门狗"
23 | #define PI_ESP_RST_TASK_WDT "任务看门狗"
24 | #define PI_ESP_RST_WDT "其他看门狗"
25 | #define PI_ESP_RST_PANIC "软件异常"
26 | #define PI_ESP_RST_BROWNOUT "掉电保护器"
27 | #define PI_ESP_RST_DEEPSLEEP "深度睡眠"
28 | #define PI_ESP_RST_SW "软件复位"
29 | #define PI_GET_RESET_AND_ONLINE_TIME "获取复位信息和启动时间"
30 |
31 | #define PI_INVALID_LENGTH_OF_ARGUMENTS "参数个数不正确"
32 | #define PI_INVALID_LENGTH_OF_ARGUMENT "参数长度不正确"
33 | #define PI_INVALID_ARGUMENT "参数不正确"
34 | #define PI_INVALID_TYPE_OF_ARGUMENT "参数类型不正确"
35 | #define PI_SUCCESS "成功"
36 | #define PI_DELETED "已删除"
37 |
38 | #define PI_TOKEN_SET "token已设置"
39 | #define PI_MODIFY_TOKEN "修改token"
40 |
41 | #define PI_USER_DELETED "用户删除成功"
42 | #define PI_ADD_MODIFY_DELETE_USER "(添加/修改/删除)用户"
43 |
44 | #define PI_WEB_SERIAL "发送数据到串口"
45 |
46 | #define PI_DATABASE_UPDATED "数据库已更新"
47 | #define PI_QUERY_UPDATE_MAIN_DATABASE_OR_LIST_ALL_KEYS_IN_MAIN_DATABASE \
48 | "((查询/更新)主数据库)/(列出所有主数据库中的所有键)"
49 |
50 | #define PI_REMOVE_VALUE_IN_MAIN_DATABASE "删除主数据库中的值"
51 |
52 | #define PI_WIFI_INFORMATION_REMOVED "WiFi信息已清除"
53 | #define PI_REMOVE_WIFI_INFORMATION "[清除WiFi信息]"
54 |
55 | #define PI_CAN_NOT_ROLLBACK "没有可供回滚的固件"
56 | #define PI_WILL_ROLLBACK_IN_TIMEOUT_SECONDS "会在3秒后回滚固件"
57 | #define PI_ROLLBACK "[回滚固件]"
58 |
59 | #define PI_FIRMWARE_PENDING_VERIFY "正在等待验证固件有效性"
60 | #define PI_FIRMWARE_VALID "固件有效"
61 | #define PI_NO_OTA_INFORMATION "没有在数据库中找到OTA升级信息"
62 | #define PI_FIRMWARE_STATUS "固件状态"
63 |
64 | #define PI_LAST_OTA_TIME "上次OTA更新时间"
65 |
66 | #define PI_MAC_ADDRESS "物理地址(MAC)"
67 |
68 | #define PI_WILL_INTO_DEEP_SLEEP_FOR_TIMEOUT_SECONDS_IN_SECONDS \
69 | "将会睡眠%u秒, %u秒后执行"
70 | #define PI_DEEP_SLEEP "[睡眠]"
71 |
72 | #define PI_ALL_INFORMATION_REMOVED_REBOOT_IN_3_SECONDS \
73 | "所有信息已被清除, 3秒后重启"
74 |
75 | #define PI_REMOVE_ALL_INFORMATION "[清除所有信息]"
76 |
77 |
78 | #define PI_NEW_SSID_OR_PASSWORD_HAS_BEEN_SET "新的%s: \"%s\"已经设置"
79 | #define PI_INVALID_SSID_PROVIDED "提供的SSID不正确"
80 | #define PI_MODIFY_SSID "[修改WiFi SSID]"
81 |
82 | #define PI_INVALID_WIFI_PASSWORD "提供了格式不正确的密码"
83 | #define PI_MODIFY_WIFI_PASSWORD "[修改WiFi密码]"
84 |
85 | #define PI_WILL_REBOOT_IN_TIMEOUT_SECONDS "将会在[%u]秒后重启"
86 | #define PI_REBOOT "[重启]"
87 |
88 | #define PI_HARDWARE_TIMESTAMP "硬件时间"
89 |
90 | #define PI_PREFIX_BYTE "字节"
91 | #define PI_FREE_HEAP "剩余堆内存"
92 |
93 | #define PI_FREE_SPACE "剩余存储空间"
94 |
95 | #define PI_FIRMWARE_ERROR_TIME "固件异常: %llu"
96 |
97 |
98 | #else
99 |
100 | #define PI_UNKNOWN "unknown"
101 | #define PI_BOOT "power on"
102 | #define PI_ESP_RST_INT_WDT "interrupt watchdog"
103 | #define PI_ESP_RST_TASK_WDT "task watchdog"
104 | #define PI_ESP_RST_WDT "other watchdogs"
105 | #define PI_ESP_RST_PANIC "software error"
106 | #define PI_ESP_RST_BROWNOUT "low voltage"
107 | #define PI_ESP_RST_DEEPSLEEP "deep sleep"
108 | #define PI_ESP_RST_SW "software reset"
109 | #define PI_GET_RESET_AND_ONLINE_TIME "Get last reset reason"
110 |
111 | #define PI_INVALID_LENGTH_OF_ARGUMENTS "Invalid length of arguments"
112 | #define PI_INVALID_LENGTH_OF_ARGUMENT "Invalid length of argument"
113 | #define PI_INVALID_ARGUMENT "Invalid argument"
114 | #define PI_INVALID_TYPE_OF_ARGUMENT "Invalid type of arguments"
115 | #define PI_SUCCESS "Success"
116 | #define PI_DELETED "Removed"
117 |
118 | #define PI_TOKEN_SET "Token has been set"
119 | #define PI_MODIFY_TOKEN "Modify token"
120 |
121 | #define PI_USER_DELETED "User removed"
122 | #define PI_ADD_MODIFY_DELETE_USER "(Add/Update/Remove)User"
123 |
124 | #define PI_WEB_SERIAL "Send data to serial"
125 |
126 | #define PI_DATABASE_UPDATED "Database updated"
127 | #define PI_QUERY_UPDATE_MAIN_DATABASE_OR_LIST_ALL_KEYS_IN_MAIN_DATABASE \
128 | "((Query/Update)value in main database)/(List all keys in main database)"
129 |
130 | #define PI_REMOVE_VALUE_IN_MAIN_DATABASE "Remove value in main database"
131 |
132 | #define PI_WIFI_INFORMATION_REMOVED "WiFi information has been removed"
133 | #define PI_REMOVE_WIFI_INFORMATION "[RESET WiFi information]"
134 |
135 | #define PI_CAN_NOT_ROLLBACK "There isn't firmware could rollback"
136 | #define PI_WILL_ROLLBACK_IN_TIMEOUT_SECONDS "Will rollback firmware in 3 seconds"
137 | #define PI_ROLLBACK "[ROLLBACK FIRMWARE]"
138 |
139 | #define PI_FIRMWARE_PENDING_VERIFY "Pending verify"
140 | #define PI_FIRMWARE_VALID "Firmware OK"
141 | #define PI_NO_OTA_INFORMATION "Couldn't detect pendingOTA in database"
142 | #define PI_FIRMWARE_STATUS "Firmware status"
143 |
144 | #define PI_LAST_OTA_TIME "Last OTA update time"
145 |
146 | #define PI_MAC_ADDRESS "MAC Address"
147 |
148 | #define PI_WILL_INTO_DEEP_SLEEP_FOR_TIMEOUT_SECONDS_IN_SECONDS \
149 | "Will into deep sleep for [%u] seconds in %u seconds"
150 | #define PI_DEEP_SLEEP "[SLEEP]"
151 |
152 | #define PI_ALL_INFORMATION_REMOVED_REBOOT_IN_3_SECONDS \
153 | "All information has been removed, reboot in 3 seconds"
154 |
155 | #define PI_REMOVE_ALL_INFORMATION "[REMOVE ALL INFORMATION]"
156 |
157 |
158 | #define PI_NEW_SSID_OR_PASSWORD_HAS_BEEN_SET "New%s: \"%s\" set"
159 | #define PI_INVALID_SSID_PROVIDED "Invalid SSID provided"
160 | #define PI_MODIFY_SSID "[UPDATE WiFi SSID]"
161 |
162 | #define PI_INVALID_WIFI_PASSWORD "Invalid password provided"
163 | #define PI_MODIFY_WIFI_PASSWORD "[UPDATE WiFi password]"
164 |
165 | #define PI_WILL_REBOOT_IN_TIMEOUT_SECONDS "Will reboot in %u second(s)"
166 | #define PI_REBOOT "[REBOOT]"
167 |
168 | #define PI_HARDWARE_TIMESTAMP "Hardware timestamp"
169 |
170 | #define PI_PREFIX_BYTE "bytes"
171 | #define PI_FREE_HEAP "Free heap"
172 |
173 | #define PI_FREE_SPACE "Free space"
174 |
175 | #define PI_FIRMWARE_ERROR_TIME "Firmware error: %llu"
176 |
177 |
178 | #endif
179 |
180 | #endif
--------------------------------------------------------------------------------
/lib/mycrypto/README.md:
--------------------------------------------------------------------------------
1 | The class WebSocketClient will use SHA1 and Base64 encode functions. Also provided AES-256-CBC encryption and decryption and SHA256. There are full comments in header file, check mycrypto.h for more information.
2 |
3 | 类WebSocketClient会使用SHA1和Base64编码功能,同时提供了AES-256-CBC和SHA256。头文件中有完整的注释,更多信息请参阅mycrypto.h。
--------------------------------------------------------------------------------
/lib/mydb/README.md:
--------------------------------------------------------------------------------
1 | ### English
2 |
3 | A key-value typed RAM database for access data in different types conveniently.
4 | There are full comments in header file, check mydb.h for more information.
5 |
6 | The file /lib/mydb/mydb.h and mydb.cpp declared and defined 3 instances of class MyDB, they are:
7 |
8 | - db
9 | - dbUser
10 | - dbApp
11 |
12 | The first one is main database for system use, you app could use this database to store data, but this is not recommended.
13 |
14 | The second one stored other users information, you **SHOULD NOT** modify any content by your way in this database.
15 |
16 | The last one is for user app, you could do any action to this instance.
17 |
18 | ### 中文
19 |
20 | 一个键值对型内存数据库,方便访问不同种类的数据。
21 | 头文件中有完整的注释,更多信息请参阅mydb.h。
22 |
23 | 文件 /lib/mydb/mydb.h 和 mydb.cpp 中声明和定义了3个数据库实例,它们是:
24 |
25 | - db
26 | - dbUser
27 | - dbApp
28 |
29 | 第一个是主数据库,给系统用的,你的app可以使用这个数据库,但是不建议。
30 |
31 | 第二个存储了其他用户信息,你 **不** 应该对这个数据库用你的方式进行任何操作。
32 |
33 | 第三个是给你的app用的,你可以随意使用。
--------------------------------------------------------------------------------
/lib/myfs/myfs.cpp:
--------------------------------------------------------------------------------
1 | #include "myfs.h"
2 |
3 | void MyFS::myfsInit()
4 | {
5 | if (!LittleFS.begin(FORMAT_LITTLEFS_IF_FAILED))
6 | {
7 | delay(1000);
8 | ESP_LOGD("myfs", "formatted");
9 | }
10 | }
11 |
12 | void MyFS::listFile(String path, fileElementList *list, String prefix)
13 | {
14 | File root = LittleFS.open(path);
15 | if (prefix != "")
16 | {
17 | prefix = "/" + prefix;
18 | }
19 |
20 | if (root)
21 | {
22 | if (root.isDirectory())
23 | {
24 | File file = root.openNextFile();
25 |
26 | while (file)
27 | {
28 | FileElement fileInfo;
29 | fileInfo.name = file.name();
30 | if (file.isDirectory())
31 | {
32 | fileInfo.isFile = false;
33 | fileInfo.size = 0;
34 | list->push_back(fileInfo);
35 | }
36 | else
37 | {
38 | if (prefix != "")
39 | {
40 | if (!fileInfo.name.startsWith(prefix))
41 | {
42 | file = root.openNextFile();
43 | continue;
44 | }
45 | }
46 | fileInfo.isFile = true;
47 | fileInfo.size = file.size();
48 | list->push_back(fileInfo);
49 | }
50 | file = root.openNextFile();
51 | }
52 | }
53 | }
54 | }
55 |
56 | bool MyFS::writeFile(const char *p, const char *data, bool base64Encode)
57 | {
58 | if (!base64Encode)
59 | {
60 | return writeFile(p, (uint8_t *)data, strlen(data));
61 | }
62 | else
63 | {
64 | char *d = mycrypto::Base64::base64Encode((uint8_t *)data, strlen(data));
65 | return writeFile(p, (uint8_t *)d, strlen(d));
66 | }
67 | }
68 |
69 | bool MyFS::writeFile(const char *p, uint8_t *data, uint64_t length)
70 | {
71 | String path = p;
72 | if (path[0] != '/')
73 | {
74 | path = "/" + path;
75 | }
76 |
77 | File file = LittleFS.open(path, FILE_WRITE);
78 | if (!file)
79 | {
80 | return false;
81 | }
82 |
83 | bool value = file.write(data, length);
84 | file.flush();
85 | file.close();
86 | return value;
87 | }
88 |
89 | bool MyFS::writeFile(String path, String data, bool base64Encode)
90 | {
91 | if (path[0] != '/')
92 | {
93 | path = "/" + path;
94 | }
95 |
96 | File file = LittleFS.open(path, FILE_WRITE);
97 | if (!file)
98 | {
99 | return false;
100 | }
101 |
102 | if (base64Encode)
103 | {
104 | data = mycrypto::Base64::base64Encode(data);
105 | }
106 |
107 | bool value = file.print(data);
108 | file.close();
109 | return value;
110 | }
111 |
112 | uint8_t *MyFS::readFile(const char *p, uint64_t *outLen)
113 | {
114 | String path = p;
115 | if (path[0] != '/')
116 | {
117 | path = "/" + path;
118 | }
119 | File file = LittleFS.open(path);
120 |
121 | if (!file || file.isDirectory())
122 | {
123 | (*outLen) = 0;
124 | return nullptr;
125 | }
126 |
127 | uint64_t size = file.size();
128 | uint8_t *data = new (std::nothrow) uint8_t[size];
129 |
130 | if (!data)
131 | {
132 | (*outLen) = 0;
133 | return nullptr;
134 | }
135 | file.readBytes((char *)data, size);
136 | file.close();
137 |
138 | (*outLen) = size;
139 | return data;
140 | }
141 |
142 | void MyFS::readFile(const char *p, std::function callback)
143 | {
144 | String path = p;
145 | if (path[0] != '/')
146 | {
147 | path = "/" + path;
148 | }
149 | File file = LittleFS.open(path);
150 |
151 | if (!file || file.isDirectory())
152 | {
153 | callback(nullptr, 0);
154 | return;
155 | }
156 | uint64_t size = 0;
157 |
158 | uint8_t *data = MyFS::readFile(p, &size);
159 |
160 | callback(data, size);
161 |
162 | delete data;
163 | }
164 |
165 | String MyFS::readFile(String path, bool base64Decode)
166 | {
167 | if (path[0] != '/')
168 | {
169 | path = "/" + path;
170 | }
171 |
172 | File file = LittleFS.open(path);
173 |
174 | if (!file)
175 | {
176 | return String("error");
177 | }
178 |
179 | if (file.isDirectory())
180 | {
181 | return String("not file");
182 | }
183 |
184 | uint32_t length = file.size();
185 | uint8_t *data = new (std::nothrow) uint8_t[length + 1];
186 |
187 | if (!data)
188 | {
189 | return String("memory full");
190 | }
191 |
192 | file.readBytes((char *)data, length);
193 | file.close();
194 | data[length] = 0;
195 | String output = String((char *)data);
196 |
197 | if (base64Decode)
198 | {
199 | output = mycrypto::Base64::base64Decode(output);
200 | }
201 |
202 | return output;
203 | }
204 |
205 | bool MyFS::appendFile(String path, String data)
206 | {
207 | if (path[0] != '/')
208 | {
209 | path = "/" + path;
210 | }
211 |
212 | File file = LittleFS.open(path, FILE_APPEND);
213 |
214 | if (!file)
215 | {
216 | return false;
217 | }
218 |
219 | bool value = file.print(data);
220 | file.close();
221 |
222 | return value;
223 | }
224 |
225 | bool MyFS::deleteFile(String path)
226 | {
227 |
228 | if (path[0] != '/')
229 | {
230 | path = "/" + path;
231 | }
232 | return LittleFS.remove(path);
233 | }
234 |
235 | bool MyFS::renameFile(String path0, String path1)
236 | {
237 | if (path0[0] != '/')
238 | {
239 | path0 = "/" + path0;
240 | }
241 | if (path1[0] != '/')
242 | {
243 | path1 = "/" + path1;
244 | }
245 |
246 | return LittleFS.rename(path0, path1);
247 | }
248 |
249 | bool MyFS::fileExist(String path)
250 | {
251 | if (path[0] != '/')
252 | {
253 | path = "/" + path;
254 | }
255 |
256 | return LittleFS.exists(path);
257 | }
258 |
259 | void MyFS::formatSPIFFS()
260 | {
261 | LittleFS.format();
262 | }
263 |
264 | size_t MyFS::getFreeSpace()
265 | {
266 | return LittleFS.totalBytes() - LittleFS.usedBytes();
267 | }
268 |
269 | size_t MyFS::getUsedSpace()
270 | {
271 | return LittleFS.usedBytes();
272 | }
--------------------------------------------------------------------------------
/lib/myfs/myfs.h:
--------------------------------------------------------------------------------
1 | /**
2 | * @file myfs.h
3 | * @author Vida Wang (support@vida.wang)
4 | * @brief This file packed some functions to access flash.
5 | * User don't need to access these functions directly, using
6 | * functions in mydb.h to instead.
7 | *
8 | * 这个文件包装了一堆函数来使用flash。
9 | * 用户不需要直接访问这里的函数,使用mydb.h中的功能来替代。
10 | *
11 | * @version 1.0.0
12 | * @date 2022-08-16
13 | *
14 | * @copyright Copyright (c) 2022
15 | *
16 | */
17 | #ifndef MYFS_H_
18 | #define MYFS_H_
19 |
20 | #include
21 | #include "FS.h"
22 | #include
23 | #include
24 | #include
25 | #include
26 |
27 | using namespace std;
28 |
29 | typedef struct
30 | {
31 | String name;
32 | int size;
33 | bool isFile;
34 | } FileElement;
35 |
36 | #define FORMAT_LITTLEFS_IF_FAILED true
37 | typedef std::vector fileElementList;
38 |
39 | class MyFS
40 | {
41 | public:
42 | static void myfsInit();
43 | static void listFile(String path, fileElementList *list, String prefix = "");
44 | static bool writeFile(String path, String data, bool base64Encode = true);
45 | static bool writeFile(const char *path, uint8_t *data, uint64_t length);
46 | static bool writeFile(const char *path, const char *data, bool base64Encode = true);
47 | static String readFile(String path, bool base64Decode = true);
48 | static void readFile(const char *p, std::function callback);
49 | static uint8_t *readFile(const char *p, uint64_t *outLen);
50 | static bool appendFile(String path, String data);
51 | static bool deleteFile(String path);
52 | static bool renameFile(String path0, String path1);
53 | static bool fileExist(String path);
54 | static void formatSPIFFS();
55 | static size_t getFreeSpace();
56 | static size_t getUsedSpace();
57 | };
58 |
59 | #endif
--------------------------------------------------------------------------------
/lib/mynet/mynet.cpp:
--------------------------------------------------------------------------------
1 | #include "mynet.h"
2 |
3 | bool MyNet::startAP(const char *ssid, IPAddress *apIP, const char *pwd)
4 | {
5 | this->apIP = apIP;
6 | if (!ssid)
7 | {
8 | return false;
9 | }
10 | if (!strlen(ssid))
11 | {
12 | return false;
13 | }
14 |
15 | WiFi.enableAP(true);
16 |
17 | WiFi.onEvent(
18 | [](arduino_event_t *event) -> void
19 | {
20 | WiFi.softAPConfig(*(myNet.apIP), *(myNet.apIP), IPAddress(255, 255, 255, 0));
21 | },
22 | ARDUINO_EVENT_WIFI_AP_START);
23 | if (pwd)
24 | {
25 | if (strlen(pwd))
26 | {
27 | WiFi.softAP(ssid, pwd);
28 | }
29 | else
30 | {
31 | WiFi.softAP(ssid);
32 | }
33 | }
34 | else
35 | {
36 | WiFi.softAP(ssid);
37 | }
38 | return true;
39 | }
40 | MyNet myNet;
--------------------------------------------------------------------------------
/lib/mynet/mynet.h:
--------------------------------------------------------------------------------
1 | /**
2 | * @file mynet.h
3 | * @author Vida Wang (support@vida.wang)
4 | * @brief This file packed soft ap method.
5 | * 这个文件把soft ap函数包装了一下
6 | *
7 | * @version 1.0.0
8 | * @date 2022-08-16
9 | *
10 | * @copyright Copyright (c) 2022
11 | *
12 | */
13 |
14 | #ifndef MYNET_H_
15 | #define MYNET_H_
16 |
17 | #include
18 | #include
19 | #include
20 | #include
21 |
22 | class MyNet
23 | {
24 | private:
25 | IPAddress *apIP = nullptr;
26 |
27 | public:
28 | /**
29 | * @brief start soft access point
30 | * 开启热点
31 | *
32 | * @param ssid service set identifier 热点名称
33 | * @param apIP default ap gateway 默认ap网关
34 | * @param pwd password 密码
35 | * @return true success 成功
36 | * @return false failed 失败
37 | */
38 | bool startAP(const char *ssid, IPAddress *apIP, const char *pwd = nullptr);
39 | };
40 | extern MyNet myNet;
41 |
42 | #endif
--------------------------------------------------------------------------------
/lib/mywebsocket/README.md:
--------------------------------------------------------------------------------
1 | This component is the core of the whole system, it will be used in transfer information to server.
2 | Currently the client part is very stable.
3 | If any error detected while using client, please check your server first. Errors with CombinedServer please submit an issue, thanks.
4 | There are full comments in header file, check mywebsocket.h for more information.
5 |
6 | 这个组件是整个系统的核心,它被用来和服务器之间传送数据。
7 | 如果你在使用客户端的过程中遇到错误,请先检查你的服务器。CombinedServer的错误请提交issue,谢谢。
8 | 目前它的客户端部分非常稳定。
9 | 头文件中有完整的注释,更多信息请参阅mywebsocket.h。
--------------------------------------------------------------------------------
/lib/ota/README.md:
--------------------------------------------------------------------------------
1 | This component enable the system update firmware over the air.
2 | More than 10000 times OTA update had been tested, it is very stable.
3 | If any error detected on your ESP32 while using OTA update, please check your remote server first.
4 | There are full comments in header file, check ota.h for more information.
5 |
6 | * If got low connection quality between your device and AP it connected, or between your server and your network, OTA update may stuck during it process, don't reboot your device or upload again, leave it, it will update successfully.
7 |
8 | 这个组件可以让系统空中升级固件。
9 | 已经经过了至少10000次的升级测试,它很稳定。
10 | 如果你在OTA升级过程中遇到了问题,请先检查你的服务器。
11 | 头文件中有完整的注释,更多信息请参阅ota.h。
12 |
13 | * 如果你的设备与它连接的AP连接质量不高或你的服务器和你的网络连接质量不高,在OTA升级的时候有时候会卡住,但是不用重启设备或重新上传固件,不用管它,它自己会更新成功的。
--------------------------------------------------------------------------------
/lib/ota/ota.h:
--------------------------------------------------------------------------------
1 | /**
2 | * @file ota.h
3 | * @author Vida Wang (support@vida.wang)
4 | * @brief This file implemented OTA update function using websocket client.
5 | * 这个文件实现了使用websocket执行OTA更新的功能
6 | *
7 | * @version 1.0.0
8 | * @date 2022-08-16
9 | *
10 | * @copyright Copyright (c) 2022
11 | *
12 | */
13 | #ifndef OTA_H_
14 | #define OTA_H_
15 | #include
16 | #include
17 | #include "esp_ota_ops.h"
18 | #include
19 | #include
20 | #include
21 | #include
22 | #include
23 |
24 | #define OTA_DEBUG_HEADER "OTAUpdate"
25 |
26 | using namespace myWebSocket;
27 |
28 | typedef std::function OTACallback;
29 |
30 | class WebsocketOTA
31 | {
32 | private:
33 | // ota update handle
34 | // ota 升级句柄
35 | esp_ota_handle_t handle = 0;
36 |
37 | // ota data block index
38 | // ota 数据块索引
39 | uint32_t index = 0;
40 |
41 | // ota update partition
42 | // ota升级分区
43 | const esp_partition_t *partition;
44 |
45 | // for request ota block from server
46 | // 用于向服务器请求ota数据块
47 | std::vector *request = nullptr;
48 |
49 | // callback for ota update aborted
50 | // ota升级中断的回调函数
51 | OTACallback abortCallback = nullptr;
52 |
53 | // callback for ota update started
54 | // ota升级开始的回调函数
55 | OTACallback startCallback = nullptr;
56 |
57 | // length of firmware
58 | // 固件长度
59 | uint32_t firmwareLength = 0;
60 |
61 | // length of single ota data block
62 | // 单个ota数据块长度
63 | uint32_t blockLength = 0;
64 |
65 | // for request ota data block from server
66 | // 用于向服务器请求ota数据块
67 | uint32_t bufferOutLen = 0;
68 |
69 | // offset of data written to ota partition
70 | // 向ota分区写入的偏移量
71 | uint64_t writeOffset = 0;
72 |
73 | /**
74 | * @brief request next ota block or resend last request
75 | * 请求下一个ota数据块或重复上次请求
76 | */
77 | void fetchNext();
78 |
79 | /**
80 | * @brief clear ota data block buffer
81 | * 清除ota数据块缓存
82 | *
83 | * @param output ota data block from server 服务器发来的ota数据块
84 | */
85 | void clearBuffer(std::vector *output);
86 |
87 | public:
88 | // websocket client to server for ota update
89 | // 用于ota升级的websocket客户端
90 | WebSocketClient *client = nullptr;
91 |
92 | inline WebsocketOTA() {}
93 |
94 | // indicate if ota update ready
95 | // 指示ota升级是否准备就绪
96 | bool otaInitialized = false;
97 |
98 | // indicate if ota update has been aborted
99 | // 指示ota升级是否被中断
100 | bool aborted = false;
101 |
102 | /**
103 | * @brief default websocket ota constructor
104 | * 默认websocket ota升级构造函数
105 | *
106 | * @param startOTARequest websocket ota request sent from web page 由前端发来的ota升级请求
107 | * @param startCallback callback for ota update started 开始ota升级的回调函数
108 | * @param abortCallback callback for ota update aborted, ota升级中断的回调函数
109 | */
110 | WebsocketOTA(std::vector *startOTARequest, OTACallback startCallback, OTACallback abortCallback);
111 |
112 | /**
113 | * @brief start ota update process
114 | * 开始ota升级
115 | *
116 | * @param universalID id of current device 当前设备id
117 | * @param domain domain for websocket ota update, websocket升级服务器域名
118 | * @param port port for websocket ota update, websocket升级服务器端口
119 | * @param path path for websocket ota update, websocket升级服务器路径
120 | */
121 | void start(Element universalID, String domain, uint16_t port, String path);
122 |
123 | ~WebsocketOTA();
124 | };
125 |
126 | #endif
--------------------------------------------------------------------------------
/lib/provider/provider.cpp:
--------------------------------------------------------------------------------
1 | #include "provider.h"
2 |
3 | Provider::Provider(uint16_t id,
4 | ProviderCallback cb,
5 | String name,
6 | uint8_t settings,
7 | uint8_t lengthOfArguments) : id(id), cb(cb), name(name), settings(settings)
8 | {
9 | if (settings & PROVIDER_ENCRYPT)
10 | {
11 | this->encrypt = true;
12 | }
13 | // length of arguments will took 3 bits, 8 arguments maximum
14 | this->settings |= (lengthOfArguments & (uint8_t)0b00000111);
15 | }
16 |
17 | uint8_t *Provider::getBuffer(uint32_t *outLen)
18 | {
19 | std::vector container;
20 | container.push_back(new Element(this->id));
21 | container.push_back(new Element(this->settings));
22 | container.push_back(new Element(this->name));
23 | container.push_back(new Element(this->customID));
24 |
25 | uint8_t *buffer = ArrayBuffer::createArrayBuffer(&container, outLen);
26 |
27 | for (uint32_t i = 0; i < container.size(); ++i)
28 | {
29 | delete container.at(i);
30 | }
31 |
32 | return buffer;
33 | }
--------------------------------------------------------------------------------
/lib/provider/provider.h:
--------------------------------------------------------------------------------
1 | /**
2 | * @file provider.h
3 | * @author Vida Wang (support@vida.wang)
4 | * @brief This file implemented a type of method to store pre-built functions and provide
5 | * interface to web.
6 | *
7 | * 这个文件实现了一种方法来保存预先构建的功能和提供给前端的接口
8 | *
9 | * @version 1.0.0
10 | * @date 2022-08-16
11 | *
12 | * @copyright Copyright (c) 2022
13 | *
14 | */
15 | #ifndef PROVIDER_H_
16 | #define PROVIDER_H_
17 |
18 | #include
19 | #include
20 | #include
21 |
22 | typedef Elements *ProviderArguments;
23 |
24 | typedef std::function ProviderCallback;
25 |
26 | typedef enum : uint8_t
27 | {
28 | // default show to administrator
29 | // 默认显示给管理员
30 | PROVIDER_COMMON = 0b10000000,
31 |
32 | // indicate current provider action should question user or not
33 | // 指示执行当前provider是否是需要确认
34 | PROVIDER_QUESTION = 0b01000000,
35 |
36 | // only administrator could execute
37 | // 仅开放给管理员执行
38 | PROVIDER_ADMIN = 0b00100000,
39 |
40 | // default show to any user ( included administrator )
41 | // 指示当前provider显示给所有人
42 | PROVIDER_USER = 0b00010000,
43 |
44 | // both request and response should be encrypted
45 | // 执行provider时输入数据和返回数据是否需要加密
46 | PROVIDER_ENCRYPT = 0b00001000
47 | } ProviderType;
48 |
49 | class Provider
50 | {
51 | public:
52 | /**
53 | * @brief id of provider, automatically set by "createProvider"
54 | * user should not modify this id
55 | *
56 | * provider的ID,由createProvider函数设置,用户不应该修改此id
57 | */
58 | uint16_t id = 0;
59 |
60 | /**
61 | * @brief id set by user for other purpose
62 | * 用于其他用途的由用户设置的id
63 | */
64 | uint64_t customID = 0;
65 |
66 | /**
67 | * @brief name of provider, for human read
68 | * privoder的名字,给人看的
69 | */
70 | String name = "";
71 |
72 | /**
73 | * @brief provider callback
74 | * provider回调函数
75 | */
76 | ProviderCallback cb = nullptr;
77 |
78 | /**
79 | * @brief part of generate buffer
80 | * 用来生成buffer的一部分
81 | */
82 | uint8_t settings = 0x00;
83 |
84 | /**
85 | * @brief indicate data of current provider should encrypt or not
86 | * 指示当前provider的数据是否需要加密
87 | */
88 | bool encrypt = false;
89 |
90 | /**
91 | * @brief indicate that current provider
92 | * is built-in or not
93 | *
94 | * 指示当前provider是内建的provider吗
95 | *
96 | */
97 | bool isBuiltIn = false;
98 |
99 | /**
100 | * @brief default empty arguments constructor
101 | * 默认无参构造
102 | */
103 | inline Provider() {}
104 |
105 | /**
106 | * @brief create a new provider
107 | * 创建一个新的provider
108 | *
109 | * @param id id set by createProvider 由createProvider自动填充的序列号
110 | * @param cb callback of provider, provider回调函数
111 | * @param name name of provider, for human read; provider的名字,给人看的
112 | * @param settings options of provider, provider的选项
113 | * @param lengthOfArguments length of arguments for js create inputs 给js用的创建参数输入框的参数长度
114 | */
115 | Provider(uint16_t id,
116 | ProviderCallback cb,
117 | String name,
118 | uint8_t settings,
119 | uint8_t lengthOfArguments = 0);
120 |
121 | inline ~Provider() {}
122 |
123 | /**
124 | * @brief create a buffer of current provider
125 | * 为当前provider创建buffer
126 | *
127 | * @param outLen output length 输出buffer的长度
128 | * @return uint8_t* buffer 缓存
129 | */
130 | uint8_t *getBuffer(uint32_t *outLen);
131 | };
132 |
133 | #endif
134 |
--------------------------------------------------------------------------------
/lib/softtimer/softtimer.h:
--------------------------------------------------------------------------------
1 | #ifndef SOFT_TIMER_H_
2 | #define SOFT_TIMER_H_
3 |
4 | #include