国产ARM/RISCV与OpenHarmony物联网项目(二)网关数据显示

本文需要Web服务器开发基础,可参考下述博文:

物联网网关Web服务器--lighttpd服务器部署与应用测试

物联网网关Web服务器--CGI开发接口

一、数据显示界面与功能设计

1、功能设计说明

程序代码结构如下,调用关系见彩色部分标示。

数据显示界面功能通过以下2个程序实现:

data_show.html 程序文件

数据显示界面用于展示各种环境数据(温度、湿度、光强和气体浓度)的可视化界面。它使用了 Bootstrap 框架来进行页面布局,ECharts 库来绘制图表,并通过 AJAX 请求从服务器端的 cgi-bin/node_data.cgi 获取实时数据。

node_data.c 程序文件

主要实现了与共享内存交互,并将共享内存中的部分数据以 JSON 格式作为 HTTP 响应输出的功能。程序会创建或连接到一个共享内存段,读取其中的数据,修改部分数据,然后将温度、湿度、光照强度和气体浓度等信息以 JSON 格式输出,最后分离共享内存。

2、界面功能运行

程序编译完成后,上传到飞腾派开发板的https服务器的文件目录/var/www/,PC机浏览器访问开发板IP地址,显示如下界面。

注意:开发板如果没有通过网络连接到节点板,界面是没有相关数据显示。

 完成后续终端节点开发,开发板服务器连接到节点板后,界面会显示实时采集到的环境数据。

二、data_show.html 程序分析与设计

1、程序流程分析与设计

2、程序功能分析与设计

  • HTML 头部部分

<!DOCTYPE html>
<html><head><meta charset="utf-8"><title>数据显示</title><link href="css/bootstrap.css" rel="stylesheet"><script src="js/jquery-1.10.2.js" type="text/javascript"></script><script src="js/bootstrap.min.js" type="text/javascript"></script><script src="js/echarts.min.js" type="text/javascript"></script>
</head>

设置文档类型和字符编码。

引入 Bootstrap 样式表和相关 JavaScript 库,以及 ECharts 库。

  • HTML 主体部分

使用 Bootstrap 的网格系统创建页面布局。

包含温度、湿度、光强的仪表盘和气体浓度的折线图。

每个面板都有一个连接状态图标,初始状态为断开连接。

  1. JavaScript 部分

<script type="text/javascript">// 初始化变量var gas_data_sender = 0;var temp_val = 0;var humi_val = 0;var light_val = 0;var gas_val = 0;var alarm_line = 0;var returnValue = 0;var str_temp, str_humidity, str_light, str_gas;// 根据页面宽度调整气体浓度折线图的高度
...// 每秒发送一次 AJAX 请求获取数据setInterval(function () {$.ajax({cache: false,async: true,dataType: 'json',type: 'get',url: "cgi-bin/node_data.cgi",success: function (data) {// 更新数据temp_val = data.temp;humi_val = data.humi;light_val = data.light;gas_val = data.gas;// 打印数据到控制台console.log("温度: " + temp_val);console.log("湿度: " + humi_val);console.log("光照: " + light_val);console.log("气体: " + gas_val);// 根据数据更新连接状态图标
...},error: function () {// 请求失败时,将所有连接状态图标设置为断开连接
...}})}, 1000)// 初始化温度、湿度、光强仪表盘和气体浓度折线图tempGauge("temp_gauge", "optionTemp", "temp");humidityGauge("humidity_gauge", "optionHumidity", "humidity");lightGauge("light_gauge", "optionLight", "light");gasLine();// 更新连接状态图标的函数function is_conn(iid, bool) {
...}// 初始化温度仪表盘的函数function tempGauge(tid, toption, str) {str_temp = echarts.init(document.getElementById(tid));toption = {// 仪表盘配置项series: [{
...}]};// 每秒更新一次仪表盘数据setInterval(function () {toption.series[0].data[0].value = temp_val;str_temp.setOption(toption, true);}, 1000);// 初始化仪表盘if (toption && typeof toption === 'object') {str_temp.setOption(toption);}}// 初始化湿度仪表盘的函数,与温度仪表盘类似function humidityGauge(tid, toption, str) {str_humidity = echarts.init(document.getElementById(tid));toption = {series: [{
...};setInterval(function () {toption.series[0].data[0].value = humi_val;str_humidity.setOption(toption, true);}, 1000);if (toption && typeof toption === 'object') {str_humidity.setOption(toption);}}// 初始化光强仪表盘的函数,与温度仪表盘类似function lightGauge(tid, toption, str) {str_light = echarts.init(document.getElementById(tid));toption = {series: [{
...};setInterval(function () {toption.series[0].data[0].value = light_val;str_light.setOption(toption, true);}, 1000);if (toption && typeof toption === 'object') {str_humidity.setOption(toption);}}// 初始化气体浓度折线图的函数function gasLine() {str_gas = echarts.init(document.getElementById('gas_line'));var data = [];var now = new Date();function randosmata() {now = new Date(+now + 1000);console.log("gas_val-----" + gas_val);return {name: now.toString(),value: [now.getTime(), gas_val],};}// 初始化折线图数据for (var i = 0; i < 30; i++) {data.push(randosmata());}option = {// 折线图配置项
...};// 每秒更新一次折线图数据setInterval(function () {for (var i = 0; i < 1; i++) {data.shift();data.push(randosmata());}str_gas.setOption({title: {text: "当前气体浓度:" + gas_val,
...});}, 1000);option && str_gas.setOption(option);}// 窗口大小改变时,调整图表大小window.onresize = function () {str_temp.resize(),str_humidity.resize(),str_light.resize(),str_gas.resize();}
</script>
  1. 初始化变量,用于存储数据和 ECharts 实例。
  2. 根据页面宽度调整气体浓度折线图的高度。
  3. 每秒发送一次 AJAX 请求,从服务器获取实时数据,并更新连接状态图标。
  4. 初始化温度、湿度、光强仪表盘和气体浓度折线图。
  5. 每秒更新一次仪表盘和折线图的数据。
  6. 窗口大小改变时,调整所有图表的大小。

三、node_data.c 程序分析与设计

程序主要实现了与共享内存交互,并将共享内存中的部分数据以 JSON 格式作为 HTTP 响应输出的功能。程序会创建或连接到一个共享内存段,读取其中的数据,修改部分数据,然后将温度、湿度、光照强度和气体浓度等信息以 JSON 格式输出,最后分离共享内存。

1、程序流程分析与设计

这个流程图展示了程序的主要执行流程,包括共享内存的设置、数据的读取和修改、HTTP 响应的输出以及共享内存的分离等步骤。如果在任何步骤中出现错误,程序会输出相应的错误信息并终止。

2、程序功能分析与设计

  • 头文件包含部分

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <signal.h>
#include <time.h>

这些头文件包含了程序所需的基本函数和数据类型定义,例如标准输入输出、内存管理、系统调用、信号处理等。

  • 宏定义部分

#define CMD_DATA 0x01
#define CMD_CTL 0x02
#define CMD_SET 0x03#define E53_IA1 0x01
#define E53_SF1 0x02

定义了一些常量,用于表示命令类型和节点类型。

  • 共享内存数据结构定义

struct st_sys {unsigned char temp_val;  // 温度值unsigned char humi_val;  // 湿度值unsigned char light_sw;  // 灯光开关状态unsigned char buzz_sw;   // 蜂鸣器开关状态unsigned int ill_val;    // 光照强度值unsigned int gas_val;    // 气体浓度值unsigned int ill_max;    // 光照强度最大值unsigned int gas_max;    // 气体浓度最大值unsigned char msg_type; //请求类型unsigned char node_id; //节点IDunsigned char data_flag;//数据更新标记 unsigned char control_flag;//控制更新标记unsigned char set_flag;//设置更新标记   
};

定义了一个结构体 st_sys,用于表示共享内存中的数据结构,包含了温度、湿度、光照、气体浓度等信息,以及请求类型、节点 ID 和更新标记。

  • 共享内存地址指针和全局变量

struct st_sys* shm_dev;
struct st_sys g_dev[1];

shm_dev 是一个指向共享内存的指针,g_dev 是一个用于存储从共享内存中读取的数据的数组。

  • 设置共享内存函数 set_web_shm

void* set_web_shm(void) {int shmid;void* shmaddr = (void*)0;// 创建或获取共享内存段if ((shmid = shmget((key_t)3456, sizeof(struct st_sys), 0666 | IPC_CREAT)) < 0) {perror("shmget error");return NULL;}// 将共享内存段附加到当前进程的地址空间if ((shmaddr = shmat(shmid, (void*)0, 0)) == (char*)-1) {perror("shmat error");return NULL;}return shmaddr;
}

该函数用于创建或获取一个共享内存段,并将其附加到当前进程的地址空间。如果创建或附加失败,会输出错误信息并返回 NULL

  • 信号处理函数 signal_handler

void signal_handler(int signum) {if (shmdt(shm_dev) == -1) {perror("shmdt error");}exit(0);
}

当程序接收到信号时,该函数会尝试分离共享内存,并退出程序。如果分离失败,会输出错误信息。

  • 主函数 main

int main() {// 构建 JSON 格式的响应数据char response[100];// 设置共享内存if ((shm_dev = (struct st_sys*)set_web_shm()) == NULL) {fprintf(stderr, "Failed to set up shared memory.\n");return 1;}// 从共享内存中读取数据memcpy(g_dev, shm_dev, sizeof(struct st_sys));shm_dev->msg_type = CMD_DATA;//命令类型shm_dev->node_id = E53_IA1;//节点类型shm_dev->data_flag++;//更新次数加1// 设置 HTTP 响应头printf("Content-type: application/json\n\n");snprintf(response, sizeof(response), "{\"temp\": %d, \"humi\": %d, \"light\": %d, \"gas\": %d}", g_dev->temp_val, g_dev->humi_val,g_dev->ill_val, g_dev->gas_val);// 输出响应数据printf("%s", response);//分离共享内存if (shmdt(shm_dev) == -1) {perror("shmdt error");}return 0;
}

主函数的主要流程如下:

  1. 定义一个字符数组 response 用于存储 JSON 格式的响应数据。

  2. 调用 set_web_shm 函数设置共享内存,如果失败则输出错误信息并返回。

  3. 从共享内存中读取数据到 g_dev 数组。

  4. 修改共享内存中的请求类型、节点 ID 和更新标记。

  5. 设置 HTTP 响应头。

  6. 使用 snprintf 函数将温度、湿度、光照强度和气体浓度信息格式化为 JSON 字符串。

  7. 输出 JSON 响应数据。

  8. 分离共享内存,如果失败则输出错误信息。

  9. 返回 0 表示程序正常结束。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/83939.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/83939.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Robyn高性能Web框架系列01:Robyn快速入门

Robyn快速入门 安装 Robyn1、仅安装基础 HTTP 路由功能2、带扩展功能的安装 第一个Robyn程序1、创建Robyn应用2、Say Hello!3、启动Robyn应用 Python世界从来不缺少对于性能的追求&#xff0c;Robyn就是其中之一&#xff0c;它将 Python 的异步功能与 Rust 相结合&#xff0c;在…

微信小程序 -----无限新增删除,同时算出总合算金额。

<view class="refuelMoney-main" style="padding-bottom: 200rpx;"><!-- <view class="add_record">添加加油记录</view> --><view class="refuel-itemTextArea"><text style="width: 35%;&quo…

linux “Permission Denied“解决方案

Linux 编译错误排查 在软件开发过程中&#xff0c;编译错误和版本控制问题是开发者每天都会遇到的挑战。本文将结合实际案例&#xff0c;详细讲解 Linux 环境下常见编译错误的排查方法 权限拒绝错误&#xff08;Permission Denied&#xff09; 当执行脚本或程序时&#xff0…

【慧游鲁博】【15】后台管理系统功能完善:仪表盘、多模态交互日志、简单问答词条管理

文章目录 本次更新多模态交互日志效果涉及代码文件 仪表盘&#xff08;部分&#xff09;效果涉及代码文件 简单问答服务词条管理效果涉及代码文件 本次更新 代码真的太多太多了&#xff0c;不放代码了 多模态交互日志 数据概览与筛选功能 时间范围筛选&#xff1a;提供"…

【力扣 简单 C】21. 合并两个有序链表

目录 题目 解法一&#xff1a;迭代 解法二&#xff1a;递归 题目 解法一&#xff1a;迭代 struct ListNode* merge(struct ListNode* head1, struct ListNode* head2) {struct ListNode* virHead malloc(sizeof(*virHead));struct ListNode* curNode virHead;struct List…

【开源工具】Windows屏幕控制大师:息屏+亮度调节+快捷键一体化解决方案

🖥️ 从零打造Windows屏幕控制大师:息屏+亮度调节+快捷键一体化解决方案 🌈 个人主页:创客白泽 - CSDN博客 🔥 系列专栏:🐍《Python开源项目实战》 💡 热爱不止于代码,热情源自每一个灵感闪现的夜晚。愿以开源之火,点亮前行之路。 🐋 希望大家多多支持,我们一…

pyhton基础【11】函数一

目录 一.函数说明 二.函数介绍 函数简介 作用 函数分类 三.自定义函数 定义函数 调用函数 pass关键字 定义一次执行多次 一.函数说明 Python中的函数是一个重要的编程概念&#xff0c;它允许编程者封装代码块以实现特定的功能。函数的作用和应用场景非常广泛&#xf…

使用Kotlin开发后端服务的核心方法

一、开发步骤 选择框架 Kotlin后端开发常用框架包括Spring Boot、Ktor和Micronaut。Spring Boot生态成熟&#xff0c;适合企业级应用&#xff1b;Ktor轻量且协程友好&#xff0c;适合高性能异步服务&#xff1b;Micronaut以低内存占用和快速启动见长。 搭建项目结构 通过Grad…

java面试总结-20250616

题目1: 求一个int类型正整数二进制中最高位1的位置&#xff1f; 比如10&#xff0c;二进制位1010&#xff0c;最高位1所在位置位4。 解体思路&#xff1a; 使用高位扩散&#xff0c;将1010扩散位1111使用二分法&#xff0c;计算32位二进制中1111前面0的位数n&#xff1b;结果…

Black自动格式化工具

文章目录 一、Black自动格式化工具二、格式化行为的核心内容1. 统一缩进和空格规则2. 括号换行&#xff1a;一致的多行结构展开3. 字符串风格统一4. 函数/类定义中的空行规则5. import 排序&#xff08;建议搭配 isort&#xff09;6. 注释不动、换行优雅7. 可配置项极少&#x…

项目拓展-简易SQL监控,P6SPY拦截所有jdbc连接并打印执行SQL

介绍一下P6spy驱动 p6spy 是一款开源的数据库监控框架&#xff0c;主要用于 拦截和记录应用程序与数据库之间的所有交互&#xff08;如 SQL 语句、参数、执行时间等&#xff09; 它通过包装现有的 JDBC 驱动&#xff08;如 MySQL JDBC 驱动&#xff09;&#xff0c;在不修改业…

洛谷B3951 [GESP样题 五级] 小杨的队列

题目描述 小杨的班级里共有 N N N 名同学&#xff0c;学号从 0 0 0 至 N − 1 N-1 N−1。某节课上&#xff0c;老师要求同学们进行列队。具体来说&#xff0c;老师会依次点名 M M M 名同学&#xff0c;让他们加入队伍。每名新入队的同学需要先站到队伍末尾&#xff08;刚开…

Java编程之外观模式

前言 想象你要去一家很复杂的餐厅吃饭&#xff0c;但不想自己点菜、排队、找位置&#xff0c;也不想管厨房、洗碗、送餐这些后端流程。你只需要告诉餐厅服务员“我要一份牛排套餐”&#xff0c;然后坐等就好。这个服务员&#xff0c;就是外观模式&#xff08;Facade Pattern&a…

告别 Java 开发困境!飞算 JavaAI 开发助手开启智能编程新时代

在 Java 开发的世界里&#xff0c;需求不明确、加班写重复代码、被 BUG 搞得焦头烂额&#xff0c;是许多开发者难以摆脱的 “三座大山”。需求文档模糊不清&#xff0c;让开发者在项目起始阶段就陷入迷茫&#xff1b;大量重复性的代码编写工作&#xff0c;不仅消耗时间和精力&a…

Node.js 中两种模块导出方式区别

两种模块到处方式 exports.xxx ... module.exports ... 1. exports.xxx ... exports 是 module.exports 的一个引用&#xff08;快捷方式&#xff09;。 当你写 exports.foo function() {}&#xff0c;实际上就是给 module.exports 对象添加了一个 foo 属性。 这种方式…

电脑出问题了,无网络环境下一键快速重装系统

在电脑使用过程中&#xff0c;系统故障、卡顿、崩溃等问题屡见不鲜。面对这些情况&#xff0c;重装系统往往是解决问题的最有效手段之一。然而对于刚接触计算机操作的新用户来说&#xff0c;如何安全、稳定地完成系统重装&#xff0c;仍是一个颇具挑战的任务。 这一款专为新手…

基于区块链的去中心化身份验证系统:原理、实现与应用

前言 在数字化时代&#xff0c;身份验证是网络安全和隐私保护的核心环节。传统的身份验证系统依赖于中心化的机构&#xff0c;如政府、银行或互联网服务提供商&#xff0c;这些机构存储和管理用户的个人信息。然而&#xff0c;中心化系统存在诸多问题&#xff0c;如数据泄露风险…

React forwardRef 与 useImperativeHandle 深度解析

在React开发中&#xff0c;组件间的通信是一个核心话题。虽然props和state能够处理大部分场景&#xff0c;但有时我们需要更直接的方式来操作子组件。今天我们来深入探讨两个强大的React Hook&#xff1a;forwardRef和useImperativeHandle。 forwardRef&#xff1a;传递引用的…

KingbaseES在线体验平台深度测评:基于MCP接口管理的Oracle风格SQL实战

文章目录 一、平台环境与准备二、引导体验1.检查数据库版本及服务状态 三、建库与建表1. 建库&#xff08;KingbaseES中通常无需显式建库&#xff0c;此处以创建schema模拟&#xff09;2. 建表 四、查库与数据操作测试1. 查库&#xff08;确认表结构&#xff09;2. 新增数据3. …

echarts开发 | 数据可视化 -- 第三篇 echart进阶配置项 数据集

文章目录 一、概念二、回顾在系列(series)中设置数据三、在数据集中设置数据3.1 数据集(dataset) 基础3.2 二维数组数据(默认) 四、把数据集(dataset) 的行或列 映射为 序列 (series)五、维度(dimension)六、数据到图形的映射 &#xff08;series.encode&#xff09; 一、概念 …