# EdgeManager(SCADA系统) - [EdgeManager(SCADA系统)](#edgemanagerscada系统) - [API](#api) - [class `EDataCapture`](#class-edatacapture) - [0. HTTP POST: `set_node_data`](#0-http-post-set_node_data) - [使用指北](#使用指北) - [后端](#后端) - [前端](#前端) - [开发环境](#开发环境) - [调试环境](#调试环境) - [技术细节](#技术细节) - [0. `EdgeManager\EDataCapture\EDataCapture -> set_data()`为什么是以`6710885`为大小chunked的?](#0-edgemanageredatacaptureedatacapture---set_data为什么是以6710885为大小chunked的) ## API > API设计最大程度遵循了已有的MES规范。 ### class `EDataCapture` #### 0. HTTP POST: `set_node_data` **请求** > 上位机程序中请单次传入尽量多的数据使得性能最大化。 > > 但仍需兼顾传输速率和超时时间。 > > 无需指定数值类型,服务端会自动根据已添加的节点信息检查,若不符则会报错。 ```json { "action": "set_node_data", "param": { "working_subclass": , "data": [ { "code": , // value的类型需与type对应 "value": , "device_code": [string], "batch": [string] }, { "code": , "value": , "device_code": [string], "batch": [string] }, ... ] } } ``` **返回** 操作成功: ```json { "action": "result_set_node_data", "errcode": 0, "errmsg": "" } ``` 操作失败(**工序单元尚未登记**): ```json { "action": "result_set_node_data", "errcode": 4002, "errmsg": "未登记过的工序单元!" } ``` 操作失败(**数值类型错误**): ```json { "action": "result_set_node_data", "errcode": 4002, "errmsg": "节点编码和数值类型不匹配!" } ``` 操作失败(不明原因): ```json { "action": "result_set_node_data", "errcode": 4002, "errmsg": "ROLLBACKed: Bad data received (structure and/or values)" } ``` ## 使用指北 本项目可独立运行,也可作为MES的插件使用。 下文简要介绍如何将代码合并入MES中。 需要保证`timescaledb`的版本在**2.2.0或以上**。 ### 后端 添加pg扩展(Ubuntu): ```bash sudo apt install php-pgsql ``` 添加pg扩展(CentOS 7): ```bash sudo yum install php-pgsql ``` 添加pg扩展(CentOS8): ```bash sudo dnf install php-pgsql ``` 目录结构: ```pre 📦EdgeManager ┣ 📂EDataCapture ┃ ┣ 📜EDataCapture.php ┃ ┗ 📜ENodeConfigure.php ┣ 📜Init.php ┗ 📜Utils.php ``` 建议使用composer autoload引入。 将目录`EdgeManager`复制至项目后在composer.json内写入: ```json "autoload": { "psr-4": { "EdgeManager\\": "EdgeManager/" }, "files": [ "EdgeManager/Utils.php", "EdgeManager/Init.php" ] }, ``` 运行`composer dump-autoload`即可正常调用EdgeManager的代码。 ### 前端 添加依赖(**使用npm**): ```bash npm i element-ui \ @d2-projects/d2-crud \ vue-cheetah-grid \ @d2-projects/vue-table-export \ @d2-projects/vue-table-import \ github-markdown-css \ marked@^2.0.0 \ jschardet -S ``` 添加依赖(**使用yarn**): ```bash yarn add element-ui \ @d2-projects/d2-crud \ vue-cheetah-grid \ @d2-projects/vue-table-export \ @d2-projects/vue-table-import \ github-markdown-css \ marked@^2.0.0 \ jschardet ``` 需要在`main.js`中增加(全局引入组件): ```js // D2-Crud import ElementUI from 'element-ui' import 'element-ui/lib/theme-chalk/index.css' import D2Crud from '@d2-projects/d2-crud' // Cheetah-Grid import vueCheetahGrid from 'vue-cheetah-grid' // 表格导出插件 import pluginExport from '@d2-projects/vue-table-export' import pluginImport from '@d2-projects/vue-table-import' Vue.use(ElementUI) Vue.use(D2Crud) Vue.use(vueCheetahGrid) Vue.use(pluginExport) Vue.use(pluginImport) ``` *(可选)* 在`package.json`里更改`element-ui`版本: ```json "element-ui": ">2.15.9 || 2.15.8", ``` `2.15.9`有一个小[bug](https://github.com/ElemeFE/element/issues/21941),会导致性能下降。 此外请参照目录结构中注释进行代码合并: ```pre 📦src ┣ 📂api ┃ ┣ 📂modules ┃ ┃ ┣ 📜scada.configure.api.js # 增添Axios请求 ┃ ┃ ┗ 📜sys.user.api.js ┃ ┣ 📜index.js ┃ ┣ 📜service.js ┃ ┗ 📜tools.js ┣ 📂assets ┣ 📂components ┃ ┣ 📂d2-markdown # 渲染markdown所需组件(在D2Admin的基础上精简了功能) ┃ ┃ ┗ 📜index.vue ┃ ┗ 📜index.js # 在此处注册d2-markdown ┣ 📂libs ┣ 📂locales ┣ 📂menu ┃ ┗ 📜index.js # 增添菜单 ┣ 📂plugin ┣ 📂router ┃ ┣ 📜index.js ┃ ┗ 📜routes.js # 增添路由 ┣ 📂store ┣ 📂views ┃ ┣ 📂scada # 增添页面 ┃ ┃ ┣ 📂scadaConfigure ┃ ┃ ┃ ┗ 📜index.vue ┃ ┃ ┗ 📂scadaQuery ┃ ┃ ┃ ┗ 📜index.vue ┃ ┗ 📂system ┣ 📜App.vue ┣ 📜i18n.js ┣ 📜main.js ┗ 📜setting.js ``` ## 开发环境 拉取代码: ```bash # 建议先配置SSH key pair git clone ssh://git@118.195.187.246:10022/ysun/EdgeManager.git cd EdgeManager ``` 一键部署PHP workerman和TimescaleDB环境: ```bash # docker build --network host -t edge_manager . docker compose up -d ``` 进入交互式Prompt: ```bash docker exec -it edge_manager bash ``` 后端调试: ```bash # In container php EdgeManager.php --server_name=GPU-server-01 --user=postgres --password=big_dick start ``` 前端调试: ```bash # In host # yarn # yarn watch yarn serve ``` 客户端连接: ```bash # sudo apt install postgresql-client # 登入 psql -h localhost -U postgres # 显示数据库列表 \l ``` ## 调试环境 不使用`docker compose`创建两个container分别运行EdgeManager和pg: ```bash # cd EdgeManager # 先定位到项目目录,方便创建image和挂载 # 创建EdgeManager的image docker build --network host -t edge_manager . # 创建container运行EdgeManager docker run --name edge_manager_test -v $PWD:/EdgeManager --network host -it edge_manager bash # 创建container运行pg,将端口映射到host的55432 docker run -d --name pg_test -v $PWD/config/postgresql.conf:/etc/postgresql/postgresql.conf -p 55432:5432 -e POSTGRES_PASSWORD=big_dick -it timescale/timescaledb-ha:pg14-latest postgres -c 'config_file=/etc/postgresql/postgresql.conf' # 进入交互式Prompt docker exec -it edge_manager_test bash # 启动EdgeManager(workerman)命令省略... # 常用命令 # 查看全部container docker ps -a # 启动已停止的container docker start [container] ``` ## 技术细节 ### 0. `EdgeManager\EDataCapture\EDataCapture -> set_data()`为什么是以`6710885`为大小chunked的? 首先明确一点,根据PostgreSQL的技术架构,条件允许的情况下,**一次性插入多条记录是效率最高的**,比如: ```sql INSERT INTO films (code, title, did, date_prod, kind) VALUES ('B6717', 'Tampopo', 110, '1985-02-10', 'Comedy'), ('HG120', 'The Dinner Game', 140, DEFAULT, 'Comedy'); ``` 这其中,仅插入部分字段的值,比如: ```sql INSERT INTO films (code, title, did, date_prod, kind) VALUES ('T_601', 'Yojimbo', 106, '1961-06-16', 'Drama'); ``` 的效率又远远不如插入全部列,但使用特殊变量DEFAULT替代缺少的字段,比如: ```sql INSERT INTO films VALUES ('UA502', 'Bananas', DEFAULT, '1971-07-13', 'Comedy', '82 minutes'); ``` PostgreSQL的文档里没有提及这个话题,因为源码里为SQL语句的内存分配[指定了一个最大长度常量`MaxAllocSize`](https://github.com/postgres/postgres/blob/2373fe78dfc9d4aa2348a86fffdf8eb9d757e9d5/src/common/stringinfo.c#L28),其大小为比1GB小1字节。这个值可以在编译前手动修改,所以理论上每个PG运行的实例都可以不一样,如果我们使用的PG并非修改过源码手动编译的,那么SQL语句的最大长度为`1024 ** 3 - 1 = 1073741823` bytes。 > 安全起见,下述计算假定working_subclass等字段的最大长度均为我们以往约定的45 bytes。 而此处我源码中的SQL语句头长度为138 bytes(注意末尾空格): ![](imgs/sql_head.png) 单个语句体的长度为160 bytes: ![](imgs/sql_body.png) 所以其最多可以一次性插入`(1073741823 - 138) / 160`条记录,向下取整后即为`6710885`。