当前位置: 首页 > news >正文

基于Google Charts与树莓派的物联网数据可视化实战

1. 项目概述:为什么选择Google Charts做物联网数据可视化?

做物联网项目,数据采集只是第一步,如何让这些数据“说话”,让非技术背景的同事或客户一眼看懂趋势,才是体现项目价值的关键。我手头有不少树莓派和传感器,常年采集温度、湿度、设备状态等数据,早期都是直接写日志文件,或者用命令行工具画个简单的折线图,自己看还行,但要分享出去或者做个简单的监控面板,就显得非常吃力。

后来我尝试过不少可视化方案,比如自己用Python的Matplotlib画图然后生成静态图片,或者用Grafana这类专业的监控工具。它们各有优劣:Matplotlib灵活但需要一定的编程基础,且实时更新和Web集成稍显繁琐;Grafana功能强大,但对于一些轻量级、定制化要求高的快速演示项目来说,部署和配置又显得有些“重”了。

直到我重新审视了Google Charts这个工具。它是一套完全免费、由Google提供的JavaScript图表库。对于物联网数据可视化来说,它有几点特别吸引人:

  1. 零服务器依赖:图表渲染完全在用户的浏览器端完成。这意味着你只需要一个能托管静态HTML文件的Web服务器(甚至可以是树莓派自带的Nginx或Apache),不需要在服务器端安装任何额外的图表渲染服务或处理大量并发请求,极大地减轻了边缘设备的负担。
  2. 丰富的图表类型:从基础的折线图、柱状图到更高级的仪表盘、地理图表,几乎涵盖了数据展示的常见需求。对于物联网场景,时序折线图(看趋势)、仪表盘(看实时状态)尤其好用。
  3. 交互性:用户可以通过鼠标悬停查看精确数据点,缩放时间范围,这对于分析特定时间段的数据异常非常友好。
  4. 易于集成:通过简单的JavaScript API调用,配合JSON或数组格式的数据,就能快速生成图表。与我们常用的数据采集脚本(如Bash、Python)可以轻松对接。

本项目就是一个典型的轻量级实践:我们利用树莓派(或任何Linux服务器),通过Bash脚本定时从OpenWeatherMap API抓取风速数据,存储到本地日志文件,然后动态生成一个包含Google Charts的HTML页面,实现数据的自动采集与可视化展示。整个方案清晰、高效,特别适合作为物联网可视化入门,或者快速搭建一个原型监控系统。

2. 核心思路与架构设计

整个项目的目标很明确:定时获取数据 -> 格式化存储 -> 动态生成可视化页面。为了实现这个目标,我设计了一个简单但稳固的三层架构,这个架构在不少我的小型物联网项目中都得到了验证。

2.1 系统架构拆解

整个流程可以清晰地分为三个环节,像一个数据流水线:

  1. 数据采集层(Bash脚本):这是系统的“感官”。我们编写一个Bash脚本 (wind_connectmyplace.sh),利用curl命令调用OpenWeatherMap的公开API,获取指定地理位置的实时天气数据。然后使用jq这个强大的命令行JSON处理器,从返回的复杂JSON数据中,精准地提取出我们关心的wind.speed(风速)字段。这个脚本被设置为定时任务(例如每30分钟执行一次),实现数据的持续采集。

  2. 数据持久层(日志文件):这是系统的“记忆”。采集脚本在获取到数据后,并不会直接去修改网页,而是以一种追加(Append)的方式,将时间戳和对应的风速值写入一个纯文本日志文件 (wind.log)。这样做的好处非常多:

    • 解耦:数据采集和页面生成是两个独立的过程。即使生成图表的HTML出错了,也不会影响数据的持续记录,保证了数据的完整性。
    • 容错与回溯:日志文件保留了历史原始数据。如果某天发现图表有异常,我们可以直接检查日志文件,进行数据回溯分析,甚至修复后重新生成图表。
    • 简单可靠:在Linux系统下,文件操作非常高效且稳定,避免了引入数据库所带来的复杂度。
  3. 可视化展示层(HTML + Google Charts):这是系统的“面孔”。我们准备三个HTML片段文件:windheader.html(网页头部,包含Google Charts库的加载代码和图表基础配置)、windfooter.html(网页尾部,结束标签)、以及一个“数据模板”文件。核心脚本的另一部分(或另一个脚本)会读取最新的日志文件,将其中的数据格式化为Google Charts能够识别的JavaScript数组格式,然后拼接上头部和尾部,最终生成一个完整的、独立的windchartline.html文件,并将其放置在Web服务器根目录下。用户通过浏览器访问这个页面,就能看到自动更新的风速趋势图。

2.2 技术选型背后的考量

  • 为什么用Bash脚本,而不用Python/Node.js?对于这种简单的、周期性的HTTP GET请求和数据提取任务,Bash脚本配合curljq的组合堪称“瑞士军刀”。它轻量(无需额外环境)、高效(直接利用系统工具),并且非常适合通过Cron来调度。当然,如果数据处理逻辑变得非常复杂(比如需要数据清洗、复杂计算),那么Python会是更好的选择。但在这个项目中,Bash的简洁性是其最大优势。

  • 为什么用文件存储,而不用数据库?这是一个重要的权衡。数据库(如SQLite、MySQL)适合数据关系复杂、需要频繁查询更新的场景。而我们当前的需求是:每分钟或每半小时追加一条数据,然后一次性读取所有数据来画图。这是一个典型的“追加写,顺序读”场景,纯文本日志文件的性能开销远低于数据库,且管理起来无比简单——用cattailgrep就能完成大部分操作。当数据量变得非常大(例如数年数据)时,我们可以考虑按日期分割日志文件,或者再迁移到时序数据库(如InfluxDB),但在项目初期和中等数据量下,文件存储是最佳选择。

  • 为什么选择OpenWeatherMap API作为数据源?因为它免费、稳定、数据全面。对于物联网可视化教学或原型验证来说,我们不需要自己去部署物理风速传感器,就能获得真实、连续的时序数据,这大大降低了入门门槛。当然,这个架构完全通用,你可以将API请求替换为从本地传感器(通过GPIO读取)、其他物联网平台(如ThingsBoard、Home Assistant)的API,或者从MQTT主题中订阅消息,逻辑是相通的。

3. 环境准备与依赖安装

“工欲善其事,必先利其器”。在开始编写代码之前,我们需要确保树莓派(或你的Linux服务器)环境就绪。以下步骤我假设你使用的是Raspberry Pi OS或类似的Debian/Ubuntu系统,并且已经具备基本的命令行操作能力。

3.1 硬件与基础软件准备

首先,你需要一个运行Linux的设备。树莓派是最佳选择,因为它功耗低、适合长期运行,但任何有SSH访问权限的云服务器或旧电脑改造的Linux主机都可以。

  1. 系统更新:首先,打开终端,更新软件包列表并升级现有软件,这是一个好习惯。

    sudo apt update sudo apt upgrade -y
  2. 安装Web服务器:我们需要一个Web服务器来托管最终生成的HTML图表文件。Nginx轻量高效,是我推荐的选择。

    sudo apt install nginx -y

    安装完成后,启动Nginx并设置开机自启:

    sudo systemctl start nginx sudo systemctl enable nginx

    此时,在同一个局域网内的浏览器中访问你树莓派的IP地址(例如http://192.168.1.100),你应该能看到Nginx的默认欢迎页面。这说明Web服务器已经正常工作。默认的网站根目录是/var/www/html,我们后续生成的图表文件就会放在这里。

3.2 关键工具安装:jq与bc

我们的数据采集脚本依赖两个重要的命令行工具:jqbc

  • jq:这是一个处理JSON数据的利器。OpenWeatherMap API返回的数据是JSON格式,我们需要从中精准地提取出风速值。jq可以像使用查询语言一样过滤、转换JSON。
  • bc:一个高精度计算器语言。虽然在本项目初始示例中可能未直接使用,但在数据处理中非常常用。例如,API返回的风速单位可能是米/秒,而你可能想转换为公里/小时,这时就需要用到bc进行浮点数计算。先安装上以备不时之需。

安装命令非常简单:

sudo apt install jq bc -y

安装完成后,可以通过jq --versionbc --version来验证是否安装成功。

3.3 获取OpenWeatherMap API密钥

数据源是开放的,但需要注册一个免费账户来获取API密钥(APPID)。

  1. 访问 OpenWeatherMap官网 并注册账号。
  2. 登录后,在用户面板中找到 “API Keys” 选项卡。
  3. 系统会默认提供一个密钥,你也可以创建一个新的。这个密钥(一串由字母数字组成的字符串)就是我们脚本中需要的YOUR_API_ID请妥善保管此密钥,不要泄露

注意:免费套餐通常有调用频率限制(如每分钟60次,每天100万次)。对于每半小时调用一次的脚本来说,这完全绰绰有余。但务必遵守其使用条款,不要滥用。

4. 核心脚本解析与实操部署

这是整个项目的“发动机”,我们将一步步拆解脚本内容,并完成部署。我建议在树莓派的用户主目录(如/home/pi)下创建一个专门的项目目录,例如iot_chart,将所有文件放在里面,便于管理。

4.1 数据采集脚本详解

首先,创建并编辑我们的核心数据采集脚本wind_connectmyplace.sh

#!/bin/bash # 定义变量:你的API密钥和地理位置 LAT="54.38" LON="-5.54" API_KEY="YOUR_ACTUAL_API_KEY_HERE" # 务必替换成你自己的密钥! LOG_FILE="/home/pi/iot_chart/wind.log" TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S') # 调用OpenWeatherMap API,并使用jq提取风速 # 注意:API返回的风速单位默认是米/秒(m/s) wind_speed=$(curl -s "https://api.openweathermap.org/data/2.5/weather?lat=${LAT}&lon=${LON}&appid=${API_KEY}" | jq '.wind.speed') # 检查是否成功获取到数据 if [ -z "$wind_speed" ] || [ "$wind_speed" = "null" ]; then echo "[$TIMESTAMP] ERROR: Failed to fetch wind data or data is null." >> /home/pi/iot_chart/error.log exit 1 fi # 将数据和时间戳写入日志文件 echo "$TIMESTAMP, $wind_speed" >> $LOG_FILE # 可选:在控制台输出一条成功信息(用于调试) echo "[$TIMESTAMP] Wind speed recorded: $wind_speed m/s"

脚本关键点解析:

  1. 变量定义:将API密钥、经纬度、日志文件路径定义为变量,方便后续修改和维护。重中之重:务必将YOUR_ACTUAL_API_KEY_HERE替换为你自己申请的真正API密钥!
  2. API调用与数据提取curl -s中的-s参数表示静默模式,不显示进度条或错误信息,让输出更干净。管道符|将curl获取的JSON数据传递给jq '.wind.speed',这个jq过滤器会直接提取出风速数值。
  3. 错误处理:这是一个非常重要的实践。我们检查wind_speed变量是否为空或为null。如果API调用失败(如网络问题、密钥无效),jq可能会输出null,脚本会将错误信息记录到单独的error.log,然后以非零状态码退出,避免将无效数据写入主日志。在物联网项目中,健全的错误处理是保证系统长期稳定运行的基础。
  4. 数据格式化:日志行的格式是时间戳, 风速值。这个逗号分隔的格式(CSV)非常通用,既便于人阅读,也便于后续脚本用awkcut等工具处理。

保存文件后,别忘了给它添加执行权限:

chmod +x /home/pi/iot_chart/wind_connectmyplace.sh

你可以手动运行一次脚本进行测试:./wind_connectmyplace.sh。然后查看wind.log文件,应该能看到一行新增的数据,例如2023-10-27 14:30:00, 4.62

4.2 构建可视化HTML组件

Google Charts需要一个包含特定数据格式的HTML页面。我们将页面拆分为头、尾和数据体三部分,这样数据更新时只需要替换数据体部分,更灵活。

1. 头部文件 (windheader.html):这个文件定义了网页的基本结构、加载Google Charts库、并设置了图表的基础选项。

<!DOCTYPE html> <html> <head> <script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script> <script type="text/javascript"> google.charts.load('current', {'packages':['corechart']}); google.charts.setOnLoadCallback(drawChart); function drawChart() { // 数据表格将在 windchartline.html 的主体部分被填充 var data = google.visualization.arrayToDataTable([ ['Time', 'Wind Speed (m/s)'], // 列标题 // 数据行会在这里动态插入 ]); var options = { title: 'Wind Speed Trend (OpenWeatherMap)', titleTextStyle: { fontSize: 18, bold: true }, curveType: 'function', // 将折线平滑处理,看起来更美观 legend: { position: 'bottom' }, hAxis: { title: 'Date/Time', titleTextStyle: { italic: false }, slantedText: true, // 时间标签倾斜,防止重叠 slantedTextAngle: 45 }, vAxis: { title: 'Wind Speed (m/s)', minValue: 0 // 风速通常从0开始 }, width: 1200, height: 600, chartArea: { width: '85%', height: '70%' } // 控制图表绘制区域大小 }; var chart = new google.visualization.LineChart(document.getElementById('chart_div')); chart.draw(data, options); } // 添加窗口大小改变时的重绘功能,提升响应性 window.addEventListener('resize', drawChart); </script> </head> <body> <div id="chart_div"></div>

2. 数据生成与页面合成脚本:这是项目的另一个关键脚本,我将其命名为generate_chart.sh。它的作用是读取日志文件,生成包含实际数据点的JavaScript代码片段,然后将其与头部、尾部拼接成完整的HTML。

#!/bin/bash # 定义路径 HEADER_FILE="/home/pi/iot_chart/windheader.html" FOOTER_FILE="/home/pi/iot_chart/windfooter.html" LOG_FILE="/home/pi/iot_chart/wind.log" OUTPUT_HTML="/var/www/html/windchartline.html" # 输出到Web服务器目录 # 临时数据文件 DATA_TEMP_FILE="/tmp/chart_data.js" # 1. 从日志文件生成Google Charts数据数组 echo " // Data rows" > $DATA_TEMP_FILE # 使用awk处理日志,格式化为JS数组格式 [new Date('YYYY-MM-DD HH:MM:SS'), value] awk -F', ' '{ printf " [new Date('\''%s'\''), %s],\n", $1, $2 }' $LOG_FILE >> $DATA_TEMP_FILE # 2. 拼接完整的HTML文件 cat $HEADER_FILE $DATA_TEMP_FILE $FOOTER_FILE > $OUTPUT_HTML # 3. 清理临时文件(可选) rm $DATA_TEMP_FILE echo "Chart updated at $(date)"

脚本关键点解析:

  • awk命令的妙用awk -F‘, ’指定了字段分隔符为“逗号+空格”,将日志的每一行拆分成时间戳($1)和风速值($2)。然后使用printf格式化成[new Date('...'), ...],的JavaScript数组格式。new Date()是Google Charts识别时间戳所必需的。
  • 输出到Web根目录:最终生成的windchartline.html被直接放到了/var/www/html/下,这样Nginx就能直接提供访问。
  • 权限问题:确保运行脚本的用户(如pi)有权限写入/var/www/html/目录。通常需要将用户加入www-data组,并修改目录权限。一个更简单直接的方法是(在生产环境中请谨慎评估):
    sudo chown pi:www-data /var/www/html/ sudo chmod 775 /var/www/html/
    然后确保generate_chart.sh也有执行权限:chmod +x generate_chart.sh

3. 尾部文件 (windfooter.html):这个文件非常简单,就是关闭HTML标签。

</body> </html>

4.3 自动化调度:使用Cron定时任务

我们不可能手动去执行这两个脚本。Linux的Cron定时任务工具正是为此而生。

  1. 编辑当前用户的Cron表

    crontab -e

    如果是第一次使用,可能会让你选择编辑器,选择熟悉的nano即可。

  2. 添加定时任务规则: 在文件末尾添加以下两行:

    # 每30分钟采集一次风速数据 */30 * * * * /home/pi/iot_chart/wind_connectmyplace.sh >> /home/pi/iot_chart/cron.log 2>&1 # 每天凌晨2点重新生成一次图表(假设数据量不大,全天数据一起渲染) 0 2 * * * /home/pi/iot_chart/generate_chart.sh >> /home/pi/iot_chart/cron.log 2>&1
    • 第一行:*/30 * * * *表示每30分钟执行一次数据采集脚本。>> /home/pi/iot_chart/cron.log 2>&1将脚本的标准输出和错误输出都重定向追加到cron.log文件,便于日后排查问题。
    • 第二行:0 2 * * *表示每天凌晨2点执行一次图表生成脚本。对于实时性要求不高的趋势观察,每天更新一次图表是合理的。如果你希望图表更实时,可以将频率提高,例如每小时一次(0 * * * *)。
  3. 保存并退出(在nano编辑器中是按Ctrl+X,然后按Y确认,再按回车)。

现在,整个系统就开始自动运行了。等待一段时间(比如一个小时后),你就可以在浏览器中访问http://你的树莓派IP/windchartline.html,看到自动生成的风速趋势图了。

5. 方案优化与扩展实践

基础版本跑通后,我们可以从稳定性、功能和美观度上进行一系列优化,让它从一个Demo变成一个更健壮、实用的工具。

5.1 增强数据采集脚本的健壮性

最初的脚本缺乏足够的错误处理和日志记录。以下是一个增强版的采集脚本片段:

#!/bin/bash CONFIG_FILE="/home/pi/iot_chart/config.cfg" LOG_DIR="/home/pi/iot_chart/logs" DATA_LOG="$LOG_DIR/wind.log" ERROR_LOG="$LOG_DIR/error.log" CRON_LOG="$LOG_DIR/cron.log" # 加载配置文件 source $CONFIG_FILE 2>/dev/null || { echo “[$(date)] ERROR: Config file missing.” >> $ERROR_LOG; exit 1; } # 检查必要的配置变量 if [ -z “$API_KEY” ] || [ -z “$LAT” ] || [ -z “$LON” ]; then echo “[$(date)] ERROR: API_KEY, LAT, or LON not set in config.” >> $ERROR_LOG exit 1 fi # 创建日志目录(如果不存在) mkdir -p $LOG_DIR # 执行数据获取,增加超时设置 response=$(curl -s -m 30 “https://api.openweathermap.org/data/2.5/weather?lat=${LAT}&lon=${LON}&appid=${API_KEY}&units=metric”) curl_exit_code=$? if [ $curl_exit_code -ne 0 ]; then echo “[$(date)] ERROR: Curl failed with code $curl_exit_code. Possible network issue.” >> $ERROR_LOG exit 1 fi wind_speed=$(echo $response | jq -r ‘.wind.speed’ 2>/dev/null) # 更全面的数据验证 if [[ ! $wind_speed =~ ^[0-9]+(\.[0-9]+)?$ ]]; then echo “[$(date)] ERROR: Invalid wind speed value fetched: ‘$wind_speed’. Full response: $response” >> $ERROR_LOG exit 1 fi # 成功,记录数据 timestamp=$(date ‘+%Y-%m-%d %H:%M:%S’) echo “$timestamp, $wind_speed” >> $DATA_LOG # 可选:控制台输出,并记录到Cron日志 echo “[$timestamp] Success: Wind speed = $wind_speed m/s” | tee -a $CRON_LOG

优化点说明:

  • 配置文件分离:将API密钥、经纬度等敏感和易变信息放入单独的config.cfg文件(记得设置该文件权限为仅所有者可读:chmod 600 config.cfg),避免将密钥硬编码在脚本中,也便于管理。
  • 集中化日志管理:创建专门的logs目录,区分数据日志、错误日志和Cron执行日志。
  • 完善的错误处理:检查curl退出码、网络超时(-m 30设置30秒超时)、使用jq -r输出原始字符串,并用正则表达式验证获取的数据是否为有效数字。
  • 使用units=metric参数:在API请求中指定单位制,确保返回的数据是公制单位(如温度摄氏、风速米/秒),避免单位混淆。

5.2 图表功能与样式优化

Google Charts的options对象非常强大,我们可以让图表更专业、更易读。

  1. 双Y轴图表:如果你想同时展示风速和温度。

    function drawChart() { var data = google.visualization.arrayToDataTable([ ['Time', 'Wind Speed (m/s)', 'Temperature (°C)'], // ... 数据行,每行三个值 [时间, 风速, 温度] ]); var options = { title: 'Weather Data Trend', series: { 0: { targetAxisIndex: 0 }, // 风速系列关联第一个Y轴(左侧) 1: { targetAxisIndex: 1 } // 温度系列关联第二个Y轴(右侧) }, vAxes: { 0: {title: 'Wind Speed (m/s)'}, 1: {title: 'Temperature (°C)'} }, // ... 其他样式选项 }; var chart = new google.visualization.LineChart(...); }
  2. 动态时间范围选择器:添加一个控制面板,让用户可以查看最近1小时、24小时或自定义时间段的数据。这需要在前端HTML中添加一些表单控件,并编写相应的JavaScript函数来过滤data对象,然后重绘图表。虽然稍复杂,但能极大提升用户体验。

  3. 样式微调

    • colors: ['#4CAF50', '#FF9800']可以自定义折线颜色。
    • lineWidth: 2设置线宽。
    • pointSize: 5设置数据点大小。
    • options中添加backgroundColor: ‘#f9f9f9’可以设置图表背景色。

5.3 从文件到数据库:应对海量数据

当日志文件变得非常大(比如积累了数年的每分钟数据)时,每次生成图表都读取整个文件会非常慢。这时,引入一个轻量级数据库是明智的选择。

SQLite是一个完美的过渡方案:它是一个单文件数据库,无需运行独立的数据库服务,管理起来像文件一样简单,但支持SQL查询,性能远超直接解析大文本文件。

  1. 安装SQLitesudo apt install sqlite3
  2. 创建数据库和表
    sqlite3 /home/pi/iot_chart/weather_data.db
    在SQLite提示符下:
    CREATE TABLE sensor_data ( id INTEGER PRIMARY KEY AUTOINCREMENT, timestamp DATETIME NOT NULL, wind_speed REAL, temperature REAL, humidity REAL ); CREATE INDEX idx_timestamp ON sensor_data(timestamp); -- 为时间戳创建索引,加速查询 .exit
  3. 修改数据采集脚本:将echo “$timestamp, $wind_speed” >> $LOG_FILE替换为向数据库插入记录:
    sqlite3 /home/pi/iot_chart/weather_data.db “INSERT INTO sensor_data (timestamp, wind_speed) VALUES (‘$timestamp’, $wind_speed);”
  4. 修改图表生成脚本:不再读取日志文件,而是查询数据库。例如,获取最近7天的数据:
    # 在generate_chart.sh中,替换awk部分 sqlite3 -csv /home/pi/iot_chart/weather_data.db “SELECT timestamp, wind_speed FROM sensor_data WHERE timestamp > datetime(‘now’, ‘-7 days’);” | awk -F‘,’ ‘{ printf “\t[new Date(‘\’‘%s’\’‘), %s],\n”, $1, $2 }’ > $DATA_TEMP_FILE
    这样,无论数据量多大,图表生成的速度都只取决于查询时间范围内的数据量,效率得到质的提升。

6. 常见问题与故障排查实录

在实际部署和运行中,你几乎一定会遇到下面这些问题。这里记录了我踩过的坑和解决方法。

6.1 数据采集失败

  • 问题现象wind.log文件没有新增记录,或者error.log中出现错误。
  • 排查步骤
    1. 手动测试脚本:在终端运行./wind_connectmyplace.sh,观察输出。这是最直接的调试方式。
    2. 检查API密钥和网络:最常见的错误是API密钥无效或过期。手动在浏览器中访问一下API链接(将密钥替换进去),看是否能返回正确的JSON数据。同时检查树莓派的网络连接是否正常(ping 8.8.8.8)。
    3. 检查工具安装:确认jqcurl已正确安装 (which jq curl)。
    4. 检查文件权限:确保脚本有执行权限 (ls -l wind_connectmyplace.sh),并且运行脚本的用户对日志文件所在目录有写权限。
    5. 查看Cron日志:系统级的Cron日志通常在/var/log/syslog/var/log/cron,可以用grep CRON /var/log/syslog查看Cron任务执行情况,看是否有错误信息。

6.2 图表页面空白或显示错误

  • 问题现象:浏览器打开页面只显示空白,或控制台(F12打开开发者工具)报JavaScript错误。
  • 排查步骤
    1. 检查HTML文件是否生成:到/var/www/html/目录下查看windchartline.html是否存在,文件大小是否正常。
    2. 检查HTML文件内容:用cathead -n 50查看生成的文件。重点检查中间的数据部分格式是否正确。常见的错误是:
      • 数据行末尾有多余的逗号:Google Charts数据数组的最后一行不能有逗号。我们的awk命令生成的每一行都带逗号,如果日志文件只有一行数据,那么数组就成了[[...], ],这是错误的。需要在生成脚本中做处理,例如用sed ‘$ s/,$//’命令删除最后一行末尾的逗号。
      • 时间格式不正确:确保new Date(‘...’)中的字符串是YYYY-MM-DD HH:MM:SS格式,且被单引号包裹。
    3. 检查浏览器控制台:按F12打开开发者工具,切换到 “Console” 标签页。任何红色的错误信息都会在这里显示,比如 “Invalid date” 或 “DataTable parsing error”,根据错误信息定位问题。
    4. 检查Nginx服务与权限:确保Nginx正在运行 (sudo systemctl status nginx),并且对/var/www/html/windchartline.html有读取权限(通常权限是644)。

6.3 图表加载缓慢或数据点太多

  • 问题现象:页面打开很慢,或者图表上数据点过于密集,无法看清。
  • 解决方案
    1. 限制数据量:在generate_chart.sh的数据库查询或文件读取步骤中,不要取出所有历史数据。例如,使用tail -n 500 wind.log只取最近500个数据点,或者在SQL查询中加上LIMIT 1000WHERE timestamp > datetime(‘now’, ‘-30 days’)
    2. 数据聚合:对于非常高频(如每秒)的数据,直接绘制会导致图表卡顿且意义不大。可以在查询时进行聚合,例如,查询每小时的平均风速:
      SELECT strftime(‘%Y-%m-%d %H:00:00’, timestamp) as hour, AVG(wind_speed) FROM sensor_data GROUP BY hour ORDER BY hour DESC LIMIT 100;
    3. 使用explorer选项:Google Charts提供了一个交互式的探索模式,允许用户缩放和拖动图表,非常适合展示大量数据。在options中添加explorer: {}即可启用。

6.4 Cron定时任务不执行

  • 问题现象:脚本手动执行正常,但到了设定时间Cron没有触发。
  • 排查步骤
    1. 检查Cron服务状态sudo systemctl status cron(在某些系统上是crond)。
    2. 检查Cron日志:如前所述,查看/var/log/syslog
    3. 检查环境变量:Cron执行的环境与用户登录Shell环境不同,可能缺少PATH等变量。一个可靠的解决方法是在脚本的开头显式设置环境变量,或者在使用命令时使用绝对路径(如/usr/bin/curl,/usr/bin/jq)。
    4. 检查文件路径:Cron任务中的文件路径最好使用绝对路径。在脚本内部使用的文件路径也应是绝对路径。
    5. 调试技巧:在Cron任务中,将输出重定向到一个文件,是查看运行时错误的最佳方式,正如我们在任务定义中使用的>> /home/pi/iot_chart/cron.log 2>&1

这个从数据采集到Web可视化的完整链路,虽然以风速数据为例,但其架构和方法是通用的。你可以轻松地替换数据源(比如换成温湿度传感器DHT11的数据、电网功耗数据、甚至是股票价格),调整图表类型(比如用仪表盘显示实时速度,用柱状图显示每日最大值),来满足你自己物联网项目的可视化需求。核心思想就是:轻量、解耦、自动化。希望这个详细的实践记录能帮你少走弯路。

http://www.rkmt.cn/news/1442354.html

相关文章:

  • 2026广州黄金奢品变现去哪?本地靠谱门店深度测评 - 合扬奢侈品交易中心
  • 保姆级教程:用EB Tresos和S32DS从零搭建AutoSar MCAL基础工程(附完整配置流程)
  • 2026 年论文降 AI 工具横评,早标网为何能实现知网检测零通过率
  • 别再硬训CLIP了!手把手教你用EVA-CLIP的三大技巧,成本减半效果还更好
  • 9V电池驱动LED灯带:从电路原理到安全实操指南
  • 别再傻傻分不清了!用大白话讲明白DDR内存里的Burst和Prefetch到底啥区别
  • 现在不掌握Sora 2新闻视频工作流,半年后将被主流媒体编辑部淘汰?——基于27家央媒/省台HR招聘JD的技能断层预警分析
  • Vivado FPGA开发入门:从VHDL编码到Basys 3板卡下载全流程
  • 电机控制器实战:如何为你的IGBT驱动电路选择合适的退饱和保护芯片?(UCC21750/BM6101FV-E2/1EDI2002AS对比)
  • DIY红外遥控测试器:基于TSOP1738的电路设计与实践
  • 暗黑破坏神2存档编辑器:免费网页工具让D2/D2R存档编辑变得简单快速
  • Illustrator脚本集合:30个免费工具提升设计效率的终极指南
  • 大理双廊海景民宿排名|芒澍・陶唐之丘领衔,侘寂美学一线海景旅居精选 - 兔兔不是荼荼
  • 如何高效定制安全测试界面:完整品牌模拟技术指南
  • 2026深度测评10款降AIGC软件红黑榜!优劣对比全解析,达标率直接对标行业天花板 - 降AI小能手
  • Hotkey Detective:深度解析Windows热键冲突检测的技术实现与专业应用
  • SPLIDT技术:数据平面决策树部署的创新架构
  • 2026年4月不锈钢管供应商推荐,不锈钢无缝管/焊管/耐蚀合金无缝管/精密无缝管/BA不锈钢管,不锈钢管生产厂家推荐 - 品牌推荐师
  • TexasSolver:超越传统CFR的并行GTO求解引擎革新
  • Claude Code Dynamic Workflows:多智能体协作编程的范式革命
  • java基础之String类
  • 2026国内GEO优化服务商权威推荐榜(综合实力TOP5) - 星际AI
  • 全国油气回收设备2026最新厂家排行:实测参数与场景适配对比 - 奔跑123
  • Yakit安装踩坑实录:从下载到连接引擎的完整避坑指南(Windows/Mac)
  • 2026上海黄金回收机构评测白名单:基于11项量化指标的六家优选商户 - 天天生活分享日志
  • 2026 南宁品牌首饰回收靠谱商家清单,资质口碑俱佳 - 合扬奢侈品交易中心
  • 如何高效管理本地音乐库:Salt Player完整使用指南
  • 建筑门窗行业开齿机厂家实测排行及核心参数2026最新对比 - 奔跑123
  • 石家庄名表回收避坑干货,远离虚报报价不良商家 - 奢侈品回收测评
  • 避开FPGA时序验证的‘坑’:除了False Path,别忘了用Set_Case_Analysis处理这些情况