安防监控项目---web网页通过A9控制Zigbee终端节点的风扇

2023-11-01 09:04

本文主要是介绍安防监控项目---web网页通过A9控制Zigbee终端节点的风扇,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • 前言
  • 一、zigbee的CGI接口
  • 二、请求线程和硬件控制
  • 三、现象展示
  • 总结


前言

书接上期,我们可以看一下前面的功能设计的部分,网页端的控制还有一个,那就是通过网页来控制zigbee上的风扇节点,这部分的工作量是相当大的,既要实现HTML发送控制命令到A9平台进行接收,又要实现A9平台串口通信控制zigbee协调器,通过zigbee协调器控制zigbee终端节点(这一步是建立在zigbee协调器和终端节点调试好的基础上的);最终呢实现网页控制zigbee节点,这也实现了无线控制!


一、zigbee的CGI接口

第一步呢还是先来看命令字是怎样下发的:

#include <stdio.h> 
#include "cgic.h" 
#include <string.h> 
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <sys/ipc.h>
#include <sys/msg.h>#define N 8
struct msg
{long type;long msgtype;unsigned char text[N];
};
int cgiMain() 
{ key_t key;char buf[N];char sto_no[2];int msgid;struct msg msg_buf;memset(&msg_buf,0,sizeof(msg_buf));cgiFormString("fan",buf,N);cgiFormString("store",sto_no,2);if((key = ftok("/tmp", 'g')) < 0){perror("ftok");exit(1);}if((msgid = msgget(key, 0666)) < 0){perror("msgget");exit(1);}bzero (msg_buf.text, sizeof (msg_buf.text));switch (buf[0]){case '0':{msg_buf.text[0] = (0 << 6) | (2 << 4) | (0 << 0);break;}case '1':{msg_buf.text[0] = (0 << 6) | (2 << 4) | (1 << 0);break;}}msg_buf.type = 1L;msg_buf.msgtype = 4L;msgsnd(msgid, &msg_buf,sizeof(msg_buf)-sizeof(long),0);sto_no[0] -= 48;cgiHeaderContentType("text/html\n\n"); fprintf(cgiOut, "<HTML><HEAD>\n"); fprintf(cgiOut, "<TITLE>My CGI</TITLE></HEAD>\n"); fprintf(cgiOut, "<BODY>"); fprintf(cgiOut, "<H2>send sucess</H2>");//fprintf(cgiOut, "<a href='.html'>返回</a>"); fprintf(cgiOut, "<meta http-equiv=\"refresh\" content=\"1;url=../a9_zigbee%d.html\">", sto_no[0]);fprintf(cgiOut, "</BODY>\n"); fprintf(cgiOut, "</HTML>\n"); return 0; 
} 

这里呢我也没有给出过多的注释,其实流程和前面的led和beep的代码基本一致,且框架结构也都一致;这就是一个好的框架所带来的优势,使得开发起来比较容易;

二、请求线程和硬件控制

请求线程只需要在switch…case语句中添加控制类型即可;这里控制的流程直接写在了switch中,也可以将其写在单独的处理线程中;这里用到了Linux下的串口编程,所以需要包含头文件linuxuart.h这个头文件;

#include "data_global.h"
#include "linuxuart.h"//消息队列id
extern int msgid;
//ipc对象键值
extern key_t key;
//锁资源
extern pthread_mutex_t mutex_client_request,mutex_refresh,mutex_sqlite,mutex_transfer,mutex_analysis,mutex_sms,mutex_buzzer,mutex_led,mutex_camera;
//条件变量
extern pthread_cond_t  cond_client_request,cond_refresh,cond_sqlite,cond_transfer,cond_analysis,cond_sms,cond_buzzer,cond_led,cond_camera;
//模块的控制命令字
extern unsigned char cmd_led;
extern unsigned char  cmd_buzzer;
extern unsigned char  cmd_fan;//GPRS模块的电话号
extern char recive_phone[12] ;
extern char center_phone[12] ;//消息队列通信结构体
struct msg msgbuf;
void *pthread_client_request(void *arg)
{if((key = ftok("/tmp",'g')) < 0){perror("ftok failed .\n");exit(-1);}msgid = msgget(key,IPC_CREAT|IPC_EXCL|0666); 		//检测消息队列中是否有这个键值,如果有则返回对应的-1,没有则创建并返回创建消息队列的idif(msgid == -1)	{if(errno == EEXIST){ 							//如果已经存在msgid = msgget(key,0777); 					//设置权限为0777}else{perror("fail to msgget");exit(1);}}printf("pthread_client_request\n");while(1){bzero(&msgbuf,sizeof(msgbuf)); 					//清理操作,但一般使用memset,功能更加强大一点printf("wait form client request...\n"); msgrcv (msgid, &msgbuf, sizeof (msgbuf) - sizeof (long), 1L, 0); //从消息队列中读取消息printf ("Get %ldL msg\n", msgbuf.msgtype); 		//打印消息类型printf ("text[0] = %#x\n", msgbuf.text[0]); 	//打印消息内容//判断消息类型,从而确定是哪一个设备switch(msgbuf.msgtype){case 1L://1L的类型是led的消息类型,此时上锁,等待消息内容也就是控制命令字复制完成后解锁,通过pthread_cond_signal唤醒pthread_led.c这个led线程,进行led的具体硬件操作pthread_mutex_lock(&mutex_led);printf("hello led\n");cmd_led = msgbuf.text[0];pthread_mutex_unlock(&mutex_led);pthread_cond_signal(&cond_led);break;case 2L://2L表示beep的消息类型//这里呢相信大家天赋异禀,看懂了上面led的,beep也不是问题pthread_mutex_unlock(&mutex_buzzer);printf("hello beep1\n");pthread_mutex_lock(&mutex_buzzer);cmd_buzzer = msgbuf.text[0];pthread_mutex_unlock(&mutex_buzzer);pthread_cond_signal(&cond_buzzer);break;case 3L:pthread_mutex_lock(&mutex_led);printf("hello seg\n");cmd_seg = msgbuf.text[0];pthread_mutex_unlock(&mutex_led);pthread_cond_signal(&cond_led);break;case 4L:pthread_mutex_lock(&mutex_sqlite);printf("hello fan\n");cmd_fan = msgbuf.text[0];int fan_fd = open_port("/dev/ttyUSB0"); //打开设备if(fan_fd < 0){printf("open failed\n");}set_com_config(fan_fd, 115200, 8, 'N', 1); //设置串口参数char cmdbuf[4] = {0};if(cmd_fan == 0x21){strcpy(cmdbuf,"1\n"); //注意点,一定要加上\n,因为串口助手是默认添加\n的,所以这里我们需要手动添加write(fan_fd,cmdbuf,sizeof(cmdbuf)/sizeof(cmdbuf[0]));sleep(2);}if(cmd_fan == 0x20){strcpy(cmdbuf,"0\n");write(fan_fd,cmdbuf,sizeof(cmdbuf)/sizeof(cmdbuf[0]));sleep(2);}char buf[32] = {0};//get data from zigbeeread(fan_fd,&buf,sizeof(buf));printf("sizeof(buf) = %d.\n",sizeof(buf));printf(">>>>>>%s\n",buf);sleep(1);pthread_mutex_unlock(&mutex_sqlite);break;default:break;}}
}
#endif 

接下来看一下linux下的串口编程,为什么要学习这个呢,其实就是要通过USB去和zigbee模块通信,那么无非就是设置通信速率,校验位,停止位等这些参数:
先看一下linuxuart.h文件:

#ifndef __LINUX_UART_H_
#define __LINUX_UART_H_#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h>#include <termios.h>
#include <string.h>
#include "data_global.h"extern int set_com_config(int fd, int baud_rate, int data_bits, char parity, int stop_bits);
extern int open_port(char *com_port);
extern void USB_UART_Config(char* path, int baud_rate);
#endif

再来看一下linuxuatr.c文件:

#include "linuxuart.h"int set_com_config(int fd, int baud_rate, int data_bits, char parity, int stop_bits)
{struct termios new_cfg, old_cfg;int speed;/*保存原有串口配置*/if (tcgetattr(fd, &old_cfg) != 0){perror("tcgetattr");return -1;}new_cfg =old_cfg;/*配置为原始模式*/cfmakeraw(&new_cfg);new_cfg.c_cflag &= ~CSIZE;/*设置波特率*/switch (baud_rate){case 2400:{speed = B2400;break; }case 4800:{speed = B4800;break;}case 9600:{speed = B9600;break;}case 19200:{speed = B19200;break;}case 38400:{speed = B38400;break;}default:case 115000:{speed = B115200;break;}}cfsetispeed(&new_cfg, speed);cfsetospeed(&new_cfg, speed);/*设置数据位*/switch (data_bits){case 7:{new_cfg.c_cflag |= CS7;break;}   default:	case 8:{new_cfg.c_cflag |= CS8;break;}}/*设置奇偶校验位*/switch (parity){default:case 'n':case 'N':{new_cfg.c_cflag &= ~PARENB;new_cfg.c_iflag &= ~INPCK;break;}case 'o':case 'O':{new_cfg.c_cflag |= (PARODD |PARENB);new_cfg.c_iflag |= INPCK;break;}case 'e':case 'E':{new_cfg.c_cflag |= PARENB;new_cfg.c_cflag &= ~PARODD;new_cfg.c_iflag |= INPCK;break;}case 's':case 'S':{new_cfg.c_cflag &= ~PARENB;new_cfg.c_cflag &= ~CSTOPB;break;}}/*设置停止位*/switch (stop_bits){default:case 1:{new_cfg.c_cflag &= ~CSTOPB;break;}   	case 2:{new_cfg.c_cflag |= CSTOPB;break;}}/*设置等待时间和最小接收字符*/new_cfg.c_cc[VTIME] = 0;new_cfg.c_cc[VMIN] = 1;tcflush(fd, TCIFLUSH);if ((tcsetattr(fd, TCSANOW, &new_cfg)) != 0){perror("tcsetattr");return -1;}return 0;
}int open_port(char *com_port)
{int fd;/*打开串口*/fd = open(com_port, O_RDWR|O_NOCTTY|O_NDELAY);if (fd < 0){perror("open serial port");return -1;}/*恢复串口阻塞状态*/if (fcntl(fd, F_SETFL, 0) < 0){perror("fcntl F_SETFL\n");}/*判断是否为终端设备*/if (isatty(fd) == 0){perror("This is not a terminal device");}return fd;
}/*--------------------CH340Ƥ׃---------------------------*/
void USB_UART_Config(char* path, int baud_rate)
{int fd;fd = open_port(path);if(fd < 0){printf("open %s failed\n",path);return ;}if (set_com_config(fd, baud_rate, 8, 'N', 1) < 0){perror("set_com_config");return ;}close(fd);return ;
}

这些函数是不是挺熟悉的,其实就是我们经常使用的串口助手呗!软件化了,没有图形化界面了!

三、现象展示

风扇静止的时候如下:
请添加图片描述
下图是风扇转动起来的图片:
请添加图片描述
下图是终端显示的控制命令字:
打开显示:
请添加图片描述
关闭显示:
请添加图片描述
这里也可以看出跟代码信息是一致的;消息类型是4L,控制命令字为0x21和0x20;且打印信息也正确;
在这里插入图片描述


总结

本期的分享就到这里结束了,需要注意的是zigbee大家必须先调整好,保证其正常工作,进而学习Linux串口编程,再将这些融合到项目中,就能够实现网页控制zigbee终端节点硬件了;最后,各位小伙伴们如果有收获,可以点赞收藏哦,你们的认可是我创作的动力,一起加油!

这篇关于安防监控项目---web网页通过A9控制Zigbee终端节点的风扇的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/321936

相关文章

网页解析 lxml 库--实战

lxml库使用流程 lxml 是 Python 的第三方解析库,完全使用 Python 语言编写,它对 XPath表达式提供了良好的支 持,因此能够了高效地解析 HTML/XML 文档。本节讲解如何通过 lxml 库解析 HTML 文档。 pip install lxml lxm| 库提供了一个 etree 模块,该模块专门用来解析 HTML/XML 文档,下面来介绍一下 lxml 库

Spring Security 基于表达式的权限控制

前言 spring security 3.0已经可以使用spring el表达式来控制授权,允许在表达式中使用复杂的布尔逻辑来控制访问的权限。 常见的表达式 Spring Security可用表达式对象的基类是SecurityExpressionRoot。 表达式描述hasRole([role])用户拥有制定的角色时返回true (Spring security默认会带有ROLE_前缀),去

流媒体平台/视频监控/安防视频汇聚EasyCVR播放暂停后视频画面黑屏是什么原因?

视频智能分析/视频监控/安防监控综合管理系统EasyCVR视频汇聚融合平台,是TSINGSEE青犀视频垂直深耕音视频流媒体技术、AI智能技术领域的杰出成果。该平台以其强大的视频处理、汇聚与融合能力,在构建全栈视频监控系统中展现出了独特的优势。视频监控管理系统EasyCVR平台内置了强大的视频解码、转码、压缩等技术,能够处理多种视频流格式,并以多种格式(RTMP、RTSP、HTTP-FLV、WebS

这15个Vue指令,让你的项目开发爽到爆

1. V-Hotkey 仓库地址: github.com/Dafrok/v-ho… Demo: 戳这里 https://dafrok.github.io/v-hotkey 安装: npm install --save v-hotkey 这个指令可以给组件绑定一个或多个快捷键。你想要通过按下 Escape 键后隐藏某个组件,按住 Control 和回车键再显示它吗?小菜一碟: <template

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

如何用Docker运行Django项目

本章教程,介绍如何用Docker创建一个Django,并运行能够访问。 一、拉取镜像 这里我们使用python3.11版本的docker镜像 docker pull python:3.11 二、运行容器 这里我们将容器内部的8080端口,映射到宿主机的80端口上。 docker run -itd --name python311 -p

综合安防管理平台LntonAIServer视频监控汇聚抖动检测算法优势

LntonAIServer视频质量诊断功能中的抖动检测是一个专门针对视频稳定性进行分析的功能。抖动通常是指视频帧之间的不必要运动,这种运动可能是由于摄像机的移动、传输中的错误或编解码问题导致的。抖动检测对于确保视频内容的平滑性和观看体验至关重要。 优势 1. 提高图像质量 - 清晰度提升:减少抖动,提高图像的清晰度和细节表现力,使得监控画面更加真实可信。 - 细节增强:在低光条件下,抖

在cscode中通过maven创建java项目

在cscode中创建java项目 可以通过博客完成maven的导入 建立maven项目 使用快捷键 Ctrl + Shift + P 建立一个 Maven 项目 1 Ctrl + Shift + P 打开输入框2 输入 "> java create"3 选择 maven4 选择 No Archetype5 输入 域名6 输入项目名称7 建立一个文件目录存放项目,文件名一般为项目名8 确定

Java Web指的是什么

Java Web指的是使用Java技术进行Web开发的一种方式。Java在Web开发领域有着广泛的应用,主要通过Java EE(Enterprise Edition)平台来实现。  主要特点和技术包括: 1. Servlets和JSP:     Servlets 是Java编写的服务器端程序,用于处理客户端请求和生成动态网页内容。     JSP(JavaServer Pages)

day-51 合并零之间的节点

思路 直接遍历链表即可,遇到val=0跳过,val非零则加在一起,最后返回即可 解题过程 返回链表可以有头结点,方便插入,返回head.next Code /*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode() {}*