1. 效果预览
这个例子包括,串口的打开和发送,包括字符串的发送和hex 的发送。最终效果如图。
点线面低代码应用下载
GitHub 下载地址 https://github.com/dotLinePlane-com/dotlineplane/releases
通过百度网盘分享的文件:dotLinePlaneV2.1.0.7z 链接:https://pan.baidu.com/s/1XUl32fFD3ssZoPMqC4NmQw?pwd=qn0d 提取码:qn0d
2. 具体步骤
创建一个应用主要有四个步骤,包括:拖拽组件、设置组件属性、编写js脚本和设置组件事件与脚本关联。
2.1 拖拽组件
界面的右边选择拖拽到画布中。
使用的组件有 dropdown (端口和波特率)、按钮(打开和发送)、复选框(Hex 发送)、文本输入框(发送区)和 多行文本输入框(接收区和log)
2.2 设置组件属性
这里主要设置组件的名称属性,其他的有程序设置。
端口----》dropdownPort
波特率----》dropdownBaud
复选框----》HexSendCheckbox
发送区----》send
接收区----》recivedData
log----》log
2.3 添加 js 脚本
***添加 init 脚本时,注意需要在Settings 中打开 在应用程序加载时运行此查询
init
//init 脚本 // 获取串口列表 const ports = await serialAPI.getSerialPorts(); console.log("v port :", ports); // 格式化串口数据 let formattedPorts = ports.map(port => ({ disable: false, visible: true, value: port.path, label: port.friendlyName || port.path, })); console.log("port:", formattedPorts); // 获取 defaultPortsValue, portsLabel 和 portsValue const defaultPortsValue = formattedPorts.length > 0 ? formattedPorts[0].value : null; const portsLabel = formattedPorts.map(port => port.label); const portsValue = formattedPorts.map(port => port.value); const portsSelect = { defaultPortsValue, portsLabel, portsValue, }; const baudsValue = [9600, 115200]; const baudsLabel = ["9600", "115200"]; const defaultBaudsValue = baudsValue[0]; const baudsSelect = { defaultBaudsValue, baudsValue, baudsLabel, }; // 更新 formattedPorts 对象结构 const formattedPortsObject = { portsSelect, baudsSelect, }; console.log("formattedPortsObject:", formattedPortsObject); // 设置页面变量 await actions.setPageVariable('ports', formattedPortsObject); await actions.setPageVariable('serialRx', ''); await actions.setPageVariable('isOpen', false); // 定义处理串口数据的函数 const handleSerialData = async (path, data) => { if (path === page.variables.usedPort) { const receiveTime = Date.now(); console.log(`[${new Date(receiveTime).toISOString()}] Received data:`, data); await actions.setPageVariable('serialRx', data); } }; // 初始化串口连接 const initializeSerialConnection = async () => { if (page.variables.isOpen) { // 设置使用的串口 await actions.setPageVariable('usedPort', components.dropdownPort.value); serialAPI.onSerialData(components.dropdownPort.value, handleSerialData); } else { await actions.setPageVariable('usedPort', ''); // serialAPI.offSerialData(portRef.current, handleSerialData); } }; // 在页面加载时执行初始化 await initializeSerialConnection(); // 返回格式化后的串口对象 return formattedPortsObject;
openPort
//openPort function mergeUint8Arrays(arrays) { console.log(`Received data:`, arrays); if (arrays instanceof Uint8Array) { arrays = [arrays]; } if (!Array.isArray(arrays)) { console.error("Input is not an array."); return null; } // 确保数组中的每个元素都是 Uint8Array for (let i = 0; i < arrays.length; i++) { if (!(arrays[i] instanceof Uint8Array)) { console.error(`Element at index ${i} is not a Uint8Array.`); return null; } } // 计算总长度 const totalLength = arrays.reduce((sum, arr) => sum + arr.length, 0); // 创建新的 Uint8Array const mergedArray = new Uint8Array(totalLength); // 复制数据 let offset = 0; arrays.forEach(arr => { mergedArray.set(arr, offset); offset += arr.length; }); return mergedArray; } const handleSerialData = async (path, data) => { if (path === page.variables.usedPort) { const receiveTime = Date.now(); console.log(`[${new Date(receiveTime).toISOString()}] Received data:`, data); const mergeData = mergeUint8Arrays(data); const decoder = new TextDecoder('utf-8'); const stringData = decoder.decode(mergeData); console.log("serialRx:",stringData); await actions.setPageVariable('serialRx', stringData); } }; if (!page.variables.isOpen) { // Open the serial port const config = { path:components.dropdownPort.value, baudRate: parseInt(components.dropdownBaud.value, 10), dataBits:8, parity:'none', stopBits:1, // dataBits: parseInt(components.dropdownBits.value, 10), // parity: components.dropdownCrc.value === 'NONE' ? 'none' : components.dropdownCrc.value.toLowerCase(), // stopBits: parseInt(components.dropdownStop.value, 10), }; try { const result = await serialAPI.openSerialPort(config); console.log(result); await actions.setPageVariable('usedPort', components.dropdownPort.value); serialAPI.onSerialData(components.dropdownPort.value, handleSerialData); await actions.setPageVariable('isOpen', true); components.openButton.setText("关闭"); } catch (error) { console.error('Failed to open serial port:', error); } } else { // Close the serial port try { await serialAPI.closeSerialPort(page.variables.usedPort); serialAPI.offSerialData(page.variables.usedPort, handleSerialData); await actions.setPageVariable('isOpen', false); components.openButton.setText("打开"); } catch (error) { console.error('Failed to close serial port:', error); await actions.setPageVariable('isOpen', false); components.openButton.setText("打开"); if(page.variables.usedPort){ serialAPI.offSerialData(page.variables.usedPort, handleSerialData); } } } return 0;
sendData
//sendData function hexStringToUint8Array(hexString) { // 确保字符串长度为偶数 if (hexString.length % 2 !== 0) { return null; } // 创建一个 Uint8Array,长度为字符串长度的一半 const length = hexString.length / 2; const uint8Array = new Uint8Array(length); // 遍历字符串,每两个字符解析为一个字节 for (let i = 0; i < length; i++) { const byteHex = hexString.substr(i * 2, 2); // 提取两个字符 uint8Array[i] = parseInt(byteHex, 16); // 将 16 进制字符串解析为数字 } return uint8Array; } if(page.variables.isOpen){ if(!components.HexSendCheckbox.value){ serialAPI.writeSerialPort(page.variables.usedPort,components.sendData.value); }else{ const hexSend = hexStringToUint8Array(components.sendData.value); if(hexSend){ serialAPI.writeSerialPort(page.variables.usedPort,hexSend); // actions.showAlert("info:"+ "发送成功"); // 使用 ToolJet 的 toast 组件 actions.setVariable("infoMessage", "发送成功"); // queries.log.run() await actions.runQuery('log',{message: "发送成功"}); } } }
log
//log // 更新 log 内容 components.log.setText(components.log.value + variables.infoMessage + "\r\n"); // 获取 TextArea 元素 // 获取外层 div 元素 const textareaWrapper = document.getElementById(components.log.id); // 从外层 div 中找到 textarea 元素 const textareaElement = textareaWrapper ? textareaWrapper.querySelector("textarea") : null; // 检查是否成功获取 textarea if (textareaElement) { // 滚动到 textarea 的底部 textareaElement.scrollTop = textareaElement.scrollHeight; }
2.4 组件事件与js脚本进行关联
3. 结束
更多的细节需要你自己的探索,那就开始你的点线面低代码的探索之旅吧!
有问题可以私信我,也可以在应用程序中找到联系方式,单独交流。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 本地部署 DeepSeek:小白也能轻松搞定!
· 传国玉玺易主,ai.com竟然跳转到国产AI
· 自己如何在本地电脑从零搭建DeepSeek!手把手教学,快来看看! (建议收藏)
· 我们是如何解决abp身上的几个痛点
· 如何基于DeepSeek开展AI项目