# NetCamera_device **Repository Path**: wudding/net-camera_device ## Basic Information - **Project Name**: NetCamera_device - **Description**: No description available - **Primary Language**: C - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 3 - **Forks**: 4 - **Created**: 2020-12-19 - **Last Updated**: 2022-03-09 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 1. 【RT-Thread作品秀】基于RT-Thread的网络照相机 **作者:wudding** ## 1.1. 概述 随着科技的进步和互联网的发展,基于物联网的可拍照设备也越来越多的融入到人们的生活中来,例如在超市中,管理者利用拍照设备定时抓取货架照片,分析货物状态,并补充、优化货物摆放;在酒吧里,管理者会利用拍照设备定时抓拍酒架照片,传送到网络平台供大众浏览,以招揽更多顾客。本网络照相机基于STM32H7+RTThread平台,采集摄像头数据,并通过无线网络传送到服务器,提供SD卡配网、手动拍摄、定时拍摄、照片推送等功能,并提供windows上位机提供控制和照片显示功能。 >主要功能有: **格式化sd卡**:格式化sd卡,但是会保留网络配置文件,其他文件全部删除 **设备重启**:重启设备 **实时拍照**:发送指令给照相机,照相机拍照,并把照片回传 **定时拍照**:照相机依据下发的拍照时间,在时间到达时拍摄一张照片,并传给服务器 **按键拍照**:点击板上用户按钮,拍摄一张照片,并传给服务器 **定时任务**:可以新建/删除/查询定时拍照任务,任务存储在sd卡中,重启有效 ## 1.2. 开发环境 硬件:ART-PI(STM32H750主控)+ OV2640模组 RT-Thread版本:4.0.3 SDK 版本:1.0.1 开发工具及版本:RT-Thread Studio 1.1.5, Qt5.14.0 ## 1.3. RT-Thread使用情况概述 > 内核部分:调度器,信号量,互斥锁,内存管理 > > 调度器:多任务调度 > > 信号量:用于唤醒对应任务 > > 互斥锁:用于互斥资源独占访问 > > 内存管理:动态内存申请与释放 > 组件部分:虚拟文件系统,IPC,I2C,RTC,NTP > > 虚拟文件系统:文件操作,sd卡、照片文件 > > IPC:mqtt发送数据需要 > > I2C:配置摄像头模块需要 > > RTC和NTP:同步时间 > 软件包部分:paho mqtt,cJSON,netutils > > pahomqtt:用于和服务器通信 > > cJSON:解析、封装mqtt消息 > > netutils:NTP网络对时 > 其他:base64 > > 用于将图片文件转换成字符串,便于mqtt传输 ## 1.4. 硬件框架 总体的硬件框架如下图所示: ```puml @startuml title: Hardware Framework package "art-pi" { [STM32H750XB] -left- [AP6212] [STM32H750XB] -right- [sd-card] [STM32H750XB] -up- [extern ram] [STM32H750XB] -up- [led] } package "Camera" { [OV2640] } [STM32H750XB] -down- [OV2640] @enduml ``` 本网络摄像机硬件结果较为简单,即art-pi连接一个摄像头模组,art-pi板上用到了AP6212无线模块,外部内存,led指示灯,和sd卡。其中,摄像头模块用于采集图像信号;AP6212用于和服务器进行通信;因一张图像数据量较大,片内内存不够,故而使用外部内存;led灯用于指示设备工作状态;sd卡用于保存网络、服务器、和定时任务配置。 ## 1.5. 软件框架说明 ### 1.5.1. 系统框架 整体的软件框架如下图所示,网络照相机内部有一个proxy线程,负责和云端进行通信,在接收到云端消息后会解析,并分发到其他的线程执行,然后将执行结果返回到云端;照相机发生了其他的事件,例如用户按键拍照,也会将数据传给proxy线程,proxy线程再将数据发送到云端。用户通过上位机终端软件连接上云服务器,实现与照相机的通信及控制。 ```puml @startuml title: Software Framework actor user node terminal cloud cloud package "camera" { component proxy component sd_card component event component main component others } cloud ~~ terminal terminal -- user cloud ~~ proxy proxy -- sd_card proxy -- event proxy -- main proxy -- others @enduml ``` 整个系统支持接入多个照相机,如下图所示,不同的照相机通过sd卡配置文件中sn进行区分,上位机软件可以显示所有在线的照相机,但同一时间只支持操作一个。 ```puml @startuml title: Multiple Cameras actor user node terminal cloud cloud component camera1 component camera2 component camera3 component camera... cloud ~~ terminal terminal -- user cloud ~~ camera1 cloud ~~ camera2 cloud ~~ camera3 cloud ~~ camera... @enduml ``` ### 1.5.2. 用户线程创建流程 如下图所示为用户线程创建流程 ```puml @startuml title: Task Initiate participant "main" as A participant "sd_card" as B participant "network" as C participant "proxy" as D participant "event" as E activate A A -> B : create sd-card task activate B A -> A : Main Loop B -> B : check sd card B -> C : if sd card exist, \nload config file, \ncreate wifi task activate C C -> C : connect to ap \nof config file B -> B : load timed task \nfile C -> D : if connected, \ncreate proxy task activate D C -> E : create time task activate E D -> D : connect to mqtt server \nof config file E -> B : query next snap time @enduml ``` 用户线程作用描述如下: **main**:用于创建sd_card 线程,检测按键事件,闪灯; **sd_card**:用于管理与sd卡相关的工作,包括拍照,网络配置,定时任务; **network**:负责联网,根据sd卡的配置文件连接到指定的wifi网络; **proxy**:负责启动mqtt,并管理与云端的通信,其他线程都需要通过proxy线程与云端交互数据; **event**:定时任务和按键任务,在定时时间到达时,或者用户按键时拍摄照片并通过proxy上传云端。 ### 1.5.3. 通信接口及流程 #### 1.5.3.1. 3.1 MQTT订阅主题 - 设备向服务器订阅主题: `/ter/query/discovery`,用于接收设备发现消息 `/ter/sn/request`,用于接收针对该设备的指令,其中`sn`为设备的SN号,下同 - 客户端向服务器订阅主题: `/dev/response/discovery`,用于接收设备发现回复 `/dev/response/will`,用于接收设备遗嘱消息 `/dev/sn/response`,用于接收设备操作指令回复 `/dev/sn/event`,用于接收设备的通知 #### 1.5.3.2. 3.2 设备发现 所有的设备均订阅`/ter/query/discovery`主题,客户端向该主题发布发现消息,所有收到消息的设备向`/dev/response/discovery`回复一条消息,而客户端又订阅了`/dev/response/discovery`主题,故而便可以知道哪些设备在线了。 设备连上服务器的时候,会定义一个遗嘱消息,主题为`/dev/sn/will`,客户端订阅了该主题,当设备因为某些原因掉线,则超过一定时间之后,客户端便可收到该消息,进而知道该设备掉线。 ```puml @startuml title: Discovery Cameras actor User participant "Terminal" as A participant "Server" as B participant "Camera" as C User -> A : Click "Discovery" Button activate A A -> B : /ter/query/discovery\n discovery message B -> C : transparent transmit activate C C -> B : /dev/response/discovery\n response deactivate C B -> A : transparent transmit A -> User: Display online cameras \n and hide offline ones deactivate A C -> C : camera offline destroy C B -> A : /dev/sn/will activate A A -> User : Hide offline Cameras deactivate A @enduml ``` - 客户端发起设备发现流程,topic: `/ter/query/discovery` ```code { "params": { "code": "0x01", "param": {} }, "ecode": 0 } ``` - 设备端回复发现命令,topic: `/dev/response/discovery` ```code { "params": { "code": "0x01", "sn":"SN-1234", "param": { "ip":"192.168.1.100", "mac":"01:0F:0A:0B" } }, "ecode":0 } ``` - 设备端掉线通知,topic: `/dev/response/will` ```code { "params": { "code": "0x11", "sn": "SN-1234", "param": {} }, "ecode":0 } ``` #### 1.5.3.3. 3.3 摄像机操作 客户端订阅`/dev/sn/response`,并通过 `/ter/sn/request`发送请求指令,设备端订阅 `/ter/sn/request`,并通过`/dev/sn/response`返回操作结果,进而实现客户端对设备端的操作。 客户端和设备端通过消息中的`code`字段区分不同的操作。 ```puml @startuml title: Manipulate Camera actor User participant "Terminal" as A participant "Server" as B participant "Camera" as C User -> A: Click buttons of \n a specific camera activate A A -> B : /ter/sn/request \n request something B -> C : transparent transmit activate C C -> B: /dev/sn/response \n response deactivate C C -> C: execute command B -> A : transparent transmit A -> User : Display result deactivate A @enduml ``` - 设备重启指令,topic: `/ter/sn/request` ```code { "params": { "code": "0x21", "param": {} }, "ecode":0 } ``` - 设备重启指令回复,topic: `/dev/sn/response` ```code { "params": { "code": "0x21", "sn": "SN-1234", "param": { "action":1 //1,重启;0,不重启 } }, "ecode":0 } ``` - 格式化sd卡指令,topic: `/ter/sn/request` ```code { "params": { "code": "0x22", "param": {} }, "ecode":0 } ``` - 格式化sd卡指令回复,topic: `/dev/sn/response` ```code { "params": { "code": "0x22", "sn": "SN-1234", "param": { "result":1 //1,成功;0,失败 } }, "ecode":0 } ``` - 实时截图指令,topic: `/ter/sn/request` ```code { "params": { "code": "0x23", "param": {} }, "ecode":0 } ``` - 实时截图回复,topic: `/dev/sn/response` ```code { "params":{ "code": "0x23", "sn": "SN-1234", "param": { "result":1, //截图结果,1-成功,0-失败 "time":1235, "pic":"xxxx" //base64编码后的图片字符串,成功时才有 } }, "ecode":0 } ``` - 下发截图定时任务,topic: `/ter/sn/request` ```code { "params":{ "code": "0x24", "param": { "total": 3, "time_list":[ 1234, 1244, 1254 ] } }, "ecode":0 } ``` - 下发截图定时任务回复,topic: `/dev/sn/response` ```code { "params": { "code":"0x24", "sn": "SN-1234", "param":{ "result":0 } } "ecode":0 } ``` - 查询截图定时任务,topic: `/ter/sn/request`,`sn`为设备的SN号 ```code { "params": { "code": "0x25", "param":{} } "ecode":0 } ``` - 返回查询定时任务结果,topic: `/dev/sn/response` ```code { "params": { "code":"0x25", "sn":"SN-1234", "param": { "result":1, 1--查询正常,0--查询出错 "total":3, "time_list":[ 1234, 1244, 1254 ] } }, "ecode":0 } ``` - 删除截图定时任务,topic: `/ter/sn/request` ```code { "params": { "code": "0x26" "param":{ "total":3, "time_list":[ 1234, 1244, 1254 ] } } "ecode":0 } ``` - 返回删除定时任务结果,topic: `/dev/sn/response` ```code { "params": { "code":"0x26", "sn":"SN-1234", "param": { "result":0 } }, "ecode":0 } ``` #### 1.5.3.4. 3.4 摄像机通知 客户端订阅`/dev/sn/event`主题,当设备端发生某些事件(目前只有定时拍照事件和按键拍照事件)的时候,向该主题发布一条消息,客户端进而刷新显示。 ```puml @startuml title: Camera notify actor User participant "Terminal" as A participant "Server" as B participant "Camera" as C activate C C -> C : something happened \n like timed capture C -> B : /dev/sn/event \n notify deactivate C B -> A : transparent transmit activate A A -> User : Display notify deactivate A @enduml ``` - 定时/按键照相通知,topic: `/dev/sn/event`,`sn`为设备的SN号 ```code { "params": { "code":"0xF0", "sn":"SN-1234", "param": { "type":0, //1,定时截图; 2,按键截图 "pic":"xxx" } } "ecode":0 } ``` ## 1.6. 演示效果 **拍照功能** ![拍照界面](_v_images/20201217224611246_28301.png) **定时拍照任务** ![任务界面](_v_images/20201217224657811_10272.png) **实物图** ![实物图](_v_images/20201217224726031_23281.jpg)