抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

前言

该项目将会使用 arduino 框架进行固件开发, 原因是轮子比较多, 方便入门和快速实现

创建项目

相信看到这里的你, 已经做好在计划当中的准备工作了

控制板方式

在终端输入

1
$ pio home

便可自动打开浏览器进入pio的控制面板

接着按照指引新建和选择主板型号开发框架即可完成项目目录的初始化创建

piohome

命令行方式

1
2
$ mkdir esp8266-litncov
$ pio init --ide vscode --board nodemcuv2 -d esp8266-litncov

pio initboard参数也按照自己的主板型号进行填写

目录结构

在初始化项目目录, 你将会看到如下的结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|--lib
| |
| |--Bar
| | |--docs
| | |--examples
| | |--src
| | |- Bar.c
| | |- Bar.h
| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
| |
| |--Foo
| | |- Foo.c
| | |- Foo.h
| |
| |- README --> THIS FILE
|
|- platformio.ini (项目配置文件)
|--src
|- main.c (程序入口位置)

联网测试

代码修改

如目录结构所示, 我们主要的代码将会编写在 main.c 文件当中

我们手动编辑此文件如下代码 (记得手动修改一下wifi名称以及密码)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <ESP8266WiFi.h>

const char *ssid = "SSID";
const char *password = "PWD";

WiFiClient client;

void setupWifi() {
delay(10);
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);

WiFi.begin(ssid, password);

while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}

Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
}

void setup ( void ) {
Serial.begin(9600);
setupWifi();
}

void loop ( void ) {
//
}

PS: 在arduino 开发框架中 setuploop 函数为必要函数, 代表初始化设置和循环任务

编译测试

固件编译

在项目目录下打开终端输入

1
$ pio run

即可进行编译

固件烧录

成功后, 将数据线连上开发板, 接着输入

1
$ pio run --target upload

即可刷写固件

串口监视

在烧写完固件之后, 输入

1
$ pio run --target monitor

接着按一下reset键, 奇迹出现了

1
2
3
4
5
Connecting to REV
.......
WiFi connected
IP address:
192.168.2.136

终端里可以看到串口中已连接wifi成功的消息

PS: 如遇到乱码, 请打开 platformio.ini 文件

1
2
3
4
5
6
[env:nodemcuv2]
platform = espressif8266
board = nodemcuv2
framework = arduino
; 添加下行设置波特率, 并保持与代码中 "Serial.begin();"函数当中一致的数值
monitor_speed = 9600

HTTP请求

登陆原理

抓包的过程, 就不在此详写啦

主要原理是通过 POST 方法, 将帐号和密码请求到登陆 API , 接着会返回带 tokenjson 格式数据

接下来将在 esp8266 上面完成对应的操作

PS: 学校健康平台的 POST 数据当中需要对密码进行 sha256 加密才能够正常登陆哦

实现加密

由于目标平台的特性, 需要将密码作为字符串即 char 类型转换为 sha256 加密的 hex 最后再转回 char

添加依赖

为了实现这个加密算法, 再次打开 platformio.ini 文件

1
2
3
4
5
6
7
8
9
[env:nodemcuv2]
platform = espressif8266
board = nodemcuv2
framework = arduino
monitor_speed = 115200
; 依次添加的是 json 库与基本的哈希加密库, 感谢造轮子的大佬们
lib_deps =
bblanchon/ArduinoJson
rweather/Crypto

构建函数

由于需要得到最终加密出来的 char 类型变量, 所以我手动构建了一个函数 (原理不详细阐述)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <Crypto.h>
#include <SHA256.h>

// 定义哈希大小
#define HASH_SIZE 32

// 将 hex 转回 char
char *btoh(char *dest, uint8_t *src, int len)
{
char *d = dest;
while (len--)
sprintf(d, "%02x", (unsigned char)*src++), d += 2;
return dest;
}

// 使用sha256加密密码
char *crypto_password(char *str)
{
char hex[256];
char *msg = str;

uint8_t result[HASH_SIZE];
SHA256 sha256Hash;

sha256Hash.reset();
sha256Hash.update(msg, strlen(msg));
sha256Hash.finalize(result, HASH_SIZE);

return btoh(hex, result, HASH_SIZE);
}

进行请求

因为目标平台所用的 Content-Typeapplication/json, 所以我们将要构建出 json 格式标准的数据

这时候 ArduinoJson 库就派上用场了

可以先创建一个配置头文件 include/config.h 用于常量的定义

1
2
// LIT(Luoyang Institute of Science and Technology) Health Platform
#define CONFIG_LIT_ENDPOINT_LOGIN "http://hmgr.sec.lit.edu.cn/wms/healthyLogin"

接着实现登陆的函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include <ArduinoJson.h>
#include <ESP8266HTTPClient.h>

#include "config.h"

......

StaticJsonDocument<200> login_data;

void litLogin(char *user, char *psw)
{
char buffer[256];

Serial.println(buffer);

login_data["cardNo"] = user;
login_data["password"] = crypto_password(psw);

serializeJson(login_data, buffer);

http.begin(CONFIG_LIT_ENDPOINT_LOGIN); //Specify request destination
http.addHeader("Content-Type", "application/json");
int httpCode = http.POST(buffer); //Send the request

if (httpCode > 0)
{ //Check the returning code

String payload = http.getString(); //Get the request response payload
Serial.println(payload); //Print the response payload
}

http.end(); //Close connection
}

void setup()
{
......

// try to login
litLogin("USERNAME", "PASSWORD");

}


最后测试

编译刷写上后, 可以在串口输出中看到如下数据即登陆成功

1
{"success":true,"code":200,"msg":"请求成功","data":{"userId":000000,"cardNo":null,"name":"******","teamId":3,"token":"******","expireTime":"2021-02-10 05:49:08","lastUpdateTime":"2021-02-09 17:49:08","sex":0,"age":19,"nativePlaceProvince":"******","nativePlaceCity":"******","nativePlaceDistrict":"******","nativePlaceAddress":"******","teamName":"******","teamProvince":"******","teamCity":"******","mobile":"******","organizationName":"******","identity":000000,"isAdmin":0,"logoUrl":"\r\nhttp://brainstormfile.oss-cn-beijing.aliyuncs.com/wms/lylglogo.png","isTwoTemperature":1,"isApprover":null,"isGeneralAdmin":0,"isReportAdmin":0,"teamNo":"******","localAddress":"******","userOrganizationId":000000,"isReturnSchoolApprover":0}}

评论