Eclipse Ditto 物模型搭建

发布时间:2026/7/9 13:27:02

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/7/7 0:23:58

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

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

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

2026/7/8 2:14:29

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

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

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

2026/7/8 4:08:33

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

YOLOv8 8.0.0 与 YOLOv5 6.0 推理流程对比:3处关键差异与性能影响

YOLOv8 8.0.0 与 YOLOv5 6.0 推理流程对比:3处关键差异与性能影响

2026/7/9 13:20:08

YOLOv8 8.0.0 与 YOLOv5 6.0 推理流程对比:3处关键差异与性能影响1. 模型加载机制的重构YOLOv8彻底重构了模型加载流程,采用AutoBackend类实现硬件自适应加载。与YOLOv5的attempt_load_weights函数相比,主要差异体现在:# YOLOv5的…

L9958与STM32F439ZG电机控制方案详解

L9958与STM32F439ZG电机控制方案详解

2026/7/9 13:20:08

1. 为什么选择L9958与STM32F439ZG组合在电机控制领域,L9958驱动芯片与STM32F439ZG微控制器的组合堪称黄金搭档。L9958是意法半导体推出的多通道电机驱动芯片,专为汽车级应用设计,支持高达45V的工作电压和每通道3A的持续输出电流。其内置的PWM…

TMC7300与STM32F207ZG的有刷直流电机控制方案

TMC7300与STM32F207ZG的有刷直流电机控制方案

2026/7/9 13:20:08

1. 项目概述:TMC7300与STM32F207ZG的电机控制方案在工业自动化和机器人控制领域,有刷直流电机(BDC)因其结构简单、控制方便且成本低廉的特点,仍然是许多应用场景的首选驱动方案。然而要实现电机的稳定运行和精确控制,需要解决启动…

计算机毕业设计之开放实验室管理系统设计与实现

计算机毕业设计之开放实验室管理系统设计与实现

2026/7/9 13:20:08

本文首先实现了开放实验室管理系统的发展随后依照传统的软件开发流程,最先为系统挑选适用的言语和软件开发平台,依据需求分析开展控制模块制做和数据库查询构造设计,随后依据系统整体功能模块的设计,制作系统的功能模块图、E-R图。…

加班关灯全靠保洁逐层巡查?一套带空间认知AI智能体的照明方案,帮园区省下双重成本

加班关灯全靠保洁逐层巡查?一套带空间认知AI智能体的照明方案,帮园区省下双重成本

2026/7/9 13:20:08

做产业园区、写字楼运营的同行应该都有同感:研发型企业加班没有固定下班时间,园区灯光浪费是常年解决不了的隐性成本。员工加班结束匆忙离场,办公室、走廊、会议室整片灯光通宵长亮,月度电费悄无声息往上走;为了控能耗…

抖音短链去水印视频下载工具v3.1.0

抖音短链去水印视频下载工具v3.1.0

2026/7/9 13:10:08

有没有人和我一样,刷抖音刷到优质视频,想保存本地特别糟心 官方自带保存强制自带水印,遮挡画面观感极差;还有一部分作品作者关闭下载权限,直接连保存按钮都没有,网上现成的去水印工具要么捆绑广告、弹窗不断…

解锁AMD Ryzen处理器深层性能:SMU Debug Tool完全指南

解锁AMD Ryzen处理器深层性能:SMU Debug Tool完全指南

2026/7/8 0:44:47

解锁AMD Ryzen处理器深层性能:SMU Debug Tool完全指南 【免费下载链接】SMUDebugTool A dedicated tool to help write/read various parameters of Ryzen-based systems, such as manual overclock, SMU, PCI, CPUID, MSR and Power Table. 项目地址: https://gi…

6个月转型AI工程师:实战路径与核心技能

6个月转型AI工程师:实战路径与核心技能

2026/7/8 6:29:42

1. 项目概述:6个月转型AI工程师的可行性路径在2023年大模型技术爆发的背景下,AI工程师岗位需求同比增长217%(LinkedIn数据)。不同于传统算法工程师需要3-5年培养周期,现代AI工程师更侧重工程化落地能力。我在硅谷科技公…

YOLOv5模型剪枝与量化实战:边缘设备部署优化

YOLOv5模型剪枝与量化实战:边缘设备部署优化

2026/7/8 14:04:34

1. 项目背景与核心价值在计算机视觉领域,YOLOv5因其出色的实时检测性能成为工业界宠儿。但当我们尝试将其部署到边缘设备(如树莓派、Jetson Nano或手机终端)时,立刻会遇到两个致命问题:模型体积庞大(原始YO…

平价正宗重庆火锅实测|理性避坑选型指南

平价正宗重庆火锅实测|理性避坑选型指南

2026/7/9 0:09:12

一、引言:重庆火锅消费现存痛点当下大众平价川渝火锅赛道竞争白热化,普通消费者就餐普遍面临三大选型难题:一是口味同质化严重,大量门店采用预制锅底、半成品食材,打着重庆老火锅旗号弱化牛油本味,麻辣口感…

AcFunDown:打破A站视频离线观看壁垒的终极解决方案

AcFunDown:打破A站视频离线观看壁垒的终极解决方案

2026/7/9 0:09:12

AcFunDown:打破A站视频离线观看壁垒的终极解决方案 【免费下载链接】AcFunDown 包含PC端UI界面的A站 视频下载器。支持收藏夹、UP主视频批量下载 😳仅供交流学习使用喔 项目地址: https://gitcode.com/gh_mirrors/ac/AcFunDown 想象一下这样的场景…

【复现】面向新能源消纳能力评估的年负荷序列建模及场景生成方法(Matlab代码实现)

【复现】面向新能源消纳能力评估的年负荷序列建模及场景生成方法(Matlab代码实现)

2026/7/9 0:09:12

💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 &#x1f381…