├── .gitignore
├── README.md
├── _config.yml
├── babel.config.js
├── package-lock.json
├── package.json
├── public
├── favicon.ico
└── index.html
├── src
├── App.vue
├── assets
│ ├── logo.png
│ └── nebula-helper.png
├── background.js
├── components
│ └── Main.vue
├── main.js
└── plugins
│ └── element.js
└── vue.config.js
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /dist
4 |
5 | # local env files
6 | .env.local
7 | .env.*.local
8 |
9 | # Log files
10 | npm-debug.log*
11 | yarn-debug.log*
12 | yarn-error.log*
13 | pnpm-debug.log*
14 |
15 | # Editor directories and files
16 | .idea
17 | .vscode
18 | *.suo
19 | *.ntvs*
20 | *.njsproj
21 | *.sln
22 | *.sw?
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Nebula Helper
2 | > 使用 Vue + Electron + node-serialport 实现的现代串行端口调试助手
3 | A modern serial port debugging assistant implemented using Vue + Electron + node-serialport
4 | ## 项目地址
5 | [GitHub](https://github.com/rymcu/nebula-helper) | [Gitee](https://gitee.com/ronger-x/nebula-helper)
6 | ## 功能特性
7 | - [x] 基础串口通信
8 | - [x] 自动发送信息
9 | - [x] 16 进制收发信息
10 | - [x] 停止/恢复显示
11 | - [x] 文件传输
12 | - [x] 保存/加载配置信息
13 | - [x] 刷新串口列表(手动刷新 视图->刷新串口列表)
14 | - [ ] 版本更新(不用每次下载完整的安装包,仅 `app.asar` 文件)
15 | ## 未来计划
16 | - [ ] 单片机程序下载(拷录程序到单片机)
17 | ## 开发指南
18 | > 本项目使用 Electron + Vue + Node-serialport 实现,以下步骤是 windows 操作系统环境配置步骤,1-5 步为安装 node-gyp ,其他操作系统请参考[官方教程](https://github.com/nodejs/node-gyp)
19 | 1. 安装 LTS 版 NodeJS
20 | 2. 安装 Python 2.7
21 | 3. 安装 Visitor Studio 2017 及更高版本(我使用的是 2019)
22 | 4. 执行 `npm install node-gyp -g`
23 | 5. 执行 `node-gyp list` 查看依赖是否全部安装
24 | 6. 执行 `git clone https://github.com/rymcu/nebula-helper.git`
25 | 7. 执行 `npm install`
26 | 8. 执行 `npm run electron:serve`
27 | ## 项目截图
28 | 
29 | ## 鸣谢
30 | - [Electron](https://github.com/electron/electron) :electron: Build cross-platform desktop apps with JavaScript, HTML, and CSS
31 | - [Vue](https://github.com/vuejs/vue) 🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
32 | - [node-serialport](https://github.com/serialport/node-serialport) Access serial ports with JavaScript. Linux, OSX and Windows. Welcome your robotic JavaScript overlords. Better yet, program them!
33 | - [vue-cli-plugin-electron-builder](https://github.com/nklayman/vue-cli-plugin-electron-builder) Easily Build Your Vue.js App For Desktop With Electron
34 | "# nebula-iot-helper"
35 |
--------------------------------------------------------------------------------
/_config.yml:
--------------------------------------------------------------------------------
1 | theme: jekyll-theme-architect
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [
3 | '@vue/cli-plugin-babel/preset'
4 | ]
5 | }
6 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "nebula-helper",
3 | "version": "0.1.5",
4 | "private": true,
5 | "scripts": {
6 | "serve": "vue-cli-service serve",
7 | "build": "vue-cli-service build",
8 | "lint": "vue-cli-service lint",
9 | "electron:build": "vue-cli-service electron:build",
10 | "electron:serve": "vue-cli-service electron:serve",
11 | "postinstall": "electron-builder install-app-deps",
12 | "postuninstall": "electron-builder install-app-deps",
13 | "install": "npm rebuild --runtime=electron --target=8.4.0 --disturl=https://npm.taobao.org/mirrors/atom-shell --abi=76"
14 | },
15 | "author": {
16 | "name": "ronger",
17 | "email": "ronger-x@outlook.com",
18 | "url": "https://rymcu.com"
19 | },
20 | "main": "background.js",
21 | "dependencies": {
22 | "@serialport/bindings": "^9.0.0",
23 | "core-js": "^3.6.5",
24 | "electron-log": "^4.2.2",
25 | "element-ui": "^2.4.5",
26 | "iconv-lite": "^0.6.2",
27 | "serialport": "^9.0.0",
28 | "vue": "^2.6.11"
29 | },
30 | "devDependencies": {
31 | "@vue/cli-plugin-babel": "^4.4.0",
32 | "@vue/cli-plugin-eslint": "^4.4.0",
33 | "@vue/cli-service": "^4.4.0",
34 | "babel-eslint": "^10.1.0",
35 | "electron": "^8.4.0",
36 | "electron-devtools-installer": "^3.1.0",
37 | "eslint": "^6.7.2",
38 | "eslint-plugin-vue": "^6.2.2",
39 | "vue-cli-plugin-electron-builder": "^2.0.0-rc.4",
40 | "vue-cli-plugin-element": "^1.0.1",
41 | "vue-template-compiler": "^2.6.11"
42 | },
43 | "eslintConfig": {
44 | "root": true,
45 | "env": {
46 | "node": true
47 | },
48 | "extends": [
49 | "plugin:vue/essential",
50 | "eslint:recommended"
51 | ],
52 | "parserOptions": {
53 | "parser": "babel-eslint"
54 | },
55 | "rules": {}
56 | },
57 | "browserslist": [
58 | "> 1%",
59 | "last 2 versions",
60 | "not dead"
61 | ]
62 | }
63 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rymcu/nebula-helper/80c742bf46b4c0fe9be4ab55014d4e7362c30726/public/favicon.ico
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | <%= htmlWebpackPlugin.options.title %>
9 |
12 |
13 |
14 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
16 |
17 |
26 |
--------------------------------------------------------------------------------
/src/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rymcu/nebula-helper/80c742bf46b4c0fe9be4ab55014d4e7362c30726/src/assets/logo.png
--------------------------------------------------------------------------------
/src/assets/nebula-helper.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rymcu/nebula-helper/80c742bf46b4c0fe9be4ab55014d4e7362c30726/src/assets/nebula-helper.png
--------------------------------------------------------------------------------
/src/background.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | import {app, protocol, BrowserWindow, Menu, shell} from 'electron'
4 | import {createProtocol} from 'vue-cli-plugin-electron-builder/lib'
5 | import installExtension, {VUEJS_DEVTOOLS} from 'electron-devtools-installer'
6 |
7 | const isDevelopment = process.env.NODE_ENV !== 'production'
8 | const serialPort = require('serialport');
9 | const iconv = require('iconv-lite');
10 |
11 | const log = require('electron-log')
12 | console.log = log.log
13 |
14 | const fs = require('fs');
15 |
16 | global.SerialPort = serialPort;
17 | global.iconv = iconv;
18 | global.log = log.log;
19 | global.fs = fs;
20 |
21 | let menuTemplate = [
22 | {
23 | label: '文件',
24 | role: 'fileMenu',
25 | submenu: [
26 | {
27 | label: '保存接收数据',
28 | accelerator: 'Ctrl + S',
29 | click: function () {
30 | win.webContents.send('writeFile');
31 | }
32 | },
33 | {
34 | label: '读取文件数据',
35 | accelerator: 'Ctrl + L',
36 | click: function () {
37 | win.webContents.send('readFile');
38 | }
39 | }
40 | ,
41 | {
42 | label: '保存配置信息',
43 | accelerator: 'Ctrl + 1',
44 | click: function () {
45 | win.webContents.send('saveOptions');
46 | }
47 | },
48 | {
49 | label: '加载配置文件',
50 | accelerator: 'Ctrl + 2',
51 | click: function () {
52 | win.webContents.send('loadOptions');
53 | }
54 | },
55 | {
56 | label: '关闭',
57 | accelerator: 'Ctrl + W',
58 | click: function () {
59 | app.quit();
60 | }
61 | }
62 | ]
63 | },
64 | {
65 | label: '视图',
66 | role: 'viewMenu',
67 | submenu: [
68 | {
69 | label: '刷新端口列表',
70 | accelerator: 'Ctrl + R',
71 | click: function () {
72 | win.webContents.send('reloadPorts');
73 | }
74 | }
75 | ]
76 | },
77 | {
78 | label: '帮助',
79 | role: 'help',
80 | accelerator: 'Ctrl + H',
81 | submenu: [
82 | {
83 | label: '问题反馈',
84 | click: function () {
85 | shell.openExternal('https://github.com/rymcu/nebula-helper/issues')
86 | }
87 | },
88 | {
89 | label: '关于我们',
90 | click: function () {
91 | shell.openExternal('https://rymcu.com')
92 | }
93 | }
94 | ]
95 | }
96 | ]
97 | // Keep a global reference of the window object, if you don't, the window will
98 | // be closed automatically when the JavaScript object is garbage collected.
99 | let win
100 |
101 | // Scheme must be registered before the app is ready
102 | protocol.registerSchemesAsPrivileged([
103 | {scheme: 'app', privileges: {secure: true, standard: true}}
104 | ])
105 |
106 | function createWindow() {
107 | // Create the browser window.
108 | win = new BrowserWindow({
109 | width: 800,
110 | height: 600,
111 | resizable: false,
112 | webPreferences: {
113 | // Use pluginOptions.nodeIntegration, leave this alone
114 | // See nklayman.github.io/vue-cli-plugin-electron-builder/guide/security.html#node-integration for more info
115 | // nodeIntegration: process.env.ELECTRON_NODE_INTEGRATION
116 | nodeIntegration: true,
117 | nodeIntegrationInWorker: true
118 | },
119 | show: false
120 | })
121 |
122 | if (process.env.WEBPACK_DEV_SERVER_URL) {
123 | // Load the url of the dev server if in development mode
124 | win.loadURL(process.env.WEBPACK_DEV_SERVER_URL)
125 | if (!process.env.IS_TEST) win.webContents.openDevTools()
126 | } else {
127 | createProtocol('app')
128 | // Load the index.html when not in development
129 | win.loadURL('app://./index.html')
130 | }
131 |
132 | win.on('closed', () => {
133 | win = null
134 | })
135 |
136 | win.once('ready-to-show', () => {
137 | win.show()
138 | })
139 |
140 | const menu = Menu.buildFromTemplate(menuTemplate);
141 | Menu.setApplicationMenu(menu);
142 | }
143 |
144 | // Quit when all windows are closed.
145 | app.on('window-all-closed', () => {
146 | // On macOS it is common for applications and their menu bar
147 | // to stay active until the user quits explicitly with Cmd + Q
148 | if (process.platform !== 'darwin') {
149 | app.quit()
150 | }
151 | })
152 |
153 | app.on('activate', () => {
154 | // On macOS it's common to re-create a window in the app when the
155 | // dock icon is clicked and there are no other windows open.
156 | if (win === null) {
157 | createWindow()
158 | }
159 | })
160 |
161 | // This method will be called when Electron has finished
162 | // initialization and is ready to create browser windows.
163 | // Some APIs can only be used after this event occurs.
164 | app.on('ready', async () => {
165 | if (isDevelopment && !process.env.IS_TEST) {
166 | // Install Vue Devtools
167 | try {
168 | await installExtension(VUEJS_DEVTOOLS)
169 | } catch (e) {
170 | console.error('Vue Devtools failed to install:', e.toString())
171 | }
172 | }
173 | createWindow()
174 | })
175 |
176 | // Exit cleanly on request from parent process in development mode.
177 | if (isDevelopment) {
178 | if (process.platform === 'win32') {
179 | process.on('message', (data) => {
180 | if (data === 'graceful-exit') {
181 | app.quit()
182 | }
183 | })
184 | } else {
185 | process.on('SIGTERM', () => {
186 | app.quit()
187 | })
188 | }
189 | }
190 |
--------------------------------------------------------------------------------
/src/components/Main.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
9 |
10 |
11 |
12 |
13 |
15 |
16 |
17 |
18 |
19 |
21 |
22 |
23 |
24 |
25 |
27 |
28 |
29 |
30 |
31 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 | 打开串口
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 | 关闭串口
49 |
50 |
51 |
52 |
53 |
54 |
55 | 清空接收区
56 |
57 |
58 | 停止显示
59 | 恢复显示
60 |
61 |
62 | 保存接收数据
63 |
64 |
65 |
66 |
67 | 自动清空
68 |
69 |
70 | 十六进制显示
71 |
72 |
73 |
74 |
75 |
76 | {{stateText}}
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 | 自动发送周期
92 | 毫秒
93 |
94 |
95 |
96 | 自动发送
97 | 十六进制发送
98 |
99 |
100 |
101 | Tx: {{pushBit}}
102 |
103 |
104 |
105 |
106 | Rx: {{pullBit}}
107 |
108 |
109 |
110 |
111 | 读取文件
112 | 清空重填
113 | 计数清零
114 | 手动发送
115 |
116 |
117 |
118 |
119 |
120 |
121 |
698 |
699 |
701 |
--------------------------------------------------------------------------------
/src/main.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import App from './App.vue'
3 | import './plugins/element.js'
4 | Vue.config.productionTip = false
5 |
6 | new Vue({
7 | render: h => h(App),
8 | }).$mount('#app')
9 |
--------------------------------------------------------------------------------
/src/plugins/element.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Element from 'element-ui'
3 | import 'element-ui/lib/theme-chalk/index.css'
4 |
5 | Vue.use(Element)
6 |
--------------------------------------------------------------------------------
/vue.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | pluginOptions: {
3 | electronBuilder: {
4 | builderOptions: {
5 | "appId": "com.rymcu.nebula-helper",
6 | "productName": "nebula-helper",
7 | "copyright": "Copyright © rymcu.com",
8 | "win": {
9 | "icon": "./favicon.ico",
10 | "target": [
11 | {
12 | "target": "nsis",
13 | "arch": [
14 | "x64",
15 | "ia32"
16 | ]
17 | }
18 | ]
19 | },
20 | "linux": {
21 | "icon": "./favicon.ico",
22 | "target": [
23 | "snap"
24 | ]
25 | }
26 | }
27 | }
28 | }
29 | }
--------------------------------------------------------------------------------