本帖最后由 cszzlsw 于 2020-7-13 22:56 编辑
项目背景:都说科技改变生活,今天来聊的这个作品可以真实的改变生活相信有车的朋友最头疼的莫过于停车问题,其他小城市还好,像深圳这样的大城市,停车问题一直困扰着有车一族:- 不知道哪里有车位可以停- 好不容易找到停车场因为方向错误或者技术不好车位被别人占了- 随意停路边容易吃罚单对于其他地方,停车场多于车辆的,停车场主面临收入问题:- 怎么让更多的车停到我这里增加收入- 我的停车场到底收入如何,如何简化做账流程- 我新建了一个停车场怎么让别人知道呢...基于以上几个痛点本人设计了一款基于腾讯云以及RT-Thread实时系统打造的智能停车平台,依靠智能车位锁,智能抬杆,以及平台的管理能力,解决以上几个生活中的问题,并具有一定及广阔的商业价值 作品构成:作品由设备,服务器及小程序组成: - 设备:设备采用雅特力ATF403A高性能MCU搭载TRT-Thread系统,实现云服务及外围设备搭建,支持本地控制和远程控制双通道
- 服务器:服务器有云开发和本地服务器,本地服务器采用Go语言+MongoDB,开发快速高效
- 小程序:微信小程序有用户端和商家端两种界面展示,真正构成平台的作用,商家发布停车场,用户使用停车场
具体系统框架图可以看下图:
智能停车平台架构设计图
项目商业价值:- 解决传统停车场停车难问题:传统停车场用户停车凭运气,有了预约平台线上查看附近哪里有停车场和车位后提前预约好车位,由于有车位锁的加持别人没法抢占,用户也不用兜兜转转找停车位浪费时间,随意停在路边还有爱车被破坏或者罚款等风险
- 帮助商家更好的管理:传统停车场依靠人力手动管理,现在依靠平台的能力商家可以随时随地进行管理,并且根据后台数据商家可以灵活调整自己的宣传,收费策略,
- 设备厂家新出路:传统的设备厂家靠卖产品盈利,新型停车平台厂家可以依靠服务,比如免费给商家安装设备,然后从停车收益中进行抽成来进行二次获利
商业价值展望:- 增加盈利:商家可以跟周围其他品类商家合作,比如小吃,车行,休闲场所合作推广,比如用户停好车后可以在小程序上发布某些吃喝玩乐的信息,用户通过推荐的链接进行消费商家会有分成
- 构建生态:从停车平台出发,可以构建关于车相关的一系列生态,比如车辆美容,汽车保养,买车建议等等内容,打造汽车业内生态圈
具体实现:设备端: 设备端采用RT-Thread驱动,利用SDK里的demo程序可以快速上云,代码片段如下: 关于上云部分可以参考本人以前的帖子:https://bbs.21ic.com/icview-2966620-1-1,https://bbs.21ic.com/icview-2966932-1-1.html 系统启动,上云:
static void data_template_light_thread(void)
{
DeviceProperty *pReportDataList[TOTAL_PROPERTY_COUNT];
int ReportCont;
Timer reportTimer;
int rc;
sReplyPara replyPara;
//init connection
TemplateInitParams init_params = DEFAULT_TEMPLATE_INIT_PARAMS;
rc = _setup_connect_init_params(&init_params);
if (rc != QCLOUD_RET_SUCCESS) {
Log_e("init params err,rc=%d", rc);
return ;
}
void *client = IOT_Template_Construct(&init_params, NULL);
if (client != NULL) {
Log_i("Cloud Device Construct Success");
} else {
Log_e("Cloud Device Construct Failed");
return;
}
//init data template
_init_data_template();
#ifdef EVENT_POST_ENABLED
rc = IOT_Event_Init(client);
if (rc < 0)
{
Log_e("event init failed: %d", rc);
return ;
}
#endif
//register data template propertys here
rc = _register_data_template_property(client);
if (rc == QCLOUD_RET_SUCCESS) {
Log_i("Register data template propertys Success");
} else {
Log_e("Register data template propertys Failed: %d", rc);
return ;
}
//register data template actions here
#ifdef ACTION_ENABLED
rc = _register_data_template_action(client);
if (rc == QCLOUD_RET_SUCCESS) {
Log_i("Register data template actions Success");
} else {
Log_e("Register data template actions Failed: %d", rc);
return ;
}
#endif
//鍚屾绂荤嚎鏁版嵁
rc = IOT_Template_GetStatus_sync(client, QCLOUD_IOT_MQTT_COMMAND_TIMEOUT);
if (rc != QCLOUD_RET_SUCCESS) {
Log_e("get device shadow failed, err: %d", rc);
return;
}
//灞炴€у畾鏃朵笂鎶imer锛屽彲浠ユ牴鎹笟鍔¢渶瑕佽鍓€? InitTimer(&reportTimer);
running_state = 1;
while (IOT_Template_IsConnected(client) || rc == QCLOUD_ERR_MQTT_ATTEMPTING_RECONNECT
|| rc == QCLOUD_RET_MQTT_RECONNECTED || QCLOUD_RET_SUCCESS == rc) {
if(0 == running_state)
{
break;
}
rc = IOT_Template_Yield(client, 2000);
if (rc == QCLOUD_ERR_MQTT_ATTEMPTING_RECONNECT) {
HAL_SleepMs(1000);
continue;
}
else if (rc != QCLOUD_RET_SUCCESS) {
Log_e("Exit loop caused of errCode: %d", rc);
}
/*鏈嶅姟绔笅琛屾秷鎭紝涓氬姟澶勭悊閫昏緫1鍏ュ彛*/
if (sg_delta_arrived) {
deal_down_stream_user_logic(&sg_ProductData);
/*涓氬姟閫昏緫澶勭悊瀹屽悗闇€瑕佸悓姝ラ€氱煡鏈嶅姟绔?璁惧鏁版嵁宸叉洿鏂帮紝鍒犻櫎dseire鏁版嵁*/
memset((char *)&replyPara, 0, sizeof(sReplyPara));
replyPara.code = eDEAL_SUCCESS;
replyPara.timeout_ms = QCLOUD_IOT_MQTT_COMMAND_TIMEOUT;
replyPara.status_msg[0] = '\0'; // add extra info to replyPara.status_msg when error occured
rc = IOT_Template_ControlReply(client, sg_data_report_buffer, sg_data_report_buffersize, &replyPara);
if (rc == QCLOUD_RET_SUCCESS) {
// rc = IOT_Shadow_Update_Sync(client, sg_data_report_buffer, sg_data_report_buffersize, QCLOUD_IOT_MQTT_COMMAND_TIMEOUT);
sg_delta_arrived = false;
// if (rc == QCLOUD_RET_SUCCESS) {
// Log_i("shadow update(desired) success");
// } else {
// Log_e("shadow update(desired) failed, err: %d", rc);
// }
} else {
Log_e("construct desire failed, err: %d", rc);
}
} else{
//Log_d("No delta msg received...");
}
/*璁惧涓婅娑堟伅,涓氬姟閫昏緫2鍏ュ彛*/
/*delta娑堟伅鏄睘鎬х殑desire鍜屽睘鎬х殑report鐨勫樊寮傞泦锛屾敹鍒癲eseire娑堟伅澶勭悊鍚庯紝瑕乺eport灞炴€х殑鐘舵€?/
if(QCLOUD_RET_SUCCESS == deal_up_stream_user_logic(pReportDataList, &ReportCont)){
Log_d("report:%s",sg_data_report_buffer);
rc = IOT_Template_JSON_ConstructReportArray(client, sg_data_report_buffer, sg_data_report_buffersize,
ReportCont, pReportDataList);
if (rc == QCLOUD_RET_SUCCESS) {
rc = IOT_Template_Report(client, sg_data_report_buffer, sg_data_report_buffersize,
OnReportReplyCallback, NULL, QCLOUD_IOT_MQTT_COMMAND_TIMEOUT);
if (rc == QCLOUD_RET_SUCCESS) {
Log_i("IOT_Template_Report success");
} else {
Log_e("IOT_Template_Report failed, err: %d", rc);
}
} else {
Log_e("construct reported failed, err: %d", rc);
}
}else{
Log_d("no data need to be reported");
ReportCont = TOTAL_PROPERTY_COUNT;
}
/*cycle report, just for example*/
if(QCLOUD_RET_SUCCESS == cycle_report(pReportDataList, &reportTimer)){
rc = IOT_Template_JSON_ConstructReportArray(client, sg_data_report_buffer, sg_data_report_buffersize,
ReportCont, pReportDataList);
if (rc == QCLOUD_RET_SUCCESS) {
rc = IOT_Template_Report(client, sg_data_report_buffer, sg_data_report_buffersize,
OnReportReplyCallback, NULL, QCLOUD_IOT_MQTT_COMMAND_TIMEOUT);
if (rc == QCLOUD_RET_SUCCESS) {
Log_i("IOT_Template_Report success");
} else {
Log_e("IOT_Template_Report failed, err: %d", rc);
}
} else {
Log_e("construct reported failed, err: %d", rc);
}
}
#ifdef EVENT_POST_ENABLED
extern int32_t g_temp;
sg_ProductData.m_temp = g_temp;
sg_temp = g_temp;
IOT_Event_setFlag(client,FLAG_EVENT0);
eventPostCheck(client);
#endif
HAL_SleepMs(5000);
}
rc = IOT_Template_Destroy(client);
running_state = 0;
Log_e("Something goes wrong or stoped");
//rt_thread_delete(rt_thread_self());
return ;
}
static int tc_data_template_light_example(int argc, char **argv)
{
rt_thread_t tid;
int stack_size = DATA_TEMPLATE_LIGHT_THREAD_STACK_SIZE;
//init log level
IOT_Log_Set_Level(eLOG_DEBUG);
if (2 == argc)
{
if (!strcmp("start", argv[1]))
{
if (1 == running_state)
{
Log_d("tc_data_template_light_example is already running\n");
return 0;
}
}
else if (!strcmp("stop", argv[1]))
{
if (0 == running_state)
{
Log_d("tc_data_template_light_example is already stopped\n");
return 0;
}
running_state = 0;
return 0;
}
else
{
Log_d("Usage: tc_data_template_light_example start/stop");
return 0;
}
}
else
{
Log_e("Para err, usage: tc_data_template_light_example start/stop");
return 0;
}
tid = rt_thread_create("data_template_light", (void (*)(void *))data_template_light_thread,
NULL, stack_size, RT_THREAD_PRIORITY_MAX / 2 - 1, 10);
if (tid != RT_NULL)
{
rt_thread_startup(tid);
}
return 0;
}
下发指令操作设备行为:
static void OnControlLockActionCallback(void *pClient, const char *pClientToken, DeviceAction *pAction){
int i;
sReplyPara replyPara;
printf("__%s__\n",__func__);
//do something base on input, just print as an sample
DeviceProperty *pActionInput = pAction->pInput;
for (i = 0; i < pAction->input_num; i++) {
if (JSTRING == pActionInput[i].type) {
Log_i("Input:[%s], data:[%s]", pActionInput[i].key, pActionInput[i].data);
HAL_Free(pActionInput[i].data);
} else {
if(JINT32 == pActionInput[i].type) {
Log_i("Input:[%s], data:[%d]", pActionInput[i].key, *((int*)pActionInput[i].data));
} else if( JFLOAT == pActionInput[i].type) {
Log_i("Input:[%s], data:[%f]", pActionInput[i].key, *((float*)pActionInput[i].data));
} else if( JUINT32 == pActionInput[i].type) {
Log_i("Input:[%s], data:[%u]", pActionInput[i].key, *((uint32_t*)pActionInput[i].data));
}
}
// sg_action_msg_arrived = true;
}
// construct output
memset((char *)&replyPara, 0, sizeof(sReplyPara));
replyPara.code = eDEAL_SUCCESS;
replyPara.timeout_ms = QCLOUD_IOT_MQTT_COMMAND_TIMEOUT;
strcpy(replyPara.status_msg, "action execute success!"); //add the message about the action resault
DeviceProperty *pActionOutnput = pAction->pOutput;
//(void)pActionOutnput; //elimate warning
//TO DO: add your aciont logic here and set output properties which will be reported by action_reply
// pole *p=getPole();
// if(p == NULL){
// sg_control_pole_out_result = 1;
// }
int road=*(int *)(pActionInput[0].data);
int direction=*(int *)(pActionInput[1].data);
printf("control %dth lock direction=%s\n",road,direction?"up":"down");
lock *l=getLock(road);
printf("get lock %p\n",l);
if(l == NULL){
sg_control_lock_out_result = 1;
}
IOT_ACTION_REPLY(pClient, pClientToken, sg_data_report_buffer, sg_data_report_buffersize, pAction, &replyPara);
// DeviceProperty *actionInput_control_pole=&pAction->pInput[0];
// int direction=*(int *)actionInput_control_pole->data;
// printf("control pole direction=%s\n",direction?"up":"down");
// if(p){
// poleAction(direction,p);
// }
if(l){
lockAction(direction,l);
}
//smotor_start(direction);
}
static void OnControlPoleActionCallback(void *pClient, const char *pClientToken, DeviceAction *pAction)
{
int i;
sReplyPara replyPara;
printf("__%s__\n",__func__);
//do something base on input, just print as an sample
DeviceProperty *pActionInput = pAction->pInput;
for (i = 0; i < pAction->input_num; i++) {
if (JSTRING == pActionInput[i].type) {
Log_i("Input:[%s], data:[%s]", pActionInput[i].key, pActionInput[i].data);
HAL_Free(pActionInput[i].data);
} else {
if(JINT32 == pActionInput[i].type) {
Log_i("Input:[%s], data:[%d]", pActionInput[i].key, *((int*)pActionInput[i].data));
} else if( JFLOAT == pActionInput[i].type) {
Log_i("Input:[%s], data:[%f]", pActionInput[i].key, *((float*)pActionInput[i].data));
} else if( JUINT32 == pActionInput[i].type) {
Log_i("Input:[%s], data:[%u]", pActionInput[i].key, *((uint32_t*)pActionInput[i].data));
}
}
// sg_action_msg_arrived = true;
}
// construct output
memset((char *)&replyPara, 0, sizeof(sReplyPara));
replyPara.code = eDEAL_SUCCESS;
replyPara.timeout_ms = QCLOUD_IOT_MQTT_COMMAND_TIMEOUT;
strcpy(replyPara.status_msg, "action execute success!"); //add the message about the action resault
DeviceProperty *pActionOutnput = pAction->pOutput;
//(void)pActionOutnput; //elimate warning
//TO DO: add your aciont logic here and set output properties which will be reported by action_reply
pole *p=getPole();
printf("get pole %p\n",p);
if(p == NULL){
sg_control_pole_out_result = 1;
}
IOT_ACTION_REPLY(pClient, pClientToken, sg_data_report_buffer, sg_data_report_buffersize, pAction, &replyPara);
DeviceProperty *actionInput_control_pole=&pAction->pInput[0];
int direction=*(int *)actionInput_control_pole->data;
printf("control pole direction=%s\n",direction?"up":"down");
if(p){
poleAction(direction,p);
}
//smotor_start(direction);
}
注册的时候会把每一个adction都注册一个回调函数.
服务器端:服务器端代码太多了,直接贴一个图片显示一下启动流程:
服务器代码启动流程
小程序端:小程序涉及的东西比较多,这里贴几个图片代表一下,具体所以的界面可以在下方PPT和视频里看到:
个人用户首页
商家首页
视频:视频分为两个,一个是ppt讲解,还有一个项目演示视频,不喜欢听PPT废话的童鞋可以直接看演示视频 PPT讲解视频:https://www.bilibili.com/video/av841360131,ppt见附件 完整演示视频:https://www.bilibili.com/video/av583817164 致谢:最后感谢21IC家提供的这个机会,让我有机会能使用上RT-Thread去实现心中的想法,感谢雅特力提供的开发板和技术支持. 感谢观看.另,开发板所用的程序见附件.采用7z算法压缩,附件不能上传改为rar格式,如果不能正常解压请修改为.7z结尾
|