mirror of
https://github.com/emqx/neuron.git
synced 2026-10-29 23:19:18 +08:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bca973293d | ||
|
|
1ef579ae45 | ||
|
|
cd0d26c110 | ||
|
|
b77ba27b24 | ||
|
|
7055ac2fb8 | ||
|
|
d3358cfb6f | ||
|
|
e90c1352d7 | ||
|
|
0499f6050c | ||
|
|
6424cfc33b | ||
|
|
88fcb9dcff | ||
|
|
ed3fb2ef60 | ||
|
|
3d705aa772 | ||
|
|
31bd132398 | ||
|
|
bf8a1a7891 | ||
|
|
be831d7333 | ||
|
|
59f1f5d97d | ||
|
|
31ffde8406 | ||
|
|
a03385af37 | ||
|
|
1f7e0ed700 | ||
|
|
c9531705bd | ||
|
|
60f4d77501 | ||
|
|
a71e2e3cbe | ||
|
|
776563a2ff | ||
|
|
5360d20da1 | ||
|
|
8be6cda1b1 | ||
|
|
f28842224d | ||
|
|
f8e879c989 | ||
|
|
a8ce8c9da0 | ||
|
|
ebc6a076fc | ||
|
|
bbad12cdd6 | ||
|
|
9614b509b1 | ||
|
|
11db02ccf5 | ||
|
|
c0dbdf39ff | ||
|
|
10c89daf5e | ||
|
|
94e492652a | ||
|
|
87aac219d7 | ||
|
|
7fdd4c4f79 | ||
|
|
7c46a3ec06 | ||
|
|
065d77dd5d | ||
|
|
68d8632fcd | ||
|
|
84ca0952e8 | ||
|
|
f74d55a98c | ||
|
|
f0d20ec77b | ||
|
|
9693d50dd0 | ||
|
|
e34d7bf3e5 | ||
|
|
8fe1202d3f | ||
|
|
11672c62ee | ||
|
|
af8d29f9e9 | ||
|
|
96fc6ebf6e | ||
|
|
b922905e39 | ||
|
|
b49f39729a | ||
|
|
128bc2820b | ||
|
|
5e33fc9d17 | ||
|
|
b1d410e497 | ||
|
|
2c09db89c0 | ||
|
|
40025265f2 | ||
|
|
725618d345 | ||
|
|
e61826de1c | ||
|
|
4beaa8c113 | ||
|
|
fbe5c2f42b | ||
|
|
6d90208a6e | ||
|
|
9c7d95d3a1 | ||
|
|
c2a59e9a23 | ||
|
|
71227496ac | ||
|
|
52d15c31de | ||
|
|
3fb501630a | ||
|
|
2b814b8fe2 | ||
|
|
336563834b | ||
|
|
59e7ff3e60 | ||
|
|
b145220585 | ||
|
|
3e4489d2c2 | ||
|
|
74dc6b9489 | ||
|
|
d6e94f7009 | ||
|
|
8930b16948 | ||
|
|
d95137d1a3 | ||
|
|
21ff7aea65 | ||
|
|
58cc696e5e | ||
|
|
76ea51be2b | ||
|
|
b91b2ef55d | ||
|
|
8fc783e679 | ||
|
|
36e66e1521 | ||
|
|
2ad3c5e87c | ||
|
|
d51ef29568 | ||
|
|
b3d88977bf | ||
|
|
330a58f825 | ||
|
|
c779d86da2 | ||
|
|
0b3075e94d | ||
|
|
33d317551c | ||
|
|
1f019eb02b | ||
|
|
2e407c3e6e | ||
|
|
a4fb604db7 | ||
|
|
090650c5c4 | ||
|
|
d6c0c04feb | ||
|
|
bf548c974f | ||
|
|
54aa2a15b3 | ||
|
|
e3040ea184 | ||
|
|
9d02f1faec | ||
|
|
34f64c832f | ||
|
|
93b488a02c |
+69
-66
@@ -9,25 +9,24 @@ on:
|
||||
|
||||
jobs:
|
||||
clang_format_check:
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-20.04
|
||||
|
||||
steps:
|
||||
# checkout
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Run clang-format style check for C/C++ programs.
|
||||
uses: DoozyX/clang-format-lint-action@v0.18
|
||||
uses: DoozyX/clang-format-lint-action@v0.12
|
||||
with:
|
||||
source: 'src plugins include tests'
|
||||
exclude: 'include/neuron/utils/uthash.h include/neuron/utils/utarray.h include/neuron/utils/utlist.h include/neuron/utils/zlog.h src/otel/trace.pb-c.h src/otel/trace.pb-c.c src/otel/resource.pb-c.h src/otel/resource.pb-c.c src/otel/common.pb-c.c src/otel/common.pb-c.h plugins/mqtt/ptformat.pb-c.h plugins/mqtt/ptformat.pb-c.c'
|
||||
style: file
|
||||
exclude: 'include/neuron/utils/uthash.h include/neuron/utils/utarray.h include/neuron/utils/utlist.h include/neuron/utils/zlog.h'
|
||||
clangFormatVersion: 10
|
||||
style: file
|
||||
|
||||
cppcheck:
|
||||
runs-on: ubuntu-24.04
|
||||
container: ghcr.io/neugates/build:x86_64-v2.13
|
||||
runs-on: ubuntu-20.04
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@@ -36,25 +35,14 @@ jobs:
|
||||
|
||||
- name: cppcheck
|
||||
run: |
|
||||
sudo apt install -y cppcheck
|
||||
cppcheck --enable=all --error-exitcode=2 --inline-suppr --suppress=missingInclude --suppress=unusedFunction --suppress=*:src/otel/trace.pb-c.c --suppress=*:src/otel/common.pb-c.c --suppress=*:src/otel/resource.pb-c.c ./plugins ./src
|
||||
cppcheck --enable=all --error-exitcode=2 --inline-suppr --suppress=missingInclude --suppress=variableScope ./simulator
|
||||
sudo apt install cppcheck
|
||||
cppcheck --enable=all --error-exitcode=2 --inline-suppr --suppress=missingInclude --suppress=unusedFunction ./plugins ./src
|
||||
cppcheck --enable=all --error-exitcode=2 --inline-suppr --suppress=missingInclude --suppress=unusedFunction --suppress=variableScope ./simulator
|
||||
|
||||
flawfinder:
|
||||
name: Flawfinder Scan
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v6
|
||||
ut:
|
||||
runs-on: ubuntu-20.04
|
||||
container: ghcr.io/neugates/build:x86_64-v2.7
|
||||
|
||||
- name: flawfinder_scan
|
||||
uses: david-a-wheeler/flawfinder@2.0.20
|
||||
with:
|
||||
arguments: '--minlevel=3 .'
|
||||
|
||||
build:
|
||||
runs-on: ubuntu-24.04
|
||||
container: ghcr.io/neugates/build:x86_64-v2.13
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@@ -66,44 +54,66 @@ jobs:
|
||||
git config --global --add safe.directory $(pwd)
|
||||
mkdir -p build && cd build
|
||||
cmake -DUSE_GCOV=1 .. -DCMAKE_TOOLCHAIN_FILE=../cmake/x86_64-linux-gnu.cmake
|
||||
make -j4
|
||||
make -j4
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
- name: unit test
|
||||
run: |
|
||||
cd build
|
||||
sudo apt-get update
|
||||
sudo apt install -y lcov
|
||||
ctest --output-on-failure -O tests/ut/reports/ut.log --output-junit tests/ut/reports/output.xml
|
||||
lcov --capture --directory . --output-file testneuron.info --test-name testneuron
|
||||
genhtml -o result testneuron.info
|
||||
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: neuron-build
|
||||
name: ut_result
|
||||
path: |
|
||||
build
|
||||
build/tests/ut/reports/ut.log
|
||||
build/tests/ut/reports/output.xml
|
||||
build/result/index.html
|
||||
build/neuron.log
|
||||
|
||||
|
||||
ut:
|
||||
runs-on: ubuntu-24.04
|
||||
container: ghcr.io/neugates/build:x86_64-v2.13
|
||||
needs: [build]
|
||||
ft:
|
||||
runs-on: ubuntu-20.04
|
||||
container: ghcr.io/neugates/build:x86_64-v2.7
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: neuron-build
|
||||
path: ./build
|
||||
|
||||
- name: unit test
|
||||
|
||||
- name: compile
|
||||
run: |
|
||||
chmod -R +x ./build/
|
||||
cd build
|
||||
git config --global --add safe.directory $(pwd)
|
||||
mkdir -p build && cd build
|
||||
cmake -DUSE_GCOV=1 .. -DCMAKE_TOOLCHAIN_FILE=../cmake/x86_64-linux-gnu.cmake
|
||||
ctest --output-on-failure
|
||||
make -j4
|
||||
|
||||
- name: function test
|
||||
run: |
|
||||
sudo apt-get install -y mosquitto
|
||||
mosquitto -v &
|
||||
python3 -m pip install -U pip
|
||||
python3 -m pip install -r ft/requirements.txt
|
||||
python3 -m robot --maxerrorlines=600 -P ft/ -d ft/reports ft
|
||||
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ft_result
|
||||
path: |
|
||||
ft/reports/log.html
|
||||
ft/reports/output.xml
|
||||
ft/reports/report.html
|
||||
build/neuron.log
|
||||
|
||||
pft:
|
||||
runs-on: ubuntu-24.04
|
||||
container: ghcr.io/neugates/build:x86_64-v2.13
|
||||
needs: [build]
|
||||
runs-on: ubuntu-20.04
|
||||
container: ghcr.io/neugates/build:x86_64-v2.7
|
||||
strategy:
|
||||
matrix:
|
||||
plugin: [core, ekuiper, modbus, mqtt, metrics]
|
||||
plugin: [core, modbus, mqtt, metrics]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
@@ -111,33 +121,26 @@ jobs:
|
||||
|
||||
- name: setup dependencies
|
||||
run: |
|
||||
sudo apt-get install -y mosquitto
|
||||
pip install -U pytest requests prometheus-client gmqtt pynng sniffio
|
||||
sudo apt-get install -y socat
|
||||
if [ "${{ matrix.plugin }}" = "mqtt" ]; then
|
||||
sudo apt-get install -y mosquitto
|
||||
pip install -U gmqtt
|
||||
fi
|
||||
pip install -U pytest requests prometheus-client
|
||||
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: neuron-build
|
||||
path: ./build
|
||||
- name: compile
|
||||
run: |
|
||||
git config --global --add safe.directory $(pwd)
|
||||
mkdir -p build && cd build
|
||||
cmake -DUSE_GCOV=1 .. -DCMAKE_TOOLCHAIN_FILE=../cmake/x86_64-linux-gnu.cmake
|
||||
make -j4
|
||||
|
||||
- name: function test
|
||||
run: |
|
||||
chmod -R +x ./build/
|
||||
cd build
|
||||
cmake -DUSE_GCOV=1 .. -DCMAKE_TOOLCHAIN_FILE=../cmake/x86_64-linux-gnu.cmake
|
||||
cd ..
|
||||
if [ "${{ matrix.plugin }}" = "core" ]; then
|
||||
pytest -s -v tests/ft \
|
||||
--ignore=tests/ft/app/test_ekuiper.py \
|
||||
--ignore=tests/ft/app/test_mqtt.py \
|
||||
--ignore=tests/ft/app/test_azure.py \
|
||||
--ignore=tests/ft/driver/test_modbus.py \
|
||||
--ignore=tests/ft/metrics/test_metrics.py \
|
||||
--ignore=tests/ft/login/test_launch.py \
|
||||
--ignore=tests/ft/login/test_filter_error.py \
|
||||
--ignore=tests/ft/login/test_login.py
|
||||
elif [ "${{ matrix.plugin }}" = "ekuiper" ]; then
|
||||
pytest -s -v tests/ft/app/"test_ekuiper.py"
|
||||
--ignore=tests/ft/metrics/test_metrics.py
|
||||
elif [ "${{ matrix.plugin }}" = "modbus" ]; then
|
||||
pytest -s -v tests/ft/driver/"test_modbus.py"
|
||||
elif [ "${{ matrix.plugin }}" = "mqtt" ]; then
|
||||
|
||||
+15
-17
@@ -8,18 +8,20 @@ on:
|
||||
- published
|
||||
|
||||
env:
|
||||
VERSION: 2.13.2
|
||||
UI_VERSION: 2.6.1
|
||||
BRANCH: v2.13
|
||||
VERSION: 2.7.4
|
||||
UI_VERSION: 2.6.3
|
||||
BRANCH: v2.7
|
||||
|
||||
jobs:
|
||||
cross-build:
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-20.04
|
||||
strategy:
|
||||
matrix:
|
||||
arch:
|
||||
- [aarch64-linux-gnu, aarch64, arm64]
|
||||
- [arm-linux-gnueabihf, armv4, armhf]
|
||||
- [x86_64-linux-gnu, x86_64, amd64]
|
||||
container: ghcr.io/neugates/build:${{ matrix.arch[1] }}-v2.13
|
||||
container: ghcr.io/neugates/build:${{ matrix.arch[1] }}-v2.7
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@@ -50,19 +52,19 @@ jobs:
|
||||
run: |
|
||||
./package-sdk.sh -p ${{ matrix.arch[2] }} -n neuron-sdk-$VERSION
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: neuron-sdk-${{ matrix.arch[2] }}
|
||||
name: neuron-sdk
|
||||
path: |
|
||||
neuron-sdk-*.tar.gz
|
||||
|
||||
build-debug-sdk:
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-20.04
|
||||
strategy:
|
||||
matrix:
|
||||
arch:
|
||||
- [x86_64-linux-gnu, x86_64, amd64]
|
||||
container: ghcr.io/neugates/build:${{ matrix.arch[1] }}-v2.13
|
||||
container: ghcr.io/neugates/build:${{ matrix.arch[1] }}-v2.7
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@@ -81,9 +83,9 @@ jobs:
|
||||
run: |
|
||||
./package-sdk.sh -p ${{ matrix.arch[2] }} -n neuron-sdk-debug-$VERSION
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: neuron-sdk-debug
|
||||
name: neuron-sdk
|
||||
path: |
|
||||
neuron-sdk-debug-*.tar.gz
|
||||
|
||||
@@ -100,13 +102,9 @@ jobs:
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- uses: actions/download-artifact@v4
|
||||
- uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: neuron-sdk-debug
|
||||
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: neuron-sdk-amd64
|
||||
name: neuron-sdk
|
||||
|
||||
- uses: softprops/action-gh-release@v1
|
||||
env:
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
name: Translate Issue from Chinese to English
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
issue_number:
|
||||
description: 'The issue number to translate'
|
||||
required: true
|
||||
type: string
|
||||
issues:
|
||||
types: [opened]
|
||||
|
||||
jobs:
|
||||
translate:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
issues: write # Grant permission to edit issues
|
||||
steps:
|
||||
- uses: emqx/translate-issue-action@ee63ec619dfc5808ee2093dba93dfd7ac3beb437 # v1.0.2
|
||||
with:
|
||||
issue_number: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.issue_number || github.event.issue.number }}
|
||||
gemini_api_key: ${{ secrets.GEMINI_API_KEY }}
|
||||
@@ -1,71 +0,0 @@
|
||||
name: manual check
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
plugins:
|
||||
description: 'Comma separated list of plugins to test (default: all unused plugins)'
|
||||
required: false
|
||||
default: 'azure,launch'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-24.04
|
||||
container: ghcr.io/neugates/build:x86_64-v2.13
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: compile
|
||||
run: |
|
||||
git config --global --add safe.directory $(pwd)
|
||||
mkdir -p build && cd build
|
||||
cmake .. -DCMAKE_TOOLCHAIN_FILE=../cmake/x86_64-linux-gnu.cmake
|
||||
make -j4
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: neuron-build-unused-plugins
|
||||
path: |
|
||||
build
|
||||
|
||||
unused_plugins_test:
|
||||
runs-on: ubuntu-24.04
|
||||
container: ghcr.io/neugates/build:x86_64-v2.13
|
||||
needs: [build]
|
||||
strategy:
|
||||
matrix:
|
||||
plugin: [azure, launch]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: setup dependencies
|
||||
run: |
|
||||
sudo apt-get install -y mosquitto
|
||||
pip install -U pytest requests prometheus-client gmqtt pynng sniffio
|
||||
sudo apt-get install -y socat
|
||||
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: neuron-build-unused-plugins
|
||||
path: ./build
|
||||
|
||||
- name: function test
|
||||
run: |
|
||||
chmod -R +x ./build/
|
||||
cd build
|
||||
cmake .. -DCMAKE_TOOLCHAIN_FILE=../cmake/x86_64-linux-gnu.cmake
|
||||
cd ..
|
||||
if [ "${{ matrix.plugin }}" = "azure" ]; then
|
||||
pytest -s -v tests/ft/app/"test_azure.py"
|
||||
elif [ "${{ matrix.plugin }}" = "launch" ]; then
|
||||
pytest -s -v tests/ft/login
|
||||
fi
|
||||
|
||||
- name: Test completed
|
||||
run: |
|
||||
echo "Testing for ${{ matrix.plugin }} completed successfully"
|
||||
+1
-2
@@ -19,5 +19,4 @@ neuron-sdk
|
||||
.vscode
|
||||
log.html
|
||||
output.xml
|
||||
report.html
|
||||
*.cache
|
||||
report.html
|
||||
+12
-36
@@ -54,27 +54,20 @@ add_custom_target(neuron-version
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/cmake/neuron-version.cmake)
|
||||
|
||||
find_package(nng CONFIG REQUIRED)
|
||||
find_package(LibXml2 REQUIRED)
|
||||
find_package(Threads)
|
||||
set(OPENSSL_USE_STATIC_LIBS TRUE)
|
||||
find_package(OpenSSL REQUIRED)
|
||||
|
||||
if (CMAKE_STAGING_PREFIX)
|
||||
include_directories(${CMAKE_STAGING_PREFIX}/include)
|
||||
link_directories(${CMAKE_STAGING_PREFIX}/lib)
|
||||
include_directories(${CMAKE_STAGING_PREFIX}/include/libxml2)
|
||||
else()
|
||||
include_directories(/usr/local/include)
|
||||
link_directories(/usr/local/lib)
|
||||
include_directories(/usr/local/include/libxml2)
|
||||
endif()
|
||||
|
||||
set(PERSIST_SOURCES
|
||||
src/persist/persist.c
|
||||
src/persist/sqlite.c
|
||||
src/persist/json/persist_json_plugin.c)
|
||||
aux_source_directory(src/parser NEURON_SRC_PARSE)
|
||||
aux_source_directory(src/otel NEURON_SRC_OTEL)
|
||||
set(NEURON_BASE_SOURCES
|
||||
src/base/tag.c
|
||||
src/base/neu_plugin_common.c
|
||||
@@ -82,6 +75,7 @@ set(NEURON_BASE_SOURCES
|
||||
src/base/group.c
|
||||
src/base/metrics.c
|
||||
src/base/msg.c
|
||||
src/base/template.c
|
||||
src/connection/connection.c
|
||||
src/connection/connection_eth.c
|
||||
src/connection/mqtt_client.c
|
||||
@@ -91,12 +85,11 @@ set(NEURON_BASE_SOURCES
|
||||
src/utils/json.c
|
||||
src/utils/http.c
|
||||
src/utils/http_handler.c
|
||||
src/utils/http_proxy.c
|
||||
src/utils/neu_jwt.c
|
||||
src/utils/base64.c
|
||||
src/utils/async_queue.c
|
||||
src/utils/log.c
|
||||
src/utils/cid.c
|
||||
src/utils/tpy.c
|
||||
${PERSIST_SOURCES})
|
||||
|
||||
if (SMART_LINK)
|
||||
@@ -111,24 +104,13 @@ if (CLIB)
|
||||
endif()
|
||||
|
||||
|
||||
if (USE_MQTT_SM)
|
||||
message(STATUS "use mqtt sm")
|
||||
add_definitions(-DNEU_USE_MQTT_SM)
|
||||
endif()
|
||||
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Release")
|
||||
message(STATUS "build release")
|
||||
add_definitions(-DNEU_RELEASE)
|
||||
endif()
|
||||
|
||||
|
||||
add_library(neuron-base SHARED)
|
||||
target_sources(neuron-base PRIVATE ${NEURON_BASE_SOURCES} ${NEURON_SRC_PARSE} ${NEURON_SRC_OTEL})
|
||||
target_sources(neuron-base PRIVATE ${NEURON_BASE_SOURCES} ${NEURON_SRC_PARSE})
|
||||
target_include_directories(neuron-base
|
||||
PRIVATE include/neuron src)
|
||||
target_link_libraries(neuron-base OpenSSL::SSL OpenSSL::Crypto)
|
||||
target_link_libraries(neuron-base nng libzlog.so jansson jwt xml2
|
||||
${CMAKE_THREAD_LIBS_INIT} -lm protobuf-c)
|
||||
target_link_libraries(neuron-base libssl.a libcrypto.a)
|
||||
target_link_libraries(neuron-base nng libzlog.so jansson jwt
|
||||
${CMAKE_THREAD_LIBS_INIT})
|
||||
add_dependencies(neuron-base neuron-version)
|
||||
|
||||
# dependency imposed by nng
|
||||
@@ -144,30 +126,26 @@ set(NEURON_SOURCES
|
||||
src/core/subscribe.c
|
||||
src/core/plugin_manager.c
|
||||
src/core/node_manager.c
|
||||
src/core/template_manager.c
|
||||
src/core/storage.c
|
||||
src/adapter/msg_q.c
|
||||
src/adapter/storage.c
|
||||
src/adapter/adapter.c
|
||||
src/adapter/driver/cache.c
|
||||
src/adapter/driver/driver.c
|
||||
plugins/restful/cert_handle.c
|
||||
plugins/restful/handle.c
|
||||
plugins/restful/log_handle.c
|
||||
plugins/restful/metric_handle.c
|
||||
plugins/restful/normal_handle.c
|
||||
plugins/restful/rw_handle.c
|
||||
plugins/restful/adapter_handle.c
|
||||
plugins/restful/ndriver_handle.c
|
||||
plugins/restful/datatag_handle.c
|
||||
plugins/restful/global_config_handle.c
|
||||
plugins/restful/group_config_handle.c
|
||||
plugins/restful/plugin_handle.c
|
||||
plugins/restful/template_handle.c
|
||||
plugins/restful/version_handle.c
|
||||
plugins/restful/scan_handle.c
|
||||
plugins/restful/otel_handle.c
|
||||
plugins/restful/cid_handle.c
|
||||
plugins/restful/tpy_handle.c
|
||||
plugins/restful/system_handle.c
|
||||
plugins/restful/datalayers_handle.c
|
||||
plugins/restful/rest.c
|
||||
plugins/restful/user.c)
|
||||
|
||||
@@ -175,7 +153,7 @@ set(CMAKE_BUILD_RPATH ./)
|
||||
add_executable(neuron)
|
||||
target_sources(neuron PRIVATE ${NEURON_SOURCES})
|
||||
target_include_directories(neuron PRIVATE include/neuron src plugins)
|
||||
target_link_libraries(neuron dl neuron-base sqlite3 -lm xml2)
|
||||
target_link_libraries(neuron dl neuron-base sqlite3 -lm)
|
||||
target_link_options(neuron PRIVATE "LINKER:--dynamic-list-data")
|
||||
|
||||
#copy file for run
|
||||
@@ -184,6 +162,8 @@ file(COPY ${CMAKE_SOURCE_DIR}/dev.conf DESTINATION ${CMAKE_BINARY_DIR}/config)
|
||||
file(COPY ${CMAKE_SOURCE_DIR}/neuron.json DESTINATION ${CMAKE_BINARY_DIR}/config)
|
||||
file(COPY ${CMAKE_SOURCE_DIR}/.gitkeep DESTINATION ${CMAKE_BINARY_DIR}/logs)
|
||||
file(COPY ${CMAKE_SOURCE_DIR}/.gitkeep DESTINATION ${CMAKE_BINARY_DIR}/persistence)
|
||||
file(COPY ${CMAKE_SOURCE_DIR}/neuron.key DESTINATION ${CMAKE_BINARY_DIR}/config)
|
||||
file(COPY ${CMAKE_SOURCE_DIR}/neuron.pem DESTINATION ${CMAKE_BINARY_DIR}/config)
|
||||
file(GLOB SQL_SCHEMAS ${CMAKE_SOURCE_DIR}/persistence/*.sql)
|
||||
file(COPY ${SQL_SCHEMAS} DESTINATION ${CMAKE_BINARY_DIR}/config)
|
||||
file(COPY ${CMAKE_SOURCE_DIR}/default_plugins.json DESTINATION ${CMAKE_BINARY_DIR}/config)
|
||||
@@ -191,9 +171,6 @@ file(COPY ${CMAKE_SOURCE_DIR}/default_plugins.json DESTINATION ${CMAKE_BINARY_DI
|
||||
add_subdirectory(plugins/modbus)
|
||||
add_subdirectory(plugins/mqtt)
|
||||
add_subdirectory(plugins/ekuiper)
|
||||
add_subdirectory(plugins/file)
|
||||
add_subdirectory(plugins/monitor)
|
||||
add_subdirectory(plugins/datalayers)
|
||||
|
||||
add_subdirectory(simulator)
|
||||
|
||||
@@ -204,7 +181,6 @@ endif()
|
||||
add_subdirectory(tests/plugins/c1)
|
||||
add_subdirectory(tests/plugins/s1)
|
||||
add_subdirectory(tests/plugins/sc1)
|
||||
add_subdirectory(tests/plugins/demo_app)
|
||||
|
||||
# Set sane defaults for multi-lib linux systems
|
||||
include(GNUInstallDirs)
|
||||
|
||||
@@ -55,47 +55,3 @@ $ tar xzf sqlite3.tar.gz --strip-components=1 -C sqlite3
|
||||
$ cd sqlite3
|
||||
$ ./configure CFLAGS=-fPIC && make && sudo make install
|
||||
```
|
||||
|
||||
[protobuf](https://github.com/protocolbuffers/protobuf)
|
||||
```shell
|
||||
$ wget --no-check-certificate --content-disposition https://github.com/protocolbuffers/protobuf/releases/download/v3.20.1/protobuf-cpp-3.20.1.tar.gz
|
||||
$ tar -xzvf protobuf-cpp-3.20.1.tar.gz
|
||||
$ cd protobuf-3.20.1
|
||||
$ ./configure --enable-shared=no CFLAGS=-fPIC CXXFLAGS=-fPIC
|
||||
$ make && sudo make install
|
||||
```
|
||||
|
||||
[protobuf-c](https://github.com/protobuf-c/protobuf-c.git)
|
||||
```shell
|
||||
$ git clone -b v1.4.0 https://github.com/protobuf-c/protobuf-c.git
|
||||
$ cd protobuf-c
|
||||
$ ./autogen.sh
|
||||
$ ./configure --disable-protoc --enable-shared=no CFLAGS=-fPIC CXXFLAGS=-fPIC
|
||||
$ make && sudo make install
|
||||
```
|
||||
|
||||
[libxml2](https://github.com/GNOME/libxml2.git)
|
||||
```shell
|
||||
$ git clone -b v2.9.14 https://github.com/GNOME/libxml2.git
|
||||
$ cd libxml2
|
||||
$ ./autogen.sh
|
||||
$ ./configure --enable-shared=no CFLAGS=-fPIC CXXFLAGS=-fPIC
|
||||
$ make && sudo make install
|
||||
```
|
||||
|
||||
[arrow](https://github.com/apache/arrow)
|
||||
|
||||
To build Apache Arrow C++ for the datalayers plugin, please refer to the [official Arrow](https://github.com/apache/arrow) for the most up-to-date information on dependencies, configuration, and build steps.
|
||||
|
||||
You must enable the following features at a minimum for the datalayers plugin:
|
||||
|
||||
```cmake
|
||||
-DARROW_FLIGHT=ON \
|
||||
-DARROW_FLIGHT_SQL=ON
|
||||
```
|
||||
|
||||
Required Dependencies:
|
||||
When enabling DARROW_FLIGHT and DARROW_FLIGHT_SQL, you must ensure the following dependencies are installed on your system at least: \
|
||||
gRPC \
|
||||
Boost \
|
||||
Thrift
|
||||
+95
-53
@@ -9,7 +9,7 @@
|
||||
|
||||
|
||||
|
||||
[English](https://github.com/emqx/neuron/blob/main/README.md) | 简体中文
|
||||
[English](https://github.com/neugates/neuron/blob/main/README.md) | 简体中文
|
||||
|
||||
Neuron 是一款开源的、轻量级工业协议网关软件,支持数十种工业协议的一站式设备连接、数据接入、MQTT 协议转换,为工业设备赋予工业 4.0 时代关键的物联网连接能力。
|
||||
|
||||
@@ -18,77 +18,45 @@ Neuron 是一款开源的、轻量级工业协议网关软件,支持数十种
|
||||
以下是 Neuron 的一些重要特性:
|
||||
|
||||
- 具有实时能力的边缘原生应用程序可以利用边缘端的低延迟网络。
|
||||
- 松耦合模块化架构设计,通过可插拔模块扩展更多功能服务。
|
||||
- 松耦合模块化 [架构设计](https://neugates.io/docs/zh/latest/introduction/architecture/architecture.html) 通过可插拔模块扩展更多功能服务。
|
||||
- 支持可以在运行时更新设备和应用程序模块的热插件。
|
||||
- 支持多种工业设备协议,包括 Modbus、OPCUA、Ethernet/IP、IEC104、BACnet 等。
|
||||
- 支持多种工业设备协议,包括 Modbus、OPCUA、Ethernet/IP、IEC104、BACnet 等 [更多协议](https://neugates.io/docs/zh/latest/configuration/south-devices/south-devices.html)。
|
||||
- 支持同时连接大量不同协议的工业设备。
|
||||
- 结合[eKuiper](https://www.lfedge.org/projects/ekuiper)提供的规则引擎功能,快速实现基于规则的设备控制或 AI/ML 分析。
|
||||
- 通过 SparkplugB 解决方案支持对工业应用程序的数据访问,例如 MES 或 ERP、SCADA、historian 和数据分析软件。
|
||||
- 通过 [SparkplugB](https://neugates.io/docs/zh/latest/use-cases/use_cases.html#mqtt-sparkplugb-%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88) 解决方案支持对工业应用程序的数据访问,例如 MES 或 ERP、SCADA、historian 和数据分析软件。
|
||||
- 具有非常低的内存占用,小于 10M 的内存占用和 CPU 使用率,可以在 ARM、x86 和 RISC-V 等资源有限的硬件上运行。
|
||||
- 支持在本地安装可执行文件或部署在容器化环境中。
|
||||
- 控制工业设备,通过 [HTTP API](docs/api/cn/http.md) 和 [MQTT API](docs/api/cn/mqtt.md) 服务更改参数和数据标签。
|
||||
- 控制工业设备,通过[HTTP API](https://neugates.io/docs/zh/latest/http-api/http-api.html)和[MQTT API](https://neugates.io/docs/en/latest/north-apps/mqtt/api.html) 服务更改参数和数据标签。
|
||||
- 与其他 EMQ 产品高度集成,包括 [EMQX](https://www.emqx.com/zh/products/emqx)、[NanoMQ](https://nanomq.io/zh)、[eKuiper](https://ekuiper.org/zh)。
|
||||
- 核心框架和 Modbus、MQTT 和 eKuiper 的代码在 LGPLv3 的许可下开源。
|
||||
- 核心框架和 Modbus、MQTT 和 eKuiper 的代码在 LGPLv3 的许可下开源。商业模块需要 [EMQ 许可证](https://neugates.io/docs/zh/latest/introduction/license-describe.html) 才能运行。
|
||||
|
||||
开源版本只提供了部分插件,要使用更多的插件以及更完善的 Dashboard,请使用 [NeuronEX](https://www.emqx.com/zh/products/neuronex)。
|
||||
获取更多信息,请访问 [Neuron 官网](https://neugates.io/zh)。
|
||||
|
||||
## 快速开始
|
||||
|
||||
Neuron 管理面板的默认登陆账号为 `admin`,密码为 `0000`。
|
||||
#### 使用 Docker 运行 Neuron
|
||||
|
||||
### 下载 tar 包运行
|
||||
|
||||
选择 [Relase](https://github.com/emqx/neuron/releases) 版本下载
|
||||
|
||||
```bash
|
||||
$ tar xvf neuron-{version}-linux-amd64.tar.gz
|
||||
$ cd neuron
|
||||
$ ./neuron --log
|
||||
```
|
||||
docker run -d --name neuron -p 7000:7000 -p 7001:7001 -p 9081:9081 --privileged=true --restart=always emqx/neuron:latest
|
||||
```
|
||||
|
||||
浏览器中打开 `http://localhost:7000` 访问 Neuron。
|
||||
接下来请参考 [快速入门](https://neugates.io/docs/zh/latest/quick-start/hardware-specifications.html) 开启您的 Neuron 之旅。
|
||||
|
||||
> **提示**
|
||||
>
|
||||
> Neuron 开源版只包含 Modbus 和 MQTT 驱动。
|
||||
>
|
||||
> 您可以[免费申请 15 天试用期限的 License](https://www.emqx.com/zh/apply-licenses/neuron),加载所有的驱动。
|
||||
|
||||
### 源码编译运行
|
||||
#### 更多安装方式
|
||||
|
||||
1. [安装依赖](https://github.com/emqx/neuron/install-dependencies.md)
|
||||
您可以从 [neugates.io/zh/downloads?os=Linux](https://neugates.io/zh/downloads?os=Linux) 下载不同格式的 Neuron 安装包进行手动安装。
|
||||
|
||||
2. 编译 Neuron
|
||||
```bash
|
||||
$ git clone https://github.com/emqx/neuron
|
||||
$ cd neuron && mkdir build && cd build
|
||||
$ cmake .. && make
|
||||
```
|
||||
也可以直接访问 [Neuron 安装文档](https://neugates.io/docs/zh/latest/installation/installation.html) 查看不同安装方式的操作步骤。
|
||||
|
||||
3. 下载并解压 Dashboard
|
||||
```bash
|
||||
$ wget https://github.com/emqx/neuron-dashboard/releases/download/2.6.3/neuron-dashboard.zip
|
||||
|
||||
# 解压 neuron-dashboard.zip 到 build 目录
|
||||
$ unzip neuron-dashboard.zip
|
||||
```
|
||||
|
||||
3. 运行 Neuron
|
||||
```bash
|
||||
$ ./neuron --log
|
||||
```
|
||||
|
||||
4. 浏览器中打开 `http://localhost:7000` 访问 Neuron。
|
||||
|
||||
### Docker
|
||||
|
||||
```bash
|
||||
$ docker run -d --name neuron -p 7000:7000 emqx/neuron:2.6.9
|
||||
```
|
||||
|
||||
目前 Neuron 维护的最新镜像是 emqx/neuron:2.6.9,2.7.x 及后续的版本不再提供镜像。
|
||||
|
||||
### [采集 Modbus TCP 数据并通过 MQTT 发送](./docs/quick_start/quick_start_cn.md)
|
||||
|
||||
## Dashboard
|
||||
|
||||
开源版 [Dashboard](https://github.com/emqx/neuron-dashboard) 最新 Release 的版本为 2.6.3,目前已暂停开发与维护,此版本也是 Neuron 默认集成的版本。要用更完善与更专业的 Dashboard,请使用 [NeuronEX](https://www.emqx.com/zh/products/neuronex)。
|
||||
## 文档
|
||||
|
||||
Neuron 文档地址:[https://neugates.io/docs/zh/latest/](https://neugates.io/docs/zh/latest/)。
|
||||
|
||||
## 社区
|
||||
|
||||
@@ -98,6 +66,80 @@ $ docker run -d --name neuron -p 7000:7000 emqx/neuron:2.6.9
|
||||
- 关注我们的 [bilibili](https://space.bilibili.com/522222081),获取最新物联网技术分享。
|
||||
- 关注我们的 [微博](https://weibo.com/emqtt) 或 [Twitter](https://twitter.com/EMQTech),获取 Neuron 最新资讯。
|
||||
|
||||
## 从源码构建
|
||||
|
||||
**安装依赖**
|
||||
|
||||
请参考 [Install-dependencies](https://github.com/emqx/neuron/blob/main/Install-dependencies.md)
|
||||
|
||||
**编译**
|
||||
|
||||
```
|
||||
$ git clone https://github.com/emqx/neuron
|
||||
$ cd neuron
|
||||
$ mkdir build && cd build
|
||||
$ cmake .. && make
|
||||
```
|
||||
|
||||
**安装 Dashboard**
|
||||
|
||||
在 [neuron-dashboard](https://github.com/emqx/neuron-dashboard/releases) 页面下载最新的 `neuron-dashboard.zip`,解压后放到 Neuron 可执行目录下的 dist 目录中。
|
||||
|
||||
**运行**
|
||||
|
||||
```
|
||||
$ cd build
|
||||
$ ./neuron
|
||||
```
|
||||
|
||||
>**修改日志级别**
|
||||
>
|
||||
>在 zlog.conf 文件的规则中更改日志级别。可用的日志级别包括 INFO,DEBUG,NOTICE,WARN,ERROR 和 FATAL。
|
||||
|
||||
## 测试
|
||||
|
||||
### 单元测试
|
||||
|
||||
运行所有的单元测试
|
||||
|
||||
```shell
|
||||
$ cd build
|
||||
$ ctest --output-on-failure
|
||||
```
|
||||
|
||||
### 功能测试
|
||||
|
||||
运行所有的功能测试
|
||||
|
||||
```shell
|
||||
$ sudo apt-get install -y mosquitto
|
||||
$ mosquitto -v &
|
||||
$ python3 -m pip install -U pip
|
||||
$ python3 -m pip install -r ft/requirements.txt
|
||||
$ python3 -m robot --maxerroelines=600 -P ft/ -d ft/reports ft
|
||||
```
|
||||
|
||||
### 压力测试
|
||||
|
||||
在目录`ft/data/persistence/`中有压力测试的数据集。
|
||||
|
||||
运行压力测试
|
||||
|
||||
```shell
|
||||
# 安装依赖
|
||||
$ pip3 install -r ft/requirements.txt
|
||||
|
||||
# 使用http接口在数据集total-10k上进行测试
|
||||
$ python3 -m robot -P ft/ --variable neuron_api:http --variable dataset:total-10k -d ft/http-total-10k ft/pressure.test
|
||||
# 使用http接口在数据集total-50k上进行测试
|
||||
$ python3 -m robot -P ft/ --variable neuron_api:http --variable dataset:total-50k -d ft/http-total-50k ft/pressure.test
|
||||
|
||||
# 如果使用mqtt接口则需要MQTT服务器,此例为mosquitto
|
||||
$ mosquitto -v &
|
||||
|
||||
# 使用mqtt接口在数据集simple-1k上进行测试
|
||||
$ python3 -m robot -P ft/ --variable neuron_api:mqtt --variable dataset:simple-1k -d ft/mqtt-simple-1k ft/pressure.test
|
||||
```
|
||||
|
||||
## 开源许可
|
||||
|
||||
|
||||
@@ -8,9 +8,6 @@
|
||||
[](https://twitter.com/EMQTech)
|
||||
[](https://www.youtube.com/channel/UC5FjR77ErAxvZENEWzQaO5Q)
|
||||
|
||||
English | [简体中文](https://github.com/emqx/neuron/blob/main/README-CN.md)
|
||||
|
||||
|
||||
Neuron is an Industrial IoT (IIoT) connectivity server for modern big data and AI/ML technology to leverage the power of Industrial 4.0. It supports one-stop access to dozens of industrial protocols and converts them into MQTT protocol and realize the interconnection between IIoT platforms and various industrial devices.
|
||||
|
||||

|
||||
@@ -18,75 +15,45 @@ Neuron is an Industrial IoT (IIoT) connectivity server for modern big data and A
|
||||
The following are some important features of Neuron:
|
||||
|
||||
- Edge native application with real-time capability to leverage the low latency network of edge side.
|
||||
- Loosely-coupled modularity architecture design for extending more functional services by pluggable modules.
|
||||
- Loosely-coupled modularity [architecture design](https://neugates.io/docs/en/latest/introduction/architecture/architecture.html) for extending more functional services by pluggable modules.
|
||||
- Support hot plugins that can update device and application modules during runtime.
|
||||
- Support numerous protocols for industrial devices, including Modbus, OPCUA, Ethernet/IP, IEC104, BACnet and more.
|
||||
- Support numerous protocols for industrial devices, including Modbus, OPCUA, Ethernet/IP, IEC104, BACnet and [more](https://neugates.io/docs/en/latest/configuration/south-devices/south-devices.html).
|
||||
- Support simultaneous connection of a large number of industrial devices with different protocols.
|
||||
- Combine with the rule engine function provided by [eKuiper](https://www.lfedge.org/projects/ekuiper) to quickly implement rule-based device control or AI/ML analytics.
|
||||
- Support data access to industrial applications, such as MES or ERP, SCADA, historian and data analytics software via SparkplugB solution.
|
||||
- Support data access to industrial applications, such as MES or ERP, SCADA, historian and data analytics software via [SparkplugB](https://neugates.io/docs/en/latest/use-cases/use_cases.html#mqtt-sparkplugb-solution) solution.
|
||||
- Has very low memory footprint, less than 10M, and CPU usage, can run on limited resource hardware like ARM, x86 and RISC-V.
|
||||
- Support installation of native executable or deployed in containerized enviornment.
|
||||
- Control industrial devices, and make changes to the parameters and data tags through [HTTP API](docs/api/english/http.md) and [MQTT API](docs/api/english/mqtt.md) services.
|
||||
- Control industrial devices, and make changes to the parameters and data tags through [HTTP API](https://neugates.io/docs/en/latest/http-api/http-api.html) and [MQTT API](https://neugates.io/docs/en/latest/configuration/north-apps/mqtt/api.html) services.
|
||||
- Highly integrated with other EMQ products, including [EMQX](https://www.emqx.com/en/products/emqx), [NanoMQ](https://nanomq.io/), [eKuiper](https://ekuiper.org/).
|
||||
- The code of the core framework and Modbus, MQTT and eKuiper are licensed under open source LGPLv3.
|
||||
- The code of the core framework and Modbus, MQTT and eKuiper are licensed under open source LGPLv3. Commercial modules require a [EMQ License](https://neugates.io/docs/en/latest/installation/license-install/license-install.html) to run.
|
||||
|
||||
Neuron only provides limited plugins in the open source version. To use more plugins and a more complete Dashboard, please use [NeuronEX](https://www.emqx.com/en/products/neuronex).
|
||||
For more information, please visit [Neuron homepage](https://neugates.io/).
|
||||
|
||||
## Quick Start
|
||||
## Get Started
|
||||
|
||||
Default username is `admin` and password is `0000`.
|
||||
#### Run Neuron using Docker
|
||||
|
||||
### Download
|
||||
|
||||
You can download from [Release](https://github.com/emqx/neuron/releases).
|
||||
|
||||
```bash
|
||||
$ tar xvf neuron-{version}-linux-amd64.tar.gz
|
||||
$ cd neuron
|
||||
$ ./neuron --log
|
||||
```
|
||||
docker run -d --name neuron -p 7000:7000 -p 7001:7001 -p 9081:9081 --privileged=true --restart=always emqx/neuron:latest
|
||||
```
|
||||
|
||||
Open a web browser and navigate to `http://localhost:7000` to access the Neuron web interface.
|
||||
Next, please follow the [getting started guide](https://neugates.io/docs/en/latest/quick-start/hardware-specifications.html) to tour the Neuron features.
|
||||
|
||||
### Build and Run
|
||||
> **Limitations**
|
||||
>
|
||||
> Neuron open source edition only includes Modbus and MQTT drivers.
|
||||
>
|
||||
> [Apply for a 15-day trial license](https://www.emqx.com/en/apply-licenses/neuron) to load all drivers.
|
||||
|
||||
1. [Install Dependencies](https://github.com/emqx/neuron/install-dependencies.md)
|
||||
#### More installation options
|
||||
|
||||
2. Build Neuron
|
||||
```bash
|
||||
$ git clone https://github.com/emqx/neuron
|
||||
$ cd neuron && mkdir build && cd build
|
||||
$ cmake .. && make
|
||||
```
|
||||
If you prefer to install and manage Neuron yourself, you can download the latest version from [neugates.io/downloads?os=Linux](https://neugates.io/downloads?os=Linux).
|
||||
|
||||
3. Download and Unzip Dashboard
|
||||
```bash
|
||||
$ wget https://github.com/emqx/neuron-dashboard/releases/download/2.6.3/neuron-dashboard.zip
|
||||
For more installation options, see the [Neuron installation documentation](https://neugates.io/docs/en/latest/installation/installation.html).
|
||||
|
||||
# Unzip neuron-dashboard.zip to the build directory
|
||||
$ unzip neuron-dashboard.zip
|
||||
```
|
||||
## Documentation
|
||||
|
||||
4. Run Neuron
|
||||
```bash
|
||||
$ ./neuron --log
|
||||
```
|
||||
|
||||
5. Open a web browser and navigate to `http://localhost:7000` to access the Neuron web interface.
|
||||
|
||||
### Docker
|
||||
|
||||
```bash
|
||||
$ docker run -d --name neuron -p 7000:7000 emqx/neuron:2.6.9
|
||||
```
|
||||
|
||||
Currently, the latest image maintained for Neuron is `emqx/neuron:2.6.9`, and images for versions `2.7.x` and later are no longer provided.
|
||||
|
||||
### [Modbus TCP Data Collection and MQTT Transmission](./docs/quick_start/quick_start.md)
|
||||
|
||||
## Dashboard
|
||||
|
||||
The open-source version of the [Dashboard](https://github.com/emqx/neuron-dashboard) is currently at version 2.6.3, which has been suspended for development and maintenance. This version is also the one integrated by default with Neuron. For a more complete and professional Dashboard, please use [NeuronEX](https://www.emqx.com/en/products/neuronex).
|
||||
The Neuron documentation is available at [neugates.io/docs/en/latest/](https://neugates.io/docs/en/latest/).
|
||||
|
||||
## Get Involved
|
||||
|
||||
@@ -95,6 +62,36 @@ The open-source version of the [Dashboard](https://github.com/emqx/neuron-dashbo
|
||||
- For general discussions, join us on the [official Discord](https://discord.gg/xYGf3fQnES) team.
|
||||
- Keep updated on [EMQ YouTube](https://www.youtube.com/channel/UC5FjR77ErAxvZENEWzQaO5Q) by subscribing.
|
||||
|
||||
## Build From Source
|
||||
|
||||
**Install required dependencies**
|
||||
|
||||
[Install-dependencies](https://github.com/emqx/neuron/blob/main/Install-dependencies.md)
|
||||
|
||||
**Build**
|
||||
|
||||
```
|
||||
$ git clone https://github.com/emqx/neuron
|
||||
$ cd neuron
|
||||
$ mkdir build && cd build
|
||||
$ cmake .. && make
|
||||
```
|
||||
|
||||
**Install Dashboard**
|
||||
|
||||
Download the latest `neuron-dashboard.zip` from the [neuron-dashboard](https://github.com/emqx/neuron-dashboard/releases) page, unzip it and put it to the `dist` directory under the Neuron executable directory.
|
||||
|
||||
**Run**
|
||||
|
||||
```
|
||||
$ cd build
|
||||
$ ./neuron
|
||||
```
|
||||
|
||||
>**Log level**
|
||||
>
|
||||
>Change the log level in the rules in the zlog.conf file. Available levels include INFO, DEBUG, NOTICE, WARN, ERROR and FATAL.
|
||||
>
|
||||
|
||||
## License
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
set(CMAKE_SYSTEM_NAME Linux)
|
||||
set(COMPILER_PREFIX aarch64-linux-gnu)
|
||||
set(CMAKE_SYSTEM_PROCESSOR aarch64)
|
||||
set(LIBRARY_DIR /home/neuron/v2.13/libs)
|
||||
set(LIBRARY_DIR /home/neuron/v2.7/libs)
|
||||
|
||||
set(CMAKE_C_COMPILER ${COMPILER_PREFIX}-gcc)
|
||||
set(CMAKE_CXX_COMPILER ${COMPILER_PREFIX}-g++)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
set(CMAKE_SYSTEM_NAME Linux)
|
||||
set(COMPILER_PREFIX arm-linux-gnueabi)
|
||||
set(CMAKE_SYSTEM_PROCESSOR armv5tejl)
|
||||
set(LIBRARY_DIR /home/neuron/v2.13/libs)
|
||||
set(LIBRARY_DIR /home/neuron/v2.7/libs)
|
||||
|
||||
set(CMAKE_C_COMPILER ${COMPILER_PREFIX}-gcc)
|
||||
set(CMAKE_CXX_COMPILER ${COMPILER_PREFIX}-g++)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
set(CMAKE_SYSTEM_NAME Linux)
|
||||
set(COMPILER_PREFIX arm-linux-gnueabihf)
|
||||
set(CMAKE_SYSTEM_PROCESSOR armv7l)
|
||||
set(LIBRARY_DIR /home/neuron/v2.13/libs)
|
||||
set(LIBRARY_DIR /home/neuron/v2.7/libs)
|
||||
|
||||
set(CMAKE_C_COMPILER ${COMPILER_PREFIX}-gcc)
|
||||
set(CMAKE_CXX_COMPILER ${COMPILER_PREFIX}-g++)
|
||||
|
||||
@@ -25,6 +25,3 @@ endif()
|
||||
if(CMAKE_SYSTEM_PROCESSOR MATCHES "riscv64")
|
||||
link_libraries(atomic)
|
||||
endif()
|
||||
if(CMAKE_SYSTEM_PROCESSOR MATCHES "loongarch64")
|
||||
link_libraries(atomic)
|
||||
endif()
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
set(CMAKE_SYSTEM_NAME Linux)
|
||||
set(COMPILER_PREFIX x86_64-linux-gnu)
|
||||
set(CMAKE_SYSTEM_PROCESSOR x86_64)
|
||||
set(LIBRARY_DIR /home/neuron/v2.13/libs)
|
||||
set(LIBRARY_DIR /home/neuron/v2.7/libs)
|
||||
|
||||
set(CMAKE_C_COMPILER ${COMPILER_PREFIX}-gcc)
|
||||
set(CMAKE_CXX_COMPILER ${COMPILER_PREFIX}-g++)
|
||||
@@ -13,11 +13,6 @@ set(CMAKE_RANLIB ${COMPILER_PREFIX}-ranlib)
|
||||
set(CMAKE_STAGING_PREFIX ${LIBRARY_DIR}/${COMPILER_PREFIX})
|
||||
set(CMAKE_PREFIX_PATH ${CMAKE_STAGING_PREFIX})
|
||||
|
||||
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION OFF)
|
||||
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-lto")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-lto")
|
||||
|
||||
include_directories(SYSTEM ${CMAKE_STAGING_PREFIX}/include)
|
||||
include_directories(SYSTEM ${CMAKE_STAGING_PREFIX}/openssl/include)
|
||||
set(CMAKE_FIND_ROOT_PATH ${CMAKE_STAGING_PREFIX})
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
ignore:
|
||||
- "src/otel/*.pb-c.c"
|
||||
- "plugins/mqtt/azure_iot_plugin.c"
|
||||
coverage:
|
||||
status:
|
||||
project:
|
||||
default:
|
||||
target: auto # the required coverage value
|
||||
threshold: 0.1% # the leniency in hitting the target
|
||||
@@ -11,24 +11,6 @@ function gen_trace () {
|
||||
}
|
||||
|
||||
case $1 in
|
||||
(ut)
|
||||
rm -f cov_report/cov-neuron.info cov_report/cov-restful.info
|
||||
for dir in build/tests/ut/CMakeFiles/*_test.dir; do
|
||||
test_name=$(basename ${dir} "_test.dir")
|
||||
lcov -c -d ${dir} -o "cov_report/cov-${test_name}_test.info"
|
||||
done
|
||||
cd cov_report
|
||||
lcov $(for file in cov-*.info; do echo "-a $file "; done) -a cov-neuron-base.info -o cov-ut.info;;
|
||||
(ft)
|
||||
lcov -c -d build/plugins/mqtt/CMakeFiles/plugin-mqtt.dir -o cov_report/cov-mqtt.info
|
||||
lcov -c -d build/plugins/modbus/CMakeFiles/plugin-modbus-rtu.dir -o cov_report/cov-modbus-rtu.info
|
||||
lcov -c -d build/plugins/modbus/CMakeFiles/plugin-modbus-tcp.dir -o cov_report/cov-modbus-tcp.info
|
||||
cd cov_report
|
||||
gen_trace -a cov-mqtt.info -a cov-modbus-rtu.info -a cov-modbus-tcp.info -o cov-ft.info;;
|
||||
(ekuiper)
|
||||
lcov -c -d build/plugins/ekuiper/CMakeFiles/plugin-ekuiper.dir -o cov_report/cov-ekuiper.info
|
||||
cd cov_report
|
||||
gen_trace -a cov-ekuiper.info -o cov-ekuiper.info;;
|
||||
(modbus)
|
||||
lcov -c -d build/plugins/modbus/CMakeFiles/plugin-modbus-rtu.dir -o cov_report/cov-modbus-rtu.info
|
||||
lcov -c -d build/plugins/modbus/CMakeFiles/plugin-modbus-tcp.dir -o cov_report/cov-modbus-tcp.info
|
||||
@@ -39,10 +21,6 @@ case $1 in
|
||||
lcov -c -d build/plugins/mqtt/CMakeFiles/plugin-mqtt.dir -o cov_report/cov-mqtt.info
|
||||
cd cov_report
|
||||
gen_trace -a cov-mqtt.info -o cov-mqtt.info;;
|
||||
(azure)
|
||||
lcov -c -d build/plugins/mqtt/CMakeFiles/plugin-azure-iot.dir -o cov_report/cov-azure.info
|
||||
cd cov_report
|
||||
gen_trace -a cov-azure.info -o cov-azure.info;;
|
||||
(core)
|
||||
cd cov_report
|
||||
gen_trace -o cov-core.info;;
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
{
|
||||
"plugins": [
|
||||
"libplugin-mqtt.so",
|
||||
"libplugin-aws-iot.so",
|
||||
"libplugin-azure-iot.so",
|
||||
"libplugin-ekuiper.so",
|
||||
"libplugin-modbus-tcp.so",
|
||||
"libplugin-modbus-rtu.so",
|
||||
"libplugin-file.so"
|
||||
"libplugin-modbus-rtu.so"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,5 +10,6 @@ syslog = "<P>%d(%Y-%m-%dT%T%z) %H neuron[%p]: level=%v msg="[%c] %m" file="%f:%L
|
||||
|
||||
[rules]
|
||||
|
||||
*.* "./logs/%c.log", 50MB * 2 ~ "./logs/%c.#2r.log"; file_format
|
||||
*.* "./logs/%c.log", 25MB * 1 ~ "./logs/%c.#2r.log"; file_format
|
||||
*.* >stdout; stdout_format
|
||||
*.* $remote_syslog,"%V"; syslog
|
||||
|
||||
-2070
File diff suppressed because it is too large
Load Diff
@@ -1,482 +0,0 @@
|
||||
# 数据上下行格式
|
||||
|
||||
以下内容描述 MQTT 插件如何上报采集的数据,以及如何通过 MQTT 插件实现读写点位数据。
|
||||
|
||||
|
||||
## 数据上报
|
||||
|
||||
MQTT 插件将采集到的数据以 JSON 形式发布到指定的主题。
|
||||
上报数据的具体格式由**上报数据格式**参数指定,有[**Values-format 格式**](#values-format-格式)、[**Tags-format 格式**](#tags-format-格式)、[**ECP-format 格式**](#ecp-format-格式)、[**Custom 自定义格式**](#custom-自定义格式)多种格式可选。
|
||||
|
||||
### 上报主题
|
||||
|
||||
上报主题在北向节点订阅中指定,其默认值为 **/neuron/{MQTT driver name}** ,见下图
|
||||
|
||||
### Values-format 格式
|
||||
|
||||
在 **Values-format** 格式中, 上报的数据由以下字段构成:
|
||||
* `timestamp` : 数据采集时的 UNIX 时间戳。
|
||||
* `node` : 被采集的南向节点的名字。
|
||||
* `group` : 被采集的南向节点的点位组的名字。
|
||||
* `values` : 存储采集成功的点位值的字典。
|
||||
* `errors` : 存储采集失败的错误码的字典。
|
||||
* `metas` : 驱动相关的元数据信息。
|
||||
|
||||
以下为使用 **values-format** 格式的数据样例,采集成功的点位数据值存放在`values`键中,采集失败的点位错误码存放在`errors`键中。
|
||||
```json
|
||||
{
|
||||
"timestamp": 1650006388943,
|
||||
"node": "modbus",
|
||||
"group": "grp",
|
||||
"values":
|
||||
{
|
||||
"tag0": 123
|
||||
},
|
||||
"errors":
|
||||
{
|
||||
"tag1": 2014
|
||||
},
|
||||
"metas":{}
|
||||
}
|
||||
```
|
||||
|
||||
::: tip 注意
|
||||
|
||||
当点位采集成功时,返回采集到的数据。当点位采集发生错误时,返回错误码,不再返回数值。
|
||||
|
||||
当 MQTT 插件配置项 **上报点位错误码** 为 **False** 时,不上报点位错误码。
|
||||
:::
|
||||
|
||||
### Tags-format 格式
|
||||
|
||||
在 **Tags-format** 格式中, 上报的数据由以下字段构成:
|
||||
* `timestamp` : 数据采集时的 UNIX 时间戳。
|
||||
* `node` : 被采集的南向节点的名字。
|
||||
* `group` : 被采集的南向节点的点位组的名字。
|
||||
* `tags` : 点位数据数组,每个元素对应一个点位。
|
||||
* `name` : 具体的点位名称字段。
|
||||
* `value` : 具体点位对应的值。
|
||||
* `error` : 具体点位对应的错误码。
|
||||
|
||||
以下为使用 **Tags-format** 格式的数据样例,其中所有点位数据存放在一个数组中,每个数组元素包含点位的名字,采集成功时的数据值或者采集失败时的错误码。
|
||||
|
||||
```json
|
||||
{
|
||||
"timestamp": 1647497389075,
|
||||
"node": "modbus",
|
||||
"group": "grp",
|
||||
"tags": [
|
||||
{
|
||||
"name": "tag0",
|
||||
"value": 123,
|
||||
},
|
||||
{
|
||||
"name": "tag1",
|
||||
"error": 2014
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
::: tip 注意
|
||||
|
||||
当点位采集成功时,返回采集到的数据。当点位采集发生错误时,返回错误码,不再返回数值。
|
||||
|
||||
当 MQTT 插件配置项 **上报点位错误码** 为 **False** 时,不上报点位错误码。
|
||||
:::
|
||||
|
||||
### ECP-format 格式
|
||||
|
||||
在 **ECP-format** 格式中, 上报的数据由以下字段构成:
|
||||
* `timestamp` : 数据采集时的 UNIX 时间戳。
|
||||
* `node` : 被采集的南向节点的名字。
|
||||
* `group` : 被采集的南向节点的点位组的名字。
|
||||
* `tags` : 点位数据数组,每个元素对应一个点位。
|
||||
* `name` : 具体的点位名称字段。
|
||||
* `value` : 具体点位对应的值。
|
||||
* `type` : 具体点位对应的数据类型,共包含布尔、整型、浮点型、字符串四种数据类型。
|
||||
|
||||
|
||||
以下为使用 *ECP-format* 格式的数据样例,其中所有点位数据存放在一个数组中,每个数组元素包含点位的名字,点位的数据类型和采集成功时的数据值,不包含采集失败的点位。
|
||||
数据类分为布尔、整型、浮点型、字符串四种。
|
||||
* type = 1 布尔
|
||||
* type = 2 整型
|
||||
* type = 3 浮点型
|
||||
* type = 4 字符串
|
||||
|
||||
```json
|
||||
{
|
||||
"timestamp": 1647497389075,
|
||||
"node": "modbus",
|
||||
"group": "grp",
|
||||
"tags": [
|
||||
{
|
||||
"name": "tag_boolean",
|
||||
"value": true,
|
||||
"type": 1,
|
||||
},
|
||||
{
|
||||
"name": "tag_int32_",
|
||||
"value": 123,
|
||||
"type": 2,
|
||||
},
|
||||
{
|
||||
"name": "tag_float",
|
||||
"value": 1.23,
|
||||
"type": 3,
|
||||
},
|
||||
{
|
||||
"name": "tag_string",
|
||||
"value": "abcd",
|
||||
"type": 4,
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
::: tip 注意
|
||||
ECP-format 格式不支持上报点位错误码。
|
||||
不管 MQTT 插件配置项 **上报点位错误码** 为 **False** 或为 **True** ,都不上报点位错误码。
|
||||
:::
|
||||
|
||||
### Custom 自定义格式
|
||||
|
||||
在自定义格式中,可以使用内置支持的变量自定义数据上报格式。
|
||||
|
||||

|
||||
|
||||
#### 内置变量
|
||||
|
||||
| **变量名称** | **说明** |
|
||||
| ------------------ | ---------------------- |
|
||||
| `${timestamp}` | 数据采集时的 UNIX 时间戳。 |
|
||||
| `${node}` | 南向采集点位所属的南向驱动名称。<br> 示例:`modbus` |
|
||||
| `${group}` | 南向采集点位所属的南向驱动的采集组的名称。<br> 示例:`group` |
|
||||
| `${tags}` | 南向采集点位有效值的数组集合。<br> 示例:`[{"name": "tag1", "value": 123}, {"name": "tag2", "value": 456}]` |
|
||||
| `${tag_values}` | 南向采集点位有效值的Json集合。<br> 示例:`{"tag1": 123, "tag2": 456}` |
|
||||
| `${tag_errors}` | 南向采集点位报错值的数组集合。<br> 示例:`[{"name": "tag3", "error": 2014}, {"name": "tag4", "error": 2015}]` |
|
||||
| `${tag_error_values}` | 南向采集点位报错值的Json集合。<br> 示例:`{"tag3": 2014, "tag4": 2015}` |
|
||||
| `${static_tags}` | 订阅采集组时,自定义配置的静态点位的数组集合。<br> 示例: `[{"name": "static_tag1", "value": "abc"}, {"name": "static_tag2", "value": "def"}]` <br> 详见 [静态点位](#静态点位)|
|
||||
| `${static_tag_values}` | 订阅采集组时,自定义配置的静态点位的Json集合。<br> 示例: `{"static_tag1": "abc", "static_tag2": "def"}`<br> 详见 [静态点位](#静态点位) |
|
||||
|
||||
::: tip 注意
|
||||
`${tags}` 和 `${tag_values}` 是采集数据点的2种不同格式,`${tags}` 是数组格式,`${tag_values}` 是Json格式。一般在构建自定义数据上报格式时,使用 `${tags}` 或 `${tag_values}` 中的一种即可。
|
||||
|
||||
`${static_tags}` 和 `${static_tag_values}`、`${tag_errors}`和`${tag_error_values}` 同理,使用其中一种即可。
|
||||
|
||||
MQTT 插件配置项 **上报点位错误码** 为 **False** 时,即使配置了`${tag_errors}` 和或 `${tag_error_values}`,也不上报点位错误码信息。
|
||||
|
||||
:::
|
||||
|
||||
|
||||
|
||||
上表中示例部分,原始南向驱动`modbus1`采集组`group1`下,包含4个点位,其中`tag1`和`tag2`的点位采集数据正常,`tag3`和`tag4`的点位采集数据异常。在北向节点订阅时,自定义配置的静态点位为`static_tag1`和`static_tag2`,其值分别为`abc`和`def`。
|
||||
|
||||
以上配置,以 Values-format 数据格式上报时,内容如下:
|
||||
|
||||
|
||||
```json
|
||||
{
|
||||
"timestamp": 1650006388943,
|
||||
"node": "modbus1",
|
||||
"group": "group1",
|
||||
"values": {"tag1": 123, "tag2": 456, "static_tag1": "abc", "static_tag2": "def"},
|
||||
"errors": {"tag3": 2014, "tag4": 2015},
|
||||
"metas":{}
|
||||
}
|
||||
```
|
||||
|
||||
以下示例通过设定不同的 Custom 配置,将上面 Json 报文输出为不同的数据上报格式。
|
||||
#### 示例一
|
||||
|
||||
将数据点位转换为数组格式,并自定义Json 键名。
|
||||
|
||||
```json
|
||||
{
|
||||
"timestamp": "${timestamp}",
|
||||
"node": "${node}",
|
||||
"group": "${group}",
|
||||
"custom_tag_name": "${tags}",
|
||||
"custom_tag_errors": "${tag_errors}",
|
||||
}
|
||||
```
|
||||
|
||||
实际输出结果如下:
|
||||
|
||||
```json
|
||||
{
|
||||
"timestamp": 1650006388943,
|
||||
"node": "modbus1",
|
||||
"group": "group1",
|
||||
"custom_tag_name": [{"name": "tag1", "value": 123}, {"name": "tag2", "value": 456}],
|
||||
"custom_tag_errors": [{"name": "tag3", "error": 2014}, {"name": "tag4", "error": 2015}]
|
||||
}
|
||||
```
|
||||
|
||||
#### 示例二
|
||||
|
||||
通过自定义数据格式,添加全局静态点位。该静态点位在所有驱动采集组上报数据时,均会携带。如 NeuronEX 部署在一个物理网关上,可将网关的SN号、IP地址、位置信息等信息,添加到所有驱动采集组中。
|
||||
|
||||
```json
|
||||
{
|
||||
"timestamp": "${timestamp}",
|
||||
"node": "${node}",
|
||||
"group": "${group}",
|
||||
"values": "${tag_values}",
|
||||
"gateway_info": {
|
||||
"ip": "192.168.1.100",
|
||||
"sn": "SN123456789",
|
||||
"location": "shanghai"
|
||||
}
|
||||
}
|
||||
```
|
||||
实际输出结果如下:
|
||||
|
||||
```json
|
||||
{
|
||||
"timestamp": 1650006388943,
|
||||
"node": "modbus1",
|
||||
"group": "group1",
|
||||
"values": {"tag1": 123, "tag2": 456},
|
||||
"gateway_info": {
|
||||
"ip": "192.168.1.100",
|
||||
"sn": "SN123456789",
|
||||
"location": "shanghai"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 示例三
|
||||
|
||||
将采集数据点位、静态点位、驱动、采集组信息放入 Json 子节点中,可自定义 Json 节点名称。目前自定义数据结构做多支持三层子层级。
|
||||
|
||||
```json
|
||||
{
|
||||
"timestamp": "${timestamp}",
|
||||
"data": {
|
||||
"child_node": {
|
||||
"node": "${node}",
|
||||
"group": "${group}",
|
||||
"tag_values": "${tag_values}",
|
||||
"static_tag_values": "${static_tag_values}",
|
||||
"tag_error_values": "${tag_error_values}"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
数据上报的格式为:
|
||||
```json
|
||||
{
|
||||
"timestamp": 1650006388943,
|
||||
"data": {
|
||||
"child_node": {
|
||||
"node": "modbus",
|
||||
"group": "group",
|
||||
"tag_values": {"tag1": 123, "tag2": 456},
|
||||
"static_tag_values": {"static_tag1": "abc", "static_tag2": "def"},
|
||||
"tag_error_values": {"tag3": 2014, "tag4": 2015}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## 静态点位
|
||||
|
||||
静态点位功能,支持在南向驱动数据上报时,由用户在**北向应用组列表**页面手动配置静态点位,在数据上报时,将静态点位数据一并上报。
|
||||
|
||||

|
||||
|
||||
静态点位配置,需输入标准JSON格式内容,每个静态点位均为JSON对象中的键值对。静态点位将根据配置的数据上报格式(Values-format、Tags-format、ECP-format)与采集组数据一并上报。
|
||||
|
||||
```json
|
||||
{
|
||||
"location": "sh",
|
||||
"sn_number": "123456"
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
每个南向采集组,可分别配置不同静态点位。表示该采集组代表的物理设备,具有哪些静态属性信息。
|
||||
|
||||
静态点位功能支持布尔、整型、浮点型、字符串四种数据类型。复杂数据类型,如数组、结构体等,将以字符串形式上报。
|
||||
|
||||
如果添加的静态点位,为 NeuronEX 实例中所有采集组共用,既可以勾选**所有采集组**,添加静态点位,也可以在 Custom 自定义格式中,统一添加静态点位,参考 [自定义格式:示例二](#自定义格式)。
|
||||
|
||||
::: tip 注意
|
||||
静态点位命名,不能和南向驱动采集的点位名称相同。
|
||||
|
||||
如命名相同,则如果选择`Values-format`上报数据时,静态点位数据将覆盖南向驱动采集的点位数据.
|
||||
|
||||
如果选择`Tags-format`、`ECP-format`或`Custom`上报数据时,静态点位数据将和南向驱动采集的点位数据一起重复上报。
|
||||
:::
|
||||
|
||||
## 读 Tags
|
||||
|
||||
### 请求
|
||||
|
||||
通过发送 JSON 形式的请求到 MQTT 主题 **/neuron/{node_name}/read/req**,您可以读取一组点位数据。
|
||||
|
||||
#### 请求体
|
||||
|
||||
读请求体由以下字段构成:
|
||||
* `uuid` : 唯一的标志,会在响应中原样返回用以区分对应的请求。
|
||||
* `node` : 某个南向节点名字。
|
||||
* `group` : 南向节点的某个组的名字。
|
||||
|
||||
以下为一个读请求样例:
|
||||
|
||||
```json
|
||||
{
|
||||
"uuid": "bca54fe7-a2b1-43e2-a4b4-1da715d28eab",
|
||||
"node": "modbus",
|
||||
"group": "grp"
|
||||
}
|
||||
```
|
||||
|
||||
### 响应
|
||||
|
||||
读响应会发布到 MQTT 主题 **/neuron/{node_name}/read/resp** 。
|
||||
|
||||
#### 响应体
|
||||
|
||||
读响应体由以下字段构成:
|
||||
* `uuid` : 对应请求中所设置的唯一标志。
|
||||
* `tags` : 点位数据数组,和 [tags 格式](#tags-格式)中的表示方法一样。
|
||||
|
||||
以下为一个读响应样例:
|
||||
|
||||
```json
|
||||
{
|
||||
"uuid": "bca54fe7-a2b1-43e2-a4b4-1da715d28eab",
|
||||
"tags": [
|
||||
{
|
||||
"name": "tag0",
|
||||
"value": 4,
|
||||
},
|
||||
{
|
||||
"name": "tag1",
|
||||
"error": 2014
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
::: tip
|
||||
当点位采集成功时,返回采集到的数据。当点位采集发生错误时,返回错误码,不再返回数值。
|
||||
:::
|
||||
|
||||
## 写 Tag
|
||||
|
||||
### 请求
|
||||
|
||||
通过发送 JSON 形式的请求到**写请求主题**参数指定的 MQTT 主题,您可以写一个点位数据。可在 MQTT 参数配置中配置写请求的主题,默认为为 **/neuron/{random_str}/write/req**。
|
||||
|
||||
|
||||
#### 请求体
|
||||
|
||||
#### 写一个 Tag
|
||||
|
||||
写请求体由以下字段构成:
|
||||
* `uuid` : 唯一的标志,会在响应中原样返回用以区分对应的请求。
|
||||
* `node` : 某个南向节点名字。
|
||||
* `group` : 南向节点的某个组的名字。
|
||||
* `tag` : 要写入的点位名字。
|
||||
* `value` : 要写入的数据值。
|
||||
|
||||
以下为一个写请求样例:
|
||||
|
||||
```json
|
||||
{
|
||||
"uuid": "cd32be1b-c8b1-3257-94af-77f847b1ed3e",
|
||||
"node": "modbus",
|
||||
"group": "grp",
|
||||
"tag": "tag0",
|
||||
"value": 1234
|
||||
}
|
||||
```
|
||||
|
||||
#### 写多个 Tag
|
||||
|
||||
Neuron 提供了对多点位写入的支持。要在一次请求中可以写入多个点位数据, 写请求体应由以下字段构成:
|
||||
* `uuid` : 唯一的标志,会在响应中原样返回用以区分对应的请求。
|
||||
* `node` : 某个南向节点名字。
|
||||
* `group` : 南向节点的某个组的名字。
|
||||
* `tags` : 点位数据数组,每个元素对应一个点位。
|
||||
|
||||
以下为一个写请求样例:
|
||||
|
||||
```json
|
||||
{
|
||||
"uuid": "cd32be1b-c8b1-3257-94af-77f847b1ed3e",
|
||||
"node": "modbus",
|
||||
"group": "grp",
|
||||
"tags": [
|
||||
{
|
||||
"tag": "tag0",
|
||||
"value": 1234
|
||||
},
|
||||
{
|
||||
"tag": "tag1",
|
||||
"value": 5678
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 响应
|
||||
|
||||
写响应会发布到**写响应主题**参数指定的 MQTT 主题。默认**写响应主题**参数为 **/neuron/{random_str}//write/resp**。
|
||||
|
||||
#### 响应体
|
||||
|
||||
写响应体由以下字段构成:
|
||||
* `uuid` : 对应请求中所设置的唯一标志。
|
||||
* `error` : 错误码。0 代表成功,非零代表失败。
|
||||
|
||||
以下为一个读响应样例:
|
||||
```json
|
||||
{
|
||||
"uuid": "cd32be1b-c8b1-3257-94af-77f847b1ed3e",
|
||||
"error": 0
|
||||
}
|
||||
```
|
||||
|
||||
## 驱动状态上报
|
||||
|
||||
上报所有南向驱动状态到指定的 MQTT 主题。
|
||||
|
||||
### 状态上报主题
|
||||
|
||||
上报主题在北向节点配置中指定,其默认值为 **/neuron/{random_str}/state/update**
|
||||
|
||||
### 状态上报间隔
|
||||
|
||||
状态上报间隔在北向节点配置中指定,指每条消息之间间隔的秒数,其默认值为 1,允许的范围为 1-3600。
|
||||
|
||||
### 上报消息格式
|
||||
|
||||
上报的数据由以下字段构成:
|
||||
* `timestamp` : 数据采集时的 UNIX 时间戳。
|
||||
* `states` : 节点状态信息的数组。
|
||||
|
||||
以下是一个驱动状态上报消息样例。
|
||||
|
||||
```json
|
||||
{
|
||||
"timestamp": 1658134132237,
|
||||
"states": [
|
||||
{
|
||||
"node": "modbus-tcp",
|
||||
"link": 1,
|
||||
"running": 3
|
||||
},
|
||||
{
|
||||
"node": "modbus-rtu",
|
||||
"link": 1,
|
||||
"running": 3
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,492 +0,0 @@
|
||||
# Upstream/Downstream Data Format
|
||||
|
||||
The following contents describe how MQTT plugin publishes collected data, and how to read or write data through MQTT plugin.
|
||||
|
||||
## Data Upload
|
||||
|
||||
The MQTT plugin publishes collected data in JSON format to some user-defined topics. The exact format of the data reported is controlled by the **Upload Format** parameter. There are four formats, [**Values-format**](#values-format), [**Tags-format**](#tags-format), [**ECP-format**](#ecp-format), and [**Custom**](#custom-format).
|
||||
|
||||
### Upload Topic
|
||||
|
||||
The upload topic is specified by the **upload-topic** parameter, and the default one set through the dashboard is **/neuron/{MQTT driver name}**.
|
||||
|
||||
### Values Format
|
||||
|
||||
In **Values-format**, the upload data has the following fields:
|
||||
* `timestamp`: the Unix timestamp when the data was collected
|
||||
* `node`: name of the south node from which data was collected
|
||||
* `group`: name of the south node group that the tags belong to
|
||||
* `values`: dictionary storing tags with successfully collected values
|
||||
* `errors`: dictionary storing tags with encountered error codes
|
||||
* `metas`: driver related metadata information
|
||||
|
||||
The following example is in **Values-format**, where tag values collected successfully are stored in a dictionary, while error codes in another.
|
||||
|
||||
```json
|
||||
{
|
||||
"timestamp": 1650006388943,
|
||||
"node": "modbus",
|
||||
"group": "grp",
|
||||
"values":
|
||||
{
|
||||
"tag0": 123
|
||||
},
|
||||
"errors":
|
||||
{
|
||||
"tag1": 2014
|
||||
},
|
||||
"metas":{}
|
||||
}
|
||||
```
|
||||
|
||||
::: tip
|
||||
When a tag is collected successfully, the collected data is returned. When a tag collection fails, the error code is returned instead of the value.
|
||||
|
||||
When the **Upload Tag Error Code** parameter is set to **False**, the error code is not reported.
|
||||
:::
|
||||
|
||||
### Tags Format
|
||||
|
||||
In **Tags-format**, the upload data has the following fields:
|
||||
* `timestamp`: the Unix timestamp when the data was collected
|
||||
* `node`: name of the south node from which data was collected
|
||||
* `group`: name of the south node group that the tags belong to
|
||||
* `tags`: tags data array where each element corresponds to one tag in the group
|
||||
* `name`: the name of the tag
|
||||
* `value`: the value of the tag
|
||||
* `error`: the error code of the tag
|
||||
|
||||
The following example is in **Tags-format**, where tag data are stored in an array. Each element has the name of the tag, and the tag value or error code if something went wrong.
|
||||
|
||||
```json
|
||||
{
|
||||
"timestamp": 1647497389075,
|
||||
"node": "modbus",
|
||||
"group": "grp",
|
||||
"tags": [
|
||||
{
|
||||
"name": "tag0",
|
||||
"value": 123,
|
||||
},
|
||||
{
|
||||
"name": "tag1",
|
||||
"error": 2014
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
::: tip
|
||||
Tag value is returned only when the tag is read successfully. If something goes wrong when reading a tag, the error code is returned.
|
||||
|
||||
When the **Upload Tag Error Code** parameter is set to **False**, the error code is not reported.
|
||||
:::
|
||||
|
||||
### ECP Format
|
||||
|
||||
In **ECP-format**, the upload data has the following fields:
|
||||
* `timestamp`: the Unix timestamp when the data was collected
|
||||
* `node`: name of the south node from which data was collected
|
||||
* `group`: name of the south node group that the tags belong to
|
||||
* `tags`: tags data array where each element corresponds to one tag in the group
|
||||
* `name`: the name of the tag
|
||||
* `value`: the value of the tag
|
||||
* `type`: the type of the tag, which can be Boolean, Integer, Float, or String
|
||||
|
||||
The following example data is in **ECP-format**, where tag data are stored in an array. Each element has the name of the tag, the tag type and the tag value, excluding tags where collection failed.
|
||||
|
||||
Data classes are divided into four types: Boolean, Integer, Float, and String.
|
||||
* type = 1 Boolean
|
||||
* type = 2 Integer
|
||||
* type = 3 Float
|
||||
* type = 4 String
|
||||
|
||||
```json
|
||||
{
|
||||
"timestamp": 1647497389075,
|
||||
"node": "modbus",
|
||||
"group": "grp",
|
||||
"tags": [
|
||||
{
|
||||
"name": "tag_boolean",
|
||||
"value": true,
|
||||
"type": 1,
|
||||
},
|
||||
{
|
||||
"name": "tag_int32_",
|
||||
"value": 123,
|
||||
"type": 2,
|
||||
},
|
||||
{
|
||||
"name": "tag_float",
|
||||
"value": 1.23,
|
||||
"type": 3,
|
||||
},
|
||||
{
|
||||
"name": "tag_string",
|
||||
"value": "abcd",
|
||||
"type": 4,
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
::: tip
|
||||
ECP-format does not support reporting tag error codes.
|
||||
|
||||
Regardless of whether the **Upload Tag Error Code** parameter is set to **False** or **True**, tag error codes are not reported.
|
||||
:::
|
||||
|
||||
### Custom Format
|
||||
|
||||
In the custom format, use built-in variables to define the data upload format.
|
||||
|
||||

|
||||
|
||||
#### Variables
|
||||
|
||||
| *variable* | *description* |
|
||||
| ------------------ | ---------------------- |
|
||||
| `${timestamp}` | The UNIX timestamp when the data was read. |
|
||||
| `${node}` | The name of the southbound node. <br> Example: `modbus` |
|
||||
| `${group}` | The name of the group. <br> Example: `group` |
|
||||
| `${tags}` | The array of valid tag values. <br> Example: `[{"name": "tag1", "value": 123}, {"name": "tag2", "value": 456}]` |
|
||||
| `${tag_values}` | The array of valid tag values, Value Format <br> Example: `{"tag1": 123, "tag2": 456}` |
|
||||
| `${tag_errors}` | The array of error codes. <br> Example: `[{"name": "tag3", "error": 2014}, {"name": "tag4", "error": 2015}]` |
|
||||
| `${tag_error_values}` | The array of error codes, Value Format <br> Example: `{"tag3": 2014, "tag4": 2015}` |
|
||||
| `${static_tags}` | The array of static tags. <br> Example: `[{"name": "static_tag1", "value": "abc"}, {"name": "static_tag2", "value": "def"}]` <br> See [Static Tags](#static-tags) |
|
||||
| `${static_tag_values}` | The array of static tags, Value Format <br> Example: `{"static_tag1": "abc", "static_tag2": "def"}` <br> See [Static Tags](#static-tags) |
|
||||
|
||||
::: tip
|
||||
`${tags}` and `${tag_values}` are two different formats for tag values. `${tags}` is an Array format, and `${tag_values}` is a JSON format. In most cases, use one of them.
|
||||
|
||||
`${static_tags}` and `${static_tag_values}`, `${tag_errors}` and `${tag_error_values}` are similar. Use one of them.
|
||||
|
||||
When the **Upload Tag Error Code** parameter is set to **False**, even if `${tag_errors}` and `${tag_error_values}` are configured, tag error codes are not reported.
|
||||
:::
|
||||
|
||||
The example above is based on the original southbound driver `modbus1` and group `group1`, which contains 4 tags. `tag1` and `tag2` are collected successfully, while `tag3` and `tag4` are collected with errors. When subscribing to the northbound node, the static tags are configured as `static_tag1` and `static_tag2`, with values of `abc` and `def` respectively.
|
||||
|
||||
The above configuration, when reported in **Values-format** data format, is as follows:
|
||||
|
||||
```json
|
||||
{
|
||||
"timestamp": 1650006388943,
|
||||
"node": "modbus1",
|
||||
"group": "group1",
|
||||
"values": {"tag1": 123, "tag2": 456, "static_tag1": "abc", "static_tag2": "def"},
|
||||
"errors": {"tag3": 2014, "tag4": 2015},
|
||||
"metas":{}
|
||||
}
|
||||
```
|
||||
|
||||
The following example shows how to output the above JSON message in different data reporting formats by setting different **Custom** configurations.
|
||||
|
||||
|
||||
#### Example One
|
||||
|
||||
Convert tag data to array format and customize the Json key name.
|
||||
|
||||
```json
|
||||
{
|
||||
"timestamp": "${timestamp}",
|
||||
"node": "${node}",
|
||||
"group": "${group}",
|
||||
"custom_tag_name": "${tags}",
|
||||
"custom_tag_errors": "${tag_errors}",
|
||||
}
|
||||
```
|
||||
|
||||
The actual output result is as follows:
|
||||
|
||||
```json
|
||||
{
|
||||
"timestamp": 1650006388943,
|
||||
"node": "modbus1",
|
||||
"group": "group1",
|
||||
"custom_tag_name": [{"name": "tag1", "value": 123}, {"name": "tag2", "value": 456}],
|
||||
"custom_tag_errors": [{"name": "tag3", "error": 2014}, {"name": "tag4", "error": 2015}]
|
||||
}
|
||||
```
|
||||
|
||||
#### Example Two
|
||||
|
||||
Add global static tags through custom data format. These static tags will be carried in all driver group data reporting. For example, if NeuronEX is deployed on a gateway hardware, you can add the gateway's SN number, IP address, and location information to all driver groups.
|
||||
|
||||
```json
|
||||
{
|
||||
"timestamp": "${timestamp}",
|
||||
"node": "${node}",
|
||||
"group": "${group}",
|
||||
"values": "${tag_values}",
|
||||
"gateway_info": {
|
||||
"ip": "192.168.1.100",
|
||||
"sn": "SN123456789",
|
||||
"location": "shanghai"
|
||||
}
|
||||
}
|
||||
```
|
||||
The actual output result is as follows:
|
||||
|
||||
```json
|
||||
{
|
||||
"timestamp": 1650006388943,
|
||||
"node": "modbus1",
|
||||
"group": "group1",
|
||||
"values": {"tag1": 123, "tag2": 456},
|
||||
"gateway_info": {
|
||||
"ip": "192.168.1.100",
|
||||
"sn": "SN123456789",
|
||||
"location": "shanghai"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Example Three
|
||||
|
||||
Put tag data, static tags, driver, and group information into a Json sub-node, and customize the Json node name. Currently, the custom data structure supports up to three sub-levels.
|
||||
|
||||
```json
|
||||
{
|
||||
"timestamp": "${timestamp}",
|
||||
"data": {
|
||||
"child_node": {
|
||||
"node": "${node}",
|
||||
"group": "${group}",
|
||||
"tag_values": "${tag_values}",
|
||||
"static_tag_values": "${static_tag_values}",
|
||||
"tag_error_values": "${tag_error_values}"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The data reporting format is as follows:
|
||||
```json
|
||||
{
|
||||
"timestamp": 1650006388943,
|
||||
"data": {
|
||||
"child_node": {
|
||||
"node": "modbus",
|
||||
"group": "group",
|
||||
"tag_values": {"tag1": 123, "tag2": 456},
|
||||
"static_tag_values": {"static_tag1": "abc", "static_tag2": "def"},
|
||||
"tag_error_values": {"tag3": 2014, "tag4": 2015}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## Static Tags
|
||||
|
||||
The static tag feature supports configuring static tags manually in the **North Application Group List** page, and reporting static tag data together with the collected data.
|
||||
|
||||

|
||||
|
||||
Static tag configuration requires inputting standard JSON format content, where each static tag is a key-value pair in the JSON object. Static tags will be reported together with the collected data according to the configured data reporting format (Values-format, Tags-format, ECP-format).
|
||||
|
||||
```json
|
||||
{
|
||||
"location": "sh",
|
||||
"sn_number": "123456"
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Each southbound collection group can configure different static tags. This represents the physical device represented by the collection group, with which static attribute information.
|
||||
|
||||
Static tag feature supports **Boolean**, **Integer**, **Float**, and **String** data types. Complex data types, such as arrays and structures, will be reported as **String**.
|
||||
|
||||
If the static tags added are shared by all collection groups in the NeuronEX instance, you can select **All Collection Groups** to add static tags, or add static tags in the **Custom** custom format, as shown in [Custom Format: Example Two](#example-two).
|
||||
|
||||
::: tip
|
||||
Static tag names must not be the same as the tag names collected by the southbound driver.
|
||||
|
||||
If the names are the same:
|
||||
- When using `Values-format` for data upload, the static tag data will overwrite the tag data collected by the southbound driver.
|
||||
- When using `Tags-format`, `ECP-format`, or `Custom` for data upload, both the static tag data and the southbound driver collected tag data will be reported together (resulting in duplicate reporting).
|
||||
|
||||
:::
|
||||
|
||||
|
||||
|
||||
## Read Tag
|
||||
|
||||
### Request
|
||||
|
||||
You can read a group of tags by sending requests in JSON to the MQTT topic **/neuron/{node_name}/read/req**.
|
||||
|
||||
#### Body
|
||||
|
||||
The read request body should have the following fields:
|
||||
* `uuid`: a unique identifier, which will be echoed back in the response to help identify the corresponding request
|
||||
* `node`: the name of a southbound node
|
||||
* `group`: the name of a group to read
|
||||
|
||||
Below is an example read request:
|
||||
|
||||
```json
|
||||
{
|
||||
"uuid": "bca54fe7-a2b1-43e2-a4b4-1da715d28eab",
|
||||
"node": "modbus",
|
||||
"group": "grp"
|
||||
}
|
||||
```
|
||||
|
||||
### Response
|
||||
|
||||
Read response will be published to the MQTT topic **/neuron/{node_name}/read/resp**.
|
||||
|
||||
#### Body
|
||||
|
||||
The read response body has the following fields:
|
||||
* `uuid`: the same unique identifier which is set by the corresponding request
|
||||
* `tags`: tags data array, same as that in [tags format](#tags-format)
|
||||
|
||||
Below is an example read response:
|
||||
|
||||
```json
|
||||
{
|
||||
"uuid": "bca54fe7-a2b1-43e2-a4b4-1da715d28eab",
|
||||
"tags": [
|
||||
{
|
||||
"name": "tag0",
|
||||
"value": 4,
|
||||
},
|
||||
{
|
||||
"name": "tag1",
|
||||
"error": 2014
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
::: tip
|
||||
Tag value is returned only when the tag is read successfully. If something goes wrong when reading a tag, the error code is returned.
|
||||
:::
|
||||
|
||||
## Write Tag
|
||||
|
||||
### Request
|
||||
|
||||
You could write a tag by sending requests in JSON to the MQTT topic designated by the **Write Request Topic** parameter.
|
||||
|
||||
::: tip
|
||||
Before Neuron version 2.4.5, the write request topic was hard-coded to **/neuron/{random_str}/write/req**.
|
||||
:::
|
||||
|
||||
#### Body
|
||||
|
||||
#### Write one tag
|
||||
|
||||
The write request body should have the following fields:
|
||||
* `uuid`: a unique identifier, which will be echoed back in the response to help identify the corresponding request
|
||||
* `node`: the name of a southbound node
|
||||
* `group`: the name of a group
|
||||
* `tag`: the name of a tag
|
||||
* `value`: the value to write
|
||||
|
||||
Below is an example of write request:
|
||||
|
||||
```json
|
||||
{
|
||||
"uuid": "cd32be1b-c8b1-3257-94af-77f847b1ed3e",
|
||||
"node": "modbus",
|
||||
"group": "grp",
|
||||
"tag": "tag0",
|
||||
"value": 1234
|
||||
}
|
||||
```
|
||||
|
||||
#### Write multiple tags
|
||||
|
||||
Since Neuron version 2.6.0, write requests also support writing multiple tags at
|
||||
a time. To write multiple tags at a time, the request body should have the
|
||||
following fields:
|
||||
* `uuid` : a unique identifier, which will be echoed back in the response to help identify the corresponding request.
|
||||
* `node` : the name of a southbound node.
|
||||
* `group` : the name of a group.
|
||||
* `tags` : tags data array where each element corresponds to one tag in the group.
|
||||
|
||||
Below is an example write request:
|
||||
|
||||
```json
|
||||
{
|
||||
"uuid": "cd32be1b-c8b1-3257-94af-77f847b1ed3e",
|
||||
"node": "modbus",
|
||||
"group": "grp",
|
||||
"tags": [
|
||||
{
|
||||
"tag": "tag0",
|
||||
"value": 1234
|
||||
},
|
||||
{
|
||||
"tag": "tag1",
|
||||
"value": 5678
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### Response
|
||||
|
||||
Write response will be published to the MQTT topic designated by the **Write Response Topic** parameter.
|
||||
|
||||
::: tip
|
||||
Before Neuron version 2.4.5, the write response topic was hard-coded to **/neuron/{random_str}//write/resp**.
|
||||
:::
|
||||
|
||||
#### Body
|
||||
|
||||
The write response body has the following fields:
|
||||
* `uuid`: the same unique identifier which is set by the corresponding request.
|
||||
* `error`: error code if something bad happens, `0` represents success.
|
||||
|
||||
Below is an example of write response:
|
||||
|
||||
```json
|
||||
{
|
||||
"uuid": "cd32be1b-c8b1-3257-94af-77f847b1ed3e",
|
||||
"error": 0
|
||||
}
|
||||
```
|
||||
|
||||
## Driver Status Report
|
||||
|
||||
Reports status of all the southbound nodes to the specified topic.
|
||||
|
||||
### Status Report Topic
|
||||
|
||||
The status report topic is specified in the northbound node configuration. Its default value is **/neuron/{random_str}/state/update**.
|
||||
|
||||
### Status Report Interval
|
||||
|
||||
The status report interval is specified in the northbound node configuration, indicating the number of seconds between each message. The default value is 1, with an allowed range of 1-3600.
|
||||
|
||||
### Reporting Message Format
|
||||
|
||||
The reported data consists of the following fields:
|
||||
* `timestamp`: The UNIX timestamp when the data was collected.
|
||||
* `states`: An array of node status information.
|
||||
|
||||
Below is an example of a driver status reporting message.
|
||||
|
||||
```json
|
||||
{
|
||||
"timestamp": 1658134132237,
|
||||
"states": [
|
||||
{
|
||||
"node": "modbus-tcp",
|
||||
"link": 1,
|
||||
"running": 3
|
||||
},
|
||||
{
|
||||
"node": "modbus-rtu",
|
||||
"link": 1,
|
||||
"running": 3
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 137 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 232 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 507 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 158 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 157 KiB |
@@ -1,89 +0,0 @@
|
||||
# Quick Start
|
||||
|
||||
This document requires that you have successfully run Neuron according to the [Installation and Operation](https://github.com/emqx/neuron/README.md) guide, and that you can open the Neuron management panel in your browser.
|
||||
|
||||
## Start the Modbus TCP Simulator
|
||||
|
||||
Two types of Modbus TCP simulators are provided. You can run one of them according to your needs.
|
||||
|
||||
### Neuron's Built-in Simulator
|
||||
|
||||
The Neuron source code or release package includes a test simulator that runs on Linux, which can read and write some fixed points. The Slave ID is 1.
|
||||
|
||||
```bash
|
||||
# If compiling from source, it's in the build/simulator directory
|
||||
# In the release package, it's in the root directory
|
||||
|
||||
# Run the Modbus simulator, use TCP mode, and bind to 0.0.0.0:1502
|
||||
$ ./modbus_simulator tcp 1502 ip_v4
|
||||
```
|
||||
|
||||
### PeakHMI Slave Simulators
|
||||
|
||||
The PeakHMI simulator needs to run on a Windows system. [PeakHMI Official Website](https://hmisys.com)
|
||||
|
||||
After downloading and installing, run the Modbus TCP slave EX simulator. The default port for this simulator is 502, which will be blocked by the default Windows firewall. Make sure the firewall allows this port or disable the firewall.
|
||||
|
||||

|
||||
|
||||
## Create a Southbound Device in Neuron
|
||||
|
||||
### Create a Device
|
||||
|
||||
**Southbound Device Management** -> **Add Device**. In the pop-up dialog box, fill in the device information and create the device. Select `Modbus TCP` for the **Plugin** and enter `modbus-tcp-1` for the **Name**.
|
||||
|
||||
### Configure the Device
|
||||
After creating the device, go to the device details page to configure the device parameters.
|
||||
|
||||
**IP Address**: Fill in the IP address of the machine running the Modbus TCP simulator. If Neuron and the simulator are running on the same machine, you can enter `127.0.0.1`.
|
||||
**Port**: The default is 502. Modify it according to the listening port of the simulator.
|
||||
|
||||
Other parameters can be left as default.
|
||||
|
||||
### Configure Data Points
|
||||
|
||||
On the **Southbound Device Management** page, click the **Device Name** to enter the group page. Add a group and name it `group1`.
|
||||
|
||||
After entering the group, click the **Group Name** to enter the tag configuration page and create a tag.
|
||||
|
||||

|
||||
|
||||
**Name**: `tag-1`
|
||||
**Address**: `1!40001` (Slave ID 1, holding register 40001)
|
||||
**Attribute**: `Read` and `Write`
|
||||
**Data Type**: `INT16`
|
||||
|
||||
### View Tag Values
|
||||
|
||||
After configuring the tags, go to the **Data Monitoring** page, select the device and group you just created, and you will see the values of the tags.
|
||||
|
||||

|
||||
|
||||
## Create a Northbound Application
|
||||
|
||||
Use MQTT to send the data collected from the Modbus device to an MQTT Broker.
|
||||
|
||||
**Northbound Application Management** -> **Add Application**. In the pop-up dialog box, fill in the application information to create the application.
|
||||
Select `MQTT` for the **Plugin** and enter `mqtt` for the **Name**.
|
||||
|
||||
### Configure the Northbound Application
|
||||
|
||||
After creating the northbound application, go to the northbound configuration page. The default server address is `broker.emqx.io` and the port is `1883`. If you need to connect to another MQTT Broker, please modify it according to the actual situation.
|
||||
|
||||
### Subscribe to Southbound Data Groups
|
||||
|
||||
On the **Northbound Application Management** page, click the northbound application to enter the **Subscription Management** page. Click **Add Subscription**, and in the pop-up dialog box, select the Modbus device and group you just created.
|
||||
|
||||

|
||||
|
||||
Remember the topic used for the subscription, as you will need to subscribe to this topic later to see the data. The default topic format is `/neuron/{application_name}`.
|
||||
|
||||
At this point, the configuration for Neuron to collect data via Modbus TCP and send it via MQTT is complete.
|
||||
|
||||
## Use MQTTX to Subscribe to the Topic and View Data
|
||||
|
||||
After subscribing, open [MQTTX](https://mqttx.app/zh), create a new connection, and connect to `broker.emqx.io:1883` (modify according to the MQTT broker configured in the northbound application).
|
||||
|
||||
After a successful connection, subscribe to the topic `/neuron/mqtt` (modify according to the topic used in the northbound subscription), and you will see the tag data.
|
||||
|
||||

|
||||
@@ -1,89 +0,0 @@
|
||||
# 快速开始
|
||||
|
||||
本文档需要先根据 [安装运行](https://github.com/emqx/neuron/README-CN.md) 成功运行 Neuron,并且能通过浏览器打开 Neuron 的管理面板。
|
||||
|
||||
## 启动 Modbus TCP 模拟器
|
||||
|
||||
提供两种 Modbus TCP 模拟器,根据情况运行一种模拟器即可。
|
||||
|
||||
### Neuron 自带模拟器
|
||||
|
||||
Neuron 源码或 Release 中自带了在 Linux 上运行的测试模拟器,可以读写一些固定点位。Slave ID 为 1。
|
||||
|
||||
```bash
|
||||
# 通过源码编译的方式,build/simulator 目录下
|
||||
# Release 包中根目录下
|
||||
|
||||
# 运行 Modbus 模拟器,使用 TCP 模式,绑定 0.0.0.0:1502
|
||||
$ ./modbus_simulator tcp 1502 ip_v4
|
||||
```
|
||||
|
||||
### PeakHMI Slave Simulators 模拟器
|
||||
|
||||
PeakHMI 模拟器需要在 Windows 系统中运行,[PeakHMI 官网](https://hmisys.com)
|
||||
|
||||
下载并安装后,运行 Modbus TCP slave EX 模拟器即可,该模拟器默认绑定的端口为 502,会被 Windows 默认的防火墙拦截,确保防火墙能开放此接口或关闭防火墙。
|
||||
|
||||

|
||||
|
||||
## Neuron 中创建南向设备
|
||||
|
||||
### 创建设备
|
||||
|
||||
**南向设备管理** -> **添加设备** 在弹出的对话框中填写设备信息后创建设备,**插件** 选择 `Modbus TCP`,**名称** 填写 `modbus-tcp-1` 即可。
|
||||
|
||||
### 配置设备
|
||||
创建设备后,进入设备详情页面配置设备参数。
|
||||
|
||||
**IP 地址**: 填写 Modbus TCP 模拟器运行机器的 IP 地址。如果 Neuron 与模拟器运行在同一台机器上,可以填写 `127.0.0.1`。
|
||||
**端口**: 默认502,根据模拟器的监听端口进行修改。
|
||||
|
||||
其他参数默认即可。
|
||||
|
||||
### 配置数据点
|
||||
|
||||
在 **南向设备管理** 页面,点击 **设备名称** 进入点位组页面,添加一个点位组,名称填写 `group1` 即可。
|
||||
|
||||
进入点位组后,点击 **组名称** 进入点位配置页面,创建点位。
|
||||
|
||||

|
||||
|
||||
**名称**: `tag-1`
|
||||
**地址**: `1!40001` ( Slave ID 1, 保持寄存器40001 )
|
||||
**属性**: `Read` 与 `Write`
|
||||
**数据类型**: `INT16`
|
||||
|
||||
### 查看点位值
|
||||
|
||||
配置完点位后,进入 **数据监控** 页面,选择刚才创建的设备以及点位组,即可看到点位的值。
|
||||
|
||||

|
||||
|
||||
## 创建北向应用
|
||||
|
||||
使用 MQTT,把刚才 modbus 设备中采集到的数据发送到 MQTT Broker。
|
||||
|
||||
**北向应用管理** -> **添加应用**,在弹出的对话框中填写应用信息创建应用。
|
||||
**插件** 选择 `MQTT`,**名称** 填写 `mqtt` 即可。
|
||||
|
||||
### 配置北向应用
|
||||
|
||||
创建北向应用后,进入北向配置页面,默认服务器地址为 `broker.emqx.io`,端口为 `1883`,如果需要连接其他 MQTT Broker,请根据实际情况修改。
|
||||
|
||||
### 订阅南向数据组
|
||||
|
||||
在**北向应用管理**页面中,点击北向应用,进入**订阅管理**页面,点击**添加订阅**,在弹出的对话框中选择刚才创建的 Modbus 设备以及点位组。
|
||||
|
||||

|
||||
|
||||
记住订阅时的 topic,后续订阅该 topic 即可看到数据。topic 默认格式为`/neuron/{应用名称}`
|
||||
|
||||
至此,Neuron 的 Modbus TCP 采集数据并通过 MQTT 发送数据的配置完成。
|
||||
|
||||
## 使用 MQTTX 订阅 topic 查看数据
|
||||
|
||||
订阅完成后,打开 [MQTTX](https://mqttx.app/zh),创建一个新的连接,连接到 `broker.emqx.io:1883`(根据北向应用配置的 MQTT broker 修改)。
|
||||
|
||||
连接成功后,订阅 topic `/neuron/mqtt` (根据北向订阅时的 topic 修改),即可看到点位数据。
|
||||
|
||||

|
||||
@@ -0,0 +1,258 @@
|
||||
import asyncio
|
||||
import time
|
||||
from collections import defaultdict, deque
|
||||
|
||||
from robot.api import logger
|
||||
from robot.api.deco import keyword, library
|
||||
from gmqtt import Client as MQTTClient, Subscription
|
||||
from gmqtt.mqtt.constants import MQTTv311
|
||||
|
||||
ROBOT_AUTO_KEYWORDS = False
|
||||
|
||||
|
||||
@library
|
||||
class Client:
|
||||
"""A keyword library for Robot Framework. It provides keywords for
|
||||
performing various operations on an MQTT broker. See http://mqtt.org/
|
||||
for more details on MQTT specification.
|
||||
|
||||
This library uses gmqtt: Python async MQTT client. For more information
|
||||
on underlying methods and documentation, see:
|
||||
https://github.com/wialon/gmqtt
|
||||
|
||||
"""
|
||||
|
||||
ROBOT_LIBRARY_SCOPE = "GLOBAL"
|
||||
ROBOT_LIBRARY_VERSION = "0.1.0"
|
||||
|
||||
def __init__(self, reconnect_retries=5, reconnect_delay=0):
|
||||
"""
|
||||
`reconnect_retries` number of reconnect attempt in case of lost
|
||||
connections, default to 5
|
||||
|
||||
`reconnect_delay` delay between reconnect attemps in seconds,
|
||||
default to 0
|
||||
|
||||
"""
|
||||
self._client = None
|
||||
self._reconnect_retries = reconnect_retries
|
||||
self._reconnect_delay = reconnect_delay
|
||||
self._messages = defaultdict(deque)
|
||||
self._subcribed = asyncio.Event()
|
||||
self._unsubcribed = asyncio.Event()
|
||||
self._recved = asyncio.Event()
|
||||
self._run = asyncio.get_event_loop().run_until_complete
|
||||
|
||||
@keyword
|
||||
def connect(
|
||||
self,
|
||||
host,
|
||||
port=1883,
|
||||
client_id="",
|
||||
username="",
|
||||
password="",
|
||||
keepalive=60,
|
||||
clean_session=True,
|
||||
):
|
||||
"""Connect to an MQTT broker. This is a pre-requisite step for publish
|
||||
and subscribe keywords.
|
||||
|
||||
`host` MQTT broker host
|
||||
|
||||
`port` broker port (default 1883)
|
||||
|
||||
`client_id` if not specified, a random id is generated
|
||||
|
||||
`username` user name, default to ""
|
||||
|
||||
`password` user password, default to ""
|
||||
|
||||
`keepalive` keepalive in seconds
|
||||
|
||||
`clean_session` specifies the clean session flag for the connection
|
||||
|
||||
Examples:
|
||||
|
||||
Connect to a broker with default port and client id
|
||||
| Connect | 127.0.0.1 |
|
||||
|
||||
Connect to a broker by specifying the port and client id explicitly
|
||||
| Connect | 127.0.0.1 | 1883 | test.client |
|
||||
|
||||
Connect to a broker with clean session flag set to false
|
||||
| Connect | 127.0.0.1 | clean_session=${false} |
|
||||
|
||||
"""
|
||||
client = MQTTClient(client_id, clean_session=clean_session)
|
||||
client.on_connect = self._on_connect
|
||||
client.on_message = self._on_message
|
||||
client.on_disconnect = self._on_disconnect
|
||||
client.on_subscribe = self._on_subscribe
|
||||
client.on_unsubscribe = self._on_unsubscribe
|
||||
client.set_config(
|
||||
{
|
||||
"reconnect_retries": self._reconnect_retries,
|
||||
"reconnect_delay": self._reconnect_delay,
|
||||
}
|
||||
)
|
||||
self._client = client
|
||||
|
||||
self._run(self._client.connect(host, port, version=MQTTv311))
|
||||
|
||||
@keyword
|
||||
def disconnect(self):
|
||||
"""Disconnect from MQTT Broker.
|
||||
|
||||
Example:
|
||||
| Disconnect |
|
||||
|
||||
"""
|
||||
self._run(self._client.disconnect())
|
||||
self._messages.clear()
|
||||
|
||||
@keyword
|
||||
def unsubscribe_all_and_clear_messages(self):
|
||||
"""Unsubscribe all subscriptions and clear all messages in queue."""
|
||||
for topic in self._messages:
|
||||
self.unsubscribe(topic)
|
||||
self._messages.clear()
|
||||
|
||||
@keyword
|
||||
def subscribe(self, topic, qos=0, timeout=1):
|
||||
"""Subscribe to a topic and return a message payload received
|
||||
within the specified time.
|
||||
|
||||
`topic` topic to subscribe to
|
||||
|
||||
`qos` quality of service for the subscription, default to QoS 0
|
||||
|
||||
`timeout` duration of subscription, default to 1 second
|
||||
|
||||
Examples:
|
||||
|
||||
Subscribe and get a list of all messages received within 5 seconds
|
||||
| ${messages}= | Subscribe | test/test | qos=1 | timeout=5 |
|
||||
|
||||
"""
|
||||
timeout = 1 if timeout < 1 else timeout
|
||||
self._client.subscribe(Subscription(topic, qos))
|
||||
if self._wait(self._subcribed, timeout=timeout):
|
||||
raise Exception(
|
||||
"MQTT client subscribe timeout topic=%s qos=%s" % (topic, qos))
|
||||
logger.info("MQTT client subscribed to topic=%s qos=%s" % (topic, qos))
|
||||
|
||||
@keyword
|
||||
def unsubscribe(self, topic, timeout=1):
|
||||
"""Unsubscribe the client from the specified topic.
|
||||
|
||||
`topic` topic to unsubscribe from
|
||||
|
||||
`timeout` duration of unsubscription, default to 1 second
|
||||
|
||||
Example:
|
||||
| Unsubscribe | test/mqtt_test |
|
||||
|
||||
"""
|
||||
timeout = 1 if timeout < 1 else timeout
|
||||
self._client.unsubscribe(topic)
|
||||
if self._wait(self._unsubcribed, timeout=timeout):
|
||||
raise Exception("MQTT client unsubscribe timeout topic=%s" % topic)
|
||||
logger.info("MQTT client unsubscribed topic=%s" % topic)
|
||||
|
||||
@keyword
|
||||
def publish(self, topic, payload, qos=0, retain=False):
|
||||
"""Publish a message to a topic with specified qos and retained flag.
|
||||
It is required that a connection has been established using `Connect`
|
||||
keyword before using this keyword.
|
||||
|
||||
`topic` topic to which the message will be published
|
||||
|
||||
`paylod` message payload to publish
|
||||
|
||||
`qos` qos of the message, default to QoS 0
|
||||
|
||||
`retain` retained flag
|
||||
|
||||
Examples:
|
||||
|
||||
| Publish | test/test | test message | 1 | ${false} |
|
||||
|
||||
"""
|
||||
self._client.publish(topic, payload, qos=qos, retain=retain)
|
||||
|
||||
@keyword
|
||||
def listen(self, topic, timeout=1):
|
||||
"""Listen to a topic and return a message payload received within the
|
||||
specified time. Requires an Subscribe to have been called previously.
|
||||
|
||||
`topic` topic to listen to
|
||||
|
||||
`timeout` duration to listen, default to 1 second
|
||||
|
||||
Examples:
|
||||
|
||||
Listen and get a message received within 5 seconds
|
||||
| ${messages}= | Listen | test/test | timeout=5 |
|
||||
|
||||
"""
|
||||
timeout = 1 if timeout < 1 else timeout
|
||||
start = time.time()
|
||||
while True:
|
||||
if topic in self._messages and self._messages[topic]:
|
||||
msg = self._messages[topic].popleft()
|
||||
return msg
|
||||
|
||||
if (
|
||||
self._wait(self._recved, timeout=timeout)
|
||||
or (time.time() - start) >= timeout
|
||||
):
|
||||
break
|
||||
|
||||
def _wait(self, event, timeout):
|
||||
"""Waits for the given event within timeout.
|
||||
Returns true on timeout, false otherwise."""
|
||||
try:
|
||||
self._run(asyncio.wait_for(event.wait(), timeout))
|
||||
event.clear()
|
||||
except asyncio.TimeoutError:
|
||||
return True
|
||||
return False
|
||||
|
||||
def _on_connect(self, client, flags, rc, properties):
|
||||
logger.info("MQTT client connected")
|
||||
|
||||
def _on_message(self, client, topic, payload, qos, properties):
|
||||
logger.info("MQTT client received: topic=%s qos=%s payload=%s" %
|
||||
(topic, qos, payload))
|
||||
self._messages[topic].append(payload.decode())
|
||||
self._recved.set()
|
||||
return 0
|
||||
|
||||
def _on_disconnect(self, client, packet, exc=None):
|
||||
logger.info("MQTT client disconnected")
|
||||
|
||||
def _on_subscribe(self, client, mid, qos, properties):
|
||||
self._subcribed.set()
|
||||
|
||||
def _on_unsubscribe(self, client, mid, granted_qos):
|
||||
self._unsubcribed.set()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# import logging
|
||||
# logging.basicConfig(level=logging.DEBUG)
|
||||
|
||||
host = "127.0.0.1"
|
||||
topic = "test/test_mqtt"
|
||||
client = Client()
|
||||
|
||||
client.connect(host)
|
||||
client.subscribe(topic)
|
||||
|
||||
for i in range(3):
|
||||
client.publish(topic, "hello world %s" % i)
|
||||
msg = client.listen(topic)
|
||||
print("MQTT client receive: topic=%s msg=%s" % (topic, msg))
|
||||
|
||||
client.unsubscribe(topic)
|
||||
client.disconnect()
|
||||
@@ -0,0 +1,235 @@
|
||||
from os import remove
|
||||
import os
|
||||
import random
|
||||
import subprocess
|
||||
import shutil
|
||||
import time
|
||||
|
||||
|
||||
def prepare_persistence_dir():
|
||||
os.system("mkdir -p build/persistence")
|
||||
|
||||
|
||||
class Neuron(object):
|
||||
process = 0
|
||||
profiler_process = None
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def Start_Neuron(self):
|
||||
prepare_persistence_dir()
|
||||
self.process = subprocess.Popen(['./neuron', '--log'], cwd='build/')
|
||||
return self.process
|
||||
|
||||
def Stop_Neuron(self, remove_persistence_data=True):
|
||||
if self.profiler_process is not None:
|
||||
# wait for plotting
|
||||
time.sleep(5)
|
||||
self.process.kill()
|
||||
if remove_persistence_data:
|
||||
os.system("rm build/persistence/sqlite.db")
|
||||
prepare_persistence_dir()
|
||||
|
||||
def End_Neuron(self, process):
|
||||
process.kill()
|
||||
|
||||
def Remove_Persistence(self):
|
||||
os.system("rm build/persistence/sqlite.db")
|
||||
prepare_persistence_dir()
|
||||
|
||||
def Profile_Neuron(self, interval, result_dir):
|
||||
cmd = [
|
||||
'psrecord', str(self.process.pid),
|
||||
'--interval', str(interval),
|
||||
'--plot', result_dir + '/cpu_mem.svg'
|
||||
]
|
||||
|
||||
self.profiler_process = subprocess.Popen(cmd)
|
||||
|
||||
|
||||
class Tool(object):
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def Array_Len(self, array):
|
||||
return len(array)
|
||||
|
||||
|
||||
class Plugin(object):
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def Get_Plugin_By_Name(self, splugins, name):
|
||||
for plugin in splugins:
|
||||
if plugin['name'] == name:
|
||||
return plugin['id']
|
||||
return 0
|
||||
|
||||
def Plugin_With_Name_Sholud_Exist(self, splugins, name):
|
||||
assert 0 != self.Get_Plugin_By_Name(splugins, name)
|
||||
|
||||
def Plugin_With_Name_Should_Not_Exist(self, splugins, name):
|
||||
assert 0 == self.Get_Plugin_By_Name(splugins, name)
|
||||
|
||||
|
||||
class GrpConfig(object):
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def Get_Interval_In_Group_Config(self, gconfigs, gname):
|
||||
for gconfig in gconfigs[0]:
|
||||
if gconfig['name'] == gname:
|
||||
return gconfig['interval']
|
||||
return 0
|
||||
|
||||
def Group_Config_Size(self, gconfigs):
|
||||
size = 0
|
||||
for gconfig in gconfigs[0]:
|
||||
size = size + 1
|
||||
return size
|
||||
|
||||
def Get_Random_Group_Config(self, gconfigs):
|
||||
return random.choice(gconfigs)['name']
|
||||
|
||||
def Group_Config_Check(self, gconfigs, name, interval):
|
||||
ret = -1
|
||||
for gconfig in gconfigs:
|
||||
if gconfig['name'] == name:
|
||||
if gconfig['interval'] == int(interval):
|
||||
ret = 0
|
||||
break
|
||||
return ret
|
||||
|
||||
def Get_Group_Config_By_Name(self, sgconfigs, name):
|
||||
for gconfig in sgconfigs:
|
||||
if gconfig['name'] == name:
|
||||
return gconfig['name']
|
||||
return 0
|
||||
|
||||
|
||||
class Node(object):
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def Get_Node_By_Name(self, snodes, name):
|
||||
for node in snodes:
|
||||
if node['name'] == name:
|
||||
return True
|
||||
return False
|
||||
|
||||
def Node_Should_Exist(self, snodes, name):
|
||||
assert True == self.Get_Node_By_Name(snodes, name)
|
||||
|
||||
def Node_Should_Not_Exist(self, snodes, name):
|
||||
assert False == self.Get_Node_By_Name(snodes, name)
|
||||
|
||||
def Node_With_Name_Should_Not_Exist(self, snodes, name):
|
||||
assert 0 == self.Get_Node_By_Name(snodes, name)
|
||||
|
||||
def Get_Random_Node(self, snodes):
|
||||
return random.choice(snodes)['id']
|
||||
|
||||
|
||||
class Tag(object):
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def Tag_Check(self, tags, name, type, group_config_name, attribute, address):
|
||||
ret = -1
|
||||
for tag in tags:
|
||||
if tag['name'] == name:
|
||||
if tag['type'] == int(type) and tag['group_config_name'] == group_config_name and tag['attribute'] == int(attribute) and tag['address'] == address:
|
||||
ret = 0
|
||||
break
|
||||
return ret
|
||||
|
||||
def Tag_Find_By_Name(self, tags, name):
|
||||
for tag in tags:
|
||||
if tag['name'] == name:
|
||||
return tag
|
||||
|
||||
return None
|
||||
|
||||
|
||||
class Subscribe(object):
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def Subscribe_Check(self, groups, node_id, group_config_name):
|
||||
ret = -1
|
||||
for group in groups:
|
||||
if group['node_id'] == int(node_id) and group['group_config_name'] == group_config_name:
|
||||
ret = 0
|
||||
break
|
||||
return ret
|
||||
|
||||
|
||||
class Read(object):
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def Compare_Tag_Value_Bool(self, tags, name, value):
|
||||
ret = -1
|
||||
for tag in tags:
|
||||
if tag['name'] == name:
|
||||
if isinstance(value, str):
|
||||
if (tag['value'] == False and value.lower() == "false" or
|
||||
tag['value'] == True and value.lower() == "true"):
|
||||
ret = 0
|
||||
elif tag['value'] == int(value):
|
||||
ret = 0
|
||||
break
|
||||
return ret
|
||||
|
||||
def Compare_Tag_Value_Int(self, tags, name, value):
|
||||
ret = -1
|
||||
for tag in tags:
|
||||
if tag['name'] == name:
|
||||
if int(tag['value']) == int(value):
|
||||
ret = 0
|
||||
break
|
||||
return ret
|
||||
|
||||
def Compare_Tag_Value_Float(self, tags, name, value):
|
||||
ret = -1
|
||||
for tag in tags:
|
||||
if tag['name'] == name:
|
||||
if float(tag['value']) <= float(value) + 0.1 and float(tag['value']) >= float(value) - 0.1:
|
||||
ret = 0
|
||||
break
|
||||
return ret
|
||||
|
||||
def Compare_Tag_Value_String(self, tags, name, value):
|
||||
ret = -1
|
||||
for tag in tags:
|
||||
if tag['name'] == name:
|
||||
if tag['value'] == str(value):
|
||||
ret = 0
|
||||
break
|
||||
return ret
|
||||
|
||||
def Compare_Tag_Value_Strings(self, tags, name, value):
|
||||
ret = -1
|
||||
for tag in tags:
|
||||
if tag['name'] == name:
|
||||
if "\"" + tag['value'] + "\"" == str(value):
|
||||
ret = 0
|
||||
break
|
||||
return ret
|
||||
|
||||
def Check_Tag_Error(self, tags, name, value):
|
||||
ret = -1
|
||||
for tag in tags:
|
||||
if tag['name'] == name:
|
||||
if int(tag['error']) == int(value):
|
||||
ret = 0
|
||||
break
|
||||
return ret
|
||||
@@ -0,0 +1,35 @@
|
||||
# Functional test
|
||||
|
||||
Functional testing uses the robotframework automated testing framework, providing templates for each test case of the northbound APP and southbound DRIVER types.
|
||||
|
||||
Testing is divided into the following categories.
|
||||
|Test case|Description|
|
||||
|-----|----------|
|
||||
|Core interface test|Mainly including the addition, deletion, modification, query, subscription, and other operations of the HTTP API interface for core data(PLUGIN, NODE, GROUP, TAG)|
|
||||
|Southbound DRIVER test||
|
||||
|Northbound APP test||
|
||||
|Plugin specific test case|Such as OPC UA specific device discovery, can different devices be connected normally|
|
||||
|
||||
To run all functional testers
|
||||
|
||||
Enter the neuron/build directory.
|
||||
Install Mosquito software.
|
||||
```shell
|
||||
$ sudo apt-get install -y mosquitto
|
||||
```
|
||||
|
||||
Start the mosquitto server.
|
||||
```shell
|
||||
$ mosquitto -v &
|
||||
```
|
||||
|
||||
Install requirements.
|
||||
```shell
|
||||
$ python3 -m pip install -U pip
|
||||
$ python3 -m pip install -r ft/requirements.txt
|
||||
```
|
||||
|
||||
Run functional tests and generate test reports.
|
||||
```shell
|
||||
$ python3 -m robot --maxerroelines=600 -P ft/ -d ft/reports ft
|
||||
```
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"nodes": [
|
||||
{
|
||||
"type": 1,
|
||||
"plugin_name": "modbus-tcp",
|
||||
"name": "modbus-tcp-0000",
|
||||
"state": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"read_interval": 1000,
|
||||
"group_config_name": "group-0000",
|
||||
"adapter_name": "modbus-tcp-0000"
|
||||
}
|
||||
+60004
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"params": {
|
||||
"host": "127.0.0.1",
|
||||
"port": 60502,
|
||||
"connection_mode": 0
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"params": {
|
||||
"req-topic": "Neuron/req",
|
||||
"res-topic": "Neuron/resp",
|
||||
"ssl": "false",
|
||||
"host": "127.0.0.1",
|
||||
"port": 1883,
|
||||
"username": "",
|
||||
"password": ""
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"subscriptions": [
|
||||
{
|
||||
"sub_adapter_name": "mqtt-0000",
|
||||
"group_config_name": "group-0000",
|
||||
"src_adapter_name": "modbus-tcp-0000",
|
||||
"read_interval": 1000
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"plugins": []
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"nodes": [
|
||||
{
|
||||
"type": 1,
|
||||
"plugin_name": "modbus-tcp",
|
||||
"name": "modbus-tcp-0000",
|
||||
"state": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"read_interval": 1000,
|
||||
"group_config_name": "group-0000",
|
||||
"adapter_name": "modbus-tcp-0000"
|
||||
}
|
||||
+6004
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"params": {
|
||||
"host": "127.0.0.1",
|
||||
"port": 60502,
|
||||
"connection_mode": 0
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"params": {
|
||||
"req-topic": "Neuron/req",
|
||||
"res-topic": "Neuron/resp",
|
||||
"ssl": "false",
|
||||
"host": "127.0.0.1",
|
||||
"port": 1883,
|
||||
"username": "",
|
||||
"password": ""
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"subscriptions": [
|
||||
{
|
||||
"sub_adapter_name": "mqtt-0000",
|
||||
"group_config_name": "group-0000",
|
||||
"src_adapter_name": "modbus-tcp-0000",
|
||||
"read_interval": 1000
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"plugins": []
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
{
|
||||
"nodes": [
|
||||
{
|
||||
"type": 1,
|
||||
"plugin_name": "modbus-tcp",
|
||||
"name": "modbus-tcp-0000",
|
||||
"state": 1
|
||||
},
|
||||
{
|
||||
"type": 1,
|
||||
"plugin_name": "modbus-tcp",
|
||||
"name": "modbus-tcp-0001",
|
||||
"state": 1
|
||||
},
|
||||
{
|
||||
"type": 1,
|
||||
"plugin_name": "modbus-tcp",
|
||||
"name": "modbus-tcp-0002",
|
||||
"state": 1
|
||||
},
|
||||
{
|
||||
"type": 1,
|
||||
"plugin_name": "modbus-tcp",
|
||||
"name": "modbus-tcp-0003",
|
||||
"state": 1
|
||||
},
|
||||
{
|
||||
"type": 1,
|
||||
"plugin_name": "modbus-tcp",
|
||||
"name": "modbus-tcp-0004",
|
||||
"state": 1
|
||||
},
|
||||
{
|
||||
"type": 1,
|
||||
"plugin_name": "modbus-tcp",
|
||||
"name": "modbus-tcp-0005",
|
||||
"state": 1
|
||||
},
|
||||
{
|
||||
"type": 1,
|
||||
"plugin_name": "modbus-tcp",
|
||||
"name": "modbus-tcp-0006",
|
||||
"state": 1
|
||||
},
|
||||
{
|
||||
"type": 1,
|
||||
"plugin_name": "modbus-tcp",
|
||||
"name": "modbus-tcp-0007",
|
||||
"state": 1
|
||||
},
|
||||
{
|
||||
"type": 1,
|
||||
"plugin_name": "modbus-tcp",
|
||||
"name": "modbus-tcp-0008",
|
||||
"state": 1
|
||||
},
|
||||
{
|
||||
"type": 1,
|
||||
"plugin_name": "modbus-tcp",
|
||||
"name": "modbus-tcp-0009",
|
||||
"state": 1
|
||||
},
|
||||
{
|
||||
"type": 1,
|
||||
"plugin_name": "neuron-opcua-plugin",
|
||||
"name": "opcua-0000",
|
||||
"state": 1
|
||||
},
|
||||
{
|
||||
"type": 1,
|
||||
"plugin_name": "neuron-opcua-plugin",
|
||||
"name": "opcua-0001",
|
||||
"state": 1
|
||||
},
|
||||
{
|
||||
"type": 1,
|
||||
"plugin_name": "neuron-opcua-plugin",
|
||||
"name": "opcua-0002",
|
||||
"state": 1
|
||||
},
|
||||
{
|
||||
"type": 1,
|
||||
"plugin_name": "neuron-opcua-plugin",
|
||||
"name": "opcua-0003",
|
||||
"state": 1
|
||||
},
|
||||
{
|
||||
"type": 1,
|
||||
"plugin_name": "neuron-opcua-plugin",
|
||||
"name": "opcua-0004",
|
||||
"state": 1
|
||||
},
|
||||
{
|
||||
"type": 1,
|
||||
"plugin_name": "neuron-opcua-plugin",
|
||||
"name": "opcua-0005",
|
||||
"state": 1
|
||||
},
|
||||
{
|
||||
"type": 1,
|
||||
"plugin_name": "neuron-opcua-plugin",
|
||||
"name": "opcua-0006",
|
||||
"state": 1
|
||||
},
|
||||
{
|
||||
"type": 1,
|
||||
"plugin_name": "neuron-opcua-plugin",
|
||||
"name": "opcua-0007",
|
||||
"state": 1
|
||||
},
|
||||
{
|
||||
"type": 1,
|
||||
"plugin_name": "neuron-opcua-plugin",
|
||||
"name": "opcua-0008",
|
||||
"state": 1
|
||||
},
|
||||
{
|
||||
"type": 1,
|
||||
"plugin_name": "neuron-opcua-plugin",
|
||||
"name": "opcua-0009",
|
||||
"state": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"read_interval": 1000,
|
||||
"group_config_name": "group-0000",
|
||||
"adapter_name": "modbus-tcp-0000"
|
||||
}
|
||||
+604
@@ -0,0 +1,604 @@
|
||||
{
|
||||
"tags": [
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus1",
|
||||
"attribute": 3,
|
||||
"address": "1!400001"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus2",
|
||||
"attribute": 3,
|
||||
"address": "1!400002"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus3",
|
||||
"attribute": 3,
|
||||
"address": "1!400003"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus4",
|
||||
"attribute": 3,
|
||||
"address": "1!400004"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus5",
|
||||
"attribute": 3,
|
||||
"address": "1!400005"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus6",
|
||||
"attribute": 3,
|
||||
"address": "1!400006"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus7",
|
||||
"attribute": 3,
|
||||
"address": "1!400007"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus8",
|
||||
"attribute": 3,
|
||||
"address": "1!400008"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus9",
|
||||
"attribute": 3,
|
||||
"address": "1!400009"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus10",
|
||||
"attribute": 3,
|
||||
"address": "1!400010"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus11",
|
||||
"attribute": 3,
|
||||
"address": "1!400011"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus12",
|
||||
"attribute": 3,
|
||||
"address": "1!400012"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus13",
|
||||
"attribute": 3,
|
||||
"address": "1!400013"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus14",
|
||||
"attribute": 3,
|
||||
"address": "1!400014"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus15",
|
||||
"attribute": 3,
|
||||
"address": "1!400015"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus16",
|
||||
"attribute": 3,
|
||||
"address": "1!400016"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus17",
|
||||
"attribute": 3,
|
||||
"address": "1!400017"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus18",
|
||||
"attribute": 3,
|
||||
"address": "1!400018"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus19",
|
||||
"attribute": 3,
|
||||
"address": "1!400019"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus20",
|
||||
"attribute": 3,
|
||||
"address": "1!400020"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus21",
|
||||
"attribute": 3,
|
||||
"address": "1!400021"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus22",
|
||||
"attribute": 3,
|
||||
"address": "1!400022"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus23",
|
||||
"attribute": 3,
|
||||
"address": "1!400023"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus24",
|
||||
"attribute": 3,
|
||||
"address": "1!400024"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus25",
|
||||
"attribute": 3,
|
||||
"address": "1!400025"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus26",
|
||||
"attribute": 3,
|
||||
"address": "1!400026"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus27",
|
||||
"attribute": 3,
|
||||
"address": "1!400027"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus28",
|
||||
"attribute": 3,
|
||||
"address": "1!400028"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus29",
|
||||
"attribute": 3,
|
||||
"address": "1!400029"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus30",
|
||||
"attribute": 3,
|
||||
"address": "1!400030"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus31",
|
||||
"attribute": 3,
|
||||
"address": "1!400031"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus32",
|
||||
"attribute": 3,
|
||||
"address": "1!400032"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus33",
|
||||
"attribute": 3,
|
||||
"address": "1!400033"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus34",
|
||||
"attribute": 3,
|
||||
"address": "1!400034"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus35",
|
||||
"attribute": 3,
|
||||
"address": "1!400035"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus36",
|
||||
"attribute": 3,
|
||||
"address": "1!400036"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus37",
|
||||
"attribute": 3,
|
||||
"address": "1!400037"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus38",
|
||||
"attribute": 3,
|
||||
"address": "1!400038"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus39",
|
||||
"attribute": 3,
|
||||
"address": "1!400039"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus40",
|
||||
"attribute": 3,
|
||||
"address": "1!400040"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus41",
|
||||
"attribute": 3,
|
||||
"address": "1!400041"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus42",
|
||||
"attribute": 3,
|
||||
"address": "1!400042"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus43",
|
||||
"attribute": 3,
|
||||
"address": "1!400043"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus44",
|
||||
"attribute": 3,
|
||||
"address": "1!400044"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus45",
|
||||
"attribute": 3,
|
||||
"address": "1!400045"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus46",
|
||||
"attribute": 3,
|
||||
"address": "1!400046"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus47",
|
||||
"attribute": 3,
|
||||
"address": "1!400047"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus48",
|
||||
"attribute": 3,
|
||||
"address": "1!400048"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus49",
|
||||
"attribute": 3,
|
||||
"address": "1!400049"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus50",
|
||||
"attribute": 3,
|
||||
"address": "1!400050"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus51",
|
||||
"attribute": 3,
|
||||
"address": "1!400051"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus52",
|
||||
"attribute": 3,
|
||||
"address": "1!400052"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus53",
|
||||
"attribute": 3,
|
||||
"address": "1!400053"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus54",
|
||||
"attribute": 3,
|
||||
"address": "1!400054"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus55",
|
||||
"attribute": 3,
|
||||
"address": "1!400055"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus56",
|
||||
"attribute": 3,
|
||||
"address": "1!400056"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus57",
|
||||
"attribute": 3,
|
||||
"address": "1!400057"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus58",
|
||||
"attribute": 3,
|
||||
"address": "1!400058"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus59",
|
||||
"attribute": 3,
|
||||
"address": "1!400059"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus60",
|
||||
"attribute": 3,
|
||||
"address": "1!400060"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus61",
|
||||
"attribute": 3,
|
||||
"address": "1!400061"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus62",
|
||||
"attribute": 3,
|
||||
"address": "1!400062"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus63",
|
||||
"attribute": 3,
|
||||
"address": "1!400063"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus64",
|
||||
"attribute": 3,
|
||||
"address": "1!400064"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus65",
|
||||
"attribute": 3,
|
||||
"address": "1!400065"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus66",
|
||||
"attribute": 3,
|
||||
"address": "1!400066"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus67",
|
||||
"attribute": 3,
|
||||
"address": "1!400067"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus68",
|
||||
"attribute": 3,
|
||||
"address": "1!400068"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus69",
|
||||
"attribute": 3,
|
||||
"address": "1!400069"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus70",
|
||||
"attribute": 3,
|
||||
"address": "1!400070"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus71",
|
||||
"attribute": 3,
|
||||
"address": "1!400071"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus72",
|
||||
"attribute": 3,
|
||||
"address": "1!400072"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus73",
|
||||
"attribute": 3,
|
||||
"address": "1!400073"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus74",
|
||||
"attribute": 3,
|
||||
"address": "1!400074"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus75",
|
||||
"attribute": 3,
|
||||
"address": "1!400075"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus76",
|
||||
"attribute": 3,
|
||||
"address": "1!400076"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus77",
|
||||
"attribute": 3,
|
||||
"address": "1!400077"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus78",
|
||||
"attribute": 3,
|
||||
"address": "1!400078"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus79",
|
||||
"attribute": 3,
|
||||
"address": "1!400079"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus80",
|
||||
"attribute": 3,
|
||||
"address": "1!400080"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus81",
|
||||
"attribute": 3,
|
||||
"address": "1!400081"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus82",
|
||||
"attribute": 3,
|
||||
"address": "1!400082"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus83",
|
||||
"attribute": 3,
|
||||
"address": "1!400083"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus84",
|
||||
"attribute": 3,
|
||||
"address": "1!400084"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus85",
|
||||
"attribute": 3,
|
||||
"address": "1!400085"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus86",
|
||||
"attribute": 3,
|
||||
"address": "1!400086"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus87",
|
||||
"attribute": 3,
|
||||
"address": "1!400087"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus88",
|
||||
"attribute": 3,
|
||||
"address": "1!400088"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus89",
|
||||
"attribute": 3,
|
||||
"address": "1!400089"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus90",
|
||||
"attribute": 3,
|
||||
"address": "1!400090"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus91",
|
||||
"attribute": 3,
|
||||
"address": "1!400091"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus92",
|
||||
"attribute": 3,
|
||||
"address": "1!400092"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus93",
|
||||
"attribute": 3,
|
||||
"address": "1!400093"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus94",
|
||||
"attribute": 3,
|
||||
"address": "1!400094"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus95",
|
||||
"attribute": 3,
|
||||
"address": "1!400095"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus96",
|
||||
"attribute": 3,
|
||||
"address": "1!400096"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus97",
|
||||
"attribute": 3,
|
||||
"address": "1!400097"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus98",
|
||||
"attribute": 3,
|
||||
"address": "1!400098"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus99",
|
||||
"attribute": 3,
|
||||
"address": "1!400099"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus100",
|
||||
"attribute": 3,
|
||||
"address": "1!400100"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"read_interval": 1000,
|
||||
"group_config_name": "group-0001",
|
||||
"adapter_name": "modbus-tcp-0000"
|
||||
}
|
||||
+604
@@ -0,0 +1,604 @@
|
||||
{
|
||||
"tags": [
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus101",
|
||||
"attribute": 3,
|
||||
"address": "1!400101"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus102",
|
||||
"attribute": 3,
|
||||
"address": "1!400102"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus103",
|
||||
"attribute": 3,
|
||||
"address": "1!400103"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus104",
|
||||
"attribute": 3,
|
||||
"address": "1!400104"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus105",
|
||||
"attribute": 3,
|
||||
"address": "1!400105"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus106",
|
||||
"attribute": 3,
|
||||
"address": "1!400106"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus107",
|
||||
"attribute": 3,
|
||||
"address": "1!400107"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus108",
|
||||
"attribute": 3,
|
||||
"address": "1!400108"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus109",
|
||||
"attribute": 3,
|
||||
"address": "1!400109"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus110",
|
||||
"attribute": 3,
|
||||
"address": "1!400110"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus111",
|
||||
"attribute": 3,
|
||||
"address": "1!400111"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus112",
|
||||
"attribute": 3,
|
||||
"address": "1!400112"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus113",
|
||||
"attribute": 3,
|
||||
"address": "1!400113"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus114",
|
||||
"attribute": 3,
|
||||
"address": "1!400114"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus115",
|
||||
"attribute": 3,
|
||||
"address": "1!400115"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus116",
|
||||
"attribute": 3,
|
||||
"address": "1!400116"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus117",
|
||||
"attribute": 3,
|
||||
"address": "1!400117"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus118",
|
||||
"attribute": 3,
|
||||
"address": "1!400118"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus119",
|
||||
"attribute": 3,
|
||||
"address": "1!400119"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus120",
|
||||
"attribute": 3,
|
||||
"address": "1!400120"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus121",
|
||||
"attribute": 3,
|
||||
"address": "1!400121"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus122",
|
||||
"attribute": 3,
|
||||
"address": "1!400122"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus123",
|
||||
"attribute": 3,
|
||||
"address": "1!400123"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus124",
|
||||
"attribute": 3,
|
||||
"address": "1!400124"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus125",
|
||||
"attribute": 3,
|
||||
"address": "1!400125"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus126",
|
||||
"attribute": 3,
|
||||
"address": "1!400126"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus127",
|
||||
"attribute": 3,
|
||||
"address": "1!400127"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus128",
|
||||
"attribute": 3,
|
||||
"address": "1!400128"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus129",
|
||||
"attribute": 3,
|
||||
"address": "1!400129"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus130",
|
||||
"attribute": 3,
|
||||
"address": "1!400130"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus131",
|
||||
"attribute": 3,
|
||||
"address": "1!400131"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus132",
|
||||
"attribute": 3,
|
||||
"address": "1!400132"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus133",
|
||||
"attribute": 3,
|
||||
"address": "1!400133"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus134",
|
||||
"attribute": 3,
|
||||
"address": "1!400134"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus135",
|
||||
"attribute": 3,
|
||||
"address": "1!400135"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus136",
|
||||
"attribute": 3,
|
||||
"address": "1!400136"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus137",
|
||||
"attribute": 3,
|
||||
"address": "1!400137"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus138",
|
||||
"attribute": 3,
|
||||
"address": "1!400138"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus139",
|
||||
"attribute": 3,
|
||||
"address": "1!400139"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus140",
|
||||
"attribute": 3,
|
||||
"address": "1!400140"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus141",
|
||||
"attribute": 3,
|
||||
"address": "1!400141"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus142",
|
||||
"attribute": 3,
|
||||
"address": "1!400142"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus143",
|
||||
"attribute": 3,
|
||||
"address": "1!400143"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus144",
|
||||
"attribute": 3,
|
||||
"address": "1!400144"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus145",
|
||||
"attribute": 3,
|
||||
"address": "1!400145"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus146",
|
||||
"attribute": 3,
|
||||
"address": "1!400146"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus147",
|
||||
"attribute": 3,
|
||||
"address": "1!400147"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus148",
|
||||
"attribute": 3,
|
||||
"address": "1!400148"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus149",
|
||||
"attribute": 3,
|
||||
"address": "1!400149"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus150",
|
||||
"attribute": 3,
|
||||
"address": "1!400150"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus151",
|
||||
"attribute": 3,
|
||||
"address": "1!400151"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus152",
|
||||
"attribute": 3,
|
||||
"address": "1!400152"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus153",
|
||||
"attribute": 3,
|
||||
"address": "1!400153"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus154",
|
||||
"attribute": 3,
|
||||
"address": "1!400154"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus155",
|
||||
"attribute": 3,
|
||||
"address": "1!400155"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus156",
|
||||
"attribute": 3,
|
||||
"address": "1!400156"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus157",
|
||||
"attribute": 3,
|
||||
"address": "1!400157"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus158",
|
||||
"attribute": 3,
|
||||
"address": "1!400158"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus159",
|
||||
"attribute": 3,
|
||||
"address": "1!400159"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus160",
|
||||
"attribute": 3,
|
||||
"address": "1!400160"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus161",
|
||||
"attribute": 3,
|
||||
"address": "1!400161"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus162",
|
||||
"attribute": 3,
|
||||
"address": "1!400162"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus163",
|
||||
"attribute": 3,
|
||||
"address": "1!400163"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus164",
|
||||
"attribute": 3,
|
||||
"address": "1!400164"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus165",
|
||||
"attribute": 3,
|
||||
"address": "1!400165"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus166",
|
||||
"attribute": 3,
|
||||
"address": "1!400166"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus167",
|
||||
"attribute": 3,
|
||||
"address": "1!400167"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus168",
|
||||
"attribute": 3,
|
||||
"address": "1!400168"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus169",
|
||||
"attribute": 3,
|
||||
"address": "1!400169"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus170",
|
||||
"attribute": 3,
|
||||
"address": "1!400170"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus171",
|
||||
"attribute": 3,
|
||||
"address": "1!400171"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus172",
|
||||
"attribute": 3,
|
||||
"address": "1!400172"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus173",
|
||||
"attribute": 3,
|
||||
"address": "1!400173"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus174",
|
||||
"attribute": 3,
|
||||
"address": "1!400174"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus175",
|
||||
"attribute": 3,
|
||||
"address": "1!400175"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus176",
|
||||
"attribute": 3,
|
||||
"address": "1!400176"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus177",
|
||||
"attribute": 3,
|
||||
"address": "1!400177"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus178",
|
||||
"attribute": 3,
|
||||
"address": "1!400178"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus179",
|
||||
"attribute": 3,
|
||||
"address": "1!400179"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus180",
|
||||
"attribute": 3,
|
||||
"address": "1!400180"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus181",
|
||||
"attribute": 3,
|
||||
"address": "1!400181"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus182",
|
||||
"attribute": 3,
|
||||
"address": "1!400182"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus183",
|
||||
"attribute": 3,
|
||||
"address": "1!400183"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus184",
|
||||
"attribute": 3,
|
||||
"address": "1!400184"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus185",
|
||||
"attribute": 3,
|
||||
"address": "1!400185"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus186",
|
||||
"attribute": 3,
|
||||
"address": "1!400186"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus187",
|
||||
"attribute": 3,
|
||||
"address": "1!400187"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus188",
|
||||
"attribute": 3,
|
||||
"address": "1!400188"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus189",
|
||||
"attribute": 3,
|
||||
"address": "1!400189"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus190",
|
||||
"attribute": 3,
|
||||
"address": "1!400190"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus191",
|
||||
"attribute": 3,
|
||||
"address": "1!400191"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus192",
|
||||
"attribute": 3,
|
||||
"address": "1!400192"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus193",
|
||||
"attribute": 3,
|
||||
"address": "1!400193"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus194",
|
||||
"attribute": 3,
|
||||
"address": "1!400194"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus195",
|
||||
"attribute": 3,
|
||||
"address": "1!400195"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus196",
|
||||
"attribute": 3,
|
||||
"address": "1!400196"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus197",
|
||||
"attribute": 3,
|
||||
"address": "1!400197"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus198",
|
||||
"attribute": 3,
|
||||
"address": "1!400198"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus199",
|
||||
"attribute": 3,
|
||||
"address": "1!400199"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"name": "modbus200",
|
||||
"attribute": 3,
|
||||
"address": "1!400200"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"params": {
|
||||
"host":"127.0.0.1",
|
||||
"port":60502,
|
||||
"connection_mode":0
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"read_interval": 1000,
|
||||
"group_config_name": "group-0000",
|
||||
"adapter_name": "modbus-tcp-0001"
|
||||
}
|
||||
+1204
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"read_interval": 1000,
|
||||
"group_config_name": "group-0001",
|
||||
"adapter_name": "modbus-tcp-0001"
|
||||
}
|
||||
+1204
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"read_interval": 1000,
|
||||
"group_config_name": "group-0002",
|
||||
"adapter_name": "modbus-tcp-0001"
|
||||
}
|
||||
+1204
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"read_interval": 1000,
|
||||
"group_config_name": "group-0003",
|
||||
"adapter_name": "modbus-tcp-0001"
|
||||
}
|
||||
+1204
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"params": {
|
||||
"host":"127.0.0.1",
|
||||
"port":60502,
|
||||
"connection_mode":0
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"read_interval": 1000,
|
||||
"group_config_name": "group-0000",
|
||||
"adapter_name": "modbus-tcp-0002"
|
||||
}
|
||||
+1204
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"read_interval": 1000,
|
||||
"group_config_name": "group-0001",
|
||||
"adapter_name": "modbus-tcp-0002"
|
||||
}
|
||||
+1204
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"read_interval": 1000,
|
||||
"group_config_name": "group-0002",
|
||||
"adapter_name": "modbus-tcp-0002"
|
||||
}
|
||||
+1204
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"read_interval": 1000,
|
||||
"group_config_name": "group-0003",
|
||||
"adapter_name": "modbus-tcp-0002"
|
||||
}
|
||||
+1204
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"read_interval": 1000,
|
||||
"group_config_name": "group-0004",
|
||||
"adapter_name": "modbus-tcp-0002"
|
||||
}
|
||||
+1204
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"params": {
|
||||
"host":"127.0.0.1",
|
||||
"port":60502,
|
||||
"connection_mode":0
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"read_interval": 1000,
|
||||
"group_config_name": "group-0000",
|
||||
"adapter_name": "modbus-tcp-0003"
|
||||
}
|
||||
+1204
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"read_interval": 1000,
|
||||
"group_config_name": "group-0001",
|
||||
"adapter_name": "modbus-tcp-0003"
|
||||
}
|
||||
+1204
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"read_interval": 1000,
|
||||
"group_config_name": "group-0002",
|
||||
"adapter_name": "modbus-tcp-0003"
|
||||
}
|
||||
+1204
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"read_interval": 1000,
|
||||
"group_config_name": "group-0003",
|
||||
"adapter_name": "modbus-tcp-0003"
|
||||
}
|
||||
+1204
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"read_interval": 1000,
|
||||
"group_config_name": "group-0004",
|
||||
"adapter_name": "modbus-tcp-0003"
|
||||
}
|
||||
+1204
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"params": {
|
||||
"host":"127.0.0.1",
|
||||
"port":60502,
|
||||
"connection_mode":0
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"read_interval": 1000,
|
||||
"group_config_name": "group-0000",
|
||||
"adapter_name": "modbus-tcp-0004"
|
||||
}
|
||||
+1204
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"read_interval": 1000,
|
||||
"group_config_name": "group-0001",
|
||||
"adapter_name": "modbus-tcp-0004"
|
||||
}
|
||||
+1204
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"read_interval": 1000,
|
||||
"group_config_name": "group-0002",
|
||||
"adapter_name": "modbus-tcp-0004"
|
||||
}
|
||||
+1204
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"read_interval": 1000,
|
||||
"group_config_name": "group-0003",
|
||||
"adapter_name": "modbus-tcp-0004"
|
||||
}
|
||||
+1204
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"read_interval": 1000,
|
||||
"group_config_name": "group-0004",
|
||||
"adapter_name": "modbus-tcp-0004"
|
||||
}
|
||||
+1204
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"params": {
|
||||
"host":"127.0.0.1",
|
||||
"port":60502,
|
||||
"connection_mode":0
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"read_interval": 1000,
|
||||
"group_config_name": "group-0000",
|
||||
"adapter_name": "modbus-tcp-0005"
|
||||
}
|
||||
+1204
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"read_interval": 1000,
|
||||
"group_config_name": "group-0001",
|
||||
"adapter_name": "modbus-tcp-0005"
|
||||
}
|
||||
+1204
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"read_interval": 1000,
|
||||
"group_config_name": "group-0002",
|
||||
"adapter_name": "modbus-tcp-0005"
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user