Compare commits

..
11 Commits
Author SHA1 Message Date
fengzeroz f86e7a7ac3 Merge pull request #674 from fengzeroz/v2.1.0
fix serial port parameter
2022-07-28 16:52:16 +08:00
fengzero 7a34bfa0be fix serial port parameter 2022-07-28 08:51:33 +00:00
fengzeroz da6d0d476a Merge pull request #673 from fengzeroz/v2.1.0
version: 2.1.2
2022-07-28 16:06:20 +08:00
fengzero 8752cb2615 version: 2.1.2 2022-07-28 08:05:27 +00:00
fengzeroz aba384db8d Merge pull request #671 from gc87/mqtt-fix669-v2.1.0
fix(mqtt): crash caused by global static variables(v2.1.0)
2022-07-28 10:57:20 +08:00
gc87 632915b4ae fix(mqtt): crash caused by global static variables 2022-07-27 17:22:07 +08:00
fengzeroz 632989865a Merge pull request #664 from fengzeroz/v2.1.0
V2.1.0
2022-07-26 15:26:59 +08:00
fengzero 3044b28a93 ci: rename daily release name 2022-07-26 07:26:02 +00:00
fengzero 8d7eeca8d6 ci: branch daily release 2022-07-26 07:25:54 +00:00
fengzeroz 3daadbfcaa Merge pull request #663 from fengzeroz/v2.1.0
ci: package modbus-tcp plugin
2022-07-26 15:18:42 +08:00
fengzero 8fee3ae7e2 ci: package modbus-tcp plugin 2022-07-26 07:15:47 +00:00
574 changed files with 447906 additions and 160923 deletions
+1
View File
@@ -12,3 +12,4 @@ PointerAlignment: Right
SpaceAfterCStyleCast: true
AllowShortFunctionsOnASingleLine: Inline
BreakBeforeBinaryOperators: None
-9
View File
@@ -1,9 +0,0 @@
# Issue Template
Please fill in the issue as required.
* System:
* Architecture:
* Version:
* Problem Description:
* Log Information:
+28
View File
@@ -0,0 +1,28 @@
name: Check helm version
on:
push:
paths:
- deploy/charts/neuron/templates/**
pull_request:
paths:
- deploy/charts/neuron/templates/**
jobs:
check-helm-version:
runs-on: ubuntu-latest
steps:
- run: minikube start
- uses: actions/checkout@v2
- name: Update helm
run: |
helm repo add emqx https://repos.emqx.io/charts
helm repo update
- name: Check helm version
run: |
old=$(helm show chart emqx/neuron |egrep "^version" | sed -r 's|^version:[[:space:]]([0-9]+.[0-9]+.[0-9]+)$|\1|g')
now=$(egrep "^version" deploy/charts/neuron/Chart.yaml | sed -r 's|^version:[[:space:]]([0-9]+.[0-9]+.[0-9]+)$|\1|g')
if [ "$old" = "$now" ];then
echo "Need update version for Chart.yaml"
exit 1
fi
+41 -117
View File
@@ -9,165 +9,89 @@ on:
jobs:
clang_format_check:
runs-on: ubuntu-24.04
runs-on: ubuntu-20.04
steps:
# checkout
- uses: actions/checkout@v4
- uses: actions/checkout@v2
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.12
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v2
with:
submodules: recursive
- 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 --suppress=missingInclude --suppress=unusedFunction ./plugins ./simulator ./src
build:
runs-on: ubuntu-24.04
container: ghcr.io/neugates/build:x86_64-v2.12
ut:
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v2
with:
submodules: recursive
- name: install dep
run: |
./install.sh -d /usr/local -a x86_64 -c x86_64-linux-gnu
- 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
- uses: actions/upload-artifact@v4
with:
name: neuron-build
path: |
build
ut:
runs-on: ubuntu-24.04
container: ghcr.io/neugates/build:x86_64-v2.12
needs: [build]
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- uses: actions/download-artifact@v4
with:
name: neuron-build
path: ./build
cmake .. -DCMAKE_TOOLCHAIN_FILE=../cmake/x86_64-linux-gnu.cmake
make -j4
- name: unit test
run: |
chmod -R +x ./build/
cd build
cmake -DUSE_GCOV=1 .. -DCMAKE_TOOLCHAIN_FILE=../cmake/x86_64-linux-gnu.cmake
ctest --output-on-failure
- name: create cov report
run: |
sudo apt-get update
sudo apt-get -y install lcov
mkdir -p cov_report
./create_cov_report.sh ut
ft:
runs-on: ubuntu-20.04
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v4
with:
verbose: true
fail_ci_if_error: true
token: ${{ secrets.CODECOV_TOKEN }}
directory: ./cov_report/
files: ./cov_report/cov-ut.info
pft:
runs-on: ubuntu-24.04
container: ghcr.io/neugates/build:x86_64-v2.12
needs: [build]
strategy:
matrix:
plugin: [core, ekuiper, modbus, mqtt, azure, metrics, launch]
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v2
with:
submodules: recursive
- name: setup dependencies
- name: install dep
run: |
sudo apt-get install -y mosquitto
pip install -U pytest requests prometheus-client gmqtt pynng sniffio
sudo apt-get install -y socat
./install.sh -d /usr/local -a x86_64 -c x86_64-linux-gnu
- uses: actions/download-artifact@v4
with:
name: neuron-build
path: ./build
- name: compile
run: |
mkdir -p build && cd build
cmake .. -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"
elif [ "${{ matrix.plugin }}" = "modbus" ]; then
pytest -s -v tests/ft/driver/"test_modbus.py"
elif [ "${{ matrix.plugin }}" = "mqtt" ]; then
pytest -s -v tests/ft/app/"test_mqtt.py"
elif [ "${{ matrix.plugin }}" = "azure" ]; then
pytest -s -v tests/ft/app/"test_azure.py"
#elif [ "${{ matrix.plugin }}" = "launch" ]; then
#pytest -s -v tests/ft/login
else
pytest -s -v tests/ft/metrics/"test_metrics.py"
fi
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
- name: create cov report
if: ${{ matrix.plugin != 'launch' }}
run: |
sudo apt-get update
sudo apt-get -y install lcov
mkdir -p cov_report
./create_cov_report.sh ${{ matrix.plugin }}
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v4
if: ${{ matrix.plugin != 'launch' }}
- uses: actions/upload-artifact@v3
with:
verbose: true
fail_ci_if_error: true
token: ${{ secrets.CODECOV_TOKEN }}
directory: ./cov_report/
files: ./cov_report/cov-${{ matrix.plugin }}.info
name: ft_result
path: |
ft/reports/log.html
ft/reports/output.xml
ft/reports/report.html
build/neuron.log
+210 -51
View File
@@ -7,71 +7,74 @@ on:
types:
- published
env:
VERSION: 2.12.2
UI_VERSION: 2.6.1
BRANCH: v2.12
jobs:
cross-build:
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.12
- [aarch64-linux-gnu, aarch64, gcc-aarch64-linux-gnu, g++-aarch64-linux-gnu, /opt/externs/libs, arm64]
- [arm-linux-gnueabihf, armv4, gcc-arm-linux-gnueabihf, g++-arm-linux-gnueabihf, /opt/externs/libs, armhf]
- [x86_64-linux-gnu, x86_64, gcc, g++, /usr/local, amd64]
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v2
with:
submodules: recursive
- name: install
run: sudo apt-get update && sudo apt-get install -y ${{ matrix.arch[2] }} ${{ matrix.arch[3] }} pkg-config alien
- name: install dep
run: |
./install.sh -d ${{ matrix.arch[4] }} -c ${{ matrix.arch[0] }} -a ${{ matrix.arch[1] }}
- name: get version
id: get_version
run: echo "::set-output name=version::$(cat version)"
- name: compile
run: |
git config --global --add safe.directory $(pwd)
mkdir -p build && cd build
cmake .. -DCMAKE_TOOLCHAIN_FILE=../cmake/${{ matrix.arch[0] }}.cmake \
-DCMAKE_BUILD_TYPE=Release -DDISABLE_UT=ON
make -j4
- name: fetch dashboard
uses: dsaltares/fetch-gh-release-asset@master
with:
repo: "emqx/neuron-dashboard-src"
version: "tags/${{ env.UI_VERSION }}"
file: "neuron-dashboard.zip"
target: "neuron-dashboard.zip"
- name: unpack dashboard
run: |
unzip neuron-dashboard.zip -d ./build
- name: Create neuron sdk package
run: |
./package-sdk.sh -p ${{ matrix.arch[2] }} -n neuron-sdk-$VERSION
./package-sdk.sh -p ${{ matrix.arch[5] }} -n neuron-sdk-${{ steps.get_version.outputs.version }}
- uses: actions/upload-artifact@v4
- uses: actions/upload-artifact@v3
with:
name: neuron-sdk-${{ matrix.arch[2] }}
name: neuron-sdk-${{ matrix.arch[5] }}
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.12
- [x86_64-linux-gnu, x86_64, gcc, g++, /usr/local, amd64]
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v2
with:
submodules: recursive
- name: install
run: sudo apt-get update && sudo apt-get install -y ${{ matrix.arch[2] }} ${{ matrix.arch[3] }} pkg-config alien
- name: install dep
run: |
./install.sh -d ${{ matrix.arch[4] }} -c ${{ matrix.arch[0] }} -a ${{ matrix.arch[1] }}
- name: get version
id: get_version
run: echo "::set-output name=version::$(cat version)"
- name: compile
run: |
git config --global --add safe.directory $(pwd)
mkdir -p build && cd build
cmake .. -DCMAKE_TOOLCHAIN_FILE=../cmake/${{ matrix.arch[0] }}.cmake \
-DDISABLE_UT=ON
@@ -79,42 +82,198 @@ jobs:
- name: Create neuron sdk package
run: |
./package-sdk.sh -p ${{ matrix.arch[2] }} -n neuron-sdk-debug-$VERSION
./package-sdk.sh -p ${{ matrix.arch[5] }} -n neuron-sdk-debug-${{ steps.get_version.outputs.version }}
- uses: actions/upload-artifact@v4
- uses: actions/upload-artifact@v3
with:
name: neuron-sdk-debug
name: neuron-sdk-debug-${{ matrix.arch[5] }}
path: |
neuron-sdk-debug-*.tar.gz
create_update_daily_release:
runs-on: ubuntu-latest
create_daily_release:
runs-on: ubuntu-20.04
if: github.event_name == 'push'
needs: [cross-build, build-debug-sdk]
steps:
- name: Extract branch name
shell: bash
run: echo "##[set-output name=branch;]$(echo ${GITHUB_REF#refs/heads/})"
id: extract_branch
- name: delete old daily-pre-release
uses: dev-drprasad/delete-tag-and-release@v0.2.1
uses: dev-drprasad/delete-tag-and-release@v0.2.0
with:
delete_release: true
tag_name: ${{ env.BRANCH }}-daily
tag_name: ${{ steps.extract_branch.outputs.branch }}-daily
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- uses: actions/download-artifact@v4
with:
name: neuron-sdk-debug
- uses: actions/download-artifact@v4
with:
name: neuron-sdk-amd64
- uses: softprops/action-gh-release@v1
- name: create daily-pre-release
id: create_release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
name: Daily Release(${{ env.BRANCH }})
tag_name: ${{ env.BRANCH }}-daily
tag_name: ${{ steps.extract_branch.outputs.branch }}-daily
release_name: Daily Release(${{ steps.extract_branch.outputs.branch }})
draft: false
prerelease: true
files: |
neuron-sdk-*
- shell: bash
run: |
echo "${{ steps.create_release.outputs.upload_url }}" > release_url.txt
- uses: actions/upload-artifact@v3
with:
name: release_url
path: release_url.txt
upload_daily_release_asset:
runs-on: ubuntu-20.04
if: github.event_name == 'push'
needs: create_daily_release
strategy:
matrix:
arch: [arm64, armhf, amd64]
type: [neuron-sdk]
package: [tar.gz]
steps:
- uses: actions/checkout@v2
with:
submodules: recursive
- name: get version
id: get_version
run: echo "::set-output name=version::$(cat version)"
- uses: actions/download-artifact@v2
with:
name: release_url
- id: release_url
run: |
value=`cat release_url.txt`
echo "::set-output name=name::$value"
- uses: actions/download-artifact@v2
with:
name: ${{ matrix.type }}-${{ matrix.arch }}
- id: package
run: echo "::set-output name=name::${{ matrix.type }}-${{ steps.get_version.outputs.version }}-${{ matrix.arch }}.${{ matrix.package }}"
- name: upload daily release asset
id: upload-release-asset
uses: actions/upload-release-asset@v1.0.2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.release_url.outputs.name }}
asset_path: ./${{ steps.package.outputs.name }}
asset_name: ${{ matrix.type }}-${{ steps.get_version.outputs.version }}-daily-linux-${{ matrix.arch }}.${{ matrix.package }}
asset_content_type: application/octet-stream
upload_daily_release_debug-asset:
runs-on: ubuntu-20.04
if: github.event_name == 'push'
needs: create_daily_release
strategy:
matrix:
arch: [amd64]
type: [neuron-sdk-debug]
package: [tar.gz]
steps:
- uses: actions/checkout@v2
with:
submodules: recursive
- name: get version
id: get_version
run: echo "::set-output name=version::$(cat version)"
- uses: actions/download-artifact@v2
with:
name: release_url
- id: release_url
run: |
value=`cat release_url.txt`
echo "::set-output name=name::$value"
- uses: actions/download-artifact@v2
with:
name: ${{ matrix.type }}-${{ matrix.arch }}
- id: package
run: echo "::set-output name=name::${{ matrix.type }}-${{ steps.get_version.outputs.version }}-${{ matrix.arch }}.${{ matrix.package }}"
- name: upload daily release asset
id: upload-release-asset
uses: actions/upload-release-asset@v1.0.2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.release_url.outputs.name }}
asset_path: ./${{ steps.package.outputs.name }}
asset_name: ${{ matrix.type }}-${{ steps.get_version.outputs.version }}-daily-linux-${{ matrix.arch }}.${{ matrix.package }}
asset_content_type: application/octet-stream
clean:
runs-on: ubuntu-20.04
needs: upload_daily_release_asset
steps:
- uses: geekyeggo/delete-artifact@v1
with:
name: release_url
release:
runs-on: ubuntu-20.04
if: github.event_name == 'release'
needs: cross-build
strategy:
matrix:
arch: [arm64, armhf, amd64]
type: [neuron-sdk]
package: [tar.gz]
steps:
- uses: actions/checkout@v2
with:
submodules: recursive
- name: get version
id: get_version
run: echo "::set-output name=version::$(cat version)"
- uses: actions/download-artifact@v2
with:
name: ${{ matrix.type }}-${{ matrix.arch }}
- id: package
run: echo "::set-output name=name::${{ matrix.type }}-${{ steps.get_version.outputs.version }}-${{ matrix.arch }}.${{ matrix.package }}"
- name: gen packages sha256
run: sudo bash -c "echo $(sha256sum ./${{ steps.package.outputs.name }} | awk '{print $1}') > ./${{ steps.package.outputs.name }}.sha256"
- uses: actions/upload-release-asset@v1
if: github.event_name == 'release'
env:
GITHUB_TOKEN: ${{ github.token }}
with:
upload_url: ${{ github.event.release.upload_url }}
asset_path: ./${{ steps.package.outputs.name}}.sha256
asset_name: ${{ matrix.type }}-${{ steps.get_version.outputs.version }}-linux-${{ matrix.arch }}.${{ matrix.package }}.sha256
asset_content_type: application/octet-stream
- uses: actions/upload-release-asset@v1
if: github.event_name == 'release'
env:
GITHUB_TOKEN: ${{ github.token }}
with:
upload_url: ${{ github.event.release.upload_url }}
asset_path: ./${{ steps.package.outputs.name}}
asset_name: ${{ matrix.type }}-${{ steps.get_version.outputs.version }}-linux-${{ matrix.arch }}.${{ matrix.package }}
asset_content_type: application/octet-stream
+42
View File
@@ -0,0 +1,42 @@
name: Release neuron
on:
push:
tags:
- "*"
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Check appVersion for helm
run: |
appVersion=$(egrep "^appVersion" deploy/charts/neuron/Chart.yaml | sed -r 's|^appVersion:[[:space:]]([0-9]+.[0-9]+.[0-9]+)$|\1|g')
if [ "$appVersion" != "${GITHUB_REF##*/}" ]; then
echo "Need update appVersion for Chart.yaml"
exit 1
fi
helm:
runs-on: self-hosted
if: github.repository_owner == 'emqx'
needs:
- release
steps:
- uses: actions/checkout@v2
- name: Check appVersion for helm
working-directory: deploy/charts/neuron
run: |
appVersion=$(egrep "^appVersion" Chart.yaml | sed -r 's|^appVersion:[[:space:]]([0-9]+.[0-9]+.[0-9]+)$|\1|g')
if [ "$appVersion" != "${GITHUB_REF##*/}" ]; then
echo "Need update appVersion for Chart.yaml"
exit 1
fi
- name: Create helm package
working-directory: deploy/charts/neuron
run: helm package .
- name: Update helm repo
run: |
sudo mv $(find deploy/charts/neuron -name "*.tgz") /repos/charts
sudo helm repo index /repos/charts
+33
View File
@@ -0,0 +1,33 @@
name: Test helm
on:
push:
tags:
- "*"
pull_request:
jobs:
deployment:
runs-on: ubuntu-latest
steps:
- run: minikube start --kubernetes-version="v1.23.0"
- uses: actions/checkout@v2
- name: Deploy neuron by helm
shell: bash
run: |
helm install neuron deploy/charts/neuron\
--set image.repository="emqx/neuron"\
--set image.tag="2.0.1"
- name: Check deployment
timeout-minutes: 5
run: |
set -euo pipefail
while [ "$(kubectl get pods -o json | jq '.items[0].status.containerStatuses[] | select(.ready==true) | .containerID')" = "" ]; do
echo "=============================="
kubectl get pods
echo "=============================="
echo "waiting neuron started"
sleep 10
done
+1 -5
View File
@@ -16,8 +16,4 @@ tmp
*.deb
*.rpm
neuron-sdk
.vscode
log.html
output.xml
report.html
*.cache
.vscode
+3
View File
@@ -0,0 +1,3 @@
[submodule "extern/uthash"]
path = extern/uthash
url = https://github.com/troydhanson/uthash.git
+37 -95
View File
@@ -27,111 +27,66 @@ elseif(CMAKE_SYSTEM_NAME MATCHES "Windows")
endif()
if(NOT DISABLE_WERROR)
set(CMAKE_C_FLAGS "$ENV{CFLAGS} -Werror")
endif()
if(USE_GCOV)
message(STATUS "using gcov")
SET(GCC_COVERAGE_COMPILE_FLAGS "-fprofile-arcs -ftest-coverage -O0")
SET(GCC_COVERAGE_LINK_FLAGS "-lgcov")
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${GCC_COVERAGE_COMPILE_FLAGS}")
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${GCC_COVERAGE_COMPILE_FLAGS}")
SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_LINKER_FLAGS} ${GCC_COVERAGE_LINK_FLAGS}")
endif(USE_GCOV)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -g")
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS} -O0")
if(NOT DISABLE_ASAN)
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS} -fsanitize=address")
set(CMAKE_CXX_FLAGS_DEBUG "-Wall -g -fsanitize=address")
endif()
set(CMAKE_C_FLAGS "$ENV{CFLAGS} -Wall -Werror -Wextra -g")
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS} -O1")
set(CMAKE_C_FLAGS_DEBUG
"${CMAKE_C_FLAGS} -O0 -fsanitize=address"
)
set(CMAKE_CXX_FLAGS_DEBUG
"-Wall -g -O0 -fsanitize=address"
)
add_custom_target(neuron-version
COMMAND ${CMAKE_COMMAND} -P
${CMAKE_CURRENT_SOURCE_DIR}/cmake/neuron-version.cmake)
configure_file(extern/uthash/include/uthash.h ${CMAKE_SOURCE_DIR}/include/neuron/utils/uthash.h)
configure_file(extern/uthash/include/utarray.h ${CMAKE_SOURCE_DIR}/include/neuron/utils/utarray.h)
configure_file(extern/uthash/include/utlist.h ${CMAKE_SOURCE_DIR}/include/neuron/utils/utlist.h)
find_package(nng CONFIG REQUIRED)
find_package(LibXml2 REQUIRED)
find_package(Threads)
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
src/base/tag_sort.c
src/base/group.c
src/base/metrics.c
src/base/msg.c
src/connection/connection.c
src/connection/connection_eth.c
src/connection/mqtt_client.c
src/connection/mqtt_c_client.c
src/connection/mqtt_client_intf.c
src/event/event_linux.c
src/event/event_unix.c
src/utils/asprintf.c
src/utils/json.c
src/utils/http.c
src/utils/http_handler.c
src/utils/neu_jwt.c
src/utils/base64.c
src/utils/async_queue.c
src/utils/log.c
src/utils/cid.c
${PERSIST_SOURCES})
if (SMART_LINK)
message(STATUS "using smart link")
add_definitions(-DNEU_SMART_LINK)
set(NEURON_BASE_SOURCES ${NEURON_BASE_SOURCES} src/connection/smart_link.c)
endif()
if (CLIB)
message(STATUS "set clib")
add_definitions(-DNEU_CLIB=${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()
src/utils/async_queue.c)
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 libssl.a libcrypto.a)
target_link_libraries(neuron-base nng libzlog.so jansson jwt xml2
${CMAKE_THREAD_LIBS_INIT} -lm protobuf-c)
target_compile_definitions(neuron-base PRIVATE MQTT_USE_BIO)
target_link_libraries(neuron-base nng libzlog.so jansson crypto ssl mqttc jwt
${CMAKE_THREAD_LIBS_INIT})
add_dependencies(neuron-base neuron-version)
# dependency imposed by nng
#find_package(MbedTLS)
target_link_libraries(neuron-base mbedtls mbedx509 mbedcrypto)
set(PERSIST_SOURCES
src/persist/persist.c
src/persist/json/persist_json_adapter.c
src/persist/json/persist_json_datatags.c
src/persist/json/persist_json_group_configs.c
src/persist/json/persist_json_plugin.c
src/persist/json/persist_json_subs.c)
set(NEURON_SOURCES
src/main.c
src/argparse.c
@@ -142,64 +97,51 @@ set(NEURON_SOURCES
src/core/plugin_manager.c
src/core/node_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/handle.c
plugins/restful/license.c
plugins/restful/license_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/datatag_handle.c
plugins/restful/global_config_handle.c
plugins/restful/group_config_handle.c
plugins/restful/plugin_handle.c
plugins/restful/version_handle.c
plugins/restful/scan_handle.c
plugins/restful/otel_handle.c
plugins/restful/cid_handle.c
plugins/restful/system_handle.c
plugins/restful/datalayers_handle.c
plugins/restful/rest.c
plugins/restful/user.c)
plugins/restful/http.c
plugins/restful/websocket.c
${PERSIST_SOURCES})
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_options(neuron PRIVATE "LINKER:--dynamic-list-data")
target_link_libraries(neuron dl neuron-base)
#copy file for run
file(COPY ${CMAKE_SOURCE_DIR}/zlog.conf DESTINATION ${CMAKE_BINARY_DIR}/config)
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(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)
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(COPY ${CMAKE_SOURCE_DIR}/default_plugins.json DESTINATION ${CMAKE_BINARY_DIR}/persistence)
file(RENAME ${CMAKE_BINARY_DIR}/persistence/default_plugins.json ${CMAKE_BINARY_DIR}/persistence/plugins.json)
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)
if(NOT DISABLE_UT)
add_subdirectory(tests/ut)
add_subdirectory(tests)
endif()
add_subdirectory(tests/plugins/c1)
add_subdirectory(tests/plugins/s1)
add_subdirectory(tests/plugins/sc1)
# Set sane defaults for multi-lib linux systems
include(GNUInstallDirs)
if(UNIX)
+14 -67
View File
@@ -12,25 +12,18 @@ $ cd zlog
$ make && sudo make install
```
[jansson](https://github.com/neugates/jansson.git)
[jansson](https://github.com/akheron/jansson)
```shell
$ git clone https://github.com/neugates/jansson.git
$ git clone -b v2.14 https://github.com/akheron/jansson.git
$ cd jansson && mkdir build && cd build
$ cmake -DJANSSON_BUILD_DOCS=OFF -DJANSSON_EXAMPLES=OFF ..&& make && sudo make install
```
[mbedtls](https://github.com/ARMmbed/mbedtls.git)
[nng](https://github.com/neugates/nng.git)
```shell
$ git clone -b v2.16.12 https://github.com/Mbed-TLS/mbedtls.git
$ cd mbedtls && mkdir build && cd build
$ cmake -DUSE_SHARED_MBEDTLS_LIBRARY=OFF -DENABLE_TESTING=OFF -DCMAKE_POSITION_INDEPENDENT_CODE=ON .. && make && sudo make install
```
[NanoSDK](https://github.com/neugates/NanoSDK.git)
```shell
$ git clone -b neuron https://github.com/neugates/NanoSDK.git
$ cd NanoSDK && mkdir build && cd build
$ cmake -DBUILD_SHARED_LIBS=OFF -DNNG_TESTS=OFF -DNNG_ENABLE_SQLITE=ON -DNNG_ENABLE_TLS=ON .. && make && sudo make install
$ git clone https://github.com/neugates/nng.git
$ cd nng && mkdir build && cd build
$ cmake -DBUILD_SHARED_LIBS=OFF -DNNG_TESTS=OFF .. && make && sudo make install
```
[jwt](https://github.com/benmcollins/libjwt.git)
@@ -40,62 +33,16 @@ $ cd libjwt && mkdir build && cd build
$ cmake -DENABLE_PIC=ON -DBUILD_SHARED_LIBS=OFF .. && make && sudo make install
```
[MQTT-C](https://github.com/neugates/MQTT-C.git)
```shell
$ git clone https://github.com/neugates/MQTT-C.git
$ cd MQTT-C && mkdir build && cd build
$ cmake -DCMAKE_POSITION_INDEPENDENT_CODE=ON -DMQTT_C_OpenSSL_SUPPORT=ON -DMQTT_C_EXAMPLES=OFF .. && make && sudo make install
```
[googletest](https://github.com/google/googletest.git)
```shell
$ git clone -b release-1.11.0 https://github.com/google/googletest.git
$ cd googletest && mkdir build && cd build
$ cmake .. && make && sudo make install
```
[sqlite](https://github.com/sqlite/sqlite)
```shell
$ curl -o sqlite3.tar.gz https://www.sqlite.org/2022/sqlite-autoconf-3390000.tar.gz
$ mkdir sqlite3
$ 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
```
+65 -76
View File
@@ -1,146 +1,135 @@
# Neuron
[![GitHub Release](https://img.shields.io/github/release/neugates/neuron?color=brightgreen&label=Release)](https://github.com/neugates/neuron/releases)
[![Docker Pulls](https://img.shields.io/docker/pulls/emqx/neuron?label=Docker%20Pulls)](https://hub.docker.com/r/emqx/neuron)
[![Slack](https://img.shields.io/badge/Slack-Neuron-39AE85?logo=slack)](https://slack-invite.emqx.io/)
[![Discord](https://img.shields.io/discord/931086341838622751?label=Discord&logo=discord)](https://discord.gg/xYGf3fQnES)
[![Twitter](https://img.shields.io/badge/Follow-EMQ-1DA1F2?logo=twitter)](https://twitter.com/EMQTech)
[![YouTube](https://img.shields.io/badge/Subscribe-EMQ-FF0000?logo=youtube)](https://www.youtube.com/channel/UC5FjR77ErAxvZENEWzQaO5Q)
[English](https://github.com/neugates/neuron/blob/main/README.md) | 简体中文
Neuron 是一款开源的、轻量级工业协议网关软件,支持数十种工业协议的一站式设备连接、数据接入、MQTT 协议转换,为工业设备赋予工业 4.0 时代关键的物联网连接能力。
Neuron 是一个工业物联网(IIoT)边缘工业协议网关软件,用于现代大数据技术,以发挥工业 4.0 的力量。它支持对多种工业协议的一站式访问,并将其转换为标准 MQTT 协议以访问工业物联网平台。
![neuron-overview](docs/pictures/neuron-final.png)
Neuron 2.0 版本对 1.x 版本中的部分非必要功能进行了精简,重点聚焦在工业协议的数据采集和转发功能上,以期为工业物联网平台建设提供更加高效灵活的一站式协议接入与管理。
以下是 Neuron 的一些重要特性:
## 产品目标和功能
- 具有实时能力的边缘原生应用程序可以利用边缘端的低延迟网络。
- 松耦合模块化 [架构设计](https://neugates.io/docs/zh/latest/introduction/architecture/architecture.html) 通过可插拔模块扩展更多功能服务。
- 支持可以在运行时更新设备和应用程序模块的热插件。
- 支持多种工业设备协议,包括 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](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](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 的许可下开源。商业模块需要 [EMQ 许可证](https://neugates.io/docs/zh/latest/introduction/license-describe.html) 才能运行。
Neuron 的设计目标是专注于工业物联网的数据采集、转发和汇聚:通过将来自繁杂多样工业设备的、不同协议类型的数据转换为统一标准的物联网 MQTT 消息,从而实现这些独立设备的互联互通,更好地融入工业物联网的大系统之中,进行远程的直接控制和信息获取。
获取更多信息,请访问 [Neuron 官网](https://neugates.io/zh)。
我们希望 Neuron 既可以在低端嵌入式 Linux 设备中运行,也可以运行在有较大内存的 Linux 主机中,以支持大规模的连接设备和海量的数据点位。因此 Neuron 的设计需要能够有极少的内存占用和极低的 CPU 占用,同时具有良好的可伸缩性,可满足不同运行资源条件下的需求。
## 快速开始
Neuron 的主要功能和特性如下:
#### 使用 Docker 运行 Neuron
- 插件化的南向设备驱动和北向应用;
- 内置有轻量级的 Web Server,可以通过浏览器来配置和控制、监听设备;
- 可替换的 MQTT 客户端,可以通过 MQTT 接口来控制和读写设备;
- 支持同时连接大量不同协议的工业设备;
- 和 EMQ 的其他产品高度融合,包括 EMQ X、NanoMQ、eKuiper(由 EMQ 发起,现归属于 LF Edge 基金会维护运营) 等;
- 支持 Neuron 运行期更新设备驱动。
```
docker run -d --name neuron -p 7000:7000 -p 7001:7001 -p 9081:9081 --privileged=true --restart=always emqx/neuron:latest
```
功能的完整列表,请参阅[应用和驱动使用介绍](https://neugates.io/plugins)。
接下来请参考 [快速入门](https://neugates.io/docs/zh/latest/quick-start/hardware-specifications.html) 开启您的 Neuron 之旅。
获取更多信息,请访问[官网](https://neugates.io)。
> **提示**
>
> Neuron 开源版只包含 Modbus 和 MQTT 驱动。
>
> 您可以[免费申请 15 天试用期限的 License](https://www.emqx.com/zh/apply-licenses/neuron),加载所有的驱动。
## 架构设计
#### 更多安装方式
现代的 CPU 大都已经是多核心的了,即便是用在嵌入式系统中比较低端的 ARM 和 Risc-V 架构的 CPU,也都拥有多核心的芯片。因此我们需要能够充分利用这些多核心 CPU ,也就是说,Neuron 需要具有非常好的多核多线程性能。为此,我们使用了 NNG 这个基础消息库,这是一个多线程的 IO 处理和消息处理的异步并发库,能够充分利用 CPU 的多个核心。
您可以从 [neugates.io/zh/downloads?os=Linux](https://neugates.io/zh/downloads?os=Linux) 下载不同格式的 Neuron 安装包进行手动安装。
我们采用了星型总线这一组织形式:有一个消息路由中心,该消息路由基于 NNG 提供高效率的消息转发。消息的发送和接收是线程间通讯,使用共享 Buffer 和智能指针,没有任何的内存拷贝,具有非常高的效率。围绕着这个路由中心,是各个具体功能的节点,由 Adapter 和 Plugin 组成。这些节点既可以是内置固有的,如轻量级的 Web Server;也可以是动态增加的,如各种设备驱动、MQTT 客户端、eKuiper 接口等。这样的设计隔离了各个设备驱动和北向应用的功能模块之间的耦合,另外采用订阅-发布机制来实现数据流的分发和聚合,使得 Neuron 有着极大的灵活性。用户可以根据现场的工作情况动态增加和减少设备驱动的节点,具有良好的可配置性。另外,当运行 Neuron 的硬件 CPU 性能好、核心多、内存大时,Neuron 能支持更多的设备驱动节点、海量的数据点位、更大的数据吞吐量、更低的响应时间,具有良好的系统可伸缩性。
也可以直接访问 [Neuron 安装文档](https://neugates.io/docs/zh/latest/installation/installation.html) 查看不同安装方式的操作步骤。
Neuron 采用了插件机制来支持变化多端的用户功能需求,用户可以根据应用场景的功能需求动态的加载不同功能的插件,得到有不同功能的节点。当设备驱动有 Bug 需要修复,或者有新的功能需要升级时,可以通过动态更新插件来解决问题,升级新功能。每个节点的运行是独立的,当升级一个节点的插件时,不会影响其他节点的运行,Neuron 也不需要重新启动。
## 文档
Neuron的总体架构概览如下图所示:
Neuron 文档地址:[https://neugates.io/docs/zh/latest/](https://neugates.io/docs/zh/latest/)。
![arch-overview](docs/pictures/neuron-arch-overview.png)
## 社区
Neuron的总线拓扑结构和数据流的分散/汇聚如下图所示:
- 访问 [Neuron 论坛](https://askemq.com/c/neuron/8) 以获取帮助,也可以分享您的想法或项目。
- 添加小助手微信号 `emqmkt`,加入 Neuron 微信技术交流群。
- 加入我们的 [Discord](https://discord.gg/xYGf3fQnES),参于实时讨论。
- 关注我们的 [bilibili](https://space.bilibili.com/522222081),获取最新物联网技术分享。
- 关注我们的 [微博](https://weibo.com/emqtt) 或 [Twitter](https://twitter.com/EMQTech),获取 Neuron 最新资讯。
![neuron-bus-topo](docs/pictures/neuron-bus-topo.png)
## 从源码构建
![neuron-dataflow](docs/pictures/neuron-dataflow.png)
**安装依赖**
Neuron的层次结构图如下图所示:
请参考 [Install-dependencies](https://github.com/emqx/neuron/blob/main/Install-dependencies.md)
![neuron-layers](docs/pictures/neuron-layers.png)
**编译**
```
## 安装
### 安装依赖
[Install Required Dependencies](https://github.com/neugates/neuron/blob/main/Install-dependencies.md)
### 编译
```shell
$ git clone https://github.com/emqx/neuron
$ cd neuron
$ git submodule update --init
$ mkdir build && cd build
$ cmake .. && make
```
**安装 Dashboard**
## 前端
[下载前端包](https://github.com/emqx/neuron-dashboard/releases)。
下载后的前端包,解压放到Neuron可执行目录下的dist目录中。
在 [neuron-dashboard](https://github.com/emqx/neuron-dashboard/releases) 页面下载最新的 `neuron-dashboard.zip`,解压后放到 Neuron 可执行目录下的 dist 目录中。
## 快速开始
**运行**
```
```shell
$ 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
mosquitto -v &
pip3 install -r ft/requirements.txt
python3 -m robot -P ft/ --variable neuron_api:http -d ft/http_reports ft
```
### 压力测试
## 压力测试
在目录`ft/data/persistence/`中有压力测试的数据集。
目录`ft/data/persistence/`下存放有用于压力测试的数据集。
运行压力测试
可运行以下命令进行压力测试
```shell
# 安装依赖
$ pip3 install -r ft/requirements.txt
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
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
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 &
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
python3 -m robot -P ft/ --variable neuron_api:mqtt --variable dataset:simple-1k -d ft/mqtt-simple-1k ft/pressure.test
```
## 开源许可
## 社区
您可通过以下途径与 Neuron 社区及开发者联系。
- 论坛:https://askemq.com/c/neuron/8
- GitHub Discussions:https://github.com/emqx/neuron/discussions
- Slack:https://slack-invite.emqx.io/
- Discord:https://discord.gg/xYGf3fQnES
详见 [LICENSE](./LICENSE)。
+90 -57
View File
@@ -1,99 +1,132 @@
# Neuron
[![GitHub Release](https://img.shields.io/github/release/emqx/neuron?color=brightgreen&label=Release)](https://github.com/emqx/neuron/releases)
[![Docker Pulls](https://img.shields.io/docker/pulls/emqx/neuron?label=Docker%20Pulls)](https://hub.docker.com/r/emqx/neuron)
[![codecov](https://codecov.io/gh/emqx/neuron/graph/badge.svg?token=X95RD0NUT0)](https://codecov.io/gh/emqx/neuron)
[![GitHub Release](https://img.shields.io/github/release/neugates/neuron?color=brightgreen&label=Release)](https://github.com/neugates/neuron/releases)
[![Slack](https://img.shields.io/badge/Slack-Neuron-39AE85?logo=slack)](https://slack-invite.emqx.io/)
[![Discord](https://img.shields.io/discord/931086341838622751?label=Discord&logo=discord)](https://discord.gg/xYGf3fQnES)
[![Twitter](https://img.shields.io/badge/Follow-EMQ-1DA1F2?logo=twitter)](https://twitter.com/EMQTech)
[![YouTube](https://img.shields.io/badge/Subscribe-EMQ-FF0000?logo=youtube)](https://www.youtube.com/channel/UC5FjR77ErAxvZENEWzQaO5Q)
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.
English | [简体中文](https://github.com/neugates/neuron/blob/main/README-CN.md)
![neuron-overview](docs/pictures/neuron-final.png)
Neuron is an Industrial IoT (IIoT) edge industrial gateway for modern big data 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 to access the IIoT platform.
The following are some important features of Neuron:
Version 2.0 streamlines some of the non-essential features in version 1.x and focuses on the data collection and forwarding of industrial protocols in order to provide more efficient and flexible one-stop protocol access and management for the IIoT platform.
- Edge native application with real-time capability to leverage the low latency network of edge side.
- 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](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](https://neugates.io/docs/en/latest/use-cases/sparkplug/sparkplug.html) 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](https://neugates.io/docs/en/latest/api/configuration.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. Commercial modules require a [EMQ License](https://neugates.io/docs/en/latest/installation/license-install/license-install.html) to run.
## Goals and Features
For more information, please visit [Neuron homepage](https://neugates.io/).
Neuron is designed to focus on data collection, forwarding, and aggregation for the IIoT - converting data from a wide variety of industrial devices with different protocol types into a unified standard MQTT message to interconnect these individual devices and better integrate them into the larger IoT system for direct remote control and information access.
## Get Started
We hope that Neuron can run on both low-end embedded Linux devices and Linux workstations with larger memory to support large numbers of connected devices and large amounts of data points. Neuron is therefore designed to have a very little memory footprint and a very low CPU footprint while being scalable to meet the needs of different operating resources.
#### Run Neuron using Docker
The following is some important features of Neuron:
```
docker run -d --name neuron -p 7000:7000 -p 7001:7001 -p 9081:9081 --privileged=true --restart=always emqx/neuron:latest
```
- Plugged-in southbound driver and northbound application.
- A light-weigh built-in web server. The user can configure, control and monitor device through browser.
- A replaceable MQTT Client. The user can control and read/write device by MQTT message.
- Support simultaneous connection of a large number of devices with different protocols.
- Highly integrated with other EMQ products, including EMQ X, NanoMQ, eKuiper(Initiated by EMQ and now maintained and operated by LF Edge).
- Support updating device drivers during Neuron runtime.
Next, please follow the [getting started guide](https://neugates.io/docs/en/latest/quick-start/hardware-specifications.html) to tour the Neuron features.
For a full list of new features, please read [Instructions for application and driver](https://neugates.io/plugins)。
> **Limitations**
>
> Neuron open source edition only includes Modbus and MQTT drivers.
>
> If you need more driver protocol support and edge computing services, you can choose Neuron's commercial version [NeuronEX](https://www.emqx.com/en/products/neuronex).
> NeuronEX comes with a built-in license for 30 data tags that can be applied to all southbound drivers. And NeuronEX also supports edge intelligent analysis of industrial data to enable you to quickly gain business insights. To download NeuronEX, please click [here](https://www.emqx.com/en/downloads-and-install/neuronex).
For more information, please visit [Homepage](https://neugates.io)。
#### More installation options
## Architecture design
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).
Most modern CPUs are already multi-core, even the lower-end ARM and Risc-V architecture CPUs used in embedded systems, most of which have multi-core chips. Therefore, we need to be able to make full use of these multi-core CPUs, that is, Neuron needs to have very good multi-core and multi-thread performance. We use library NNG, which is an asynchronous concurrent library for multi-threaded IO processing and message passing, which can make full use of the multiple cores of the CPU.
For more installation options, see the [Neuron installation documentation](https://neugates.io/docs/en/latest/installation/installation.html).
We use the star bus mode as an organizational form, and there is a message routing center. This message routing is based on NNG to provide high-efficiency message forwarding. The sending and receiving of messages is communication between threads. By using shared buffers and smart pointers, there is no memory copy, which is very efficient. Around this routing center are nodes, every node includes an adapter and plugin. These nodes can be built-in with Neuron, such as a lightweight web server, or they can be dynamically added, such as various device drivers, MQTT clients, eKuiper interface, and so on. By this design, it isolates the coupling between each device driver and northbound application. In addition, the subscription-publishing mechanism is used to realize the scattering and gathering of data streams, which makes Neuron extremely flexible. Users can dynamically increase and decrease device-driven nodes according to the working load of the site, with good configurability. In addition, when the hardware CPU running Neuron has good performance, more cores, and large memory, Neuron can support more device driver nodes, massive data points, greater data throughput, and lower response time. Has good system scalability.
## Documentation
Neuron uses a plugged-in mechanism to support changing user functional requirements. Users can dynamically load plug-ins with different functions according to the functional requirements of the application scenario. When the device driver has a bug fix and needs to be upgraded, you can also dynamically update the new plug-in to solve the problem and get the new feature. The running state of each node is independent. When the plug-in of one node is upgraded, it will not affect the running state of other nodes, and Neuron does not need to be restarted.
The Neuron documentation is available at [neugates.io/docs/en/latest/](https://neugates.io/docs/en/latest/).
An overview of Neuron's architecture is shown in the figure below:
## Get Involved
![arch-overview](docs/pictures/neuron-arch-overview.png)
- Follow [@EMQTech on Twitter](https://twitter.com/EMQTech).
- If you have a specific question, check out our [discussion forums](https://github.com/emqx/neuron/discussions).
- 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.
The topology of bus in Neuron and the scattering/gathering of data flow are shown in the figure below:
## Build From Source
![neuron-bus-topo](docs/pictures/neuron-bus-topo.png)
**Install required dependencies**
![neuron-dataflow](docs/pictures/neuron-dataflow.png)
[Install-dependencies](https://github.com/emqx/neuron/blob/main/Install-dependencies.md)
The hierarchical layer diagram of Neuron is shown in the figure below:
**Build**
![neuron-layers](docs/pictures/neuron-layers.png)
```
## Installation
### Required Dependencies
[Install Required Dependencies](https://github.com/neugates/neuron/blob/main/Install-dependencies.md)
## Build
```shell
$ git clone https://github.com/emqx/neuron
$ cd neuron
$ git submodule update --init
$ mkdir build && cd build
$ cmake .. && make
```
**Install Dashboard**
## Dashboard
[Download Dashboard Package](https://github.com/emqx/neuron-dashboard/releases).
After downloading the dashboard package, put it in the **dist** directory of the neuron executable directory.
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.
## Quick Start
**Run**
```
```shell
$ 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.
>
## Test
## License
To run all unit testers
See [LICENSE](./LICENSE).
```shell
$ cd build
$ ctest --output-on-failure
```
## Functional test
To run all functional testers
```shell
mosquitto -v &
pip3 install -r ft/requirements.txt
python3 -m robot -P ft/ --variable neuron_api:http -d ft/http_reports ft
```
## Pressure test
There are datasets for pressure testing in directory `ft/data/persistence/`.
To run pressure tests
```shell
# python dependencies
pip3 install -r ft/requirements.txt
# through http api, on dataset total-10k
python3 -m robot -P ft/ --variable neuron_api:http --variable dataset:total-10k -d ft/http-total-10k ft/pressure.test
# through http api, on dataset total-50k
python3 -m robot -P ft/ --variable neuron_api:http --variable dataset:total-50k -d ft/http-total-50k ft/pressure.test
# A MQTT broker is needed if using the mqtt api, mosquitto in this example
mosquitto -v &
# through mqtt api, on dataset simple-1k
python3 -m robot -P ft/ --variable neuron_api:mqtt --variable dataset:simple-1k -d ft/mqtt-simple-1k ft/pressure.test
```
## Community
You can connect with the Neuron community and developers in the following ways.
- Discussions:https://github.com/emqx/neuron/discussions
- Slack:https://slack-invite.emqx.io/
- Discord:https://discord.gg/xYGf3fQnES
+2 -3
View File
@@ -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.12/libs)
set(LIBRARY_DIR /opt/externs/libs)
set(CMAKE_C_COMPILER ${COMPILER_PREFIX}-gcc)
set(CMAKE_CXX_COMPILER ${COMPILER_PREFIX}-g++)
@@ -19,6 +19,5 @@ set(CMAKE_FIND_ROOT_PATH ${CMAKE_STAGING_PREFIX})
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_SYSROOT ${CMAKE_STAGING_PREFIX})
link_directories(${CMAKE_STAGING_PREFIX})
file(COPY ${CMAKE_STAGING_PREFIX}/lib/libzlog.so.1.2 DESTINATION /usr/local/lib)
+2 -3
View File
@@ -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.12/libs)
set(LIBRARY_DIR /opt/externs/libs)
set(CMAKE_C_COMPILER ${COMPILER_PREFIX}-gcc)
set(CMAKE_CXX_COMPILER ${COMPILER_PREFIX}-g++)
@@ -19,6 +19,5 @@ set(CMAKE_FIND_ROOT_PATH ${CMAKE_STAGING_PREFIX})
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_SYSROOT ${CMAKE_STAGING_PREFIX})
link_directories(${CMAKE_STAGING_PREFIX})
file(COPY ${CMAKE_STAGING_PREFIX}/lib/libzlog.so.1.2 DESTINATION /usr/local/lib)
+2 -3
View File
@@ -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.12/libs)
set(LIBRARY_DIR /opt/externs/libs)
set(CMAKE_C_COMPILER ${COMPILER_PREFIX}-gcc)
set(CMAKE_CXX_COMPILER ${COMPILER_PREFIX}-g++)
@@ -19,6 +19,5 @@ set(CMAKE_FIND_ROOT_PATH ${CMAKE_STAGING_PREFIX})
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_SYSROOT ${CMAKE_STAGING_PREFIX})
link_directories(${CMAKE_STAGING_PREFIX})
file(COPY ${CMAKE_STAGING_PREFIX}/lib/libzlog.so.1.2 DESTINATION /usr/local/lib)
-30
View File
@@ -1,30 +0,0 @@
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_C_COMPILER ${TOOL_DIR}/${COMPILER_PREFIX}-gcc)
set(CMAKE_CXX_COMPILER ${TOOL_DIR}/${COMPILER_PREFIX}-g++)
set(CMAKE_AR ${TOOL_DIR}/${COMPILER_PREFIX}-ar)
set(CMAKE_LINKER ${TOOL_DIR}/${COMPILER_PREFIX}-ld)
set(CMAKE_NM ${TOOL_DIR}/${COMPILER_PREFIX}-nm)
set(CMAKE_OBJDUMP ${TOOL_DIR}/${COMPILER_PREFIX}-objdump)
set(CMAKE_RANLIB ${TOOL_DIR}/${COMPILER_PREFIX}-ranlib)
set(CMAKE_STAGING_PREFIX ${LIBRARY_DIR}/${COMPILER_PREFIX})
set(CMAKE_PREFIX_PATH ${CMAKE_STAGING_PREFIX})
include_directories(SYSTEM ${CMAKE_STAGING_PREFIX}/include)
include_directories(SYSTEM ${CMAKE_STAGING_PREFIX}/openssl/include)
set(CMAKE_FIND_ROOT_PATH ${CMAKE_STAGING_PREFIX})
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
link_directories(${CMAKE_STAGING_PREFIX})
if(CMAKE_SYSTEM_PROCESSOR MATCHES "mips32")
link_libraries(atomic)
endif()
if(CMAKE_SYSTEM_PROCESSOR MATCHES "riscv64")
link_libraries(atomic)
endif()
if(CMAKE_SYSTEM_PROCESSOR MATCHES "loongarch64")
link_libraries(atomic)
endif()
+2 -24
View File
@@ -1,29 +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.12/libs)
set(LIBRARY_DIR /usr/local)
set(CMAKE_C_COMPILER ${COMPILER_PREFIX}-gcc)
set(CMAKE_CXX_COMPILER ${COMPILER_PREFIX}-g++)
set(CMAKE_AR ${COMPILER_PREFIX}-ar)
set(CMAKE_LINKER ${COMPILER_PREFIX}-ld)
set(CMAKE_NM ${COMPILER_PREFIX}-nm)
set(CMAKE_OBJDUMP ${COMPILER_PREFIX}-objdump)
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})
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
link_directories(${CMAKE_STAGING_PREFIX})
file(COPY ${CMAKE_STAGING_PREFIX}/lib/libzlog.so.1.2 DESTINATION /usr/local/lib)
set(CMAKE_PREFIX_PATH ${CMAKE_STAGING_PREFIX})
-8
View File
@@ -1,8 +0,0 @@
ignore:
- "src/otel/*.pb-c.c"
coverage:
status:
project:
default:
target: auto # the required coverage value
threshold: 0.1% # the leniency in hitting the target
-54
View File
@@ -1,54 +0,0 @@
#!/bin/bash
# core trace
lcov -c -d build/CMakeFiles/neuron-base.dir/src -o cov_report/cov-neuron-base.info
lcov -c -d build/CMakeFiles/neuron.dir/src -o cov_report/cov-neuron.info
lcov -c -d build/CMakeFiles/neuron.dir/plugins/restful -o cov_report/cov-restful.info
# always with core trace
function gen_trace () {
lcov -a cov-neuron-base.info -a cov-neuron.info -a cov-restful.info $@;
}
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
lcov -c -d build/simulator/CMakeFiles/modbus_simulator.dir -o cov_report/cov-simulator-modbus.info
cd cov_report
gen_trace -a cov-simulator-modbus.info -a cov-modbus-rtu.info -a cov-modbus-tcp.info -o cov-modbus.info;;
(mqtt)
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;;
(metrics)
cd cov_report
gen_trace -o cov-metrics.info;;
(*)
lcov -c -d build/plugins/$1/CMakeFiles/plugin-$1.dir -o cov_report/cov-$1.info;;
esac
+2 -6
View File
@@ -1,11 +1,7 @@
{
"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-mqtt.so",
"libplugin-modbus-tcp.so"
]
}
+2 -2
View File
@@ -15,10 +15,10 @@ type: application
# This is the chart version. This version number should be incremented each time you make changes
# to the chart and its templates, including the app version.
# Versions are expected to follow Semantic Versioning (https://semver.org/)
version: 1.0.6
version: 1.0.0
# This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application. Versions are not expected to
# follow Semantic Versioning. They should reflect the version the application is using.
# It is recommended to use it with quotes.
appVersion: 2.2.8
appVersion: "2.0.1"
+24 -19
View File
@@ -1,10 +1,9 @@
# neuron
![Version: 1.0.6](https://img.shields.io/badge/Version-1.0.6-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 2.2.8](https://img.shields.io/badge/AppVersion-2.2.8-informational?style=flat-square)
![Version: 1.0.0](https://img.shields.io/badge/Version-1.0.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 2.0.1](https://img.shields.io/badge/AppVersion-2.0.1-informational?style=flat-square)
A Helm chart for Kubernetes
## Install the Chart
- From Github
@@ -24,27 +23,37 @@ helm uninstall my-neuron
| Key | Type | Default | Description |
|-----|------|---------|-------------|
| affinity | object | `{}` | |
| autoscaling.enabled | bool | `false` | |
| autoscaling.maxReplicas | int | `100` | |
| autoscaling.minReplicas | int | `1` | |
| autoscaling.targetCPUUtilizationPercentage | int | `80` | |
| clusterDomain | string | `"cluster.local"` | Kubernetes Cluster Domain |
| containerPorts | object | `{"api":7001,"web":7000}` | Container Ports |
| containerPorts.api | int | `7001` | containerPorts.api |
| containerPorts.web | int | `7000` | containerPorts.web |
| fullnameOverride | string | `""` | |
| hostPorts | object | `{"api":30371,"enabled":false,"web":30370}` | only for kubeedge deployment |
| image.pullPolicy | string | `"IfNotPresent"` | |
| image.repository | string | `"emqx/neuron"` | |
| image.tag | string | `""` | Overrides the image tag whose default is the chart appVersion. |
| imagePullSecrets | list | `[]` | |
| ingress.annotations | object | `{}` | |
| ingress.className | string | `""` | |
| ingress.enabled | bool | `false` | |
| ingress.hosts[0].host | string | `"chart-example.local"` | |
| ingress.hosts[0].paths[0].path | string | `"/"` | |
| ingress.hosts[0].paths[0].pathType | string | `"ImplementationSpecific"` | |
| ingress.tls | list | `[]` | |
| nameOverride | string | `""` | |
| neuronEnv.enabled | bool | `true` | |
| neuronEnv.keys.disableAuth | string | `"DISABLE_AUTH"` | |
| neuronEnv.values.disableAuth | bool | `true` | |
| neuronMounts[0].capacity | string | `"100Mi"` | |
| neuronMounts[0].mountPath | string | `"/opt/neuron/persistence"` | |
| neuronMounts[0].name | string | `"pvc-neuron-data"` | |
| nodeSelector | object | `{}` | |
| persistence.accessMode | string | `"ReadWriteOnce"` | |
| persistence.enabled | bool | `false` | |
| persistence.storageClass | string | `"standard"` | |
| persistence.existingClaim | string | `""` | Existing PersistentVolumeClaims The value is evaluated as a template So, for example, the name can depend on .Release or .Chart |
| podAnnotations | object | `{}` | |
| readinessProbe.enabled | bool | `true` | |
| readinessProbe.initialDelaySeconds | int | `5` | |
| readinessProbe.periodSeconds | int | `5` | |
| resources | object | `{}` | |
| service.annotations | object | `{"eip.openelb.kubesphere.io/v1alpha2":"eip-pool","lb.kubesphere.io/v1alpha1":"openelb","protocol.openelb.kubesphere.io/v1alpha1":"layer2"}` | Provide any additional annotations which may be required. Evaluated as a template |
| service.annotations | object | `{}` | Provide any additional annotations which may be required. Evaluated as a template |
| service.enabled | bool | `true` | |
| service.loadBalancerSourceRanges | list | `[]` | loadBalancerSourceRanges: - 10.10.10.0/24 |
| service.nodePorts | object | `{"api":null,"web":null}` | Specify the nodePort(s) value for the LoadBalancer and NodePort service types. ref: https://kubernetes.io/docs/concepts/services-networking/service/#type-nodeport |
@@ -54,11 +63,7 @@ helm uninstall my-neuron
| service.ports.web.name | string | `"web"` | Neuron Dashboard port name |
| service.ports.web.port | int | `7000` | Neuron Dashboard port |
| service.type | string | `"ClusterIP"` | |
| tolerations[0].effect | string | `"NoExecute"` | |
| tolerations[0].key | string | `"node.kubernetes.io/not-ready"` | |
| tolerations[0].operator | string | `"Exists"` | |
| tolerations[0].tolerationSeconds | int | `30` | |
| tolerations[1].effect | string | `"NoExecute"` | |
| tolerations[1].key | string | `"node.kubernetes.io/unreachable"` | |
| tolerations[1].operator | string | `"Exists"` | |
| tolerations[1].tolerationSeconds | int | `30` | |
| serviceAccount.annotations | object | `{}` | Annotations to add to the service account |
| serviceAccount.create | bool | `true` | Specifies whether a service account should be created |
| serviceAccount.name | string | `""` | The name of the service account to use. If not set and create is true, a name is generated using the fullname template |
| tolerations | list | `[]` | |
@@ -50,6 +50,16 @@ app.kubernetes.io/name: {{ include "neuron.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}
{{/*
Create the name of the service account to use
*/}}
{{- define "neuron.serviceAccountName" -}}
{{- if .Values.serviceAccount.create }}
{{- default (include "neuron.fullname" .) .Values.serviceAccount.name }}
{{- else }}
{{- default "default" .Values.serviceAccount.name }}
{{- end }}
{{- end }}
{{/*
Get the TLS secret.
+10 -17
View File
@@ -15,17 +15,15 @@ spec:
labels:
{{- include "neuron.selectorLabels" . | nindent 8 }}
spec:
serviceAccountName: {{ include "neuron.serviceAccountName" . }}
volumes:
{{- range $mount := .Values.neuronMounts }}
- name: {{ $mount.name }}
{{- if $.Values.persistence.enabled }}
- name: neuron-persistence
{{- if .Values.persistence.enabled }}
persistentVolumeClaim:
claimName: {{ printf "%s-%s" $.Release.Name (tpl $mount.name $) }}
claimName: {{ (tpl .Values.persistence.existingClaim $) | default (include "neuron.fullname" .) }}
{{- else }}
emptyDir: {}
{{- end }}
{{- end }}
{{- if .Values.tls.enabled }}
- name: certs
secret:
@@ -40,32 +38,27 @@ spec:
- name: neuron
image: "{{ .Values.image.repository }}:{{ .Chart.AppVersion }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
{{- if .Values.neuronEnv.enabled }}
env:
- name: {{ .Values.neuronEnv.keys.disableAuth }}
value: "{{ .Values.neuronEnv.values.disableAuth }}"
{{- end }}
{{- if .Values.readinessProbe.enabled }}
readinessProbe:
httpGet:
port: {{ .Values.service.web | default 7000 }}
initialDelaySeconds: 5
periodSeconds: 5
{{- end }}
ports:
- name: web
containerPort: {{ .Values.service.ports.web.port | default 7000 }}
containerPort: {{ .Values.containerPorts.web | default 7000 }}
{{- if .Values.hostPorts.enabled }}
hostPort: {{ .Values.hostPorts.web | default 7000 }}
{{- end}}
- name: api
containerPort: {{ .Values.service.ports.api.port | default 7001 }}
containerPort: {{ .Values.containerPorts.api | default 7001 }}
{{- if .Values.hostPorts.enabled }}
hostPort: {{ .Values.hostPorts.api | default 7001 }}
{{- end}}
volumeMounts:
{{- range $mount := .Values.neuronMounts }}
- name: {{ $mount.name }}
mountPath: {{ $mount.mountPath }}
{{- end }}
- name: neuron-persistence
mountPath: "/opt/neuron/persistence"
{{- if .Values.tls.enabled }}
- name: certs
mountPath: "/opt/neuron/config/neuron.pem"
@@ -0,0 +1,61 @@
{{- if .Values.ingress.enabled -}}
{{- $fullName := include "neuron.fullname" . -}}
{{- $svcPort := .Values.service.port -}}
{{- if and .Values.ingress.className (not (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion)) }}
{{- if not (hasKey .Values.ingress.annotations "kubernetes.io/ingress.class") }}
{{- $_ := set .Values.ingress.annotations "kubernetes.io/ingress.class" .Values.ingress.className}}
{{- end }}
{{- end }}
{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}}
apiVersion: networking.k8s.io/v1
{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}}
apiVersion: networking.k8s.io/v1beta1
{{- else -}}
apiVersion: extensions/v1beta1
{{- end }}
kind: Ingress
metadata:
name: {{ $fullName }}
labels:
{{- include "neuron.labels" . | nindent 4 }}
{{- with .Values.ingress.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
{{- if and .Values.ingress.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }}
ingressClassName: {{ .Values.ingress.className }}
{{- end }}
{{- if .Values.ingress.tls }}
tls:
{{- range .Values.ingress.tls }}
- hosts:
{{- range .hosts }}
- {{ . | quote }}
{{- end }}
secretName: {{ .secretName }}
{{- end }}
{{- end }}
rules:
{{- range .Values.ingress.hosts }}
- host: {{ .host | quote }}
http:
paths:
{{- range .paths }}
- path: {{ .path }}
{{- if and .pathType (semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion) }}
pathType: {{ .pathType }}
{{- end }}
backend:
{{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }}
service:
name: {{ $fullName }}
port:
number: {{ $svcPort }}
{{- else }}
serviceName: {{ $fullName }}
servicePort: {{ $svcPort }}
{{- end }}
{{- end }}
{{- end }}
{{- end }}
-41
View File
@@ -1,41 +0,0 @@
{{- if $.Values.persistence.enabled }}
{{- $top := . -}}
{{- range $mount := .Values.ekuiperMounts }}
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: {{ printf "%s-%s" $.Release.Name (tpl $mount.name $) }}
namespace: {{ $.Release.Namespace }}
annotations:
kubesphere.io/creator: admin
finalizers:
- kubernetes.io/pvc-protection
spec:
accessModes:
- {{ $.Values.persistence.accessMode }}
resources:
requests:
storage: {{ $mount.capacity }}
storageClassName: {{ $.Values.persistence.storageClass }}
{{- end }}
{{- range $mount := .Values.neuronMounts }}
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: {{ printf "%s-%s" $.Release.Name (tpl $mount.name $) }}
namespace: {{ $.Release.Namespace }}
annotations:
kubesphere.io/creator: admin
finalizers:
- kubernetes.io/pvc-protection
spec:
accessModes:
- {{ $.Values.persistence.accessMode }}
resources:
requests:
storage: {{ $mount.capacity }}
storageClassName: {{ $.Values.persistence.storageClass }}
{{- end }}
{{- end }}
@@ -0,0 +1,12 @@
{{- if .Values.serviceAccount.create -}}
apiVersion: v1
kind: ServiceAccount
metadata:
name: {{ include "neuron.serviceAccountName" . }}
labels:
{{- include "neuron.labels" . | nindent 4 }}
{{- with .Values.serviceAccount.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- end }}
-6
View File
@@ -6,12 +6,6 @@ metadata:
namespace: {{ .Release.Namespace }}
labels:
{{- include "neuron.labels" . | nindent 4 }}
{{- if eq .Values.service.type "LoadBalancer" }}
{{- with .Values.service.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- end }}
spec:
type: {{ .Values.service.type }}
{{- if eq .Values.service.type "LoadBalancer" }}
+48 -28
View File
@@ -13,6 +13,15 @@ imagePullSecrets: []
nameOverride: ""
fullnameOverride: ""
serviceAccount:
# -- Specifies whether a service account should be created
create: true
# -- Annotations to add to the service account
annotations: {}
# -- The name of the service account to use.
# If not set and create is true, a name is generated using the fullname template
name: ""
podAnnotations: {}
# @ignored
@@ -62,24 +71,32 @@ service:
# - 10.10.10.0/24
#
loadBalancerSourceRanges: []
## TODO: it's just for OpenELB
# -- Provide any additional annotations which may be required. Evaluated as a template
annotations:
lb.kubesphere.io/v1alpha1: openelb
eip.openelb.kubesphere.io/v1alpha2: eip-pool
protocol.openelb.kubesphere.io/v1alpha1: layer2
annotations: {}
ingress:
enabled: false
className: ""
annotations: {}
# kubernetes.io/ingress.class: nginx
# kubernetes.io/tls-acme: "true"
hosts:
- host: chart-example.local
paths:
- path: /
pathType: ImplementationSpecific
tls: []
# - secretName: chart-example-tls
# hosts:
# - chart-example.local
persistence:
enabled: false
accessMode: ReadWriteOnce
## TODO: not all storage class can work well, it depends on the specific storage
storageClass: standard
# storageClass: huawei-nfs
neuronMounts:
- name: pvc-neuron-data
capacity: 100Mi
mountPath: "/opt/neuron/persistence"
# -- Existing PersistentVolumeClaims
# The value is evaluated as a template
# So, for example, the name can depend on .Release or .Chart
existingClaim: ""
resources: {}
# We usually recommend not to specify default resources and to leave this as a conscious
@@ -93,17 +110,16 @@ resources: {}
# cpu: 100m
# memory: 128Mi
autoscaling:
enabled: false
minReplicas: 1
maxReplicas: 100
targetCPUUtilizationPercentage: 80
# targetMemoryUtilizationPercentage: 80
nodeSelector: {}
tolerations:
- key: "node.kubernetes.io/not-ready"
operator: "Exists"
effect: "NoExecute"
tolerationSeconds: 30
- key: "node.kubernetes.io/unreachable"
operator: "Exists"
effect: "NoExecute"
tolerationSeconds: 30
tolerations: []
affinity: {}
@@ -155,13 +171,17 @@ tls:
-----END RSA PRIVATE KEY-----
neuronEnv:
readinessProbe:
enabled: true
keys:
disableAuth: DISABLE_AUTH
initialDelaySeconds: 5
periodSeconds: 5
values:
disableAuth: true
# -- Container Ports
containerPorts:
# -- containerPorts.web
web: 7000
# -- containerPorts.api
api: 7001
# -- only for kubeedge deployment
hostPorts:
+3 -10
View File
@@ -1,15 +1,8 @@
[global]
file perms = 666
[formats]
stdout_format = "%d:%ms [%V] [%c] %f:%L %m%n"
file_format = "%d:%ms [%V] %f:%L %m%n"
syslog = "<P>%d(%Y-%m-%dT%T%z) %H neuron[%p]: level=%v msg="[%c] %m" file="%f:%L"%n"
simple = "%d [%V] [%c] %f:%L %m%n"
[rules]
*.* "./logs/%c.log", 25MB * 1 ~ "./logs/%c.#2r.log"; file_format
*.* >stdout; stdout_format
*.* $remote_syslog,"%V"; syslog
*.DEBUG >stdout; simple
*.DEBUG $ws, "%V,%c"; simple
Binary file not shown.

Before

Width:  |  Height:  |  Size: 307 KiB

Vendored Submodule
+1
Submodule extern/uthash added at 44a66fe8e0
@@ -2,41 +2,48 @@ 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, MQTTv50
from gmqtt.mqtt.constants import MQTTv311
def info(msg):
print(msg)
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
"""
def __init__(self, reconnect_retries=-1, reconnect_delay=0.1):
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 -1
connections, default to 5
`reconnect_delay` delay between reconnect attemps in seconds,
default to 0.1
default to 0
"""
self._client = None
self._reconnect_retries = reconnect_retries
self._reconnect_delay = reconnect_delay
self._messages = defaultdict(deque)
self._handlers = {}
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,
@@ -64,6 +71,17 @@ class Client:
`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
@@ -79,24 +97,28 @@ class Client:
)
self._client = client
self._run(self._client.connect(host, port, version=MQTTv50))
self._run(self._client.connect(host, port, version=MQTTv311))
@keyword
def disconnect(self):
"""Disconnect from MQTT Broker."""
"""Disconnect from MQTT Broker.
Example:
| Disconnect |
"""
self._run(self._client.disconnect())
self._messages.clear()
self._handlers.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()
self._handlers.clear()
def subscribe(
self, topic, qos=0, timeout=1, handler=None, no_except=False
):
@keyword
def subscribe(self, topic, qos=0, timeout=1):
"""Subscribe to a topic and return a message payload received
within the specified time.
@@ -106,47 +128,38 @@ class Client:
`timeout` duration of subscription, default to 1 second
`handler` callback on received message, should take one parameter `payload`
Examples:
`no_except` indicate to not throw exception
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):
if no_except:
info(
f"WARN: MQTT client subscribe timeout, topic={topic} qos={qos}"
)
else:
raise Exception(
f"MQTT client subscribe timeout, topic={topic} qos={qos}"
)
info(f"MQTT client subscribed to topic={topic} qos={qos}")
if handler:
self._handlers[topic] = handler
raise Exception(
"MQTT client subscribe timeout topic=%s qos=%s" % (topic, qos))
logger.info("MQTT client subscribed to topic=%s qos=%s" % (topic, qos))
def unsubscribe(self, topic, timeout=1, no_except=False):
@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
`no_except` indicate to not throw exception
Example:
| Unsubscribe | test/mqtt_test |
"""
timeout = 1 if timeout < 1 else timeout
self._client.unsubscribe(topic)
if self._wait(self._unsubcribed, timeout=timeout):
if no_except:
info(f"WARN: MQTT client unsubscribe timeout, topic={topic}")
else:
raise Exception(
f"MQTT client unsubscribe timeout, topic={topic}"
)
self._messages[topic].clear()
self._handlers.pop(topic, None)
info(f"MQTT client unsubscribed topic={topic}")
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`
@@ -160,10 +173,14 @@ class Client:
`retain` retained flag
"""
self._client.publish(topic, payload, qos=qos,
retain=retain, user_property=[('traceparent', '00-8fb7651916cd43dd8448eb211c80319c-0000000000000000-01'), ('tracestate', 'service.name=ex,a=b,c=d,e=f,g=h')])
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.
@@ -172,8 +189,14 @@ class Client:
`timeout` duration to listen, default to 1 second
Examples:
Listen and get a message received within 5 seconds
| ${messages}= | Listen | test/test | timeout=5 |
"""
start = time.time_ns()
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()
@@ -181,7 +204,7 @@ class Client:
if (
self._wait(self._recved, timeout=timeout)
or (time.time_ns() - start) >= timeout * 1_000_000_000
or (time.time() - start) >= timeout
):
break
@@ -190,29 +213,23 @@ class Client:
Returns true on timeout, false otherwise."""
try:
self._run(asyncio.wait_for(event.wait(), timeout))
event.clear()
except asyncio.TimeoutError:
return True
finally:
event.clear()
return False
def _on_connect(self, client, flags, rc, properties):
info("MQTT client connected")
logger.info("MQTT client connected")
def _on_message(self, client, topic, payload, qos, properties):
info(
"MQTT client received: topic=%s qos=%s payload=%s"
% (topic, qos, payload)
)
if topic in self._handlers:
self._handlers[topic](payload=payload.decode())
else:
self._messages[topic].append(payload.decode())
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):
info("MQTT client disconnected")
logger.info("MQTT client disconnected")
def _on_subscribe(self, client, mid, qos, properties):
self._subcribed.set()
@@ -222,6 +239,9 @@ class Client:
if __name__ == "__main__":
# import logging
# logging.basicConfig(level=logging.DEBUG)
host = "127.0.0.1"
topic = "test/test_mqtt"
client = Client()
+234
View File
@@ -0,0 +1,234 @@
from os import remove
import os
import random
import subprocess
import shutil
import time
class Neuron(object):
process = 0
profiler_process = None
def __init__(self):
pass
def Start_Neuron(self):
os.system("mkdir -p build/persistence")
os.system("cp default_plugins.json build/persistence/plugins.json")
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:
shutil.rmtree("build/persistence", ignore_errors=True)
os.system("mkdir -p build/persistence")
os.system("cp default_plugins.json build/persistence/plugins.json")
def End_Neuron(self, process):
process.kill()
def Remove_Persistence(self):
shutil.rmtree("build/persistence", ignore_errors=True)
os.system("mkdir -p build/persistence")
os.system("cp default_plugins.json build/persistence/plugins.json")
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['id']
return -1
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,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"
}
@@ -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"
}
@@ -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": []
}
+124
View File
@@ -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"
}
@@ -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"
}
@@ -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"
}
@@ -0,0 +1,5 @@
{
"read_interval": 1000,
"group_config_name": "group-0001",
"adapter_name": "modbus-tcp-0001"
}
@@ -0,0 +1,5 @@
{
"read_interval": 1000,
"group_config_name": "group-0002",
"adapter_name": "modbus-tcp-0001"
}
@@ -0,0 +1,5 @@
{
"read_interval": 1000,
"group_config_name": "group-0003",
"adapter_name": "modbus-tcp-0001"
}
@@ -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"
}
@@ -0,0 +1,5 @@
{
"read_interval": 1000,
"group_config_name": "group-0001",
"adapter_name": "modbus-tcp-0002"
}
@@ -0,0 +1,5 @@
{
"read_interval": 1000,
"group_config_name": "group-0002",
"adapter_name": "modbus-tcp-0002"
}
@@ -0,0 +1,5 @@
{
"read_interval": 1000,
"group_config_name": "group-0003",
"adapter_name": "modbus-tcp-0002"
}
@@ -0,0 +1,5 @@
{
"read_interval": 1000,
"group_config_name": "group-0004",
"adapter_name": "modbus-tcp-0002"
}
@@ -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"
}
@@ -0,0 +1,5 @@
{
"read_interval": 1000,
"group_config_name": "group-0001",
"adapter_name": "modbus-tcp-0003"
}
@@ -0,0 +1,5 @@
{
"read_interval": 1000,
"group_config_name": "group-0002",
"adapter_name": "modbus-tcp-0003"
}
@@ -0,0 +1,5 @@
{
"read_interval": 1000,
"group_config_name": "group-0003",
"adapter_name": "modbus-tcp-0003"
}
@@ -0,0 +1,5 @@
{
"read_interval": 1000,
"group_config_name": "group-0004",
"adapter_name": "modbus-tcp-0003"
}
@@ -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"
}
@@ -0,0 +1,5 @@
{
"read_interval": 1000,
"group_config_name": "group-0001",
"adapter_name": "modbus-tcp-0004"
}
@@ -0,0 +1,5 @@
{
"read_interval": 1000,
"group_config_name": "group-0002",
"adapter_name": "modbus-tcp-0004"
}
@@ -0,0 +1,5 @@
{
"read_interval": 1000,
"group_config_name": "group-0003",
"adapter_name": "modbus-tcp-0004"
}
@@ -0,0 +1,5 @@
{
"read_interval": 1000,
"group_config_name": "group-0004",
"adapter_name": "modbus-tcp-0004"
}
@@ -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"
}

Some files were not shown because too many files have changed in this diff Show More