AIoT应用创新大赛-基于TencentOS Tiny的多模输入的门禁系统

2022-03-16 10:51:45 浏览数 (1)

目录结构:

1.项目目标及意义

2.硬件准备和硬件驱动实现

3.软件和服务器实现

4.通信安全设计

5.总结

基于TencentOS Tiny的多模输入的门禁系统.pptx

视频如下:

视频内容

1.项目目标及意义

  • 基于TencentOS Tiny系统,实现门禁与考勤的二合一设备开发,
  • 与设备交互方式多样,蓝牙,wifi,人脸等多方式用来开门和考勤
  • 采用加密算法与服务器通讯,将所有原始数据存储在设备内部,服务器仅能获得秘文和部分明文,解密后用于验证用户身份。
  • 加密算法,保护了用户个人隐私和设备OT安全
  • 关键个人隐私数据保存在本地避免用户对于个人隐私泄露的焦虑。

项目目标:

识别功能:

蓝牙开发,WIFI开发,人脸识别开发,

网络功能:

网络连接,加密通信

本地存储功能:

设备端保护用户个人信息,服务器只能收到密文或部分明文

安全功能:

加密算法,用户隐私保护

2.硬件准备和硬件驱动实现

包括蓝牙模块(TB03F)、wifi模块(esp8266)、门禁控制器(电插锁 继电器),RT1062开发板(带摄像头),

2.1蓝牙模块(TB03F)

安信可TB-03F蓝牙模块安信可TB-03F蓝牙模块

用于RT1062开发板和手机微信小程序的直接通信,传输开门指令。

代码使用了安信可提供的模块透传代码,即蓝牙接收到的数据直接发送给RT1062开发板。数据传输逻辑如下图所示

蓝牙模块数据传输流程蓝牙模块数据传输流程

模块烧录软件TB-TOOL和透传固件从安信可官网获取

https://docs.ai-thinker.com/blue_tooth

2.2 Wi-Fi

Wi-Fi模块(esp8266)

用途:Wi-Fi模块与路由器连接,实现RT1062开发板上云,实现网络连接,方便后续通过微信小程序与服务器控制开发板。

Wi-Fi模块如下图所示:

Wi-Fi模块(esp8266)Wi-Fi模块(esp8266)

Wi-Fi模块开发方式:

通过VSCODE和PlatformIO插件的方式,实现了对Wi-Fi模块二次开发,

PlatformIO的框架地址:

https://github.com/platformio

PlatformIO的下载安装方式:

在VSCODE的插件市场下载即可。

基础的使用教程查看官网:

https://docs.platformio.org/en/latest/

Wi-Fi模块开发功能

在Wi-Fi模块上实现MQTT协议,和透传功能,具体流程如下图所示

Wi-Fi模块数据传输流程Wi-Fi模块数据传输流程

Wi-Fi模块主要代码

代码语言:c复制
/*
 Basic ESP8266 MQTT example
 This sketch demonstrates the capabilities of the pubsub library in combination
 with the ESP8266 board/library.
 It connects to an MQTT server then:
  - publishes "hello world" to the topic "outTopic" every two seconds
  - subscribes to the topic "inTopic", printing out any messages
    it receives. NB - it assumes the received payloads are strings not binary
  - If the first character of the topic "inTopic" is an 1, switch ON the ESP Led,
    else switch it off
 It will reconnect to the server if the connection is lost using a blocking
 reconnect function. See the 'mqtt_reconnect_nonblocking' example for how to
 achieve the same result without blocking the main loop.
 To install the ESP8266 board, (using Arduino 1.6.4 ):
  - Add the following 3rd party board manager under "File -> Preferences -> Additional Boards Manager URLs":
       http://arduino.esp8266.com/stable/package_esp8266com_index.json
  - Open the "Tools -> Board -> Board Manager" and click install for the ESP8266"
  - Select your ESP8266 in "Tools -> Board"
*/

#include <DNSServer.h>
#include <ESP8266WebServer.h>
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
// Update these with values suitable for your network.
//mqtt连接历程

// const char *ssid = "babybed";
// const char *password = "babybed123";
const char *ssid = "access_control";
const char *password = "access123!@#";
const char *mqtt_server = "118.178.180.56";
// const char *pub_topic = "/babybed_status";
// const char *sub_topic = "/babybed_command";
const char *pub_topic = "/Access_control_system_device";
const char *sub_topic = "/Access_control_system_command";

WiFiClient espClient;
PubSubClient client(espClient);
unsigned long lastMsg = 0;
#define MSG_BUFFER_SIZE (80)
char msg[MSG_BUFFER_SIZE];
int value = 0;
#define LED_BUILTIN 0

void setup_wifi()
{
    delay(10);
    // We start by connecting to a WiFi network
    Serial.println();
    Serial.print("Connecting to ");
    Serial.println(ssid);

    WiFi.mode(WIFI_STA);
    WiFi.begin(ssid, password);

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

    //randomSeed(micros());

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

void callback(char *topic, byte *payload, int length)
{
    // Serial.print("Message arrived [");
    // Serial.print(sub_topic);
    // Serial.print("] ");
    for (int i = 0; i < length; i  )
    {
        Serial.print((char)payload[i]);
    }
    Serial.println();
}

void reconnect()
{
    // Loop until we're reconnected
    while (!client.connected())
    {
        Serial.print("Attempting MQTT connection...");
        // Create a random client ID
        String clientId = "ESP8266Client-";
        clientId  = String(random(0xffff), HEX);
        // Attempt to connect
        if (client.connect(clientId.c_str()))
        {
            Serial.println("connected");
            // Once connected, publish an announcement...
            client.publish(pub_topic, "hello world");
            // ... and resubscribe
            client.subscribe(sub_topic);
        }
        else
        {
            Serial.print("failed, rc=");
            Serial.print(client.state());
            Serial.println(" try again in 5 seconds");
            // Wait 5 seconds before retrying
            delay(5000);
        }
    }
}

void setup()
{
    //pinMode(BUILTIN_LED, OUTPUT);     // Initialize the BUILTIN_LED pin as an output
    Serial.begin(115200);
    setup_wifi();
    client.setServer(mqtt_server, 1883);
    //client.subscribe("/test1");此处订阅没用,因为未连接mqtt服务器。
    client.setCallback(callback);
    //test
}
String RXString = "";
int count = 0;
int flag = 0;
char c[80]="";
void loop()
{
    if (!client.connected())
    {
        reconnect();
    }
    client.loop();

    while (Serial.available() > 0) //判断
    {
        RXString  = char(Serial.read()); //https://www.cnblogs.com/anandexuechengzhangzhilu/p/10719546.html
        delay(2);
        wdt_reset();//feed watchdog https://www.cnblogs.com/Mysterious/p/4817054.html 
    }
    if (RXString.length() > 0)
    {
        //Serial.println(RXString); //打印接收到的字符
        strcpy(c,RXString.c_str());//https://blog.csdn.net/dagjj/article/details/108185706
        //snprintf(msg, MSG_BUFFER_SIZE, "head%s", c); //client.publish的payload不能为string,通过snprintf处理即可。添加了报头报尾
        snprintf(msg, MSG_BUFFER_SIZE, "%s", c); 
        client.publish(pub_topic, msg);
        RXString = "";
        wdt_reset();
    }

}

通过上述代码,实现了80位字节大小以内的数据透传任务。

代码

代码语言:javascript复制
#defineMSG_BUFFER_SIZE(80)

用来控制数据透传的长度,设置为变量可以节约空间,可以根据数据和指令长度灵活修改。

2.3 RT1062开发板(带摄像头)

  • 核心板采用的RT1062处理器属于i.MX RT 系列 MCU,是由 NXP 推出的跨界处理器,既具备高频率(最高主频600M)、高处理性能,也具备中断响应迅速、实时性高的特点。
  • 1M RAM 16M SDRAM 64MB qspi flash 128MB spi flash。

开发方式使用MCUXpressoIDE,按照教程移植了TencentOS Tiny内核。

项目工程代码如下

https://share.weiyun.com/P3PhAyxI

使用了SM4.c文件对来自蓝牙和串口的数据加密

SM4代码如下

代码语言:javascript复制
#include "string.h"
#include <stdio.h>
#include <stdlib.h>
#include "sm4.h"


#define u32 unsigned long
const u32 TBL_SYS_PARAMS[4] = {
    0xa3b1bac6,
    0x56aa3350,
    0x677d9197,
    0xb27022dc};

/******************************??????CK???****************************************/
const u32 TBL_FIX_PARAMS[32] = {

    0x00070e15, 0x1c232a31, 0x383f464d, 0x545b6269,
    0x70777e85, 0x8c939aa1, 0xa8afb6bd, 0xc4cbd2d9,
    0xe0e7eef5, 0xfc030a11, 0x181f262d, 0x343b4249,
    0x50575e65, 0x6c737a81, 0x888f969d, 0xa4abb2b9,
    0xc0c7ced5, 0xdce3eaf1, 0xf8ff060d, 0x141b2229,
    0x30373e45, 0x4c535a61, 0x686f767d, 0x848b9299,
    0xa0a7aeb5, 0xbcc3cad1, 0xd8dfe6ed, 0xf4fb0209,
    0x10171e25, 0x2c333a41, 0x484f565d, 0x646b7279};

/******************************SBox????****************************************/
const u8 TBL_SBOX[256] = {

    0xd6, 0x90, 0xe9, 0xfe, 0xcc, 0xe1, 0x3d, 0xb7, 0x16, 0xb6, 0x14, 0xc2, 0x28, 0xfb, 0x2c, 0x05,
    0x2b, 0x67, 0x9a, 0x76, 0x2a, 0xbe, 0x04, 0xc3, 0xaa, 0x44, 0x13, 0x26, 0x49, 0x86, 0x06, 0x99,
    0x9c, 0x42, 0x50, 0xf4, 0x91, 0xef, 0x98, 0x7a, 0x33, 0x54, 0x0b, 0x43, 0xed, 0xcf, 0xac, 0x62,
    0xe4, 0xb3, 0x1c, 0xa9, 0xc9, 0x08, 0xe8, 0x95, 0x80, 0xdf, 0x94, 0xfa, 0x75, 0x8f, 0x3f, 0xa6,
    0x47, 0x07, 0xa7, 0xfc, 0xf3, 0x73, 0x17, 0xba, 0x83, 0x59, 0x3c, 0x19, 0xe6, 0x85, 0x4f, 0xa8,
    0x68, 0x6b, 0x81, 0xb2, 0x71, 0x64, 0xda, 0x8b, 0xf8, 0xeb, 0x0f, 0x4b, 0x70, 0x56, 0x9d, 0x35,
    0x1e, 0x24, 0x0e, 0x5e, 0x63, 0x58, 0xd1, 0xa2, 0x25, 0x22, 0x7c, 0x3b, 0x01, 0x21, 0x78, 0x87,
    0xd4, 0x00, 0x46, 0x57, 0x9f, 0xd3, 0x27, 0x52, 0x4c, 0x36, 0x02, 0xe7, 0xa0, 0xc4, 0xc8, 0x9e,
    0xea, 0xbf, 0x8a, 0xd2, 0x40, 0xc7, 0x38, 0xb5, 0xa3, 0xf7, 0xf2, 0xce, 0xf9, 0x61, 0x15, 0xa1,
    0xe0, 0xae, 0x5d, 0xa4, 0x9b, 0x34, 0x1a, 0x55, 0xad, 0x93, 0x32, 0x30, 0xf5, 0x8c, 0xb1, 0xe3,
    0x1d, 0xf6, 0xe2, 0x2e, 0x82, 0x66, 0xca, 0x60, 0xc0, 0x29, 0x23, 0xab, 0x0d, 0x53, 0x4e, 0x6f,
    0xd5, 0xdb, 0x37, 0x45, 0xde, 0xfd, 0x8e, 0x2f, 0x03, 0xff, 0x6a, 0x72, 0x6d, 0x6c, 0x5b, 0x51,
    0x8d, 0x1b, 0xaf, 0x92, 0xbb, 0xdd, 0xbc, 0x7f, 0x11, 0xd9, 0x5c, 0x41, 0x1f, 0x10, 0x5a, 0xd8,
    0x0a, 0xc1, 0x31, 0x88, 0xa5, 0xcd, 0x7b, 0xbd, 0x2d, 0x74, 0xd0, 0x12, 0xb8, 0xe5, 0xb4, 0xb0,
    0x89, 0x69, 0x97, 0x4a, 0x0c, 0x96, 0x77, 0x7e, 0x65, 0xb9, 0xf1, 0x09, 0xc5, 0x6e, 0xc6, 0x84,
    0x18, 0xf0, 0x7d, 0xec, 0x3a, 0xdc, 0x4d, 0x20, 0x79, 0xee, 0x5f, 0x3e, 0xd7, 0xcb, 0x39, 0x48};
//4???????????long?
void four_uCh2uLong(u8 *in, u32 *out)
{
    int i = 0;
    *out = 0;
    for (i = 0; i < 4; i  )
        *out = ((u32)in[i] << (24 - i * 8)) ^ *out;
}

//???long??4???????
void uLong2four_uCh(u32 in, u8 *out)
{
    int i = 0;
    //?32?unsigned long??????
    for (i = 0; i < 4; i  )
        *(out   i) = (u32)(in >> (24 - i * 8));
}

//??,?????????
u32 move(u32 data, int length)
{
    u32 result = 0;
    result = (data << length) ^ (data >> (32 - length));

    return result;
}

//??????,???Sbox???????,??????L???L'
u32 func_key(u32 input)
{
    int i = 0;
    u32 ulTmp = 0;
    u8 ucIndexList[4] = {0};
    u8 ucSboxValueList[4] = {0};
    uLong2four_uCh(input, ucIndexList);
    for (i = 0; i < 4; i  )
    {
        ucSboxValueList[i] = TBL_SBOX[ucIndexList[i]];
    }
    four_uCh2uLong(ucSboxValueList, &ulTmp);
    ulTmp = ulTmp ^ move(ulTmp, 13) ^ move(ulTmp, 23);

    return ulTmp;
}

//?????????,???Sbox???????,???????L
u32 func_data(u32 input)
{
    int i = 0;
    u32 ulTmp = 0;
    u8 ucIndexList[4] = {0};
    u8 ucSboxValueList[4] = {0};
    uLong2four_uCh(input, ucIndexList);
    for (i = 0; i < 4; i  )
    {
        ucSboxValueList[i] = TBL_SBOX[ucIndexList[i]];
    }
    four_uCh2uLong(ucSboxValueList, &ulTmp);
    ulTmp = ulTmp ^ move(ulTmp, 2) ^ move(ulTmp, 10) ^ move(ulTmp, 18) ^ move(ulTmp, 24);

    return ulTmp;
}

//????(??????????,16???????,?????0??16??????)
//len:????(??????) key:??(16??) input:??????? output:???????
void encode_fun(u8 len, u8 *key, u8 *input, u8 *output)
{
    int i = 0, j = 0;
    u8 *p = (u8 *)malloc(50);  //????50?????
    u32 ulKeyTmpList[4] = {0}; //?????u32??
    u32 ulKeyList[36] = {0};   //?????????????FK????????
    u32 ulDataList[36] = {0};  //????????

    /***************************???????********************************************/
    four_uCh2uLong(key, &(ulKeyTmpList[0]));
    four_uCh2uLong(key   4, &(ulKeyTmpList[1]));
    four_uCh2uLong(key   8, &(ulKeyTmpList[2]));
    four_uCh2uLong(key   12, &(ulKeyTmpList[3]));

    ulKeyList[0] = ulKeyTmpList[0] ^ TBL_SYS_PARAMS[0];
    ulKeyList[1] = ulKeyTmpList[1] ^ TBL_SYS_PARAMS[1];
    ulKeyList[2] = ulKeyTmpList[2] ^ TBL_SYS_PARAMS[2];
    ulKeyList[3] = ulKeyTmpList[3] ^ TBL_SYS_PARAMS[3];

    for (i = 0; i < 32; i  ) //32???????
    {
        //5-36?32????
        ulKeyList[i   4] = ulKeyList[i] ^ func_key(ulKeyList[i   1] ^ ulKeyList[i   2] ^ ulKeyList[i   3] ^ TBL_FIX_PARAMS[i]);
    }
    /***********************************??32?32???????**********************************/

    for (i = 0; i < len; i  ) //????????p???
        *(p   i) = *(input   i);
    for (i = 0; i < 16 - len % 16; i  ) //???16??0??16????
        *(p   len   i) = 0;

    for (j = 0; j < len / 16   ((len % 16) ? 1 : 0); j  ) //??????,?????????(????????16???????,????,??16???????,17???0?32?????????,????)
    {
        /*????????*/
        four_uCh2uLong(p   16 * j, &(ulDataList[0]));
        four_uCh2uLong(p   16 * j   4, &(ulDataList[1]));
        four_uCh2uLong(p   16 * j   8, &(ulDataList[2]));
        four_uCh2uLong(p   16 * j   12, &(ulDataList[3]));
        //??
        for (i = 0; i < 32; i  )
        {
            ulDataList[i   4] = ulDataList[i] ^ func_data(ulDataList[i   1] ^ ulDataList[i   2] ^ ulDataList[i   3] ^ ulKeyList[i   4]);
        }
        /*????????*/
        uLong2four_uCh(ulDataList[35], output   16 * j);
        uLong2four_uCh(ulDataList[34], output   16 * j   4);
        uLong2four_uCh(ulDataList[33], output   16 * j   8);
        uLong2four_uCh(ulDataList[32], output   16 * j   12);
    }
    free(p);
}

//????(?????????,???????????,???????????)
//len:???? key:?? input:???????? output:????????
void decode_fun(u8 len, u8 *key, u8 *input, u8 *output)
{
    int i = 0, j = 0;
    u32 ulKeyTmpList[4] = {0}; //?????u32??
    u32 ulKeyList[36] = {0};   //?????????????FK????????
    u32 ulDataList[36] = {0};  //????????

    /*???????*/
    four_uCh2uLong(key, &(ulKeyTmpList[0]));
    four_uCh2uLong(key   4, &(ulKeyTmpList[1]));
    four_uCh2uLong(key   8, &(ulKeyTmpList[2]));
    four_uCh2uLong(key   12, &(ulKeyTmpList[3]));

    ulKeyList[0] = ulKeyTmpList[0] ^ TBL_SYS_PARAMS[0];
    ulKeyList[1] = ulKeyTmpList[1] ^ TBL_SYS_PARAMS[1];
    ulKeyList[2] = ulKeyTmpList[2] ^ TBL_SYS_PARAMS[2];
    ulKeyList[3] = ulKeyTmpList[3] ^ TBL_SYS_PARAMS[3];

    for (i = 0; i < 32; i  ) //32???????
    {
        //5-36?32????
        ulKeyList[i   4] = ulKeyList[i] ^ func_key(ulKeyList[i   1] ^ ulKeyList[i   2] ^ ulKeyList[i   3] ^ TBL_FIX_PARAMS[i]);
    }
    /*??32?32???????*/

    for (j = 0; j < len / 16; j  ) //??????,?????????
    {
        /*????????*/
        four_uCh2uLong(input   16 * j, &(ulDataList[0]));
        four_uCh2uLong(input   16 * j   4, &(ulDataList[1]));
        four_uCh2uLong(input   16 * j   8, &(ulDataList[2]));
        four_uCh2uLong(input   16 * j   12, &(ulDataList[3]));

        //??
        for (i = 0; i < 32; i  )
        {
            ulDataList[i   4] = ulDataList[i] ^ func_data(ulDataList[i   1] ^ ulDataList[i   2] ^ ulDataList[i   3] ^ ulKeyList[35 - i]); //??????????????????
        }
        /*????????*/
        uLong2four_uCh(ulDataList[35], output   16 * j);
        uLong2four_uCh(ulDataList[34], output   16 * j   4);
        uLong2four_uCh(ulDataList[33], output   16 * j   8);
        uLong2four_uCh(ulDataList[32], output   16 * j   12);
    }
}

//????????16????
void print_hex(u8 *data, int len)
{
    int i = 0;
    char alTmp[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
    for (i = 0; i < len; i  )
    {
        printf("%c", alTmp[data[i] / 16]);
        printf("%c", alTmp[data[i] % 16]);
        putchar(' ');
    }
    putchar('n');
}
char HexToChar(uint8_t hex)
{
    char ch = 0;
    if (hex > 0x0f)
        return -1;
    if ((hex >= 0) && (hex <= 0x09))
        ch = hex   '0';
    else if ((hex >= 0x0a) && (hex <= 0x0f))
        ch = (hex & 0x0f)   ('a' - 0x0a);
    return ch;
}
void ArryToString(uint8_t *data, uint8_t data_len, uint8_t *string)
{
    uint8_t *p_string = string;
    for (uint8_t i = 0; i < data_len; i  )
    {
        *(p_string  ) = HexToChar(data[i] >> 4);
        *(p_string  ) = HexToChar(data[i] & 0x0f);
    }
    *p_string = '';
}
int StringToHex(char *str, unsigned char *out, unsigned int *outlen)
{
    char *p = str;
    char high = 0, low = 0;
    int tmplen = strlen(p), cnt = 0;
    tmplen = strlen(p);
    while (cnt < (tmplen / 2))
    {
        high = ((*p > '9') && ((*p <= 'F') || (*p <= 'f'))) ? *p - 48 - 7 : *p - 48;
        low = (*(  p) > '9' && ((*p <= 'F') || (*p <= 'f'))) ? *(p)-48 - 7 : *(p)-48;
        out[cnt] = ((high & 0x0f) << 4 | (low & 0x0f));
        p  ;
        cnt  ;
    }
    if (tmplen % 2 != 0)
        out[cnt] = ((*p > '9') && ((*p <= 'F') || (*p <= 'f'))) ? *p - 48 - 7 : *p - 48;

    if (outlen != NULL)
        *outlen = tmplen / 2   tmplen % 2;
    return tmplen / 2   tmplen % 2;
}
// int main()
// {
//     /*  Write C code in this online editor and run it. */
//     char Plaintext[24] = "I LOVE YOU123456789a212";
//     printf("原文:%s rn", Plaintext);
//     //int len=((sizeof(Plaintext)) 1)*16;  //获得大于等于明文长度的最小的16的倍数
//     char encoderesult[32]={0};
//     char strresult[48]={0};     //转换后长度增加,溢出了,
//     char decoderesult[32]={0};
//     u8 key[16] = {0x6A, 0x79, 0x75, 0x69, 0x6f, 0x74, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x30, 0x30, 0x30, 0x30};
//     encode_fun(32, key, Plaintext, encoderesult);
//     decode_fun(32, key, encoderesult, decoderesult);//第一位变量(长度)必须为16倍数
//     ArryToString(encoderesult,sizeof(encoderesult),strresult);
//     printf("原文:%s rn密文:", Plaintext);
//     for (int i = 0; i < 32; i  )
//     {
//         printf("%x", encoderesult[i]);
//     }
//     printf("rn转换成字符串后:%srn", strresult);
//     printf("解密后:%srn", decoderesult);

//     return 0;
// }

串口在接收到来自蓝牙的“开锁指令”后,sm4算法加密“开锁指令”,转发到wifi模块,进而上传到服务器。

2.4继电器

用途:通过继电器来控制门锁开关

继电器模块继电器模块

2.5 门锁

介绍:门锁采用KOB的电吸锁,通电时上锁,断电时开锁,配合继电器即可实现开发板控制门禁。

门锁(已经装在门上了,所以没法拆下来拍照)门锁(已经装在门上了,所以没法拆下来拍照)

3.软件和服务器实现

服务器使用Linux服务器,CentOS系统,通信协议选择MQTT,部署EMQ X开源 MQTT 消息服务器。

3.1部署EMQ X开源 MQTT 消息服务器

基于MQTT协议的相关框架有许多,主流的有EMQX和VerneMQ。二者都具备负载均衡、集群、SSL/TLS、插件等功能。在对比二者之后,由于VerneMQ并非开源软件,考虑到系统后续的灵活性。本项目选择EMQX开发。

EMQX服务器安装部署流程如下:

EMQX安装方式多样,可以采用linux脚本一键部署,在linux系统执行下列命令即可。

curl https://repos.emqx.io/install_emqx.sh | bash

也可以选择包管理器安装,以CentOS为例:

1.$ sudo yum install -y yum-utils device-mapper-persistent-data lvm2

2.$ sudo yum-config-manager --add-repo https://repos.emqx.io/emqx-ce/redhat/centos/7/emqx-ce.repo

3.$ sudo yum install emqx

三步即可完成EMQX在服务器上的安装

安装完成后,在linux系统的终端执行下列命令

$ emqx start

emqx 4.0.0 is started successfully!

$ emqx_ctl status

Node 'emqx@127.0.0.1' is started

emqx v4.0.0 is running

出现上述反馈说明,EMQX已经启动,默认通讯端口18083,也可以在EMQX后台修改。

通过MQTT连接测试工具MQTTX进行测试,在设置中,输入服务器和端口号,在subscribe中输入任意主题,在publish订阅同样的主题,任意输入一段文字,subscribe中出现相同信息,说明EMQX服务器正常运行。

如下图所示:

3.2 前端微信小程序设计

前端微信小程序包括三个页面:

  1. 登陆页面

登录页登录页

2.蓝牙搜索连接页面

蓝牙搜索页蓝牙搜索页

3.门禁控制页面

在蓝牙连接后进入登陆页面

门锁控制页门锁控制页

包括开门和关门按钮,点击按钮后会通过蓝牙,向设备发送开锁指令和关锁指令

4.安全设计

系统整体采用加密通讯的方式,使用SM4算法加密,加密通信方式如下:

为了防止开锁命令固定导致的重放攻击,开锁明文即为用户名(在注册用户时确保用户名唯一),将明文传输到开发板后,进行加密,然后将开锁密文发送到服务器进行对比,如果数据对比成功,服务器向设备发送开锁指令

5.总结

本项目由于时间紧张,最初设想过于发散,导致一些预期功能,如人脸验证,本地周期开关锁等功能,未能实现,未能充分发挥开发板的AI能力。

但是作为一个门禁系统,借助TencentOS Tiny系统,蓝牙、WIFI、MQTT等多种协议,基本功能已经实现,同时使用国密SM4算法保证了系统的安全性和用户隐私。

如果后续有时间的话,会对项目做进一步完善。

0 人点赞