5、FUXA ODBC 配置与实战

手把手教你用开源 HMI 工具 FUXA 对接 MySQL、PostgreSQL、SQL Server,实现报警记录、生产报表、工单同步等高级功能!


在工业自动化项目中,你是否遇到过这些场景?

  • 想把 PLC 的报警信息自动存到数据库,方便后期分析?
  • 需要从 MES 系统读取当日工单,并在 HMI 上显示?
  • 希望操作员点击"保存"按钮,就把产品批次写入 SQL Server?
  • 但又不想花大价钱买商业 SCADA 的历史数据库模块?

好消息是------开源 HMI 工具 FUXA 完全可以做到!

通过 ODBC 接口 ,FUXA 能轻松连接 MySQL、PostgreSQL、SQL Server 等主流数据库,实现数据双向交互。今天,我们就来从零开始,一步步配置并实战应用


🔧 一、为什么选 FUXA + ODBC?

FUXA 是一个基于 Web 的开源 SCADA/HMI 框架,支持 Modbus、S7、OPC UA 等工业协议。而它的 ODBC 功能,让你能:

  • 将实时数据持久化存储
  • 查询历史记录生成报表
  • 与企业 ERP/MES 系统集成
  • 构建完整的"边缘采集 + 中心存储"架构

最关键的是:完全免费、开源、可私有部署


🐳 二、最快上手方式:用 Docker 一键启动

如果你只是想快速测试,强烈推荐使用官方 Docker 镜像------已内置所有常用 ODBC 驱动

复制代码
docker run -d -p 1881:1881 --name fuxa frangoteam/fuxa:latest

访问 http://你的IP:1881,即可打开 FUXA 编辑器。

✅ 无需安装驱动,开箱即用!

💡 提示:生产环境建议挂载配置卷,避免重启丢失工程。


⚙️ 三、本地部署?手动安装 ODBC 驱动也不难!

如果你在 Ubuntu/Debian 上用 NPM 安装 FUXA,则需手动配置驱动。

第一步:安装基础依赖
复制代码
sudo apt update
sudo apt install -y unixodbc unixodbc-dev
第二步:下载 FUXA 官方驱动包

前往 GitHub 仓库的 odbc 目录,下载:

  • install_odbc_drivers.sh
  • odbcinst.ini
第三步:运行安装脚本
复制代码
chmod +x install_odbc_drivers.sh
sudo ./install_odbc_drivers.sh
sudo cp odbcinst.ini /etc/odbcinst.ini

完成后,执行 odbcinst -q -d,应能看到:

复制代码
[MySQL]
[PostgreSQL]
[ODBC Driver 17 for SQL Server]

✅ 驱动就绪!


🌐 四、两种连接方式:DSN vs 连接字符串

方式 1:配置 DSN(适合固定部署)

编辑 /etc/odbc.ini

复制代码
[my-mysql-db]
Driver = MySQL
Server = 192.168.1.50
Database = factory_db
User = scada
Password = your_password
Port = 3306

测试连接:

复制代码
isql my-mysql-db
方式 2:直接用连接字符串(推荐!灵活迁移)

在 FUXA 设备配置中填写:

复制代码
DRIVER=PostgreSQL Unicode;SERVER=10.0.0.10;PORT=5432;DATABASE=plant;UID=scada;PWD=pass;

✅ 优点:不依赖服务器配置,工程可移植性强。


🖥️ 五、在 FUXA 中添加 ODBC 设备

  1. 打开 FUXA 编辑器 → Devices+ Add Device
  2. 类型选择 ODBC
  3. Name 填 myDB(后续脚本中引用)
  4. Connection 填 DSN 名或完整连接串
  5. 保存!

💻 六、实战代码:读写数据库就这么简单!

场景 1:每秒读取最新报警
复制代码
// Server Script
setInterval(async () => {
  const db = await $getDevice('myDB', true);
  const alarms = await db.pool.query(
    'SELECT * FROM alarms WHERE resolved = false ORDER BY time DESC'
  );
  $setTag($getTagId('activeAlarms'), JSON.stringify(alarms));
}, 1000);
场景 2:点击按钮保存产品信息
复制代码
// 边沿检测,防止重复触发
let lastClick = false;
setInterval(async () => {
  const clicked = $getTag($getTagId('btnSave'));
  const name = $getTag($getTagId('productName'));

  if (clicked && !lastClick) {
    const db = await $getDevice('myDB', true);
    await db.pool.query(
      'INSERT INTO products (name, created_at) VALUES (?, NOW())',
      [name]
    );
  }
  lastClick = clicked;
}, 100);
场景 3:前端表格展示历史数据
  • Server 脚本定时拉取数据并存入 Tag
  • Client 脚本解析 JSON 并绑定到 Table 控件
  • 用户看到动态刷新的生产报表!
步骤 1:Server 脚本定时拉取数据

位置:View 编辑器 → 右侧 "Script" 标签 → 切换到 Server 选项卡

复制代码
// === Server Script: 定时从数据库拉取数据并更新 Tag ===

// 每 2000 毫秒(2秒)执行一次
setInterval(async () => {
  try {
    // 1. 获取已配置的 ODBC 设备(名称需与 Devices 中一致)
    const db = await $getDevice('myProductionDB', true); // ← 替换为你自己的设备名!

    // 2. 执行 SQL 查询(以 PostgreSQL 为例)
    // 注意:PostgreSQL 表名区分大小写,建议加双引号
    const result = await db.pool.query(`
      SELECT 
        "id",
        "product_name" AS name,
        "output_qty" AS qty,
        "shift",
        TO_CHAR("log_time", 'YYYY-MM-DD HH24:MI:SS') AS time
      FROM "production_log"
      ORDER BY "log_time" DESC
      LIMIT 50
    `);

    // 3. 将结果转为 JSON 字符串,存入 Tag
    const jsonData = JSON.stringify(result);
    $setTag($getTagId('productionTableData'), jsonData);

    // 可选:打印日志(在 FUXA 后台 Console 查看)
    console.log(`[DB] Fetched ${result.length} records`);

  } catch (error) {
    console.error('[DB ERROR]', error.message || error);
    // 即使出错,也可清空表格或显示错误提示
    $setTag($getTagId('productionTableData'), '[]');
  }
}, 2000);

🔧 你需要修改的地方

  • 'myProductionDB' → 替换为你在 Devices 中创建的 ODBC 设备名称
  • SQL 语句 → 根据你的实际表结构调整字段名和表名
步骤 2:Client 脚本绑定到 Table 控件

位置:View 编辑器 → "Script" 标签 → 切换到 Client 选项卡

复制代码
// === Client Script: 监听 Tag 变化,更新前端表格 ===

// 监听 productionTableData 的变化
$watch($getTagId('productionTableData'), (newValue) => {
  if (!newValue || newValue === '[]') {
    // 数据为空时清空表格
    const emptyTable = { columns: [], rows: [] };
    $invokeObject('productionTable', 'setTableAndData', emptyTable);
    return;
  }

  try {
    // 解析 JSON 数据
    const rows = JSON.parse(newValue);

    // 定义表格列(必须与 SQL 查询的 AS 别名一致)
    const columns = [
      { id: 'id', label: 'ID', width: 60 },
      { id: 'name', label: '产品名称', width: 120 },
      { id: 'qty', label: '产量', width: 80 },
      { id: 'shift', label: '班次', width: 80 },
      { id: 'time', label: '时间', width: 160 }
    ];

    // 构造表格数据对象
    const tableData = {
      columns: columns,
      rows: rows
    };

    // 调用 Table 控件的方法更新内容
    $invokeObject('productionTable', 'setTableAndData', tableData);

  } catch (e) {
    console.error('Failed to parse table data:', e);
    // 可选:显示错误提示
    alert('表格数据解析失败,请检查数据库返回格式');
  }
});

✅ 关键点:

  • 使用 $watch 监听 Tag 变化,自动响应更新
  • columns.id 必须与 SQL 中的字段别名(AS)完全一致
  • $invokeObject('productionTable', ...) 中的 ID 必须与 Table 控件 ID 一致

⚠️ 七、避坑指南:这些细节你必须知道

|-----------------|-----------------------------|
| 问题 | 解决方案 |
| MySQL 连不上 | 加 SSLMODE=DISABLED (测试环境) |
| PostgreSQL 表名报错 | 用双引号:"Customer" |
| 脚本改了没生效 | 重启 FUXA 服务 |
| 密码明文不安全 | 用环境变量或加密 Tag |
| 高频写入卡顿 | 降低轮询频率,启用连接池 |


🚀 八、不止于数据库:FUXA 的更多可能

  • 结合 Node-RED 做数据清洗
  • WebSocket 推送实时变化
  • 部署在 树莓派 上做边缘 HMI
  • 对接 阿里云/华为云 IoT 平台

FUXA 不只是一个 HMI,更是你构建 低成本工业智能系统 的核心引擎!


📣 结语

开源的力量,正在改变工业软件的格局。

FUXA + ODBC,让你用 零成本 实现过去万元级 SCADA 才有的数据库功能。

🔗 项目地址:https://github.com/frangoteam/FUXA

📘 官方 Wiki:https://github.com/frangoteam/FUXA/wiki/HowTo-ODBC

如果你觉得有用,欢迎点赞、转发,或在评论区留下你的应用场景!

相关推荐
欢乐熊嵌入式编程18 小时前
IoT 场景中的 DHCP、ARP、ICMP 到底在干嘛?
物联网·wifi·dhcp·iot wifi
MDIOT旗舰18 小时前
ZL401核心板:一站式物联网数据采集的理想之选
物联网·无线通信·数据采集·智能硬件·工业物联网·4g通信·cat1模块
DS小龙哥18 小时前
基于STM32设计的智能鞋柜【华为云IOT】
stm32·物联网·华为云
WangUnionpub18 小时前
2026 国自然基金申请全周期时间线
大数据·人工智能·物联网·机器学习·计算机视觉
DBA小马哥18 小时前
时序数据库在物联网中的应用
数据库·物联网·时序数据库
乾元19 小时前
IoT 大量接入场景下的网络切片与安全隔离——AI 驱动的策略生成、验证与落地工程
运维·网络·人工智能·物联网·网络协议·安全
珠海西格电力1 天前
零碳园区有哪些政策支持?
大数据·数据库·人工智能·物联网·能源
金线银线还是铜线?1 天前
米德方格MF9005/MF9006:低功耗光能利用的PMIC芯片解析
嵌入式硬件·物联网·iot·太阳能
pingao1413781 天前
物联网赋能供暖:插座式室温采集器,数据驱动高效管理
物联网·信息可视化