【IoT应用创新大赛】基于腾讯云的智能停车平台

项目背景:

都说科技改变生活,今天来聊的这个作品可以真实的改变生活相信有车的朋友最头疼的莫过于停车问题,其他小城市还好,像深圳这样的大城市,停车问题一直困扰着有车一族:- 不知道哪里有车位可以停- 好不容易找到停车场因为方向错误或者技术不好车位被别人占了- 随意停路边容易吃罚单对于其他地方,停车场多于车辆的,停车场主面临收入问题:- 怎么让更多的车停到我这里增加收入- 我的停车场到底收入如何,如何简化做账流程- 我新建了一个停车场怎么让别人知道呢...基于以上几个痛点本人设计了一款基于腾讯云以及TencentOS Tiny实时系统打造的智能停车平台,依靠智能车位锁,智能抬杆,以及平台的管理能力,解决以上几个生活中的问题,并具有一定及广阔的商业价值

作品构成:

作品由设备,服务器及小程序组成:

  • 设备:设备采用STM32高性能MCU搭载TencentOS tiny系统,实现云服务及外围设备搭建,支持本地控制和远程控制双通道
  • 服务器:服务器有云开发和本地服务器,本地服务器采用Go语言+MongoDB,开发快速高效
  • 小程序:微信小程序有用户端和商家端两种界面展示,真正构成平台的作用,商家发布停车场,用户使用停车场

具体系统框架图可以看下图:

智能停车平台架构设计图

项目商业价值:

  1. 解决传统停车场停车难问题:传统停车场用户停车凭运气,有了预约平台线上查看附近哪里有停车场和车位后提前预约好车位,由于有车位锁的加持别人没法抢占,用户也不用兜兜转转找停车位浪费时间,随意停在路边还有爱车被破坏或者罚款等风险
  2. 帮助商家更好的管理:传统停车场依靠人力手动管理,现在依靠平台的能力商家可以随时随地进行管理,并且根据后台数据商家可以灵活调整自己的宣传,收费策略,
  3. 设备厂家新出路:传统的设备厂家靠卖产品盈利,新型停车平台厂家可以依靠服务,比如免费给商家安装设备,然后从停车收益中进行抽成来进行二次获利

商业价值展望:

  1. 增加盈利:商家可以跟周围其他品类商家合作,比如小吃,车行,休闲场所合作推广,比如用户停好车后可以在小程序上发布某些吃喝玩乐的信息,用户通过推荐的链接进行消费商家会有分成
  2. 构建生态:从停车平台出发,可以构建关于车相关的一系列生态,比如车辆美容,汽车保养,买车建议等等内容,打造汽车业内生态圈

具体实现:

设备端:

设备端采用TencentOS Tiny驱动,利用SDK里的demo程序可以快速上云,代码片段如下:

系统启动,上云:

代码语言:c
复制
int data_template_light_thread(void) {
    int rc;
	sReplyPara replyPara;
	DeviceProperty *pReportDataList[TOTAL_PROPERTY_COUNT];
	int ReportCont;
registerPole();
registerLock();

//init log level
IOT_Log_Set_Level(eLOG_INFO);

//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 rc;
}

void *client = IOT_Template_Construct(&init_params);
if (client != NULL) {
    Log_i("Cloud Device Construct Success");
} else {
    Log_e("Cloud Device Construct Failed");
    return QCLOUD_ERR_FAILURE;
}

///////////////////////////////////

int first_time_report = 1;
light_power_off();

///////////////////////////////////

//init data template
_init_data_template();

//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 rc;
}

//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 rc;
}
#endif

//report device info, then you can manager your product by these info, like position
rc = _get_sys_info(client, sg_data_report_buffer, sg_data_report_buffersize);
if(QCLOUD_RET_SUCCESS == rc){
	rc = IOT_Template_Report_SysInfo_Sync(client, sg_data_report_buffer, sg_data_report_buffersize, QCLOUD_IOT_MQTT_COMMAND_TIMEOUT);
	if (rc != QCLOUD_RET_SUCCESS) {
		Log_e("Report system info fail, err: %d", rc);
		goto exit;
	}
}else{
	Log_e("Get system info fail, err: %d", rc);
}

//get the property changed during offline
rc = IOT_Template_GetStatus_sync(client, QCLOUD_IOT_MQTT_COMMAND_TIMEOUT);
if (rc != QCLOUD_RET_SUCCESS) {
	Log_e("Get data status fail, err: %d", rc);
	//goto exit;
}else{
	Log_d("Get data status success");
}

while (IOT_Template_IsConnected(client) || rc == QCLOUD_ERR_MQTT_ATTEMPTING_RECONNECT
	|| rc == QCLOUD_RET_MQTT_RECONNECTED || QCLOUD_RET_SUCCESS == rc) {

// ...

#ifdef EVENT_POST_ENABLED
eventPostCheck(client);
#endif

     HAL_SleepMs(3000);
}

exit:
rc = IOT_Template_Destroy(client);

return rc;

}

其中车锁和抬杆的注册:

代码语言:c
复制
static pole m_pole={
.motor={.motor_pins={

{GPIOB,	GPIO_PIN_5},
{GPIOB,	GPIO_PIN_6},
{GPIOB,	GPIO_PIN_7},
{GPIOB,	GPIO_PIN_8},	

}
}
};

int registerPole(){
smotor_init(&m_pole.motor);
return 0;

}

代码语言:c
复制

lock m_lock[]={

{
.motor={
	.motor_pins={
	
{GPIOB,	GPIO_PIN_12},
{GPIOB,	GPIO_PIN_13},

		},
	.limit_pins={
{GPIOB,	GPIO_PIN_14},
{GPIOB,	GPIO_PIN_15},
},
	.light_pin={GPIOC,	GPIO_PIN_6},

},
	},

	{
.motor={.motor_pins={
	
{GPIOB,	GPIO_PIN_9},
{GPIOC,	GPIO_PIN_0},

		},
.limit_pins={
{GPIOC,	GPIO_PIN_1},
{GPIOC,	GPIO_PIN_2},
},
	.light_pin={GPIOC,	GPIO_PIN_3},

},
	
},

};

uint8_t lock_num=sizeof(m_lock)/sizeof(m_lock[0]);

int registerLock(){
printf("lock_num = %d\n",lock_num);
for(int i=0;i<lock_num;i++){
printf("init %d start\n",i);
motor_init(&(m_lock[i].motor));
printf("init %d end\n",i);
}

return 0;

}

下发指令操作设备行为:

代码语言:javascript
复制

#ifdef ACTION_ENABLED
#include "action_config.c"

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-&gt;pInput;
for (i = 0; i &lt; pAction-&gt;input_num; i++) {
	if (JSTRING == pActionInput[i].type) {
		Log_i(&#34;Input:[%s], data:[%s]&#34;,  pActionInput[i].key, pActionInput[i].data);
		HAL_Free(pActionInput[i].data);
	} else {
		if(JINT32 == pActionInput[i].type) {
			Log_i(&#34;Input:[%s], data:[%d]&#34;,  pActionInput[i].key, *((int*)pActionInput[i].data));
		} else if( JFLOAT == pActionInput[i].type) {
			Log_i(&#34;Input:[%s], data:[%f]&#34;,  pActionInput[i].key, *((float*)pActionInput[i].data));
		} else if( JUINT32 == pActionInput[i].type) {
			Log_i(&#34;Input:[%s], data:[%u]&#34;,  pActionInput[i].key, *((uint32_t*)pActionInput[i].data));
		}
	}
	
//	sg_action_msg_arrived = true;
}

// construct output
memset((char *)&amp;replyPara, 0, sizeof(sReplyPara));
replyPara.code = eDEAL_SUCCESS;
replyPara.timeout_ms = QCLOUD_IOT_MQTT_COMMAND_TIMEOUT;
strcpy(replyPara.status_msg, &#34;action execute success!&#34;); //add the message about the action resault


DeviceProperty *pActionOutnput = pAction-&gt;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(&#34;control %dth lock direction=%s\n&#34;,road,direction?&#34;up&#34;:&#34;down&#34;);

lock *l=getLock(road);
printf(&#34;get lock  %p\n&#34;,l);
if(l == NULL){
	
	sg_control_lock_out_result = 1;
}

IOT_ACTION_REPLY(pClient, pClientToken, sg_data_report_buffer, sg_data_report_buffersize, pAction, &amp;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-&gt;pInput;
for (i = 0; i &lt; pAction-&gt;input_num; i++) {
	if (JSTRING == pActionInput[i].type) {
		Log_i(&#34;Input:[%s], data:[%s]&#34;,  pActionInput[i].key, pActionInput[i].data);
		HAL_Free(pActionInput[i].data);
	} else {
		if(JINT32 == pActionInput[i].type) {
			Log_i(&#34;Input:[%s], data:[%d]&#34;,  pActionInput[i].key, *((int*)pActionInput[i].data));
		} else if( JFLOAT == pActionInput[i].type) {
			Log_i(&#34;Input:[%s], data:[%f]&#34;,  pActionInput[i].key, *((float*)pActionInput[i].data));
		} else if( JUINT32 == pActionInput[i].type) {
			Log_i(&#34;Input:[%s], data:[%u]&#34;,  pActionInput[i].key, *((uint32_t*)pActionInput[i].data));
		}
	}
	
//	sg_action_msg_arrived = true;
}

// construct output
memset((char *)&amp;replyPara, 0, sizeof(sReplyPara));
replyPara.code = eDEAL_SUCCESS;
replyPara.timeout_ms = QCLOUD_IOT_MQTT_COMMAND_TIMEOUT;
strcpy(replyPara.status_msg, &#34;action execute success!&#34;); //add the message about the action resault


DeviceProperty *pActionOutnput = pAction-&gt;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(&#34;get pole  %p\n&#34;,p);
if(p == NULL){
	sg_control_pole_out_result = 1;
}



IOT_ACTION_REPLY(pClient, pClientToken, sg_data_report_buffer, sg_data_report_buffersize, pAction, &amp;replyPara);
DeviceProperty *actionInput_control_pole=&amp;pAction-&gt;pInput[0];
int direction=*(int *)actionInput_control_pole-&gt;data;
printf(&#34;control pole direction=%s\n&#34;,direction?&#34;up&#34;:&#34;down&#34;);


if(p){
	poleAction(direction,p);
}

//smotor_start(direction);

}

static void OnLightBlinkActionCallback(void *pClient, const char *pClientToken, DeviceAction *pAction)
{

int i;
sReplyPara replyPara;
printf(&#34;__%s__\n&#34;,__func__);

//do something base on input, just print as an sample
DeviceProperty *pActionInput = pAction-&gt;pInput;
for (i = 0; i &lt; pAction-&gt;input_num; i++) {
	if (JSTRING == pActionInput[i].type) {
		Log_i(&#34;Input:[%s], data:[%s]&#34;,  pActionInput[i].key, pActionInput[i].data);
		HAL_Free(pActionInput[i].data);
	} else {
		if(JINT32 == pActionInput[i].type) {
			Log_i(&#34;Input:[%s], data:[%d]&#34;,  pActionInput[i].key, *((int*)pActionInput[i].data));
		} else if( JFLOAT == pActionInput[i].type) {
			Log_i(&#34;Input:[%s], data:[%f]&#34;,  pActionInput[i].key, *((float*)pActionInput[i].data));
		} else if( JUINT32 == pActionInput[i].type) {
			Log_i(&#34;Input:[%s], data:[%u]&#34;,  pActionInput[i].key, *((uint32_t*)pActionInput[i].data));
		}
	}
	
	sg_action_msg_arrived = true;
}

// construct output
memset((char *)&amp;replyPara, 0, sizeof(sReplyPara));
replyPara.code = eDEAL_SUCCESS;
replyPara.timeout_ms = QCLOUD_IOT_MQTT_COMMAND_TIMEOUT;
strcpy(replyPara.status_msg, &#34;action execute success!&#34;); //add the message about the action resault


DeviceProperty *pActionOutnput = pAction-&gt;pOutput;
//(void)pActionOutnput; //elimate warning
//TO DO: add your aciont logic here and set output properties which will be reported by action_reply


IOT_ACTION_REPLY(pClient, pClientToken, sg_data_report_buffer, sg_data_report_buffersize, pAction, &amp;replyPara);

}

static int _register_data_template_action(void *pTemplate_client)
{
int i,rc;

for (i = 0; i &lt; TOTAL_ACTION_COUNTS; i++) {
    rc = IOT_Template_Register_Action(pTemplate_client, &amp;g_actions[i], g_actions[i].OnActionHandleCallback);
    if (rc != QCLOUD_RET_SUCCESS) {
        rc = IOT_Template_Destroy(pTemplate_client);
        Log_e(&#34;register device data template action failed, err: %d&#34;, rc);
        return rc;
    } else {
        Log_i(&#34;data template action=%s registered.&#34;, g_actions[i].pActionId);
    }
}

return QCLOUD_RET_SUCCESS;

}
#endif

注册的时候会把每一个adction都注册一个回调函数.

服务器端:

服务器端代码太多了,直接贴一个图片显示一下启动流程:

服务器代码启动流程

小程序端:

小程序涉及的东西比较多,这里贴几个图片代表一下,具体所以的界面可以在下方PPT和视频里看到:

个人用户首页
商家首页

PPT和视频:

PPT:

本次大赛所制作的ppt在下方,点击左右箭头可以换页

IoT应用创新大赛作品-智能停车平台.pptx

视频:视频分为两个,一个是ppt讲解,还有一个项目演示视频,不喜欢听PPT废话的童鞋可以直接看演示视频

PPT讲解视频:

PPT录像的麦克风不太好,所以导致有的地方有破音,还有的地方不清晰,建议调大音量或者戴上耳机效果最好

视频内容

项目演示视频:

视频内容

致谢:

最后感谢腾讯提供的这个机会,让我有机会能真正使用上TencentOS和腾讯云这两款优秀的产品.

感谢观看.