Eclipse Ditto 物模型搭建

发布时间:2026/8/27 12:39:23

Eclipse Ditto 物模型搭建
需要知道Eclipse Ditto是什么 、怎么安装就点击下面的链接查阅。Eclipse Ditto 、 Mosquitto MQTT 、 OpenModelica 开发工具-CSDN博客Eclipse Ditto 开发环境 搭建-CSDN博客Eclipse Ditto开源物联网数字孪生平台技术深度解析 - 东峰叵,com - 博客园一、主要内容本文主要讲解Eclipse Ditto物模型的搭建及数据传输步骤供大家参考。二、界面预览下发的数据对应的控制面板三、Eclipse Ditto 物模型1创建物模型curl -X PUT http://localhost:8080/api/2/things/my-demo:device001 \ -u ditto:ditto \ -H Content-Type: application/json \ -d { attributes: { deviceName: 粉体料仓设备, model: TSK-001, location: 1号车间 }, features: { sensor: { properties: { pressure: 0, temperature: 25, level: 0, coConcentration: 0 } }, actuator: { properties: { valveOpen: false, fanRun: false } } } } 如果需要可以增加 { thingId: the.namespace:the-thing-id, policyId: the.namespace:the-policy-id }2测试反馈ianhang:~$ curl http://localhost:8080/api/2/things -u ditto:ditto [{thingId:my-demo:device001,policyId:my-demo:device001,attributes:{deviceName:粉体料仓设备,model:TSK-001,location:1号车间},features:{sensor:{properties:{pressure:-60,temperature:35,level:85,coConcentration:22}},actuator:{properties:{valveOpen:false,fanRun:false}}}}]四、代码文件展示src/utils/dittoWs.ts type DittoMsgCallback (msg: Recordstring, any) void export class DittoWebSocket { private ws: WebSocket | null null private url /ditto-ws private msgCallback: DittoMsgCallback | null null private reconnectTimer: number | null null private readonly RECONNECT_DELAY 3000 connect() { if (this.ws this.ws.readyState WebSocket.OPEN) return this.ws new WebSocket(this.url) this.bindEvent() } private bindEvent() { if (!this.ws) return this.ws.onopen () { console.log(✅ Ditto WebSocket 代理连接成功) this.subscribeAllThings() } this.ws.onmessage (ev) { try { const data JSON.parse(ev.data) console.log(收到Ditto原始消息, data) // 过滤错误消息不抛给页面 if(data.topic data.topic.includes(errors)) return this.msgCallback?.(data) } catch (err) { console.error(消息解析失败, ev.data, err) } } this.ws.onclose () { console.warn(WS断开3s后重连) this.reconnect() } this.ws.onerror (e) { console.error(WS异常, e) this.ws?.close() } } private reconnect() { if (this.reconnectTimer) clearTimeout(this.reconnectTimer) this.reconnectTimer window.setTimeout(() this.connect(), this.RECONNECT_DELAY) } // ✅ 修正订阅格式符合 Ditto WebSocket API subscribeAllThings() { const subCmd { topic: _/_/things/twin/commands/subscribe, headers: { response-required: false }, path: / } this.send(subCmd) console.log(✅ 标准订阅报文已发送) } // ✅ 新增检索指定 thing 的完整状态 retrieveThing(thingId: string) { const [ns, id] thingId.split(:) const cmd { topic: ${ns}/${id}/things/twin/commands/retrieve, headers: { response-required: true }, path: / } this.send(cmd) console.log(✅ 检索报文已发送: ${thingId}) } send(data: Recordstring, any) { if (!this.ws || this.ws.readyState ! WebSocket.OPEN) { console.warn(WS未就绪发送失败) return } this.ws.send(JSON.stringify(data)) } setMessageCallback(cb: DittoMsgCallback) { this.msgCallback cb } close() { if (this.reconnectTimer) clearTimeout(this.reconnectTimer) this.ws?.close() this.ws null } // 控制执行器格式正确未改动 controlActuator(thingId: string, valveOpen: boolean, fanRun: boolean) { const [ns, id] thingId.split(:) const cmd { topic: ${ns}/${id}/things/twin/commands/modify, path: features/actuator/properties, value: { valveOpen, fanRun } } this.send(cmd) } } export const dittoWs new DittoWebSocket() DigitalTwin.vue文件内容 template div classtwin-container h2 classtitle数字孪生设备实时面板/h2 div v-ifdeviceData classdevice-card p classrow span classlabel设备ID/span span classval{{ deviceId }}/span /p p classrow span classlabel仓内负压/span span classval{{ deviceData.features?.sensor?.properties?.pressure }} kPa/span /p p classrow span classlabel温度/span span classval{{ deviceData.features?.sensor?.properties?.temperature }} ℃/span /p p classrow span classlabel料位/span span classval{{ deviceData.features?.sensor?.properties?.level }} %/span /p p classrow span classlabelCO浓度/span span classval{{ deviceData.features?.sensor?.properties?.coConcentration }}/span /p div classdivider/div div classbtn-group button clicksetValve(true)打开卸料阀/button button clicksetValve(false)关闭卸料阀/button button clicksetFan(true)启动风机/button button clicksetFan(false)停止风机/button /div /div div v-else classloading 正在加载设备数据... /div /div /template script setup langts import { ref, onMounted, onUnmounted } from vue const deviceId my-demo:device001 const deviceData refany(null) let pollTimer: number | null null // 拉取设备全量数据 async function fetchThing() { try { const res await fetch(/api/2/things/${deviceId}) if (res.ok) { deviceData.value await res.json() } } catch (err) { console.error(拉取设备数据失败, err) } } // 修改执行器状态 async function updateActuator(data: Recordstring, boolean) { try { await fetch(/api/2/things/${deviceId}/features/actuator/properties, { method: PUT, headers: { Content-Type: application/json }, body: JSON.stringify(data) }) fetchThing() } catch (err) { console.error(修改执行器失败, err) } } // 按钮操作 const setValve (open: boolean) { if (!deviceData.value) return const fanRun deviceData.value.features?.actuator?.properties?.fanRun ?? false updateActuator({ valveOpen: open, fanRun }) } const setFan (run: boolean) { if (!deviceData.value) return const valveOpen deviceData.value.features?.actuator?.properties?.valveOpen ?? false updateActuator({ valveOpen, fanRun: run }) } onMounted(() { fetchThing() // 2秒轮询一次模拟实时更新 pollTimer window.setInterval(fetchThing, 2000) }) onUnmounted(() { if (pollTimer) clearInterval(pollTimer) }) /script style scoped .twin-container { padding: 16px; color: #e8f0ff; } .title { margin: 0 0 16px; font-size: 18px; color: #ffffff; } .device-card { font-size: 14px; } .row { display: flex; margin: 8px 0; } .label { width: 100px; color: #a0c4e8; } .val { color: #fff; } .divider { height: 1px; background: rgba(255,255,255,0.2); margin: 16px 0; } .btn-group { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; } button { border: none; border-radius: 4px; padding: 8px 0; background: #1f589c; color: white; cursor: pointer; } button:hover { background: #2b72c2; } .loading { color: #b4cce6; text-align: center; margin-top: 40px; } /style vite.config.js文件内容 import { defineConfig } from vite import vue from vitejs/plugin-vue import { resolve } from path export default defineConfig({ plugins: [vue()], resolve: { alias: { : resolve(__dirname, src) } }, server: { proxy: { // 直接对齐 Ditto 原生 /api 前缀自动携带鉴权无需路径重写 /api: { target: http://localhost:8080, changeOrigin: true, headers: { Authorization: Basic ZGl0dG86ZGl0dG8 } }, // WebSocket 通道代理后续升级实时推送备用 /ws/2: { target: ws://localhost:8080, ws: true, changeOrigin: true, headers: { Authorization: Basic ZGl0dG86ZGl0dG8 } } } } })五、数据联动1点击开卸料阀按钮和启动风机按钮后界面2点击关闭卸料阀按钮和关闭风机按钮后界面3检查数据流正常

相关新闻

Java工程师资格证?别被忽悠了!个人根本报不了名

Java工程师资格证?别被忽悠了!个人根本报不了名

2026/8/27 12:39:07

什么是 Ja 书, 需要啥条件, 各位学员, 大家好。到 2025 年, 就目前这种状况而言, 个人没办法报考 Ja 工程师证书, 得去询问了解报考 Ja 工程师证书的培训机构, 以及进行报考事宜, 之后由培训机构统一向上报送。然后去参加包括报名、学习、培训等一系列的整个流程。它是经过权威…

free-stockdb免费开源的本地股票数据库

free-stockdb免费开源的本地股票数据库

2026/8/26 22:37:04

什么是free-stockdb 这是一个基于c的股票专用定制版纯磁盘存储数据库,项目地址: https://github.com/hello245m/free-stockdb 为什么选free-stockdb? ❤️ 日线分钟线数据前/后复权,2000年到2026-07-06 最全历史最新数据&#x…

前端学习日志:从零开始构建个人复盘网站(2026年7月3日)

前端学习日志:从零开始构建个人复盘网站(2026年7月3日)

2026/8/23 18:27:00

1. 今日学习目标与项目启动今天是 2026年7月3日,我正式开始了前端开发的学习之旅。我的第一个项目目标是:在AI的协助下,独立完成一个个人复盘网站。这个网站将作为我学习过程的记录和复盘工具,计划包含以下核心功能模块&#xff1…

halcon之第4讲--亚像素以及相应算子学习

halcon之第4讲--亚像素以及相应算子学习

2026/8/27 12:37:59

文章目录前言亚像素(XLD)介绍生成XLD的常用算子edges_sub_pixthreshold_sub_pixgen_contour_region_xld筛选、分割、拼接轮廓select_contours_xldsegment_contours_xldsplit_contours_xld拟合常用算子fit_line_contour_xldfit_circle_contour_xld算子fit…

Python构建AI股票分析系统:从数据获取到策略回测全流程详解

Python构建AI股票分析系统:从数据获取到策略回测全流程详解

2026/8/27 12:37:59

简介:机器学习与深度学习作为人工智能的核心技术,通过从数据中自动学习模式与规律,为复杂决策提供支持。其原理在于利用算法构建模型,对历史数据进行训练,从而实现对未知数据的预测或分类。在金融科技领域,…

回归分析实战指南:从线性回归到Cox模型,掌握数据建模核心

回归分析实战指南:从线性回归到Cox模型,掌握数据建模核心

2026/8/27 12:37:59

1. 从“相关性”到“因果性”的桥梁:回归分析到底是什么?如果你在数据分析、金融风控、市场研究甚至生物统计领域工作过,那么“回归分析”这个词你肯定不陌生。它可能是你工具箱里最常用,但也最容易用错的一把“瑞士军刀”。很多人…

基于大数据的专业智能导学系统的设计与实现(毕业设计项目源码+文档)

基于大数据的专业智能导学系统的设计与实现(毕业设计项目源码+文档)

2026/8/27 12:37:59

温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台…

LVD+CFCR:线性调频信号参数估计的工程实战指南

LVD+CFCR:线性调频信号参数估计的工程实战指南

2026/8/27 12:37:59

简介:在雷达、声呐与振动分析等工程领域,线性调频(Chirp)信号的频率随时间线性变化,精确估计其中心频率与调频斜率是关键任务。传统短时傅里叶变换受窗长限制分辨率不足,Wigner-Ville分布则易受交叉项干扰。…

从蓝桥杯真题解析“车的放置”:组合数学与回溯算法的实战应用

从蓝桥杯真题解析“车的放置”:组合数学与回溯算法的实战应用

2026/8/27 12:27:58

1. 项目概述:从一道蓝桥杯真题看“车的放置”问题最近在整理蓝桥杯的备赛资料,翻到了ALGO-996这道题——“车的放置”。这题目名字听起来平平无奇,不就是国际象棋里“车”(Rook)的摆放问题吗?但真正上手去解…

[光学原理与应用-521]:对光的错误理解与纠偏

[光学原理与应用-521]:对光的错误理解与纠偏

2026/8/27 11:10:02

首先光是一种能量的载体和形态,宏观上观察到的光是由无数个微观的光量子组成的,每个光子在产生的瞬间,其在真空的空间中以确定不变的速度沿着一个初始的方向一直向前,在微观层面,每个光量子的运动轨迹是以波函数所展现…

SIP通话转接原理与REFER方法实战解析

SIP通话转接原理与REFER方法实战解析

2026/8/27 7:25:23

1. 通话转接不是“挂断再拨号”,而是SIP会话的动态重定向你有没有遇到过这样的场景:客服坐席A正在和客户通电话,突然需要把这通对话无缝转给专家坐席B,客户完全感知不到中间的断连——既没听到忙音,也没被要求重新拨号…

Kolla-ansible单节点OpenStack部署实战:从环境准备到排坑指南

Kolla-ansible单节点OpenStack部署实战:从环境准备到排坑指南

2026/8/26 17:50:58

1. 为什么选择Kolla-ansible来部署单节点OpenStack?如果你正在寻找一种能把OpenStack从“概念”快速变成“可用的实验环境”的方法,那么Kolla-ansible几乎是当前最主流、最省心的选择。我见过太多人卡在手动编译依赖、配置服务、处理版本冲突的泥潭里&am…

Go语言构建企业级AI服务网关:统一管理英伟达等AI接口调用

Go语言构建企业级AI服务网关:统一管理英伟达等AI接口调用

2026/8/27 0:07:12

1. 项目概述:从零构建一个企业级的AI服务网关 最近在帮一个做内容审核的团队做技术架构升级,他们原来的业务里,每天有几十万张图片和短视频需要过审,最初是接了几个开源的AI模型自己部署,但效果和性能一直不太稳定。后…

LeetCode Hot100(51-60)算法精解与面试技巧

LeetCode Hot100(51-60)算法精解与面试技巧

2026/8/27 0:07:12

1. 题目背景与核心价值"hot100(51-60)"这个标题看起来像是某个编程题库或算法练习集中的一组题目编号。在技术社区中,类似命名通常指向LeetCode、牛客网等平台的热门题目集合。作为刷过300题的算法老手,我理解这类题目的核心价值在于&#xff…

CRC校验实战:从模2除法到HJ212协议排错

CRC校验实战:从模2除法到HJ212协议排错

2026/8/27 0:07:12

1. 为什么一个“校验码”能扛住工业现场90%的数据 corruption? 你有没有遇到过这样的场景:嵌入式设备通过RS-485上传温湿度数据,上位机偶尔收到一帧乱码——温度显示成-273℃,湿度跳到999%,但串口波形看起来完全正常&a…

摆脱论文困扰!盘点2026年全网爆红的的AI论文写作工具

摆脱论文困扰!盘点2026年全网爆红的的AI论文写作工具

2026/8/22 2:02:26

一天写完毕业论文在2026年已不再是天方夜谭。2026年最炸裂、实测能大幅提速的AI论文写作工具,覆盖选题构思、文献整理、内容生成、格式排版等核心场景,真正帮你高效搞定论文难题。 一、全流程王者:一站式搞定论文全链路(一天定稿首…

导师推荐!2026最新AI论文工具测评与实用推荐

导师推荐!2026最新AI论文工具测评与实用推荐

2026/8/26 18:07:30

2026年真正好用的AI论文工具,核心看生成的论文质量、低AI味、格式正确、学术适配四大指标。综合实测,千笔AI、ThouPen、豆包、DeepSeek、Grammarly 是当前最值得推荐的梯队,覆盖从免费到付费、从中文到英文、从文科到理工的全场景需求。 一、…

告别游戏崩溃:XCOM 2模组管理器的智能革命

告别游戏崩溃:XCOM 2模组管理器的智能革命

2026/8/26 17:57:52

告别游戏崩溃:XCOM 2模组管理器的智能革命 【免费下载链接】xcom2-launcher The Alternative Mod Launcher (AML) is a replacement for the default game launchers from XCOM 2 and XCOM Chimera Squad. 项目地址: https://gitcode.com/gh_mirrors/xc/xcom2-lau…