Compare commits

..
22 Commits
Author SHA1 Message Date
fengzeroz 369c5fb34a Merge pull request #709 from fengzeroz/v2.1.0
version: 2.1.3
2022-08-12 17:46:45 +08:00
fengzero 07d3b6eb08 version: 2.1.3 2022-08-12 09:46:13 +00:00
fengzeroz e7f39c467f Merge pull request #706 from fengzeroz/v2.1.0
fix(http): remove aio timeout
2022-08-12 13:52:44 +08:00
fengzero 79665e140b fix(http): remove aio timeout 2022-08-12 05:44:11 +00:00
fengzeroz 2bef69d0ee Merge pull request #686 from fengzeroz/v2.1.0
connection: serial port support more baud rates
2022-08-02 14:35:16 +08:00
fengzero dd62f111eb connection: serial port support more baud rates 2022-08-02 02:00:48 +00:00
fengzeroz 0f1b454c01 Merge pull request #680 from fengzeroz/v2.1.0
http aio cancel fn
2022-08-01 10:59:37 +08:00
fengzero ed1dca302c fix: http aio cancel fn 2022-08-01 02:58:07 +00:00
fengzero 83233ace32 chore: log aio error 2022-08-01 02:52:11 +00:00
fengzeroz f022427cb8 Merge pull request #676 from fengzeroz/v2.1.0
ci: fix upload daily assert
2022-07-28 17:31:44 +08:00
fengzero f8ae3a30c1 ci: fix upload daily assert 2022-07-28 09:31:01 +00:00
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
322 changed files with 12359 additions and 42033 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
+17 -70
View File
@@ -13,7 +13,7 @@ jobs:
steps:
# checkout
- uses: actions/checkout@v4
- uses: actions/checkout@v2
with:
submodules: recursive
@@ -29,65 +29,54 @@ jobs:
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v2
with:
submodules: recursive
- name: cppcheck
run: |
sudo apt install cppcheck
cppcheck --enable=all --error-exitcode=2 --inline-suppr --suppress=missingInclude --suppress=unusedFunction ./plugins ./src
cppcheck --enable=all --error-exitcode=2 --inline-suppr --suppress=missingInclude --suppress=unusedFunction --suppress=variableScope ./simulator
cppcheck --enable=all --error-exitcode=2 --suppress=missingInclude --suppress=unusedFunction ./plugins ./simulator ./src
ut:
runs-on: ubuntu-20.04
container: ghcr.io/neugates/build:x86_64-v2.7
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
cmake .. -DCMAKE_TOOLCHAIN_FILE=../cmake/x86_64-linux-gnu.cmake
make -j4
- name: unit test
run: |
cd build
sudo apt-get update
sudo apt install -y lcov
ctest --output-on-failure -O tests/ut/reports/ut.log --output-junit tests/ut/reports/output.xml
lcov --capture --directory . --output-file testneuron.info --test-name testneuron
genhtml -o result testneuron.info
- uses: actions/upload-artifact@v3
with:
name: ut_result
path: |
build/tests/ut/reports/ut.log
build/tests/ut/reports/output.xml
build/result/index.html
build/neuron.log
ctest --output-on-failure
ft:
runs-on: ubuntu-20.04
container: ghcr.io/neugates/build:x86_64-v2.7
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
cmake .. -DCMAKE_TOOLCHAIN_FILE=../cmake/x86_64-linux-gnu.cmake
make -j4
- name: function test
@@ -105,46 +94,4 @@ jobs:
ft/reports/log.html
ft/reports/output.xml
ft/reports/report.html
build/neuron.log
pft:
runs-on: ubuntu-20.04
container: ghcr.io/neugates/build:x86_64-v2.7
strategy:
matrix:
plugin: [core, modbus, mqtt, metrics]
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: setup dependencies
run: |
if [ "${{ matrix.plugin }}" = "mqtt" ]; then
sudo apt-get install -y mosquitto
pip install -U gmqtt
fi
pip install -U pytest requests prometheus-client
- name: compile
run: |
git config --global --add safe.directory $(pwd)
mkdir -p build && cd build
cmake -DUSE_GCOV=1 .. -DCMAKE_TOOLCHAIN_FILE=../cmake/x86_64-linux-gnu.cmake
make -j4
- name: function test
run: |
if [ "${{ matrix.plugin }}" = "core" ]; then
pytest -s -v tests/ft \
--ignore=tests/ft/app/test_mqtt.py \
--ignore=tests/ft/driver/test_modbus.py \
--ignore=tests/ft/metrics/test_metrics.py
elif [ "${{ matrix.plugin }}" = "modbus" ]; then
pytest -s -v tests/ft/driver/"test_modbus.py"
elif [ "${{ matrix.plugin }}" = "mqtt" ]; then
pytest -s -v tests/ft/app/"test_mqtt.py"
else
pytest -s -v tests/ft/metrics/"test_metrics.py"
fi
build/neuron.log
+206 -45
View File
@@ -7,54 +7,46 @@ on:
types:
- published
env:
VERSION: 2.7.3
UI_VERSION: 2.6.3
BRANCH: v2.7
jobs:
cross-build:
runs-on: ubuntu-20.04
strategy:
matrix:
arch:
- [aarch64-linux-gnu, aarch64, arm64]
- [arm-linux-gnueabihf, armv4, armhf]
- [x86_64-linux-gnu, x86_64, amd64]
container: ghcr.io/neugates/build:${{ matrix.arch[1] }}-v2.7
- [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@v3
with:
name: neuron-sdk
name: neuron-sdk-${{ matrix.arch[5] }}
path: |
neuron-sdk-*.tar.gz
@@ -63,17 +55,26 @@ jobs:
strategy:
matrix:
arch:
- [x86_64-linux-gnu, x86_64, amd64]
container: ghcr.io/neugates/build:${{ matrix.arch[1] }}-v2.7
- [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
@@ -81,38 +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@v3
with:
name: neuron-sdk
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@v3
with:
name: neuron-sdk
- 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, upload_daily_release_debug_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 -4
View File
@@ -16,7 +16,4 @@ tmp
*.deb
*.rpm
neuron-sdk
.vscode
log.html
output.xml
report.html
.vscode
+3
View File
@@ -0,0 +1,3 @@
[submodule "extern/uthash"]
path = extern/uthash
url = https://github.com/troydhanson/uthash.git
+33 -73
View File
@@ -27,32 +27,23 @@ 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(Threads)
@@ -64,59 +55,38 @@ else()
link_directories(/usr/local/lib)
endif()
set(PERSIST_SOURCES
src/persist/persist.c
src/persist/json/persist_json_plugin.c)
aux_source_directory(src/parser NEURON_SRC_PARSE)
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/base/template.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/http_proxy.c
src/utils/neu_jwt.c
src/utils/base64.c
src/utils/async_queue.c
src/utils/log.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()
src/utils/async_queue.c)
add_library(neuron-base SHARED)
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 atomic libssl.a libcrypto.a)
target_link_libraries(neuron-base nng libzlog.so jansson jwt
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
@@ -126,47 +96,41 @@ set(NEURON_SOURCES
src/core/subscribe.c
src/core/plugin_manager.c
src/core/node_manager.c
src/core/template_manager.c
src/core/storage.c
src/adapter/msg_q.c
src/adapter/storage.c
src/adapter/adapter.c
src/adapter/driver/cache.c
src/adapter/driver/driver.c
plugins/restful/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/ndriver_handle.c
plugins/restful/datatag_handle.c
plugins/restful/global_config_handle.c
plugins/restful/group_config_handle.c
plugins/restful/plugin_handle.c
plugins/restful/template_handle.c
plugins/restful/version_handle.c
plugins/restful/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)
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(COPY ${CMAKE_SOURCE_DIR}/neuron.key DESTINATION ${CMAKE_BINARY_DIR}/config)
file(COPY ${CMAKE_SOURCE_DIR}/neuron.pem DESTINATION ${CMAKE_BINARY_DIR}/config)
file(GLOB SQL_SCHEMAS ${CMAKE_SOURCE_DIR}/persistence/*.sql)
file(COPY ${SQL_SCHEMAS} DESTINATION ${CMAKE_BINARY_DIR}/config)
file(COPY ${CMAKE_SOURCE_DIR}/default_plugins.json DESTINATION ${CMAKE_BINARY_DIR}/config)
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)
@@ -175,13 +139,9 @@ add_subdirectory(plugins/ekuiper)
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 -23
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,18 +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
```
```
+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 -56
View File
@@ -1,98 +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/use_cases.html#mqtt-sparkplugb-solution) solution.
- Has very low memory footprint, less than 10M, and CPU usage, can run on limited resource hardware like ARM, x86 and RISC-V.
- Support installation of native executable or deployed in containerized enviornment.
- Control industrial devices, and make changes to the parameters and data tags through [HTTP API](https://neugates.io/docs/en/latest/http-api/http-api.html) and [MQTT API](https://neugates.io/docs/en/latest/configuration/north-apps/mqtt/api.html) services.
- Highly integrated with other EMQ products, including [EMQX](https://www.emqx.com/en/products/emqx), [NanoMQ](https://nanomq.io/), [eKuiper](https://ekuiper.org/).
- The code of the core framework and Modbus, MQTT and eKuiper are licensed under open source LGPLv3. 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.
>
> [Apply for a 15-day trial license](https://www.emqx.com/en/apply-licenses/neuron) to load all drivers.
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.7/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.7/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.7/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)
-23
View File
@@ -1,23 +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()
+2 -19
View File
@@ -1,24 +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.7/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})
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})
-32
View File
@@ -1,32 +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
(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;;
(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
+3 -4
View File
@@ -1,8 +1,7 @@
{
"plugins": [
"libplugin-mqtt.so",
"libplugin-ekuiper.so",
"libplugin-modbus-tcp.so",
"libplugin-modbus-rtu.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
+10 -11
View File
@@ -6,10 +6,6 @@ import shutil
import time
def prepare_persistence_dir():
os.system("mkdir -p build/persistence")
class Neuron(object):
process = 0
profiler_process = None
@@ -18,7 +14,8 @@ class Neuron(object):
pass
def Start_Neuron(self):
prepare_persistence_dir()
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
@@ -28,15 +25,17 @@ class Neuron(object):
time.sleep(5)
self.process.kill()
if remove_persistence_data:
os.system("rm build/persistence/sqlite.db")
prepare_persistence_dir()
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):
os.system("rm build/persistence/sqlite.db")
prepare_persistence_dir()
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 = [
@@ -152,9 +151,9 @@ class Tag(object):
def Tag_Find_By_Name(self, tags, name):
for tag in tags:
if tag['name'] == name:
return tag
return tag['id']
return None
return -1
class Subscribe(object):
-35
View File
@@ -1,35 +0,0 @@
# Functional test
Functional testing uses the robotframework automated testing framework, providing templates for each test case of the northbound APP and southbound DRIVER types.
Testing is divided into the following categories.
|Test case|Description|
|-----|----------|
|Core interface test|Mainly including the addition, deletion, modification, query, subscription, and other operations of the HTTP API interface for core data(PLUGIN, NODE, GROUP, TAG)|
|Southbound DRIVER test||
|Northbound APP test||
|Plugin specific test case|Such as OPC UA specific device discovery, can different devices be connected normally|
To run all functional testers
Enter the neuron/build directory.
Install Mosquito software.
```shell
$ sudo apt-get install -y mosquitto
```
Start the mosquitto server.
```shell
$ mosquitto -v &
```
Install requirements.
```shell
$ python3 -m pip install -U pip
$ python3 -m pip install -r ft/requirements.txt
```
Run functional tests and generate test reports.
```shell
$ python3 -m robot --maxerroelines=600 -P ft/ -d ft/reports ft
```
-153
View File
@@ -5,8 +5,6 @@ Resource resource/error.resource
Suite Setup Start Neuronx
Suite Teardown Stop Neuronx
*** Variables ***
${g_long_str} ${{'a'*200}}
*** Test Cases ***
Add group under non-existent node, it should return failure
@@ -67,154 +65,3 @@ Add group under app node, it should return failure
Check Error Code ${res} ${NEU_ERR_GROUP_NOT_ALLOW}
[Teardown] Del Node mqtt
Update group with nonexistent node, it should fail.
${res} = Update Group modbus-node group interval=${1000}
Check Response Status ${res} 404
Check Error Code ${res} ${NEU_ERR_NODE_NOT_EXIST}
[Teardown] Del Node modbus-node
Update group using too long node name, it should fail.
${res} = Update Group ${g_long_str} group interval=${1000}
Check Response Status ${res} 400
Check Error Code ${res} ${NEU_ERR_NODE_NAME_TOO_LONG}
[Teardown] Del Node modbus-node
Update group with nonexistent group, it should fail.
Add Node modbus-node ${PLUGIN-MODBUS-TCP}
${res} = Update Group modbus-node group interval=${1000}
Check Response Status ${res} 404
Check Error Code ${res} ${NEU_ERR_GROUP_NOT_EXIST}
[Teardown] Del Node modbus-node
Update group using to long group name, it should fail.
Add Node modbus-node ${PLUGIN-MODBUS-TCP}
${res} = Update Group modbus-node ${g_long_str} interval=${1000}
Check Response Status ${res} 400
Check Error Code ${res} ${NEU_ERR_GROUP_NAME_TOO_LONG}
[Teardown] Del Node modbus-node
Update group with too small interval, it should fail.
Add Node modbus-node ${PLUGIN-MODBUS-TCP}
Add Group modbus-node group 1000
${res} = Update Group modbus-node group interval=${10}
Check Response Status ${res} 400
Check Error Code ${res} ${NEU_ERR_GROUP_PARAMETER_INVALID}
[Teardown] Del Node modbus-node
Update group with too large interval, it should fail.
Add Node modbus-node ${PLUGIN-MODBUS-TCP}
Add Group modbus-node group 1000
${res} = Update Group modbus-node group interval=${100000000000}
Check Response Status ${res} 400
Check Error Code ${res} ${NEU_ERR_GROUP_PARAMETER_INVALID}
[Teardown] Del Node modbus-node
Update group interval, it should success.
Add Node modbus-node ${PLUGIN-MODBUS-TCP}
Add Group modbus-node group 1000
${res} = Update Group modbus-node group interval=${2000}
Check Response Status ${res} 200
Check Error Code ${res} ${NEU_ERR_SUCCESS}
${res} = Get Group modbus-node
Set Local Variable ${groups} ${res}[groups]
Should Match Group ${groups} group ${2000}
[Teardown] Del Node modbus-node
Update group with empty new name, it should fail.
Add Node modbus-node ${PLUGIN-MODBUS-TCP}
Add Group modbus-node group 1000
${res} = Update Group modbus-node group new_name=${EMPTY}
Check Response Status ${res} 400
Check Error Code ${res} ${NEU_ERR_BODY_IS_WRONG}
[Teardown] Del Node modbus-node
Update group with too long new name, it should fail.
Add Node modbus-node ${PLUGIN-MODBUS-TCP}
Add Group modbus-node group 1000
${res} = Update Group modbus-node group new_name=${g_long_str}
Check Response Status ${res} 400
Check Error Code ${res} ${NEU_ERR_GROUP_NAME_TOO_LONG}
[Teardown] Del Node modbus-node
Update group name to conflicting group name, it should fail.
Add Node modbus-node ${PLUGIN-MODBUS-TCP}
Add Group modbus-node group 1000
Add Group modbus-node grp 1000
${res} = Update Group modbus-node group new_name=grp
Check Response Status ${res} 409
Check Error Code ${res} ${NEU_ERR_GROUP_EXIST}
[Teardown] Del Node modbus-node
Update group name, it should success.
Add Node modbus-node ${PLUGIN-MODBUS-TCP}
Add Group modbus-node group 1000
${res} = Update Group modbus-node group new_name=grp
Check Response Status ${res} 200
Check Error Code ${res} ${NEU_ERR_SUCCESS}
${res} = Get Group modbus-node
Set Local Variable ${groups} ${res}[groups]
Should Match Group ${groups} grp ${1000}
[Teardown] Del Node modbus-node
Update group name and interval, it should success.
Add Node modbus-node ${PLUGIN-MODBUS-TCP}
Add Group modbus-node group 1000
${res} = Update Group modbus-node group new_name=grp interval=${2000}
Check Response Status ${res} 200
Check Error Code ${res} ${NEU_ERR_SUCCESS}
${res} = Get Group modbus-node
Set Local Variable ${groups} ${res}[groups]
Should Match Group ${groups} grp ${2000}
[Teardown] Del Node modbus-node
Update group name, subscriptions should be updated.
Add Node mqtt-node ${PLUGIN-MQTT}
Add Node modbus-node ${PLUGIN-MODBUS-TCP}
Add Group modbus-node group 1000
Subscribe Group mqtt-node modbus-node group
${res} = Update Group modbus-node group new_name=grp
Check Response Status ${res} 200
Check Error Code ${res} ${NEU_ERR_SUCCESS}
${res} = Get Subscribe Group mqtt-node
Check Response Status ${res} 200
Set Local Variable ${groups} ${res}[groups]
List Length Should Be ${groups} 1
Should Be Equal As Strings ${groups}[0][driver] modbus-node
Should Be Equal As Strings ${groups}[0][group] grp
[Teardown] Del Node modbus-node
*** Keywords ***
Should Match Group
[Arguments] ${groups} ${name} ${interval}
List Length Should Be ${groups} 1
Should Be Equal As Strings ${name} ${groups}[0][name]
Should Be Equal As Integers ${interval} ${groups}[0][interval]
-43
View File
@@ -1,43 +0,0 @@
*** Settings ***
Library String
Library Collections
Resource resource/api.resource
Resource resource/common.resource
Resource resource/error.resource
Suite Setup Metrics Test Setup
Suite Teardown Metrics Test Teardown
*** Test Cases ***
Get all metrics, it should return success
${res}= Get all metrics
Check Response Status ${res} 200
Get single node metrics, it should return success
${res}= Get single node metrics mqtt app
Check Response Status ${res} 200
Check Prometheus format, it should return success
${nlines}= Get metrics lines
${parameter_lines}= Get parameter lines ${nlines}
Check endswith isdigit ${parameter_lines}
Check node state, it should return success
${nlines}= Get metrics lines
${parameter_lines}= Get parameter lines ${nlines}
Check node state ${parameter_lines} mqtt
*** Keywords ***
Metrics Test Setup
Start Neuronx
${res}= Add Node mqtt ${PLUGIN_MQTT}
Check Response Status ${res} 200
Metrics Test Teardown
Del Node mqtt
Stop Neuronx
+187
View File
@@ -0,0 +1,187 @@
*** Settings ***
Resource resource/api.resource
Resource resource/common.resource
Resource resource/error.resource
Resource resource/driver.resource
Suite Setup Modbus Test Setup
Suite Teardown Modbus Test Teardown
*** Variables ***
${modbus_node} modbus_node
${MODBUS_TCP_CONFIG_WRONG} {"host": "127.0.0.1", "port": 60502}
${hold_bit} {"name": "hold_bit", "address": "1!400001.15", "attribute": ${TAG_ATTRIBUTE_READ}, "type": ${TAG_TYPE_BIT}}
${hold_int16} {"name": "hold_int16", "address": "1!400001", "attribute": ${TAG_ATTRIBUTE_RW}, "type": ${TAG_TYPE_INT16}}
${hold_uint16} {"name": "hold_uint16", "address": "1!400002", "attribute": ${TAG_ATTRIBUTE_RW}, "type": ${TAG_TYPE_UINT16}}
${hold_int32} {"name": "hold_int32", "address": "1!400003", "attribute": ${TAG_ATTRIBUTE_RW}, "type": ${TAG_TYPE_INT32}}
${hold_uint32} {"name": "hold_uint32", "address": "1!400015", "attribute": ${TAG_ATTRIBUTE_RW}, "type": ${TAG_TYPE_UINT32}}
${hold_float} {"name": "hold_float", "address": "1!400017", "attribute": ${TAG_ATTRIBUTE_RW}, "type": ${TAG_TYPE_FLOAT}}
${hold_string} {"name": "hold_string", "address": "1!400020.10", "attribute": ${TAG_ATTRIBUTE_RW}, "type": ${TAG_TYPE_STRING}}
${coil_bit_1} {"name": "coil_bit_1", "address": "1!000001", "attribute": ${TAG_ATTRIBUTE_RW}, "type": ${TAG_TYPE_BIT}}
${coil_bit_2} {"name": "coil_bit_2", "address": "1!000002", "attribute": ${TAG_ATTRIBUTE_RW}, "type": ${TAG_TYPE_BIT}}
${coil_bit_3} {"name": "coil_bit_3", "address": "1!000003", "attribute": ${TAG_ATTRIBUTE_RW}, "type": ${TAG_TYPE_BIT}}
${coil_bit_4} {"name": "coil_bit_4", "address": "1!000005", "attribute": ${TAG_ATTRIBUTE_RW}, "type": ${TAG_TYPE_BIT}}
${coil_bit_5} {"name": "coil_bit_5", "address": "1!000010", "attribute": ${TAG_ATTRIBUTE_RW}, "type": ${TAG_TYPE_BIT}}
${input_bit_1} {"name": "input_bit_1", "address": "1!100001", "attribute": ${TAG_ATTRIBUTE_READ}, "type": ${TAG_TYPE_BIT}}
${input_bit_2} {"name": "input_bit_2", "address": "1!100002", "attribute": ${TAG_ATTRIBUTE_READ}, "type": ${TAG_TYPE_BIT}}
${input_bit_3} {"name": "input_bit_3", "address": "1!100003", "attribute": ${TAG_ATTRIBUTE_READ}, "type": ${TAG_TYPE_BIT}}
${input_bit_4} {"name": "input_bit_4", "address": "1!100005", "attribute": ${TAG_ATTRIBUTE_READ}, "type": ${TAG_TYPE_BIT}}
${input_bit_5} {"name": "input_bit_5", "address": "1!100010", "attribute": ${TAG_ATTRIBUTE_READ}, "type": ${TAG_TYPE_BIT}}
${input_register_bit} {"name": "input_register_bit", "address": "1!30101.15", "attribute": ${TAG_ATTRIBUTE_READ}, "type": ${TAG_TYPE_BIT}}
${input_register_int16} {"name": "input_register_int16", "address": "1!30101", "attribute": ${TAG_ATTRIBUTE_READ}, "type": ${TAG_TYPE_INT16}}
${input_register_uint16} {"name": "input_register_uint16", "address": "1!30102", "attribute": ${TAG_ATTRIBUTE_READ}, "type": ${TAG_TYPE_UINT16}}
${input_register_int32} {"name": "input_register_int32", "address": "1!30103", "attribute": ${TAG_ATTRIBUTE_READ}, "type": ${TAG_TYPE_INT32}}
${input_register_uint32} {"name": "input_register_uint32", "address": "1!30115", "attribute": ${TAG_ATTRIBUTE_READ}, "type": ${TAG_TYPE_UINT32}}
${input_register_float} {"name": "input_register_float", "address": "1!30117", "attribute": ${TAG_ATTRIBUTE_READ}, "type": ${TAG_TYPE_FLOAT}}
${input_register_string} {"name": "input_register_string", "address": "1!30120.10", "attribute": ${TAG_ATTRIBUTE_READ}, "type": ${TAG_TYPE_STRING}}
${hold_int16_address_update} {"name": "hold_int16", "address": "1!400100", "attribute": ${TAG_ATTRIBUTE_RW}, "type": ${TAG_TYPE_INT16}}
${hold_int16_type_update} {"name": "hold_int16", "address": "1!400001", "attribute": ${TAG_ATTRIBUTE_RW}, "type": ${TAG_TYPE_INT32}}
${input_bit_1_name_wrong} {"name": "input_bit", "address": "1!100001", "attribute": ${TAG_ATTRIBUTE_READ}, "type": ${TAG_TYPE_BIT}}
${input_bit_1_attribute_unmatch} {"name": "input_bit_1", "address": "1!100001", "attribute": ${TAG_ATTRIBUTE_RW}, "type": ${TAG_TYPE_BIT}}
${input_bit_1_type_unmatch} {"name": "input_bit_1", "address": "1!100001", "attribute": ${TAG_ATTRIBUTE_READ}, "type": ${TAG_TYPE_INT16}}
*** Test Cases ***
Set a node with right settings, it should be success.
[Template] Set a ${node} with right ${node_settings}, it will be success.
${modbus_node} ${MODBUS_TCP_CONFIG}
Set a node with wrong settings, it should be failure.
[Template] Set a ${node} with wrong ${node_settings}, it will be failure.
${modbus_node} ${MODBUS_TCP_CONFIG_WRONG}
Set tags with multiple address and types and attribute, it should be success.
[Template] Add a ${tag} with right address and type and attribute from ${node}, it will be success.
${hold_int16} ${modbus_node}
${hold_uint16} ${modbus_node}
${hold_int32} ${modbus_node}
${hold_uint32} ${modbus_node}
${hold_float} ${modbus_node}
${hold_string} ${modbus_node}
${coil_bit_1} ${modbus_node}
${coil_bit_2} ${modbus_node}
${coil_bit_3} ${modbus_node}
${coil_bit_4} ${modbus_node}
${coil_bit_5} ${modbus_node}
${input_register_int16} ${modbus_node}
${input_register_uint16} ${modbus_node}
${input_register_int32} ${modbus_node}
${input_register_uint32} ${modbus_node}
${input_register_float} ${modbus_node}
${input_register_string} ${modbus_node}
${input_bit_1} ${modbus_node}
${input_bit_2} ${modbus_node}
${input_bit_3} ${modbus_node}
${input_bit_4} ${modbus_node}
${input_bit_5} ${modbus_node}
Set tags with unmatch address, type or attribute, it should be failure.
[Template] Set a ${tag} with unmatch address, type or attribute from ${node}, it will be failure and return ${resp_status} and ${error_code}.
${input_bit_1_type_unmatch} ${modbus_node} 200 ${NEU_ERR_TAG_TYPE_NOT_SUPPORT}
${input_bit_1_attribute_unmatch} ${modbus_node} 200 ${NEU_ERR_TAG_ATTRIBUTE_NOT_SUPPORT}
Write and Read all type tag with same slave id in hold register and coil, it should be success.
[Template] Write and Read a ${tag} named ${tag_name} from ${node}, using ${check} to check the ${value}, it will be success.
${hold_int16} hold_int16 ${modbus_node} Compare Tag Value As Int 120
${hold_uint16} hold_uint16 ${modbus_node} Compare Tag Value As Int 65535
${hold_int32} hold_int32 ${modbus_node} Compare Tag Value As Int 77889912
${hold_uint32} hold_uint32 ${modbus_node} Compare Tag Value As Int 88991232
${hold_float} hold_float ${modbus_node} Compare Tag Value As Float 12.34
${hold_string} hold_string ${modbus_node} Compare Tag Value As Strings "abc123"
${coil_bit_1} coil_bit_1 ${modbus_node} Compare Tag Value As Int 1
${coil_bit_2} coil_bit_2 ${modbus_node} Compare Tag Value As Int 0
${coil_bit_3} coil_bit_3 ${modbus_node} Compare Tag Value As Int 0
${coil_bit_4} coil_bit_4 ${modbus_node} Compare Tag Value As Int 1
${coil_bit_5} coil_bit_5 ${modbus_node} Compare Tag Value As Int 1
Read all type tag with same slave id in input register and input, it should be success.
[Template] Read a ${tag} named ${tag_name} from ${node}, using ${check} to check the ${value}, it will be success.
${input_register_int16} input_register_int16 ${modbus_node} Compare Tag Value As Int 0
${input_register_uint16} input_register_uint16 ${modbus_node} Compare Tag Value As Int 0
${input_register_int32} input_register_int32 ${modbus_node} Compare Tag Value As Int 0
${input_register_uint32} input_register_uint32 ${modbus_node} Compare Tag Value As Int 0
${input_register_float} input_register_float ${modbus_node} Compare Tag Value As Float 0
${input_register_string} input_register_string ${modbus_node} Compare Tag Value As Strings ""
${input_bit_1} input_bit_1 ${modbus_node} Compare Tag Value As Int 0
${input_bit_2} input_bit_2 ${modbus_node} Compare Tag Value As Int 0
${input_bit_3} input_bit_3 ${modbus_node} Compare Tag Value As Int 0
${input_bit_4} input_bit_4 ${modbus_node} Compare Tag Value As Int 0
${input_bit_5} input_bit_5 ${modbus_node} Compare Tag Value As Int 0
Read some tags at time, it will be success.
${input_register_tags}= Create List ${input_register_int16} ${input_register_uint16} ${input_register_int32} ${input_register_uint32} ${input_register_float} ${input_register_string} ${input_register_bit}
Read some ${input_register_tags} from ${modbus_node}, it will be success.
${hold_tags}= Create List ${hold_int16} ${hold_uint16} ${hold_int32} ${hold_uint32} ${hold_float} ${hold_string} ${hold_bit}
Read some ${hold_tags} from ${modbus_node}, it will be success.
${coil_tags}= Create List ${coil_bit_1} ${coil_bit_2} ${coil_bit_3} ${coil_bit_4} ${coil_bit_5}
Read some ${coil_tags} from ${modbus_node}, it will be success.
${input_tags}= Create List ${input_bit_1} ${input_bit_2} ${input_bit_3} ${input_bit_4} ${input_bit_5}
Read some ${input_tags} from ${modbus_node}, it will be success.
Write and read a tag with same name and same address that in different groups, it should be success.
${groups}= Create List group-1 group-2 group-3
Write and read a ${hold_int16} with same hold_int16 and same address in different ${groups} that from ${modbus_node}, using Compare Tag Value As Int to check the 2, it will be success.
Write and read a tag with same name but different address that in different groups, it should be success.
${groups}= Create List group-1 group-2 group-3
Write and read ${hold_int16} ${hold_int16_address_update} with same hold_int16 but different address in different ${groups} that from ${modbus_node}, using Compare Tag Value As Int to check the 2, it will be success.
Update a tag with right address and types and attribute, it will be success
[Template] Update a ${tag} by a ${tag_update} named ${tag_name} from ${node} , it can read and write, using ${check} to check the ${value}, it will be success.
${hold_int16} ${hold_int16_address_update} hold_int16 ${modbus_node} Compare Tag Value As Int 120
${hold_int16} ${hold_int16_type_update} hold_int16 ${modbus_node} Compare Tag Value As Int 120
Update a tag with unmatch address and types and attribute, it should be failure.
[Template] Update a ${tag} by a ${tag_update} with the unmatch settings from ${node} , it will be failure and return ${resp_status} and ${error_code}.
${input_bit_1} ${input_bit_1_attribute_unmatch} ${modbus_node} 200 ${NEU_ERR_TAG_ATTRIBUTE_NOT_SUPPORT}
${input_bit_1} ${input_bit_1_type_unmatch} ${modbus_node} 200 ${NEU_ERR_TAG_TYPE_NOT_SUPPORT}
${input_bit_1} ${input_bit_1_name_wrong} ${modbus_node} 200 ${NEU_ERR_TAG_NOT_EXIST}
Write a value to a tag that don't exit in plc or neuron, it will be failure.
[Template] Write a ${value} to a ${tag} with named ${tag_name} that don't exist in neuron or plc from ${node}, it will be failure.
12 ${input_bit_1} input ${modbus_node}
Write value to a tag without write attribute, it will be failure.
[Template] Write a ${value} to a ${tag} named ${tag_name} that without write attribute from ${node}, it will be failure.
1 ${input_bit_1} input_bit_1 ${modbus_node}
Write and read a value to a tag when the node is stoped, it will be failure.
[Template] Write and read a ${value} to a ${tag} named ${tag_name} when the ${node} is stoped, it will be failure.
1 ${hold_int16} hold_int16 ${modbus_node}
*** Keywords ***
Modbus Test Setup
Start Modbus Simulator
Start Neuronx
${res}= Add Node ${modbus_node} ${PLUGIN-MODBUS-TCP}
Check Response Status ${res} 200
${res}= Node Setting ${modbus_node} ${MODBUS_TCP_CONFIG}
Check Response Status ${res} 200
${res}= Node Ctl ${modbus_node} ${NODE_CTL_START}
Check Response Status ${res} 200
${state}= Get Node State ${modbus_node}
Should Be Equal As Integers ${state}[running] ${NODE_STATE_RUNNING}
Should Be Equal As Integers ${state}[link] ${NODE_LINK_STATE_CONNECTING}
Modbus Test Teardown
Del Node ${modbus_node}
Stop Neuronx
Terminate All Processes kill=false
+94
View File
@@ -0,0 +1,94 @@
*** Settings ***
Resource resource/api.resource
Resource resource/common.resource
Resource resource/error.resource
Suite Setup Start Neuronx
Suite Teardown Stop Neuronx
*** Test Cases ***
Start an unconfigured node, it should return failure
${res}= Add Node modbus-node ${PLUGIN-MODBUS-TCP}
Sleep 1s
${state} = Get Node State modbus-node
Should Be Equal As Integers ${state}[running] ${NODE_STATE_INIT}
Should Be Equal As Integers ${state}[link] ${NODE_LINK_STATE_DISCONNECTED}
${res} = Node Ctl modbus-node ${NODE_CTL_START}
Check Response Status ${res} 409
Check Error Code ${res} ${NEU_ERR_NODE_NOT_READY}
Stop node that is ready(init/idle), it should return failure
${res} = Node Ctl modbus-node ${NODE_CTL_STOP}
Check Response Status ${res} 409
Check Error Code ${res} ${NEU_ERR_NODE_NOT_RUNNING}
${state} = Get Node State modbus-node
Should Be Equal As Integers ${state}[running] ${NODE_STATE_INIT}
Should Be Equal As Integers ${state}[link] ${NODE_LINK_STATE_DISCONNECTED}
[Teardown] Del Node modbus-node
Start the configured node, it should return success
${res}= Add Node modbus-node ${PLUGIN-MODBUS-TCP}
Sleep 1s
Node Setting modbus-node ${MODBUS_TCP_CONFIG}
${state} = Get Node State modbus-node
Should Be Equal As Integers ${state}[running] ${NODE_STATE_READY}
Should Be Equal As Integers ${state}[link] ${NODE_LINK_STATE_CONNECTING}
${res} = Node Ctl modbus-node ${NODE_CTL_START}
Check Response Status ${res} 200
Check Error Code ${res} ${NEU_ERR_SUCCESS}
#${state} = Get Node State modbus-node
#Should Be Equal As Integers ${state}[running] ${NODE_STATE_RUNNING}
#Should Be Equal As Integers ${state}[link] ${NODE_LINK_STATE_CONNECTING}
${res} = Node Ctl modbus-node ${NODE_CTL_STOP}
Check Response Status ${res} 200
Check Error Code ${res} ${NEU_ERR_SUCCESS}
${state} = Get Node State modbus-node
Should Be Equal As Integers ${state}[running] ${NODE_STATE_STOP}
Should Be Equal As Integers ${state}[link] ${NODE_LINK_STATE_CONNECTING}
Stop node that is stopped, it should return failure
${res} = Node Ctl modbus-node ${NODE_CTL_STOP}
Check Response Status ${res} 409
Check Error Code ${res} ${NEU_ERR_NODE_IS_STOPED}
Start the stopped node, it should return success
${res} = Node Ctl modbus-node ${NODE_CTL_START}
Check Response Status ${res} 200
Check Error Code ${res} ${NEU_ERR_SUCCESS}
${state} = Get Node State modbus-node
Should Be Equal As Integers ${state}[running] ${NODE_STATE_RUNNING}
Should Be Equal As Integers ${state}[link] ${NODE_LINK_STATE_CONNECTING}
Start the running node, it should return failure
${res} = Node Ctl modbus-node ${NODE_CTL_START}
Check Response Status ${res} 409
Check Error Code ${res} ${NEU_ERR_NODE_IS_RUNNING}
When setting up a READY/RUNNING/STOPED node, the node status will not change
${res} = Node Setting modbus-node ${MODBUS_TCP_CONFIG}
${state} = Get Node State modbus-node
Should Be Equal As Integers ${state}[running] ${NODE_STATE_RUNNING}
Should Be Equal As Integers ${state}[link] ${NODE_LINK_STATE_CONNECTING}
${res} = Node Ctl modbus-node ${NODE_CTL_STOP}
Check Response Status ${res} 200
Check Error Code ${res} ${NEU_ERR_SUCCESS}
${res} = Node Setting modbus-node ${MODBUS_TCP_CONFIG}
${state} = Get Node State modbus-node
Should Be Equal As Integers ${state}[running] ${NODE_STATE_STOP}
Should Be Equal As Integers ${state}[link] ${NODE_LINK_STATE_CONNECTING}
[Teardown] Del Node modbus-node
-52
View File
@@ -59,58 +59,6 @@ Get APP node, it should be success.
Check Response Status ${res} 200
Node Should Exist ${res}[nodes] mqtt-node
Update node name to empty string, it should fail.
${res} = Update Node modbus-node ${EMPTY}
Check Response Status ${res} 400
Check Error Code ${res} ${NEU_ERR_NODE_NAME_EMPTY}
Update node name to excessive long string, it should fail.
${name} = Evaluate 'a'*200
${res} = Update Node modbus-node ${name}
Check Response Status ${res} 400
Check Error Code ${res} ${NEU_ERR_NODE_NAME_TOO_LONG}
Update driver node name, it should fail if the node does not exist
${res} = Update Node modbus-node-nonexistent mqtt-node
Check Response Status ${res} 404
Check Error Code ${res} ${NEU_ERR_NODE_NOT_EXIST}
Update driver node name, it should fail if node name conflicts
${res} = Update Node modbus-node mqtt-node
Check Response Status ${res} 409
Check Error Code ${res} ${NEU_ERR_NODE_EXIST}
Update node name to the same, it should fail as name conflicts
${res} = Update Node modbus-node modbus-node
Check Response Status ${res} 409
Check Error Code ${res} ${NEU_ERR_NODE_EXIST}
${res} = Update Node mqtt-node mqtt-node
Check Response Status ${res} 409
Check Error Code ${res} ${NEU_ERR_NODE_EXIST}
Update driver node name, it should success
${res} = Update Node modbus-node modbus-node-new
Check Response Status ${res} 200
Check Error Code ${res} ${NEU_ERR_SUCCESS}
${res} = Update Node modbus-node-new modbus-node
Check Response Status ${res} 200
Check Error Code ${res} ${NEU_ERR_SUCCESS}
Update app node name, it should success
${res} = Update Node mqtt-node mqtt-node-new
Check Response Status ${res} 200
Check Error Code ${res} ${NEU_ERR_SUCCESS}
${res} = Update Node mqtt-node-new mqtt-node
Check Response Status ${res} 200
Check Error Code ${res} ${NEU_ERR_SUCCESS}
Delete a APP node with an existing name, it should be success.
${res}= Del Node mqtt-node
+17
View File
@@ -0,0 +1,17 @@
*** Settings ***
Resource resource/api.resource
Resource resource/common.resource
Resource resource/error.resource
Suite Setup Start Neuronx
Suite Teardown Stop Neuronx
*** Test Cases ***
login with invalid username and password, it should return failure
POST /api/v2/login {"name":"admin1", "pass": "0000"}
Integer response status 401
Integer $.error ${NEU_ERR_INVALID_USER_OR_PASSWORD}
login with username and password, it should return success
POST /api/v2/login {"name":"admin", "pass": "0000"}
Integer response status 200
output $.token
+23 -120
View File
@@ -6,16 +6,14 @@ Suite Setup Neuron Context Ready
Suite Teardown Neuron Context Stop
*** Variables ***
${test_gconfig1} test_gconfig1
${test_gconfig2} test_gconfig2
${test_gconfig3} test_gconfig3
${modbus-tcp-1} modbus-tcp-1
${modbus-tcp-2} modbus-tcp-2
${modbus-tcp-3} modbus-tcp-3
${modbus-tcp-4} modbus-tcp-4
${modbus-tcp-1-new} modbus-tcp-1-new
${mqtt-1} mqtt-1
${mqtt-1-new} mqtt-1-new
${test_gconfig1} test_gconfig1
${test_gconfig2} test_gconfig2
${test_gconfig3} test_gconfig3
${modbus-tcp-1} modbus-tcp-1
${modbus-tcp-2} modbus-tcp-2
${modbus-tcp-3} modbus-tcp-3
${modbus-tcp-4} modbus-tcp-4
${mqtt-1} mqtt-1
${tag1} {"name": "tag1", "address": "1!400001", "attribute": ${TAG_ATTRIBUTE_READ}, "type": ${TAG_TYPE_INT16}}
${tag2} {"name": "tag2", "address": "1!00001", "attribute": ${TAG_ATTRIBUTE_RW}, "type": ${TAG_TYPE_BIT}}
${tag3} {"name": "tag3", "address": "2!400003", "attribute": ${TAG_ATTRIBUTE_READ}, "type": ${TAG_TYPE_INT32}}
@@ -23,7 +21,7 @@ ${tag4} {"name": "tag4", "address": "2!400005", "attribute": ${TAG_A
${tag5} {"name": "tag5", "address": "2!400006", "attribute": ${TAG_ATTRIBUTE_READ}, "type": ${TAG_TYPE_INT16}}
${tag6} {"name": "tag6", "address": "2!400007", "attribute": ${TAG_ATTRIBUTE_READ}, "type": ${TAG_TYPE_INT16}}
${tag7} {"name": "tag7", "address": "2!400008", "attribute": ${TAG_ATTRIBUTE_READ}, "type": ${TAG_TYPE_INT16}}
${tag8} {"name": "tag8", "address": "2!400009", "attribute": ${TAG_ATTRIBUTE_READ}, "type": ${TAG_TYPE_INT16}}
${tag8} {"name": "tag8", "address": "2!400009", "attribute": %{TAG_ATTRIBUTE_READ}, "type": ${TAG_TYPE_INT16}}
*** Test Cases ***
Get the newly added adapters after stopping and restarting Neuron, it should return success
@@ -74,9 +72,9 @@ Get the deleted adapter after stopping and restarting Neuron, it should return f
Get the setted adapters information after stopping and restarting Neuron, it should return the correct information
${process} = Neuron Start Running
Node Setting ${modbus-tcp-1} {"host": "127.0.0.1", "port": 502, "timeout": 3000, "connection_mode": 0, "transport_mode": 0, "interval": 20}
Node Setting ${modbus-tcp-2} {"host": "127.0.0.1", "port": 502, "timeout": 3000, "connection_mode": 0, "transport_mode": 0, "interval": 20}
Node Setting ${mqtt-1} {"client-id":"123456", "upload-topic":"/neuron/mqtt-1/upload", "heartbeat-topic": "/neuron/mqtt-1/heartbeat","format": 0,"cache-mem-size": 10,"cache-disk-size": 10,"ssl":false,"host":"127.0.0.1","port":1883,"username":"admin","password":"0000","ca":"", "cert":"", "key":"", "keypass":""}
Node Setting ${modbus-tcp-1} {"host": "127.0.0.1", "port": 502, "timeout": 3000}
Node Setting ${modbus-tcp-2} {"host": "127.0.0.1", "port": 502, "timeout": 3000}
Node Setting ${mqtt-1} {"client-id":"upload123", "upload-topic":"", "format": 0, "ssl":false,"host":"127.0.0.1","port":1883,"username":"admin","password":"0000","ca":"", "cert":"", "key":"", "keypass":""}
Neuron Stop Running ${process}
${process} = Neuron Start Running
@@ -101,25 +99,20 @@ Get the setted adapters information after stopping and restarting Neuron, it sho
${params} = Set Variable ${res}[params]
Check Response Status ${res} 200
Should Be Equal As Strings ${res}[node] ${mqtt-1}
Should Be Equal As Strings ${params}[upload-topic] /neuron/mqtt-1/upload
Should Be Equal As Strings ${params}[heartbeat-topic] /neuron/mqtt-1/heartbeat
Should Be Equal As Integers ${params}[format] 0
Should Be Equal As Integers ${params}[port] 1883
Should Be Equal As Strings ${params}[client-id] upload123
Should Not Be True ${params}[ssl]
Should Be Equal As Strings ${params}[host] 127.0.0.1
Should Be Equal As Integers ${params}[port] 1883
Should Be Equal As Strings ${params}[username] admin
Should Be Equal As Strings ${params}[password] 0000
Should Be Empty ${params}[ca]
Should Be Empty ${params}[cert]
Should Be Empty ${params}[key]
Should Be Empty ${params}[keypass]
[Teardown] Neuron Stop Running ${process}
Get the updated adapters settings information after stopping and restarting Neuron, it should return the correct information
${process} = Neuron Start Running
Node Setting ${modbus-tcp-2} {"host": "127.0.0.1", "port": 502, "timeout": 3000, "connection_mode": 0, "transport_mode": 0, "interval": 20}
Node Setting ${modbus-tcp-2} {"host": "127.0.0.1", "port": 502, "timeout": 3000}
Neuron Stop Running ${process}
${process} = Neuron Start Running
@@ -244,17 +237,15 @@ Get the update tags after stopping ande restarting Neuron, it should return the
${len} = Get Length ${res}[tags]
Should Be Equal As Integers ${len} 2
${tag1} = Tag Find By Name ${res}[tags] tag1
Should Be Equal As Strings ${tag1}[name] tag1
Should Be Equal As Strings ${tag1}[address] 1!400002
Should Be Equal As Strings ${tag1}[attribute] ${TAG_ATTRIBUTE_READ}
Should Be Equal As Strings ${tag1}[type] ${TAG_TYPE_INT16}
Should Be Equal As Strings ${res}[tags][1][name] tag1
Should Be Equal As Strings ${res}[tags][1][address] 1!400002
Should Be Equal As Strings ${res}[tags][1][attribute] ${TAG_ATTRIBUTE_READ}
Should Be Equal As Strings ${res}[tags][1][type] ${TAG_TYPE_INT16}
${tag2} = Tag Find By Name ${res}[tags] tag2
Should Be Equal As Strings ${tag2}[name] tag2
Should Be Equal As Strings ${tag2}[address] 1!00001
Should Be Equal As Strings ${tag2}[attribute] ${TAG_ATTRIBUTE_RW}
Should Be Equal As Strings ${tag2}[type] ${TAG_TYPE_BIT}
Should Be Equal As Strings ${res}[tags][0][name] tag2
Should Be Equal As Strings ${res}[tags][0][address] 1!00001
Should Be Equal As Strings ${res}[tags][0][attribute] ${TAG_ATTRIBUTE_RW}
Should Be Equal As Strings ${res}[tags][0][type] ${TAG_TYPE_BIT}
[Teardown] Neuron Stop Running ${process}
@@ -282,94 +273,6 @@ Get the subscribed groups after stopping and restarting Neuron, it should return
[Teardown] Neuron Stop Running ${process}
Update driver name, it should keep the setting, groups, tags and subscription
${process} = Neuron Start Running
${res} = Update Node ${modbus-tcp-1} ${modbus-tcp-1-new}
Check Response Status ${res} 200
Check Error Code ${res} ${NEU_ERR_SUCCESS}
Neuron Stop Running ${process}
${process} = Neuron Start Running
${res} = Get Node Setting ${modbus-tcp-1-new}
${params} = Set Variable ${res}[params]
Check Response Status ${res} 200
Should Be Equal As Strings ${res}[node] ${modbus-tcp-1-new}
Should Be Equal As Integers ${params}[port] 502
Should Be Equal As Integers ${params}[timeout] 3000
Should Be Equal As Strings ${params}[host] 127.0.0.1
${res} = Get Tags ${modbus-tcp-1-new} ${test_gconfig1}
Check Response Status ${res} 200
${len} = Get Length ${res}[tags]
Should Be Equal As Integers ${len} 2
${tag1} = Tag Find By Name ${res}[tags] tag1
Should Be Equal As Strings ${tag1}[name] tag1
Should Be Equal As Strings ${tag1}[address] 1!400002
Should Be Equal As Strings ${tag1}[attribute] ${TAG_ATTRIBUTE_READ}
Should Be Equal As Strings ${tag1}[type] ${TAG_TYPE_INT16}
${tag2} = Tag Find By Name ${res}[tags] tag2
Should Be Equal As Strings ${tag2}[name] tag2
Should Be Equal As Strings ${tag2}[address] 1!00001
Should Be Equal As Strings ${tag2}[attribute] ${TAG_ATTRIBUTE_RW}
Should Be Equal As Strings ${tag2}[type] ${TAG_TYPE_BIT}
${res} = Get Subscribe Group ${mqtt-1}
${len} = Get Length ${res}[groups]
Should Be Equal As Integers ${len} 2
Should Be Equal As Strings ${res}[groups][0][driver] ${modbus-tcp-1-new}
Should Be Equal As Strings ${res}[groups][0][group] ${test_gconfig1}
Should Be Equal As Strings ${res}[groups][1][driver] ${modbus-tcp-1-new}
Should Be Equal As Strings ${res}[groups][1][group] ${test_gconfig2}
${res} = Update Node ${modbus-tcp-1-new} ${modbus-tcp-1}
Check Response Status ${res} 200
Check Error Code ${res} ${NEU_ERR_SUCCESS}
[Teardown] Neuron Stop Running ${process}
Update app name, it should keep the setting and subscription
${process} = Neuron Start Running
${res} = Update Node ${mqtt-1} ${mqtt-1-new}
Check Response Status ${res} 200
Check Error Code ${res} ${NEU_ERR_SUCCESS}
Neuron Stop Running ${process}
${process} = Neuron Start Running
${res} = Get Node Setting ${mqtt-1-new}
${params} = Set Variable ${res}[params]
Check Response Status ${res} 200
Should Be Equal As Strings ${res}[node] ${mqtt-1-new}
Should Be Equal As Strings ${params}[upload-topic] /neuron/mqtt-1/upload
Should Be Equal As Strings ${params}[heartbeat-topic] /neuron/mqtt-1/heartbeat
Should Be Equal As Integers ${params}[format] 0
Should Not Be True ${params}[ssl]
Should Be Equal As Strings ${params}[host] 127.0.0.1
Should Be Equal As Integers ${params}[port] 1883
Should Be Equal As Strings ${params}[username] admin
Should Be Equal As Strings ${params}[password] 0000
Should Be Empty ${params}[ca]
Should Be Empty ${params}[cert]
Should Be Empty ${params}[key]
Should Be Empty ${params}[keypass]
${res} = Get Subscribe Group ${mqtt-1-new}
${len} = Get Length ${res}[groups]
Should Be Equal As Integers ${len} 2
Should Be Equal As Strings ${res}[groups][0][driver] ${modbus-tcp-1}
Should Be Equal As Strings ${res}[groups][0][group] ${test_gconfig1}
Should Be Equal As Strings ${res}[groups][1][driver] ${modbus-tcp-1}
Should Be Equal As Strings ${res}[groups][1][group] ${test_gconfig2}
${res} = Update Node ${mqtt-1-new} ${mqtt-1}
Check Response Status ${res} 200
Check Error Code ${res} ${NEU_ERR_SUCCESS}
[Teardown] Neuron Stop Running ${process}
Get the unsubscribed groups after stopping ande restarting Neuron, it should return failure
${process} = Neuron Start Running
+17 -201
View File
@@ -1,22 +1,24 @@
*** Settings ***
Library REST http://127.0.0.1:7000
Library REST http://127.0.0.1:7001
Resource common.resource
*** Variables ***
${PLUGIN-MODBUS-TCP} Modbus TCP
${PLUGIN-MQTT} MQTT
${PLUGIN-EKUIPER} eKuiper
${PLUGIN-MODBUS-TCP} modbus-tcp
${PLUGIN-MQTT} mqtt
${PLUGIN-EKUIPER} ekuiper
${NODE_DRIVER} 1
${NODE_APP} 2
${NODE_STATE_IDLE} 0
${NODE_STATE_INIT} 1
${NODE_STATE_READY} 2
${NODE_STATE_RUNNING} 3
${NODE_STATE_STOP} 4
${NODE_LINK_STATE_DISCONNECTED} 0
${NODE_LINK_STATE_CONNECTED} 1
${NODE_LINK_STATE_CONNECTING} 1
${NODE_LINK_STATE_CONNECTED} 2
${NODE_CTL_START} 0
${NODE_CTL_STOP} 1
@@ -24,9 +26,7 @@ ${NODE_CTL_STOP} 1
${TAG_ATTRIBUTE_READ} 1
${TAG_ATTRIBUTE_WRITE} 2
${TAG_ATTRIBUTE_SUBSCRIBE} 4
${TAG_ATTRIBUTE_STATIC} 8
${TAG_ATTRIBUTE_RW} 3
${TAG_ATTRIBUTE_STATIC_RW} 11
${TAG_TYPE_INT8} 1
${TAG_TYPE_UINT8} 2
@@ -69,12 +69,6 @@ Add Node
${res} Object response body
[RETURN] ${res}[0]
Update Node
[Arguments] ${name} ${new_name}
PUT /api/v2/node {"name": "${name}", "new_name": "${new_name}"}
${res} Object response body
[RETURN] ${res}[0]
Del Node
[Arguments] ${name}
DELETE /api/v2/node {"name": "${name}"}
@@ -117,14 +111,6 @@ Add Group
${res} = Object response body
[RETURN] ${res}[0]
Update Group
[Arguments] ${node} ${group} &{updates}
${dict} = Evaluate {"node":$node, "group":$group, **$updates}
${data} = Evaluate json.dumps(${dict}) json
PUT /api/v2/group ${data}
${res} = Object response body
[RETURN] ${res}[0]
Del Group
[Arguments] ${node} ${group}
DELETE /api/v2/group {"node": "${node}", "group": "${group}"}
@@ -149,20 +135,6 @@ Unsubscribe Group
${res} = Object response body
[RETURN] ${res}[0]
Update Subscribe
[Arguments] ${app} ${driver} ${group} &{params}
${data} = Evaluate json.dumps(${params}) json
PUT /api/v2/subscribe {"app": "${app}", "driver": "${driver}", "group": "${group}", "params": ${data}}
${res} = Object response body
[RETURN] ${res}[0]
Subscribe Groups
[Arguments] ${app} @{groups}
${data} = Evaluate json.dumps(${groups}) json
POST /api/v2/subscribes {"app": "${app}", "groups": ${data}}
${res} = Object response body
[RETURN] ${res}[0]
Get Subscribe Group
[Arguments] ${app}
GET /api/v2/subscribe?app=${app}
@@ -196,6 +168,16 @@ Del Tags
[RETURN] ${res}[0]
Get Tag ID
[Arguments] ${node_id} ${group} ${tag_name}
${res} = Get Tags ${node_id} ${group}
Check Response Status ${res} 200
${id} = Tag Find By Name ${res}[tags] ${tag_name}
Should Not Be Equal As Integers ${id} 0
[Return] ${id}
Read Tags
[Arguments] ${node} ${group}
POST /api/v2/read {"node": "${node}", "group": "${group}"}
@@ -207,169 +189,3 @@ Write Tags
POST /api/v2/write {"node": "${node}", "group": "${group}", "tag": "${tag}", "value": ${value}}
${res} = Object response body
[RETURN] ${res}[0]
Write 3 Tags 1 Time
[Arguments] ${node} ${group} ${tag1} ${value1} ${tag2} ${value2} ${tag3} ${value3}
POST /api/v2/write/tags {"node": "${node}", "group": "${group}", "tags": [{"tag": "${tag1}", "value": ${value1}}, {"tag": "${tag2}", "value": ${value2}}, {"tag": "${tag3}", "value": ${value3}}]}
${res} = Object response body
[RETURN] ${res}[0]
Add Template
[Arguments] ${name} ${plugin} ${groups}
${data} = Evaluate json.dumps(${groups}) json
POST /api/v2/template {"name": "${name}", "plugin": "${plugin}", "groups": ${data} }
${res} Object response body
[RETURN] ${res}[0]
Del Template
[Arguments] ${name}
DELETE /api/v2/template?name=${name}
${res} Object response body
[RETURN] ${res}[0]
Inst Template
[Arguments] ${name} ${node}
POST /api/v2/template/inst {"name": "${name}", "node": "${node}" }
${res} Object response body
[RETURN] ${res}[0]
Inst Templates
[Arguments] @{insts}
${data} = Evaluate json.dumps(${insts}) json
POST /api/v2/template/instances {"nodes": ${data}}
${res} Object response body
[RETURN] ${res}[0]
Get Template
[Arguments] ${name}
GET /api/v2/template?name=${name}
${res} Object response body
[RETURN] ${res}[0]
Get Templates
GET /api/v2/template
${res} Object response body
[RETURN] ${res}[0]
Add Template Group
[Arguments] ${tmpl} ${group} ${interval}
POST /api/v2/template/group {"template": "${tmpl}", "group": "${group}", "interval": ${interval}}
${res} = Object response body
[RETURN] ${res}[0]
Put Template Group
[Arguments] ${tmpl} ${group} &{updates}
${data} = Evaluate json.dumps({"template": "${tmpl}", "group": "${group}", **$updates}) json
PUT /api/v2/template/group ${data}
${res} = Object response body
[RETURN] ${res}[0]
Del Template Group
[Arguments] ${tmpl} ${group}
DELETE /api/v2/template/group {"template": "${tmpl}", "group": "${group}"}
${res} = Object response body
[RETURN] ${res}[0]
Get Template Groups
[Arguments] ${tmpl}
GET /api/v2/template/group?name=${tmpl}
${res} = Object response body
[RETURN] ${res}[0]
Add Template Tags
[Arguments] ${tmpl} ${group} @{tags}
${data} = Evaluate json.dumps(${tags}) json
POST /api/v2/template/tag {"template": "${tmpl}", "group": "${group}", "tags": ${data}}
${res} = Object response body
[RETURN] ${res}[0]
Get Template Tags
[Arguments] ${tmpl} ${group}
GET /api/v2/template/tag?template=${tmpl}&group=${group}
${res} = Object response body
[RETURN] ${res}[0]
Grep Template Tags
[Arguments] ${tmpl} ${group} ${pattern}
GET /api/v2/template/tag?template=${tmpl}&group=${group}&name=${pattern}
${res} = Object response body
[RETURN] ${res}[0]
Put Template Tags
[Arguments] ${tmpl} ${group} @{tags}
${data} = Evaluate json.dumps(${tags}) json
PUT /api/v2/template/tag {"template": "${tmpl}", "group": "${group}", "tags": ${data}}
${res} = Object response body
[RETURN] ${res}[0]
Del Template Tags
[Arguments] ${tmpl} ${group} @{tags}
${data} = Evaluate json.dumps(${tags}) json
DELETE /api/v2/template/tag {"template": "${tmpl}", "group": "${group}", "tags": ${data}}
${res} = Object response body
[RETURN] ${res}[0]
Get all metrics
GET /api/v2/metrics
${res} = String response body
[RETURN] ${res}
Get single node metrics
[Arguments] ${node_name} ${category}
GET /api/v2/metrics?node=${node_name}&category=${category}
${res} = String response body
[RETURN] ${res}
Get metrics lines
${lines}= Get all metrics
${lines_str}= Convert To String ${lines}
${lines_str} Evaluate str(${lines_str}).strip('[]')
${lines_str} Evaluate str(${lines_str}).strip(\"'\")
${nlines}= Split String ${lines_str} \n
Remove From List ${nlines} -1
[RETURN] ${nlines}
Get parameter lines
[Arguments] ${nlines}
${description_lines} Create List
${parameter_lines} Create List
FOR ${line} IN @{nlines}
${first_char}= Get Substring ${line} 0 1
IF "${first_char}"=="#"
Append To List ${description_lines} ${line}
ELSE
Append To List ${parameter_lines} ${line}
END
END
[RETURN] ${parameter_lines}
Check endswith isdigit
[Arguments] ${parameter_lines}
FOR ${line} IN @{parameter_lines}
${last_char}= Get Substring ${line} -1
Should Be True '${last_char}'.isdigit()
END
Check node state
[Arguments] ${parameter_lines} ${node}
${link_state} Create List
${running_state} Create List
${node_state}= Get Node State ${node}
FOR ${line} IN @{parameter_lines}
${param}= Get Substring ${line} 0 10
IF "${param}"=="link_state"
Append To List ${link_state} ${line}
END
IF "${param}"=="running_st"
Append To List ${running_state} ${line}
END
END
${metrics_link}= Get Substring ${link_state}[0] -1
${metrics_link}= Convert To Integer ${metrics_link}
Should Be Equal As Integers ${metrics_link} ${node_state}[link]
${metrics_running}= Get Substring ${running_state}[0] -1
${metrics_running}= Convert To Integer ${metrics_running}
Should Be Equal As Integers ${metrics_running} ${node_state}[running]
+1 -1
View File
@@ -1,7 +1,7 @@
*** Settings ***
Library Collections
Library Keyword.MQTT.Client reconnect_retries=5 reconnect_delay=0
Library REST http://127.0.0.1:7000
Library REST http://127.0.0.1:7001
Resource common.resource
*** Keywords ***
+4 -10
View File
@@ -17,9 +17,8 @@ Resource simulator.resource
${test_data_dir} ft/data
${PLUGIN_MODBUS_TCP} Modbus TCP
${PLUGIN_MONITOR} Monitor
${PLUGIN_MQTT} MQTT
${PLUGIN_MODBUS_TCP} modbus-tcp
${PLUGIN_MQTT} mqtt
${MQTT_CMD_NONE}
@@ -40,12 +39,12 @@ ${MQTT_CONFIG} {"client-id": "${MQTT_CLIENTID}", "u
... "ssl": false, "host": "${MQTT_CONFIG_HOST}", "port": ${MQTT_CONFIG_PORT},
... "username": "", "password": "", "ca":"", "cert":"", "key":"", "keypass":""}
${MODBUS_TCP_CONFIG} {"host": "127.0.0.1", "port": 60502, "connection_mode": 0, "transport_mode": 0, "timeout": 3000, "interval": 20}
${MODBUS_TCP_CONFIG} {"host": "127.0.0.1", "port": 60502, "timeout": 3000}
*** Variables ***
${neuron_process}
${MODBUS_PLUS_TCP_CONFIG} {"host": "127.0.0.1", "port": 60502, "connection_mode": 0, "transport_mode": 0, "timeout": 3000}
${MODBUS_PLUS_TCP_CONFIG} {"host": "127.0.0.1", "port": 60502, "connection_mode": 0, "timeout": 3000}
*** Keywords ***
Start Neuronx
@@ -71,11 +70,6 @@ Neuron Ready
Start Neuron
Sleep 3
List Length Should Be
[Arguments] ${data} ${len}
${res} = Get Length ${data}
Should Be Equal As Integers ${len} ${res}
Compare Tag Value As Bool
[Arguments] ${tags} ${name} ${value}
+9 -39
View File
@@ -70,9 +70,13 @@ Read some ${tags} from ${node}, it will be success.
Check Response Status ${res} 200
Check Error Code ${res} ${NEU_ERR_SUCCESS}
${res}= Add Tags ${node} group ${tags}
Check Response Status ${res} 200
Check Error Code ${res} ${NEU_ERR_SUCCESS}
Log ${tags}
FOR ${tag} IN @{tags}
${res}= Add Tags ${node} group ${tag}
Check Response Status ${res} 200
Check Error Code ${res} ${NEU_ERR_SUCCESS}
END
Sleep 290ms
${res}= Read Tags ${node} group
@@ -234,7 +238,7 @@ Write a ${value} to a ${tag} with named ${tag_name} that don't exist in neuron o
[Teardown] Del Group ${node} group
Read a ${tag} with named ${tag_name} that don't exist in plc form ${node}, it will be failure ${error}.
Read a ${tag} with named ${tag_name} that don't exist in plc form ${node}, it will be failure.
[Tags] Driver 15
${res}= Add Group ${node} group 100
@@ -248,7 +252,7 @@ Read a ${tag} with named ${tag_name} that don't exist in plc form ${node}, it wi
Sleep 290ms
${res}= Read Tags ${node} group
Check Response Status ${res} 200
Check Tag Error As Int ${res}[tags] ${tag_name} ${error}
Check Tag Error As Int ${res} ${tag_name} ${NEU_ERR_TAG_NOT_EXIST}
[Teardown] Del Group ${node} group
@@ -293,37 +297,3 @@ Write and read a ${value} to a ${tag} named ${tag_name} when the ${node} is stop
Check Tag Error As Int ${res}[tags] ${tag_name} ${NEU_ERR_PLUGIN_NOT_RUNNING}
[Teardown] Del Group ${node} group
Write and Read ${tag_data1}, ${tag_data2} and ${tag_data3} named ${tag1}, ${tag2} and ${tag3} from ${node}, using ${check} to check the ${value1}, ${value2} and ${value3}, it will be success.
[Tags] Driver 18
${res}= Add Group ${node} group 100
Check Response Status ${res} 200
Check Error Code ${res} ${NEU_ERR_SUCCESS}
${res}= Add Tags ${node} group ${tag_data1}
Check Response Status ${res} 200
Check Error Code ${res} ${NEU_ERR_SUCCESS}
${res}= Add Tags ${node} group ${tag_data2}
Check Response Status ${res} 200
Check Error Code ${res} ${NEU_ERR_SUCCESS}
${res}= Add Tags ${node} group ${tag_data3}
Check Response Status ${res} 200
Check Error Code ${res} ${NEU_ERR_SUCCESS}
Sleep 290ms
${res}= Write 3 Tags 1 Time ${node} group ${tag1} ${value1} ${tag2} ${value2} ${tag3} ${value3}
Check Response Status ${res} 200
Check Error Code ${res} ${NEU_ERR_SUCCESS}
Sleep 100ms
${res}= Read Tags ${node} group
Check Response Status ${res} 200
Run Keyword ${check} ${res}[tags] ${tag1} ${value1}
Run Keyword ${check} ${res}[tags] ${tag2} ${value2}
Run Keyword ${check} ${res}[tags] ${tag3} ${value3}
[Teardown] Del Group ${node} group
+59 -91
View File
@@ -1,99 +1,67 @@
*** Variables ***
${NEU_ERR_SUCCESS} 0
${NEU_ERR_SUCCESS} 0
${NEU_ERR_FAILURE} 1000
${NEU_ERR_EINTERNAL} 1001
${NEU_ERR_BODY_IS_WRONG} 1002
${NEU_ERR_PARAM_IS_WRONG} 1003
${NEU_ERR_NEED_TOKEN} 1004
${NEU_ERR_DECODE_TOKEN} 1005
${NEU_ERR_EXPIRED_TOKEN} 1006
${NEU_ERR_VALIDATE_TOKEN} 1007
${NEU_ERR_INVALID_TOKEN} 1008
${NEU_ERR_INVALID_USER_OR_PASSWORD} 1009
${NEU_ERR_IS_BUSY} 1010
${NEU_ERR_FILE_NOT_EXIST} 1011
${NEU_ERR_INVALID_PASSWORD_LEN} 1012
${NEU_ERR_DUPLICATE_PASSWORD} 1013
${NEU_ERR_COMMAND_EXECUTION_FAILED} 1014
${NEU_ERR_IP_ADDRESS_INVALID} 1015
${NEU_ERR_IP_ADDRESS_IN_USE} 1016
${NEU_ERR_INVALID_USER} 1017
${NEU_ERR_INVALID_PASSWORD} 1018
${NEU_ERR_FAILURE} 1000
${NEU_ERR_EINTERNAL} 1001
${NEU_ERR_BODY_IS_WRONG} 1002
${NEU_ERR_PARAM_IS_WRONG} 1003
${NEU_ERR_NEED_TOKEN} 1004
${NEU_ERR_DECODE_TOKEN} 1005
${NEU_ERR_EXPIRED_TOKEN} 1006
${NEU_ERR_VALIDATE_TOKEN} 1007
${NEU_ERR_INVALID_TOKEN} 1008
${NEU_ERR_INVALID_USER_OR_PASSWORD} 1009
${NEU_ERR_IS_BUSY} 1010
${NEU_ERR_NODE_EXIST} 2002
${NEU_ERR_NODE_NOT_EXIST} 2003
${NEU_ERR_NODE_SETTING_INVALID} 2004
${NEU_ERR_NODE_SETTING_NOT_FOUND} 2005
${NEU_ERR_NODE_NOT_READY} 2006
${NEU_ERR_NODE_IS_RUNNING} 2007
${NEU_ERR_NODE_NOT_RUNNING} 2008
${NEU_ERR_NODE_IS_STOPED} 2009
${NEU_ERR_NODE_NAME_TOO_LONG} 2010
${NEU_ERR_NODE_EXIST} 2002
${NEU_ERR_NODE_NOT_EXIST} 2003
${NEU_ERR_NODE_SETTING_INVALID} 2004
${NEU_ERR_NODE_SETTING_NOT_FOUND} 2005
${NEU_ERR_NODE_NOT_READY} 2006
${NEU_ERR_NODE_IS_RUNNING} 2007
${NEU_ERR_NODE_NOT_RUNNING} 2008
${NEU_ERR_NODE_IS_STOPED} 2009
${NEU_ERR_NODE_NAME_TOO_LONG} 2010
${NEU_ERR_NODE_NOT_ALLOW_DELETE} 2011
${NEU_ERR_NODE_NOT_ALLOW_SUBSCRIBE} 2012
${NEU_ERR_NODE_NOT_ALLOW_UPDATE} 2013
${NEU_ERR_NODE_NOT_ALLOW_MAP} 2014
${NEU_ERR_NODE_NAME_EMPTY} 2015
${NEU_ERR_GROUP_ALREADY_SUBSCRIBED} 2101
${NEU_ERR_GROUP_NOT_SUBSCRIBE} 2102
${NEU_ERR_GROUP_NOT_ALLOW} 2103
${NEU_ERR_GROUP_EXIST} 2104
${NEU_ERR_GROUP_PARAMETER_INVALID} 2105
${NEU_ERR_GROUP_NOT_EXIST} 2106
${NEU_ERR_GROUP_NAME_TOO_LONG} 2107
${NEU_ERR_GROUP_ALREADY_SUBSCRIBED} 2101
${NEU_ERR_GROUP_NOT_SUBSCRIBE} 2102
${NEU_ERR_GROUP_NOT_ALLOW} 2103
${NEU_ERR_GROUP_EXIST} 2104
${NEU_ERR_GROUP_PARAMETER_INVALID} 2105
${NEU_ERR_GROUP_NOT_EXIST} 2106
${NEU_ERR_GROUP_NAME_TOO_LONG} 2107
${NEU_ERR_TAG_NOT_EXIST} 2201
${NEU_ERR_TAG_NAME_CONFLICT} 2202
${NEU_ERR_TAG_ATTRIBUTE_NOT_SUPPORT} 2203
${NEU_ERR_TAG_TYPE_NOT_SUPPORT} 2204
${NEU_ERR_TAG_ADDRESS_FORMAT_INVALID} 2205
${NEU_ERR_TAG_NAME_TOO_LONG} 2206
${NEU_ERR_TAG_ADDRESS_TOO_LONG} 2207
${NEU_ERR_TAG_DESCRIPTION_TOO_LONG} 2208
${NEU_ERR_TAG_NOT_EXIST} 2201
${NEU_ERR_TAG_NAME_CONFLICT} 2202
${NEU_ERR_TAG_ATTRIBUTE_NOT_SUPPORT} 2203
${NEU_ERR_TAG_TYPE_NOT_SUPPORT} 2204
${NEU_ERR_TAG_ADDRESS_FORMAT_INVALID} 2205
${NEU_ERR_TAG_NAME_TOO_LONG} 2206
${NEU_ERR_TAG_ADDRESS_TOO_LONG} 2207
${NEU_ERR_TAG_DESCRIPTION_TOO_LONG} 2208
${NEU_ERR_TAG_PRECISION_INVALID} 2209
${NEU_ERR_TAG_EXIST} 2210
${NEU_ERR_LIBRARY_NOT_FOUND} 2301
${NEU_ERR_LIBRARY_INFO_INVALID} 2302
${NEU_ERR_LIBRARY_NAME_CONFLICT} 2303
${NEU_ERR_LIBRARY_FAILED_TO_OPEN} 2304
${NEU_ERR_LIBRARY_MODULE_INVALID} 2305
${NEU_ERR_LIBRARY_SYSTEM_NOT_ALLOW_DEL} 2306
${NEU_ERR_LIBRARY_NOT_FOUND} 2301
${NEU_ERR_LIBRARY_INFO_INVALID} 2302
${NEU_ERR_LIBRARY_NAME_CONFLICT} 2303
${NEU_ERR_LIBRARY_FAILED_TO_OPEN} 2304
${NEU_ERR_LIBRARY_MODULE_INVALID} 2305
${NEU_ERR_LIBRARY_SYSTEM_NOT_ALLOW_DEL} 2306
${NEU_ERR_LIBRARY_NOT_ALLOW_CREATE_INSTANCE} 2307
${NEU_ERR_LIBRARY_ARCH_NOT_SUPPORT} 2308
${NEU_ERR_LICENSE_NOT_FOUND} 2400
${NEU_ERR_LICENSE_INVALID} 2401
${NEU_ERR_LICENSE_EXPIRED} 2402
${NEU_ERR_LICENSE_DISABLED} 2403
${NEU_ERR_LICENSE_MAX_NODES} 2404
${NEU_ERR_LICENSE_MAX_TAGS} 2405
${NEU_ERR_LICENSE_NOT_FOUND} 2400
${NEU_ERR_LICENSE_INVALID} 2401
${NEU_ERR_LICENSE_EXPIRED} 2402
${NEU_ERR_LICENSE_DISABLED} 2403
${NEU_ERR_LICENSE_MAX_NODES} 2404
${NEU_ERR_LICENSE_MAX_TAGS} 2405
${NEU_ERR_LICENSE_TOKEN_NOT_MATCH} 2406
${NEU_ERR_LICENSE_BAD_CLOCK} 2407
${NEU_ERR_LICENSE_MODULE_INVALID} 2408
${NEU_ERR_TEMPLATE_EXIST} 2500
${NEU_ERR_TEMPLATE_NOT_FOUND} 2501
${NEU_ERR_TEMPLATE_NAME_TOO_LONG} 2502
${NEU_ERR_PLUGIN_READ_FAILURE} 3000
${NEU_ERR_PLUGIN_WRITE_FAILURE} 3001
${NEU_ERR_PLUGIN_DISCONNECTED} 3002
${NEU_ERR_PLUGIN_TAG_NOT_ALLOW_READ} 3003
${NEU_ERR_PLUGIN_TAG_NOT_ALLOW_WRITE} 3004
${NEU_ERR_PLUGIN_TAG_TYPE_MISMATCH} 3007
${NEU_ERR_PLUGIN_TAG_VALUE_EXPIRED} 3008
${NEU_ERR_PLUGIN_PROTOCOL_DECODE_FAILURE} 3009
${NEU_ERR_PLUGIN_NOT_RUNNING} 3010
${NEU_ERR_PLUGIN_TAG_NOT_READY} 3011
${NEU_ERR_PLUGIN_PACKET_OUT_OF_ORDER} 3012
${NEU_ERR_PLUGIN_NAME_TOO_LONG} 3013
${NEU_ERR_PLUGIN_NOT_FOUND} 3014
${NEU_ERR_PLUGIN_DEVICE_NOT_RESPONSE} 3015
${NEU_ERR_PLUGIN_NOT_SUPPORT_TEMPLATE} 3016
${NEU_ERR_PLUGIN_NOT_SUPPORT_WRITE_TAGS} 3017
${NEU_ERR_MQTT_SUBSCRIBE_FAILURE} 4010
${NEU_ERR_PLUGIN_READ_FAILURE} 3000
${NEU_ERR_PLUGIN_WRITE_FAILURE} 3001
${NEU_ERR_PLUGIN_DISCONNECTED} 3002
${NEU_ERR_PLUGIN_TAG_NOT_ALLOW_READ} 3003
${NEU_ERR_PLUGIN_TAG_NOT_ALLOW_WRITE} 3004
${NEU_ERR_PLUGIN_TAG_TYPE_MISMATCH} 3007
${NEU_ERR_PLUGIN_TAG_VALUE_EXPIRED} 3008
${NEU_ERR_PLUGIN_PROTOCOL_DECODE_FAILURE} 3009
${NEU_ERR_PLUGIN_NOT_RUNNING} 3010
${NEU_ERR_PLUGIN_TAG_NOT_READY} 3011
${NEU_ERR_PLUGIN_PACKET_OUT_OF_ORDER} 3012
+1 -1
View File
@@ -8,7 +8,7 @@ ${OPCUA_SERVER_SIMULATOR} ./opcua_simulator
*** Keywords ***
Start Modbus Simulator
${handle} = Start Process ${MODBUS_TCP_SERVER_SIMULATOR} tcp 60502 ip_v4 cwd=build/simulator
${handle} = Start Process ${MODBUS_TCP_SERVER_SIMULATOR} tcp 60502 cwd=build/simulator
[Return] ${handle}
Start Simulator Arg
-44
View File
@@ -24,49 +24,6 @@ North APP subscribe existent group, it should return success
Check Response Status ${res} 200
Check Error Code ${res} ${NEU_ERR_SUCCESS}
North APP update subscribe nonexistent group, it should return success
${res}= Update Subscribe mqtt modbus-node group1 topic=/neuron
Check Response Status ${res} 404
Check Error Code ${res} ${NEU_ERR_GROUP_NOT_SUBSCRIBE}
North APP update subscribe existent group, it should return success
${res}= Update Subscribe mqtt modbus-node group topic=/neuron
Check Response Status ${res} 200
Check Error Code ${res} ${NEU_ERR_SUCCESS}
North APP subscribe multiple nonexistent groups, it should fail.
${g1} = Evaluate {"driver":"modbus-node", "group": "group1"}
${g2} = Evaluate {"driver": "modbus-node", "group": "group2", "params":{"topic":"/neuron"}}
${res}= Subscribe Groups mqtt ${g1} ${g2}
Check Response Status ${res} 404
Check Error Code ${res} ${NEU_ERR_GROUP_NOT_EXIST}
North MQTT APP subscribe with empty topic, it should fail.
${g1} = Evaluate {"driver": "modbus-node", "group": "group1", "params":{"topic":""}}
${res}= Subscribe Groups mqtt ${g1}
Check Response Status ${res} 200
Check Error Code ${res} ${NEU_ERR_MQTT_SUBSCRIBE_FAILURE}
North APP subscribe multiple groups, it should return success
Add Group modbus-node group1 1000
Add Group modbus-node group2 1000
${g1} = Evaluate {"driver":"modbus-node", "group": "group1"}
${g2} = Evaluate {"driver": "modbus-node", "group": "group2", "params":{"topic":"/neuron"}}
${res}= Subscribe Groups mqtt ${g1} ${g2}
Check Response Status ${res} 200
Check Error Code ${res} ${NEU_ERR_SUCCESS}
[Teardown] Run Keywords Del Group modbus-node group1
... AND Del Group modbus-node group2
Query the subscribers of the group, it should return all nodes subscribed to this group
${res} = Get Subscribe Group mqtt
Check Response Status ${res} 200
@@ -75,7 +32,6 @@ Query the subscribers of the group, it should return all nodes subscribed to thi
Should Be Equal As Integers ${len} 1
Should Be Equal As Strings ${res}[groups][0][driver] modbus-node
Should Be Equal As Strings ${res}[groups][0][group] group
Should Be Equal As Strings ${res}[groups][0][params][topic] /neuron
Add Group modbus-node group1 1000
Subscribe Group mqtt modbus-node group1
+21 -92
View File
@@ -11,11 +11,7 @@ ${tag2} {"name": "tag2", "address": "1!00001", "attribute": ${TAG_AT
${tag3} {"name": "tag3", "address": "1!00001", "attribute": ${TAG_ATTRIBUTE_RW}, "type": ${TAG_TYPE_UINT16}}
${tag4} {"name": "tag4", "address": "1!00031", "attribute": ${TAG_ATTRIBUTE_RW}, "type": ${TAG_TYPE_BIT}}
${tag1update} {"name": "tag1", "address": "1!400002", "attribute": ${TAG_ATTRIBUTE_RW}, "type": ${TAG_TYPE_INT32}}
${tag_desc} {"name": "tag_desc", "description": "description info", "address": "1!400001", "attribute": ${TAG_ATTRIBUTE_READ}, "type": ${TAG_TYPE_INT16}}
${tag1_static} {"name": "tag1", "address": "1!400001", "attribute": ${TAG_ATTRIBUTE_STATIC_RW}, "type": ${TAG_TYPE_INT16}, "value": 1}
${tag1_static_no_value} {"name": "tag1", "address": "1!400001", "attribute": ${TAG_ATTRIBUTE_STATIC_RW}, "type": ${TAG_TYPE_INT16}}
${tag_decimal} {"name": "tag_decimal", "address": "1!400003", "attribute": ${TAG_ATTRIBUTE_RW}, "type": ${TAG_TYPE_INT16}, "decimal": 0.1}
${tag_desc} {"name": "tag_desc", "description": "description info", "address": "1!400001", "attribute": ${TAG_ATTRIBUTE_READ}, "type": ${TAG_TYPE_INT16}}
*** Test Cases ***
Add tags to non-existent node, it should return failure
@@ -24,29 +20,12 @@ Add tags to non-existent node, it should return failure
Check Response Status ${res} 404
Check Error Code ${res} ${NEU_ERR_NODE_NOT_EXIST}
Add tags to the non-existent group, it should return success
Add tags to the non-existent group, it should return failure
Add Node modbus-node ${PLUGIN-MODBUS-TCP}
${res}= Add Tags modbus-node group ${tag1},${tag2}
Check Response Status ${res} 200
Check Error Code ${res} ${NEU_ERR_SUCCESS}
[Teardown] Del Tags modbus-node group "tag1","tag2"
Add static tag, it should return success.
${res}= Add Tags modbus-node group ${tag1_static}
Check Response Status ${res} 200
Check Error Code ${res} 0
[Teardown] Del Tags modbus-node group "tag1"
Add static tag without value, it should fail.
${res}= Add Tags modbus-node group ${tag1_static_no_value}
Check Response Status ${res} 400
Check Error Code ${res} ${NEU_ERR_BODY_IS_WRONG}
[Teardown] Del Tags modbus-node group "tag1"
Check Error Code ${res} ${NEU_ERR_GROUP_NOT_EXIST}
Add different types of tags to the group, it should return success
Add Group modbus-node group 5000
@@ -59,7 +38,7 @@ Add different types of tags to the group, it should return success
Add a list of tags with errors, it should return the number of successful additions.
${res}= Add Tags modbus-node group ${tag1},${tag2},${tag3},${tag4}
Check Response Status ${res} 409
Check Response Status ${res} 200
Check Error Code ${res} ${NEU_ERR_TAG_NAME_CONFLICT}
Should Be Equal As Integers ${res}[index] 0
@@ -80,34 +59,6 @@ Get tag list from modbus-node, it should return success.
Should Be Equal As Strings ${res}[tags][1][attribute] ${TAG_ATTRIBUTE_RW}
Should Be Equal As Strings ${res}[tags][1][type] ${TAG_TYPE_BIT}
Update tag to be static, it should return success.
${res}= Update Tags modbus-node group ${tag1_static}
Check Response Status ${res} 200
Check Error Code ${res} ${NEU_ERR_SUCCESS}
${res}= Get Tags modbus-node group
Check Response Status ${res} 200
${len} = Get Length ${res}[tags]
Should Be Equal As Integers ${len} 2
Should Be Equal As Strings ${res}[tags][0][name] tag1
Should Be Equal As Strings ${res}[tags][0][address] 1!400001
Should Be Equal As Strings ${res}[tags][0][attribute] ${TAG_ATTRIBUTE_STATIC_RW}
Should Be Equal As Strings ${res}[tags][0][type] ${TAG_TYPE_INT16}
Should Be Equal As Strings ${res}[tags][1][name] tag2
Should Be Equal As Strings ${res}[tags][1][address] 1!00001
Should Be Equal As Strings ${res}[tags][1][attribute] ${TAG_ATTRIBUTE_RW}
Should Be Equal As Strings ${res}[tags][1][type] ${TAG_TYPE_BIT}
Update static tag without value, it should fail.
${res}= Update Tags modbus-node group ${tag1_static_no_value}
Check Response Status ${res} 400
Check Error Code ${res} ${NEU_ERR_BODY_IS_WRONG}
Update tag, it should return success.
${res}= Update Tags modbus-node group ${tag1update}
@@ -120,15 +71,15 @@ Update tag, it should return success.
${len} = Get Length ${res}[tags]
Should Be Equal As Integers ${len} 2
Should Be Equal As Strings ${res}[tags][0][name] tag1
Should Be Equal As Strings ${res}[tags][0][address] 1!400002
Should Be Equal As Strings ${res}[tags][0][attribute] ${TAG_ATTRIBUTE_RW}
Should Be Equal As Strings ${res}[tags][0][type] ${TAG_TYPE_INT32}
Should Be Equal As Strings ${res}[tags][1][name] tag2
Should Be Equal As Strings ${res}[tags][1][address] 1!00001
Should Be Equal As Strings ${res}[tags][1][name] tag1
Should Be Equal As Strings ${res}[tags][1][address] 1!400002
Should Be Equal As Strings ${res}[tags][1][attribute] ${TAG_ATTRIBUTE_RW}
Should Be Equal As Strings ${res}[tags][1][type] ${TAG_TYPE_BIT}
Should Be Equal As Strings ${res}[tags][1][type] ${TAG_TYPE_INT32}
Should Be Equal As Strings ${res}[tags][0][name] tag2
Should Be Equal As Strings ${res}[tags][0][address] 1!00001
Should Be Equal As Strings ${res}[tags][0][attribute] ${TAG_ATTRIBUTE_RW}
Should Be Equal As Strings ${res}[tags][0][type] ${TAG_TYPE_BIT}
Delete tag from non-existent group, it should return success
${res}= Del Tags modbus-node group1 "tag1"
@@ -139,7 +90,7 @@ Delete tag from non-existent group, it should return success
Update non-existent tag, it should return failure.
${res}= Update Tags modbus-node group ${tag4}
Check Response Status ${res} 404
Check Response Status ${res} 200
Check Error Code ${res} ${NEU_ERR_TAG_NOT_EXIST}
${res}= Get Tags modbus-node group
@@ -148,15 +99,15 @@ Update non-existent tag, it should return failure.
${len} = Get Length ${res}[tags]
Should Be Equal As Integers ${len} 2
Should Be Equal As Strings ${res}[tags][0][name] tag1
Should Be Equal As Strings ${res}[tags][0][address] 1!400002
Should Be Equal As Strings ${res}[tags][0][attribute] ${TAG_ATTRIBUTE_RW}
Should Be Equal As Strings ${res}[tags][0][type] ${TAG_TYPE_INT32}
Should Be Equal As Strings ${res}[tags][1][name] tag2
Should Be Equal As Strings ${res}[tags][1][address] 1!00001
Should Be Equal As Strings ${res}[tags][1][name] tag1
Should Be Equal As Strings ${res}[tags][1][address] 1!400002
Should Be Equal As Strings ${res}[tags][1][attribute] ${TAG_ATTRIBUTE_RW}
Should Be Equal As Strings ${res}[tags][1][type] ${TAG_TYPE_BIT}
Should Be Equal As Strings ${res}[tags][1][type] ${TAG_TYPE_INT32}
Should Be Equal As Strings ${res}[tags][0][name] tag2
Should Be Equal As Strings ${res}[tags][0][address] 1!00001
Should Be Equal As Strings ${res}[tags][0][attribute] ${TAG_ATTRIBUTE_RW}
Should Be Equal As Strings ${res}[tags][0][type] ${TAG_TYPE_BIT}
Delete tags, it should return success
Del Tags modbus-node group "tag1","tag2"
@@ -185,25 +136,3 @@ Add a tag with description, it should return success
Should Be Equal As Strings ${res}[tags][0][description] description info
Should Be Equal As Strings ${res}[tags][0][attribute] ${TAG_ATTRIBUTE_READ}
Should Be Equal As Strings ${res}[tags][0][type] ${TAG_TYPE_INT16}
[Teardown] Del Tags modbus-node group "tag_desc"
Add a tag with decimal, it should return success
${res}= Add Tags modbus-node group ${tag_decimal}
Check Response Status ${res} 200
Check Error Code ${res} ${NEU_ERR_SUCCESS}
Should Be Equal As Integers ${res}[index] 1
${res}= Get Tags modbus-node group
Check Response Status ${res} 200
${len} = Get Length ${res}[tags]
Should Be Equal As Integers ${len} 1
Should Be Equal As Strings ${res}[tags][0][name] tag_decimal
Should Be Equal As Strings ${res}[tags][0][address] 1!400003
Should Be Equal As Strings ${res}[tags][0][decimal] 0.1
Should Be Equal As Strings ${res}[tags][0][attribute] ${TAG_ATTRIBUTE_RW}
Should Be Equal As Strings ${res}[tags][0][type] ${TAG_TYPE_INT16}
-1350
View File
File diff suppressed because it is too large Load Diff
+483 -22
View File
@@ -26,43 +26,504 @@ extern "C" {
#include <stdint.h>
#include "define.h"
#include "metrics.h"
#include "msg.h"
#include <nng/nng.h>
#include "define.h"
#include "tag.h"
#include "type.h"
typedef struct {
neu_node_running_state_e running;
neu_node_link_state_e link;
} neu_node_state_t;
typedef enum neu_reqresp_type {
NEU_RESP_ERROR,
NEU_REQRESP_TRANS_DATA,
NEU_REQ_UPDATE_LICENSE,
NEU_REQ_READ_GROUP,
NEU_RESP_READ_GROUP,
NEU_REQ_WRITE_TAG,
NEU_REQ_SUBSCRIBE_GROUP,
NEU_REQ_UNSUBSCRIBE_GROUP,
NEU_REQ_GET_SUBSCRIBE_GROUP,
NEU_RESP_GET_SUBSCRIBE_GROUP,
NEU_REQ_APP_SUBSCRIBE_GROUP,
NEU_RESP_APP_SUBSCRIBE_GROUP,
NEU_REQ_APP_UNSUBSCRIBE_GROUP,
NEU_REQ_NODE_INIT,
NEU_REQ_NODE_UNINIT,
NEU_RESP_NODE_UNINIT,
NEU_REQ_ADD_NODE,
NEU_REQ_DEL_NODE,
NEU_REQ_GET_NODE,
NEU_RESP_GET_NODE,
NEU_REQ_NODE_SETTING,
NEU_REQ_GET_NODE_SETTING,
NEU_RESP_GET_NODE_SETTING,
NEU_REQ_GET_NODE_STATE,
NEU_RESP_GET_NODE_STATE,
NEU_REQ_NODE_CTL,
NEU_REQ_ADD_GROUP,
NEU_REQ_DEL_GROUP,
NEU_REQ_UPDATE_GROUP,
NEU_REQ_GET_GROUP,
NEU_RESP_GET_GROUP,
NEU_REQ_ADD_TAG,
NEU_RESP_ADD_TAG,
NEU_REQ_DEL_TAG,
NEU_REQ_UPDATE_TAG,
NEU_RESP_UPDATE_TAG,
NEU_REQ_GET_TAG,
NEU_RESP_GET_TAG,
NEU_REQ_ADD_PLUGIN,
NEU_REQ_DEL_PLUGIN,
NEU_REQ_GET_PLUGIN,
NEU_RESP_GET_PLUGIN,
} neu_reqresp_type_e;
static const char *neu_reqresp_type_string_t[] = {
[NEU_RESP_ERROR] = "NEU_RESP_ERROR",
[NEU_REQRESP_TRANS_DATA] = "NEU_REQRESP_TRANS_DATA",
[NEU_REQ_UPDATE_LICENSE] = "NEU_REQ_UPDATE_LICENSE",
[NEU_REQ_READ_GROUP] = "NEU_REQ_READ_GROUP",
[NEU_RESP_READ_GROUP] = "NEU_RESP_READ_GROUP",
[NEU_REQ_WRITE_TAG] = "NEU_REQ_WRITE_TAG",
[NEU_REQ_SUBSCRIBE_GROUP] = "NEU_REQ_SUBSCRIBE_GROUP",
[NEU_REQ_UNSUBSCRIBE_GROUP] = "NEU_REQ_UNSUBSCRIBE_GROUP",
[NEU_REQ_GET_SUBSCRIBE_GROUP] = "NEU_REQ_GET_SUBSCRIBE_GROUP",
[NEU_RESP_GET_SUBSCRIBE_GROUP] = "NEU_RESP_GET_SUBSCRIBE_GROUP",
[NEU_REQ_APP_SUBSCRIBE_GROUP] = "NEU_REQ_APP_SUBSCRIBE_GROUP",
[NEU_RESP_APP_SUBSCRIBE_GROUP] = "NEU_RESP_APP_SUBSCRIBE_GROUP",
[NEU_REQ_APP_UNSUBSCRIBE_GROUP] = "NEU_REQ_APP_UNSUBSCRIBE_GROUP",
[NEU_REQ_NODE_INIT] = "NEU_REQ_NODE_INIT",
[NEU_REQ_NODE_UNINIT] = "NEU_REQ_NODE_UNINIT",
[NEU_RESP_NODE_UNINIT] = "NEU_RESP_NODE_UNINIT",
[NEU_REQ_ADD_NODE] = "NEU_REQ_ADD_NODE",
[NEU_REQ_DEL_NODE] = "NEU_REQ_DEL_NODE",
[NEU_REQ_GET_NODE] = "NEU_REQ_GET_NODE",
[NEU_RESP_GET_NODE] = "NEU_RESP_GET_NODE",
[NEU_REQ_NODE_SETTING] = "NEU_REQ_NODE_SETTING",
[NEU_REQ_GET_NODE_SETTING] = "NEU_REQ_GET_NODE_SETTING",
[NEU_RESP_GET_NODE_SETTING] = "NEU_RESP_GET_NODE_SETTING",
[NEU_REQ_GET_NODE_STATE] = "NEU_REQ_GET_NODE_STATE",
[NEU_RESP_GET_NODE_STATE] = "NEU_RESP_GET_NODE_STATE",
[NEU_REQ_NODE_CTL] = "NEU_REQ_NODE_CTL",
[NEU_REQ_ADD_GROUP] = "NEU_REQ_ADD_GROUP",
[NEU_REQ_DEL_GROUP] = "NEU_REQ_DEL_GROUP",
[NEU_REQ_UPDATE_GROUP] = "NEU_REQ_UPDATE_GROUP",
[NEU_REQ_GET_GROUP] = "NEU_REQ_GET_GROUP",
[NEU_RESP_GET_GROUP] = "NEU_RESP_GET_GROUP",
[NEU_REQ_ADD_TAG] = "NEU_REQ_ADD_TAG",
[NEU_RESP_ADD_TAG] = "NEU_RESP_ADD_TAG",
[NEU_REQ_DEL_TAG] = "NEU_REQ_DEL_TAG",
[NEU_REQ_UPDATE_TAG] = "NEU_REQ_UPDATE_TAG",
[NEU_RESP_UPDATE_TAG] = "NEU_RESP_UPDATE_TAG",
[NEU_REQ_GET_TAG] = "NEU_REQ_GET_TAG",
[NEU_RESP_GET_TAG] = "NEU_RESP_GET_TAG",
[NEU_REQ_ADD_PLUGIN] = "NEU_REQ_ADD_PLUGIN",
[NEU_REQ_DEL_PLUGIN] = "NEU_REQ_DEL_PLUGIN",
[NEU_REQ_GET_PLUGIN] = "NEU_REQ_GET_PLUGIN",
[NEU_RESP_GET_PLUGIN] = "NEU_RESP_GET_PLUGIN",
};
inline static const char *neu_reqresp_type_string(neu_reqresp_type_e type)
{
return neu_reqresp_type_string_t[type];
}
typedef struct neu_reqresp_head {
neu_reqresp_type_e type;
void * ctx;
char sender[NEU_NODE_NAME_LEN];
char receiver[NEU_NODE_NAME_LEN];
} neu_reqresp_head_t;
typedef struct neu_resp_error {
int error;
} neu_resp_error_t;
typedef struct {
char node[NEU_NODE_NAME_LEN];
} neu_req_node_init_t, neu_req_node_uninit_t, neu_resp_node_uninit_t;
typedef struct neu_req_add_plugin {
char library[NEU_PLUGIN_LIBRARY_LEN];
} neu_req_add_plugin_t;
typedef struct neu_req_del_plugin {
char plugin[NEU_PLUGIN_NAME_LEN];
} neu_req_del_plugin_t;
typedef struct neu_req_get_plugin {
} neu_req_get_plugin_t;
typedef struct neu_resp_plugin_info {
char name[NEU_PLUGIN_NAME_LEN];
char description[NEU_PLUGIN_DESCRIPTION_LEN];
char library[NEU_PLUGIN_LIBRARY_LEN];
neu_plugin_kind_e kind;
neu_node_type_e type;
} neu_resp_plugin_info_t;
typedef struct neu_resp_get_plugin {
UT_array *plugins; // array neu_resp_plugin_info_t
} neu_resp_get_plugin_t;
typedef struct neu_req_add_node {
char node[NEU_NODE_NAME_LEN];
char plugin[NEU_PLUGIN_NAME_LEN];
} neu_req_add_node_t;
typedef struct neu_req_del_node {
char node[NEU_NODE_NAME_LEN];
} neu_req_del_node_t;
typedef struct neu_req_get_node {
neu_node_type_e type;
} neu_req_get_node_t;
typedef struct neu_resp_node_info {
char node[NEU_NODE_NAME_LEN];
char plugin[NEU_PLUGIN_NAME_LEN];
} neu_resp_node_info_t;
typedef struct neu_resp_get_node {
UT_array *nodes; // array neu_resp_node_info_t
} neu_resp_get_node_t;
typedef struct {
char driver[NEU_NODE_NAME_LEN];
char group[NEU_GROUP_NAME_LEN];
uint32_t interval;
} neu_req_add_group_t, neu_req_update_group;
typedef struct neu_req_del_group {
char driver[NEU_NODE_NAME_LEN];
char group[NEU_GROUP_NAME_LEN];
} neu_req_del_group_t;
typedef struct neu_req_get_group {
char driver[NEU_NODE_NAME_LEN];
} neu_req_get_group_t;
typedef struct neu_resp_group_info {
char name[NEU_GROUP_NAME_LEN];
uint16_t tag_count;
uint32_t interval;
} neu_resp_group_info_t;
typedef struct neu_resp_get_group {
UT_array *groups; // array neu_resp_group_info_t
} neu_resp_get_group_t;
typedef struct {
char driver[NEU_NODE_NAME_LEN];
char group[NEU_GROUP_NAME_LEN];
uint16_t n_tag;
neu_datatag_t *tags;
} neu_req_add_tag_t, neu_req_update_tag_t;
typedef struct {
uint16_t index;
int error;
} neu_resp_add_tag_t, neu_resp_update_tag_t;
typedef struct neu_req_del_tag {
char driver[NEU_NODE_NAME_LEN];
char group[NEU_GROUP_NAME_LEN];
uint16_t n_tag;
char ** tags;
} neu_req_del_tag_t;
typedef struct neu_req_get_tag {
char driver[NEU_NODE_NAME_LEN];
char group[NEU_GROUP_NAME_LEN];
} neu_req_get_tag_t;
typedef struct neu_resp_get_tag {
UT_array *tags; // array neu_datatag_t
} neu_resp_get_tag_t;
typedef struct {
char driver[NEU_NODE_NAME_LEN];
char group[NEU_GROUP_NAME_LEN];
UT_array *tags; // array neu_datatag_t
} neu_resp_app_subscribe_group_t;
typedef struct {
char driver[NEU_NODE_NAME_LEN];
char group[NEU_GROUP_NAME_LEN];
} neu_req_app_subscribe_group_t, neu_req_app_unsubscribe_group_t;
typedef struct {
char app[NEU_NODE_NAME_LEN];
char driver[NEU_NODE_NAME_LEN];
char group[NEU_GROUP_NAME_LEN];
} neu_req_subscribe_t, neu_req_unsubscribe_t;
typedef struct neu_req_get_subscribe_group {
char app[NEU_NODE_NAME_LEN];
} neu_req_get_subscribe_group_t;
typedef struct neu_resp_subscribe_info {
char app[NEU_NODE_NAME_LEN];
char driver[NEU_NODE_NAME_LEN];
char group[NEU_GROUP_NAME_LEN];
} neu_resp_subscribe_info_t;
typedef struct neu_resp_get_subscribe_group {
UT_array *groups; // array neu_resp_subscribe_info_t
} neu_resp_get_subscribe_group_t;
typedef struct neu_req_node_setting {
char node[NEU_NODE_NAME_LEN];
char *setting;
} neu_req_node_setting_t;
typedef struct neu_req_get_node_setting {
char ndoe[NEU_NODE_NAME_LEN];
} neu_req_get_node_setting_t;
typedef struct neu_resp_get_node_setting {
char *setting;
} neu_resp_get_node_setting_t;
typedef enum neu_adapter_ctl {
NEU_ADAPTER_CTL_START = 0,
NEU_ADAPTER_CTL_STOP,
} neu_adapter_ctl_e;
typedef struct neu_req_node_ctl {
char node[NEU_NODE_NAME_LEN];
neu_adapter_ctl_e ctl;
} neu_req_node_ctl_t;
typedef struct neu_req_get_node_state {
char node[NEU_NODE_NAME_LEN];
} neu_req_get_node_state_t;
typedef struct neu_resp_get_node_state {
neu_node_state_t state;
} neu_resp_get_node_state_t;
typedef struct neu_req_update_license {
} neu_req_update_license_t;
typedef struct neu_req_read_group {
char driver[NEU_NODE_NAME_LEN];
char group[NEU_GROUP_NAME_LEN];
} neu_req_read_group_t;
typedef struct neu_req_write_tag {
char driver[NEU_NODE_NAME_LEN];
char group[NEU_GROUP_NAME_LEN];
char tag[NEU_TAG_NAME_LEN];
neu_dvalue_t value;
} neu_req_write_tag_t;
typedef struct neu_resp_tag_value {
char tag[NEU_TAG_NAME_LEN];
neu_dvalue_t value;
} neu_resp_tag_value_t;
typedef struct {
char driver[NEU_NODE_NAME_LEN];
char group[NEU_GROUP_NAME_LEN];
uint16_t n_tag;
neu_resp_tag_value_t *tags;
} neu_resp_read_group_t;
typedef struct {
char driver[NEU_NODE_NAME_LEN];
char group[NEU_GROUP_NAME_LEN];
uint16_t n_tag;
neu_resp_tag_value_t tags[];
} neu_reqresp_trans_data_t;
inline static nng_msg *neu_msg_gen(neu_reqresp_head_t *header, void *data)
{
nng_msg *msg = NULL;
void * body = NULL;
size_t data_size = 0;
switch (header->type) {
case NEU_REQ_NODE_INIT:
case NEU_REQ_NODE_UNINIT:
case NEU_RESP_NODE_UNINIT:
data_size = sizeof(neu_req_node_init_t);
break;
case NEU_RESP_ERROR:
data_size = sizeof(neu_resp_error_t);
break;
case NEU_REQ_ADD_PLUGIN:
data_size = sizeof(neu_req_add_plugin_t);
break;
case NEU_REQ_DEL_PLUGIN:
data_size = sizeof(neu_req_del_plugin_t);
break;
case NEU_REQ_GET_PLUGIN:
data_size = sizeof(neu_req_get_plugin_t);
break;
case NEU_RESP_GET_PLUGIN:
data_size = sizeof(neu_resp_get_plugin_t);
break;
case NEU_REQ_ADD_NODE:
data_size = sizeof(neu_req_add_node_t);
break;
case NEU_REQ_DEL_NODE:
data_size = sizeof(neu_req_del_node_t);
break;
case NEU_REQ_GET_NODE:
data_size = sizeof(neu_req_get_node_t);
break;
case NEU_RESP_GET_NODE:
data_size = sizeof(neu_resp_get_node_t);
break;
case NEU_REQ_ADD_GROUP:
case NEU_REQ_UPDATE_GROUP:
data_size = sizeof(neu_req_add_group_t);
break;
case NEU_REQ_DEL_GROUP:
data_size = sizeof(neu_req_del_group_t);
break;
case NEU_REQ_GET_GROUP:
data_size = sizeof(neu_req_get_group_t);
break;
case NEU_RESP_GET_GROUP:
data_size = sizeof(neu_resp_get_group_t);
break;
case NEU_REQ_ADD_TAG:
data_size = sizeof(neu_req_add_tag_t);
break;
case NEU_RESP_ADD_TAG:
data_size = sizeof(neu_resp_add_tag_t);
break;
case NEU_RESP_UPDATE_TAG:
data_size = sizeof(neu_resp_update_tag_t);
break;
case NEU_REQ_UPDATE_TAG:
data_size = sizeof(neu_req_update_tag_t);
break;
case NEU_REQ_DEL_TAG:
data_size = sizeof(neu_req_del_tag_t);
break;
case NEU_REQ_GET_TAG:
data_size = sizeof(neu_req_get_tag_t);
break;
case NEU_RESP_GET_TAG:
data_size = sizeof(neu_resp_get_tag_t);
break;
case NEU_REQ_SUBSCRIBE_GROUP:
data_size = sizeof(neu_req_subscribe_t);
break;
case NEU_REQ_UNSUBSCRIBE_GROUP:
data_size = sizeof(neu_req_unsubscribe_t);
break;
case NEU_REQ_GET_SUBSCRIBE_GROUP:
data_size = sizeof(neu_req_get_subscribe_group_t);
break;
case NEU_RESP_GET_SUBSCRIBE_GROUP:
data_size = sizeof(neu_resp_get_subscribe_group_t);
break;
case NEU_REQ_NODE_SETTING:
data_size = sizeof(neu_req_node_setting_t);
break;
case NEU_REQ_GET_NODE_SETTING:
data_size = sizeof(neu_req_get_node_setting_t);
break;
case NEU_RESP_GET_NODE_SETTING:
data_size = sizeof(neu_resp_get_node_setting_t);
break;
case NEU_REQ_NODE_CTL:
data_size = sizeof(neu_req_node_ctl_t);
break;
case NEU_REQ_GET_NODE_STATE:
data_size = sizeof(neu_req_get_node_state_t);
break;
case NEU_RESP_GET_NODE_STATE:
data_size = sizeof(neu_resp_get_node_state_t);
break;
case NEU_REQ_READ_GROUP:
data_size = sizeof(neu_req_read_group_t);
break;
case NEU_REQ_WRITE_TAG:
data_size = sizeof(neu_req_write_tag_t);
break;
case NEU_RESP_READ_GROUP:
data_size = sizeof(neu_resp_read_group_t);
break;
case NEU_REQRESP_TRANS_DATA: {
neu_reqresp_trans_data_t *trans = (neu_reqresp_trans_data_t *) data;
data_size = sizeof(neu_reqresp_trans_data_t) +
trans->n_tag * sizeof(neu_resp_tag_value_t);
break;
}
case NEU_REQ_UPDATE_LICENSE:
data_size = sizeof(neu_req_update_license_t);
break;
case NEU_RESP_APP_SUBSCRIBE_GROUP:
data_size = sizeof(neu_resp_app_subscribe_group_t);
break;
case NEU_REQ_APP_SUBSCRIBE_GROUP:
case NEU_REQ_APP_UNSUBSCRIBE_GROUP:
data_size = sizeof(neu_req_app_unsubscribe_group_t);
break;
default:
assert(false);
break;
}
nng_msg_alloc(&msg, sizeof(neu_reqresp_head_t) + data_size);
body = nng_msg_body(msg);
memcpy(body, header, sizeof(neu_reqresp_head_t));
memcpy((uint8_t *) body + sizeof(neu_reqresp_head_t), data, data_size);
return msg;
}
inline static void neu_msg_exchange(neu_reqresp_head_t *header)
{
char tmp[NEU_NODE_NAME_LEN] = { 0 };
strcpy(tmp, header->sender);
memset(header->sender, 0, sizeof(header->sender));
strcpy(header->sender, header->receiver);
memset(header->receiver, 0, sizeof(header->receiver));
strcpy(header->receiver, tmp);
}
typedef struct neu_adapter neu_adapter_t;
typedef struct neu_adapter_driver neu_adapter_driver_t;
typedef struct neu_adapter_app neu_adapter_app_t;
typedef int (*neu_adapter_update_metric_cb_t)(neu_adapter_t *adapter,
const char * metric_name,
uint64_t n, const char *group);
typedef int (*neu_adapter_register_metric_cb_t)(neu_adapter_t * adapter,
const char * name,
const char * help,
neu_metric_type_e type,
uint64_t init);
typedef struct adapter_callbacks {
int (*command)(neu_adapter_t *adapter, neu_reqresp_head_t head, void *data);
int (*response)(neu_adapter_t *adapter, neu_reqresp_head_t *head,
void *data);
int (*responseto)(neu_adapter_t *adapter, neu_reqresp_head_t *head,
void *data, struct sockaddr_in dst);
neu_adapter_register_metric_cb_t register_metric;
neu_adapter_update_metric_cb_t update_metric;
union {
struct {
void (*update)(neu_adapter_t *adapter, const char *group,
const char *tag, neu_dvalue_t value);
void (*update_with_meta)(neu_adapter_t *adapter, const char *group,
const char *tag, neu_dvalue_t value,
neu_tag_meta_t *metas, int n_meta);
void (*write_response)(neu_adapter_t *adapter, void *req,
int error);
void (*update_im)(neu_adapter_t *adapter, const char *group,
const char *tag, neu_dvalue_t value,
neu_tag_meta_t *metas, int n_meta);
} driver;
};
} adapter_callbacks_t;
-133
View File
@@ -1,133 +0,0 @@
/**
* NEURON IIoT System for Industry 4.0
* Copyright (C) 2020-2022 EMQ Technologies Co., Ltd All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
**/
#ifndef NEURON_CONNECTION_MQTT_CLIENT_H
#define NEURON_CONNECTION_MQTT_CLIENT_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include "utils/zlog.h"
// number of messages cached
#define NEU_METRIC_CACHED_MSGS_NUM "cached_msgs"
#define NEU_METRIC_CACHED_MSGS_NUM_TYPE NEU_METRIC_TYPE_GAUAGE
#define NEU_METRIC_CACHED_MSGS_NUM_HELP "Number of messages cached"
#define NEU_MQTT_CACHE_SYNC_INTERVAL_MIN 10
#define NEU_MQTT_CACHE_SYNC_INTERVAL_MAX 12000
#define NEU_MQTT_CACHE_SYNC_INTERVAL_DEFAULT 100
typedef enum {
NEU_MQTT_VERSION_V31 = 3,
NEU_MQTT_VERSION_V311 = 4,
NEU_MQTT_VERSION_V5 = 5,
} neu_mqtt_version_e;
typedef enum {
NEU_MQTT_QOS0,
NEU_MQTT_QOS1,
NEU_MQTT_QOS2,
} neu_mqtt_qos_e;
typedef struct neu_mqtt_client_s neu_mqtt_client_t;
typedef void (*neu_mqtt_client_connection_cb_t)(void *data);
typedef void (*neu_mqtt_client_publish_cb_t)(int errcode, neu_mqtt_qos_e qos,
char *topic, uint8_t *payload,
uint32_t len, void *data);
typedef void (*neu_mqtt_client_subscribe_cb_t)(neu_mqtt_qos_e qos,
const char * topic,
const uint8_t *payload,
uint32_t len, void *data);
neu_mqtt_client_t *neu_mqtt_client_new(neu_mqtt_version_e version);
neu_mqtt_client_t *neu_mqtt_client_from_addr(const char *host, uint16_t port,
neu_mqtt_version_e version);
void neu_mqtt_client_free(neu_mqtt_client_t *client);
bool neu_mqtt_client_is_open(neu_mqtt_client_t *client);
bool neu_mqtt_client_is_connected(neu_mqtt_client_t *client);
size_t neu_mqtt_client_get_cached_msgs_num(neu_mqtt_client_t *client);
int neu_mqtt_client_set_addr(neu_mqtt_client_t *client, const char *host,
uint16_t port);
int neu_mqtt_client_set_id(neu_mqtt_client_t *client, const char *id);
int neu_mqtt_client_set_will_msg(neu_mqtt_client_t *client, const char *topic,
uint8_t *msg, uint32_t len, bool retain,
uint8_t qos);
int neu_mqtt_client_set_user(neu_mqtt_client_t *client, const char *username,
const char *password);
int neu_mqtt_client_set_connect_cb(neu_mqtt_client_t * client,
neu_mqtt_client_connection_cb_t cb,
void * data);
int neu_mqtt_client_set_disconnect_cb(neu_mqtt_client_t * client,
neu_mqtt_client_connection_cb_t cb,
void * data);
int neu_mqtt_client_set_tls(neu_mqtt_client_t *client, bool enabled,
const char *ca, const char *cert, const char *key,
const char *keypass);
int neu_mqtt_client_set_cache_size(neu_mqtt_client_t *client,
size_t mem_size_bytes, size_t db_size_bytes);
// default to NEU_MQTT_CACHE_SYNC_INTERVAL_DEFAULT if not set
int neu_mqtt_client_set_cache_sync_interval(neu_mqtt_client_t *client,
uint32_t interval);
int neu_mqtt_client_set_zlog_category(neu_mqtt_client_t *client,
zlog_category_t * cat);
int neu_mqtt_client_open(neu_mqtt_client_t *client);
int neu_mqtt_client_close(neu_mqtt_client_t *client);
/** Publish a `qos` message with `len` bytes `payload` on `topic`.
*
* This function initiates sending a `PUBLISH` packet, and if successful
* returns zero and the callback `cb` will be called once on completion of
* message delivery, otherwise returns a nonzero value. Callback invocation
* will be of the form `cb(errcode, qos, topic, payload, len, data)`, where
* `errcode` is zero if delivery was successful and nonzero otherwise, and
* the other arguments are exactly the same what you pass into this function.
* You may set `cb` to NULL if you do not care about the result.
*/
int neu_mqtt_client_publish(neu_mqtt_client_t *client, neu_mqtt_qos_e qos,
char *topic, uint8_t *payload, uint32_t len,
void *data, neu_mqtt_client_publish_cb_t cb);
/** Subscribe to `topic` with service quality `qos`.
*
* This function tries to send a `SUBSCRIBE` packet with the given `qos` and
* `topic`. If this was successful returns zero and the callback `cb` will be
* called on each received message with the matching topic, otherwise a nonzero
* value is returned.
*/
int neu_mqtt_client_subscribe(neu_mqtt_client_t *client, neu_mqtt_qos_e qos,
const char *topic, void *data,
neu_mqtt_client_subscribe_cb_t cb);
int neu_mqtt_client_unsubscribe(neu_mqtt_client_t *client, const char *topic);
#ifdef __cplusplus
}
#endif
#endif
@@ -0,0 +1,101 @@
/**
* NEURON IIoT System for Industry 4.0
* Copyright (C) 2020-2022 EMQ Technologies Co., Ltd All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
**/
#ifndef NEURON_NEU_MQTT_INTERFACE
#define NEURON_NEU_MQTT_INTERFACE
#ifdef __cplusplus
extern "C" {
#endif
#include "neuron.h"
#include <stddef.h>
#include <stdint.h>
typedef void (*state_update)(void *context, int state);
typedef struct {
/* debug app options */
int verbose;
/* MQTT options */
int MQTT_version; // 3-3_1, 4-3_3_1, 5-5
char *clientid;
int qos;
int retained;
char *username;
char *password;
char *host;
char *port;
char *connection; // tcp://, ssl://, ws://, wss://
int keepalive;
int keepalive_interval;
int clean_session;
/* will options */
char *will_topic;
char *will_payload;
int will_qos;
int will_retain;
/* TLS options */
char *ca;
char *cert;
char *key;
char *keypass;
/*application*/
int format;
char * upload_topic;
char * heartbeat_topic;
char * group_id;
state_update state_update_func;
zlog_category_t *log;
} neu_mqtt_option_t;
typedef void *neu_mqtt_client_t;
typedef void (*neu_subscribe_handle)(const char *topic_name, size_t topic_len,
void *payload, const size_t len,
void *context);
neu_err_code_e neu_mqtt_client_open(neu_mqtt_client_t * p_client,
const neu_mqtt_option_t *option,
void * context);
neu_err_code_e neu_mqtt_client_is_connected(neu_mqtt_client_t client);
neu_err_code_e neu_mqtt_client_subscribe(neu_mqtt_client_t client,
const char *topic, const int qos,
neu_subscribe_handle handle);
neu_err_code_e neu_mqtt_client_unsubscribe(neu_mqtt_client_t client,
const char * topic);
neu_err_code_e neu_mqtt_client_publish(neu_mqtt_client_t client,
const char *topic, int qos,
unsigned char *payload, size_t len);
neu_err_code_e neu_mqtt_client_suspend(neu_mqtt_client_t client);
neu_err_code_e neu_mqtt_client_continue(neu_mqtt_client_t client);
neu_err_code_e neu_mqtt_client_close(neu_mqtt_client_t client);
#ifdef __cplusplus
}
#endif
#endif
+31 -169
View File
@@ -30,7 +30,6 @@ typedef enum neu_conn_type {
NEU_CONN_TCP_CLIENT,
NEU_CONN_UDP,
NEU_CONN_TTY_CLIENT,
NEU_CONN_UDP_TO,
} neu_conn_type_e;
typedef enum neu_conn_tty_baud {
@@ -41,12 +40,6 @@ typedef enum neu_conn_tty_baud {
NEU_CONN_TTY_BAUD_9600,
NEU_CONN_TTY_BAUD_4800,
NEU_CONN_TTY_BAUD_2400,
NEU_CONN_TTY_BAUD_1800,
NEU_CONN_TTY_BAUD_1200,
NEU_CONN_TTY_BAUD_600,
NEU_CONN_TTY_BAUD_300,
NEU_CONN_TTY_BAUD_200,
NEU_CONN_TTY_BAUD_150,
} neu_conn_tty_baud_e;
typedef enum neu_conn_tty_parity {
@@ -74,7 +67,7 @@ typedef enum neu_conn_tty_flow {
NEU_CONN_TTYP_FLOW_ENABLE,
} neu_conn_tty_flow_e;
typedef void (*neu_conn_callback)(void *ctx, int fd);
typedef void (*neu_conn_callback)(void *data, int fd);
typedef struct neu_conn_param {
zlog_category_t *log;
@@ -104,12 +97,6 @@ typedef struct neu_conn_param {
uint16_t timeout; // millisecond
} udp;
struct {
char * src_ip;
uint16_t src_port;
uint16_t timeout; // millisecond
} udpto;
struct {
char * device;
neu_conn_tty_data_e data;
@@ -124,181 +111,56 @@ typedef struct neu_conn_param {
typedef struct neu_conn neu_conn_t;
typedef struct neu_conn_state {
uint64_t send_bytes;
uint64_t recv_bytes;
} neu_conn_state_t;
/**
* @brief create a new connection.
*
* @param[in] param required to create a connection.
* @param[in] ctx Mainly used in the neu_conn_callback callback function.
* @param[in] connected The neu_conn_callback callback function will be
* triggered when the connection is successful.
* @param[in] disconnected The callback function of neu_conn_callback will be
* triggered when the connection fails.
* @return Connection on success, NULL on failure.
*/
neu_conn_t *neu_conn_new(neu_conn_param_t *param, void *ctx,
neu_conn_t *neu_conn_new(neu_conn_param_t *param, void *data,
neu_conn_callback connected,
neu_conn_callback disconnected);
/**
* @brief Reconfigure the connection.
*
* @param[in] conn Connection that need to be configured.
* @param[in] param New configuration parameters for the connection.
* @return Connection on success, NULL on failure.
*/
neu_conn_t *neu_conn_reconfig(neu_conn_t *conn, neu_conn_param_t *param);
void neu_conn_destory(neu_conn_t *conn);
void neu_conn_disconnect(neu_conn_t *conn);
int neu_conn_tcp_server_accept(neu_conn_t *conn);
int neu_conn_tcp_server_close_client(neu_conn_t *conn, int fd);
/**
* @brief Destroy connection
*
* @param conn
*/
void neu_conn_destory(neu_conn_t *conn);
/**
* @brief Connect
*
*
* @param[in] conn
*/
void neu_conn_connect(neu_conn_t *conn);
/**
* @brief Get connection fd
*
*
* @param[in] conn
* @return Successfully returns a number greater than 0, -1 or 0 on
* failure.
*/
int neu_conn_fd(neu_conn_t *conn);
/**
* @brief Disconnect
*
*
* @param[in] conn
*/
void neu_conn_disconnect(neu_conn_t *conn);
/**
* @brief Stop the connection
*
*
* @param[in] conn
*/
void neu_conn_stop(neu_conn_t *conn);
/**
* @brief Start the connection
*
*
* @param[in] conn
*/
void neu_conn_start(neu_conn_t *conn);
/**
* @brief get state of connection
*
*
* @param[in] conn
* @return returns state.
*/
neu_conn_state_t neu_conn_state(neu_conn_t *conn);
/**
* @brief Receive connection requests from clients.
*
* @param[in] conn
* @return Successfully returns a number greater than 0, i.e. client fd, -1 on
* failure.
*/
int neu_conn_tcp_server_accept(neu_conn_t *conn);
/**
* @brief Close a client connection.
*
* @param[in] conn
* @param[in] fd Get the fd from neu_conn_tcp_server_accept function.
* @return 0 on success, -1 on failure.
*/
int neu_conn_tcp_server_close_client(neu_conn_t *conn, int fd);
/**
* @brief Send data over the connection.
*
* @param[in] conn
* @param[in] buf Store the data to be sent.
* @param[in] len Length of data to be sent.
* @return When greater than 0, returns the number of bytes successfully sent,
* less than or equal to 0 fails.
*/
void neu_conn_flush(neu_conn_t *conn);
ssize_t neu_conn_send(neu_conn_t *conn, uint8_t *buf, ssize_t len);
ssize_t neu_conn_udp_sendto(neu_conn_t *conn, uint8_t *buf, ssize_t len,
void *dst);
/**
* @brief Receive data via connection read.
*
* @param[in] conn
* @param[in] buf The received data is stored in buf.
* @param[in] len Length of buf.
* @return When greater than 0, it will return the number of bytes successfully
* received, less than or equal to 0 fails.
*/
ssize_t neu_conn_recv(neu_conn_t *conn, uint8_t *buf, ssize_t len);
ssize_t neu_conn_udp_recvfrom(neu_conn_t *conn, uint8_t *buf, ssize_t len,
void *src);
/**
* @brief Specify the client to send data.
*
* @param[in] conn
* @param[in] fd Client's file descriptor.
* @param[in] buf Store the data to be sent.
* @param[in] len Length of data to be sent.
* @return When greater than 0, returns the number of bytes successfully sent,
* less than or equal to 0 fails.
*/
void neu_conn_tcp_server_flush(neu_conn_t *conn, int fd);
ssize_t neu_conn_tcp_server_send(neu_conn_t *conn, int fd, uint8_t *buf,
ssize_t len);
/**
* @brief Receive data via tcp server connection read.
*
* @param[in] conn
* @param[in] fd Client's file descriptor.
* @param[in] buf The received data is stored in buf.
* @param[in] len Length of buf.
* @return When greater than 0, returns the number of bytes successfully
* received, less than or equal to 0 fails.
*/
ssize_t neu_conn_tcp_server_recv(neu_conn_t *conn, int fd, uint8_t *buf,
ssize_t len);
#define NEU_STREAM_CONSUME(buf, size) \
neu_protocol_unpack_buf_t protocol_buf = { 0 }; \
neu_protocol_unpack_buf_init(&protocol_buf, (buf), (size)); \
while (neu_protocol_unpack_buf_unused_size(&protocol_buf) > 0)
#define NEU_STREAM_CONSUME_USED_SIZE(used) \
offset -= used; \
memmove(recv_buf, recv_buf + used, offset);
#define NEU_TCP_CLIENT_CONSUME(conn) \
static __thread uint8_t recv_buf[2048] = { 0 }; \
static __thread uint16_t offset = 0; \
ssize_t ret = \
neu_conn_recv((conn), recv_buf + offset, sizeof(recv_buf) - offset); \
if (ret > 0) \
offset += ret; \
if (ret > 0) \
NEU_STREAM_CONSUME(recv_buf, offset)
typedef int (*neu_conn_stream_consume_fn)(
void *context, neu_protocol_unpack_buf_t *protocol_buf);
int neu_conn_stream_consume(neu_conn_t *conn, void *context,
neu_conn_stream_consume_fn fn);
int neu_conn_stream_tcp_server_consume(neu_conn_t *conn, int fd, void *context,
neu_conn_stream_consume_fn fn);
void neu_conn_stream_consume(neu_conn_t *conn, void *context,
neu_conn_stream_consume_fn fn);
void neu_conn_stream_tcp_server_consume(neu_conn_t *conn, int fd, void *context,
neu_conn_stream_consume_fn fn);
typedef neu_buf_result_t (*neu_conn_process_msg)(
void *context, neu_protocol_unpack_buf_t *protocol_buf);
int neu_conn_wait_msg(neu_conn_t *conn, void *context, uint16_t n_byte,
neu_conn_process_msg fn);
int neu_conn_tcp_server_wait_msg(neu_conn_t *conn, int fd, void *context,
uint16_t n_byte, neu_conn_process_msg fn);
int is_ipv4(const char *ip);
int is_ipv6(const char *ip);
#endif
@@ -1,50 +0,0 @@
/**
* NEURON IIoT System for Industry 4.0
* Copyright (C) 2020-2023 EMQ Technologies Co., Ltd All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
**/
#ifndef NEURON_CONNECTION_ETH_H
#define NEURON_CONNECTION_ETH_H
#include <stdint.h>
#include "define.h"
// profinet
typedef struct neu_conn_eth neu_conn_eth_t;
neu_conn_eth_t *neu_conn_eth_init(const char *interface, void *ctx);
int neu_conn_eth_uninit(neu_conn_eth_t *conn);
int neu_conn_eth_check_interface(const char *interface);
void neu_conn_eth_get_mac(neu_conn_eth_t *conn, uint8_t *mac);
int neu_conn_eth_size();
typedef void (*neu_conn_eth_msg_callback)(neu_conn_eth_t *conn, void *ctx,
uint16_t protocol, uint16_t n_byte,
uint8_t *bytes, uint8_t src_mac[6]);
typedef struct neu_conn_eth_sub neu_conn_eth_sub_t;
neu_conn_eth_sub_t *neu_conn_eth_register(neu_conn_eth_t *conn, uint8_t mac[6],
neu_conn_eth_msg_callback callback);
int neu_conn_eth_unregister(neu_conn_eth_t *conn, neu_conn_eth_sub_t *sub);
int neu_conn_eth_send(neu_conn_eth_t *conn, uint16_t protocol, uint16_t n_byte,
uint8_t *bytes);
#endif
@@ -1,25 +0,0 @@
/**
* NEURON IIoT System for Industry 4.0
* Copyright (C) 2020-2023 EMQ Technologies Co., Ltd All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
**/
#ifndef NEURON_CONNECTION_SMART_LINK_H
#define NEURON_CONNECTION_SMART_LINK_H
int neu_conn_smart_link_auto_set(const char *dev_path);
#endif
+12 -54
View File
@@ -20,51 +20,16 @@
#ifndef _NEU_DEFINE_H_
#define _NEU_DEFINE_H_
#include <stdbool.h>
#define NEU_VERSION_MAJOR 2
#define NEU_VERSION_MINOR 7
#define NEU_VERSION_FIX 3
#define NEU_GET_VERSION_MAJOR(V) ((0xffff0000 & V) >> 16)
#define NEU_GET_VERSION_MINOR(V) ((0x0000ff00 & V) >> 8)
#define NEU_GET_VERSION_FIX(V) ((0x000000ff & V))
#define NEU_VERSION(MAJOR, MINOR, FIX) ((MAJOR << 16) | (MINOR << 8) | FIX)
#define NEU_TAG_NAME_LEN 128
#define NEU_TAG_ADDRESS_LEN 128
#define NEU_TAG_NAME_LEN 32
#define NEU_TAG_ADDRESS_LEN 64
#define NEU_TAG_DESCRIPTION_LEN 128
#define NEU_GROUP_MAX_PER_NODE 512
#define NEU_GROUP_NAME_LEN 128
#define NEU_GROUP_NAME_LEN 32
#define NEU_GROUP_INTERVAL_LIMIT 100
#define NEU_DEFAULT_GROUP_INTERVAL 100
#define NEU_NODE_NAME_LEN 128
#define NEU_NODE_NAME_LEN 32
#define NEU_PLUGIN_NAME_LEN 32
#define NEU_PLUGIN_LIBRARY_LEN 64
#define NEU_PLUGIN_DESCRIPTION_LEN 512
#define NEU_TEMPLATE_NAME_LEN 128
#define NEU_DRIVER_TAG_CACHE_EXPIRE_TIME 60
#define NEU_APP_SUBSCRIBE_MSG_SIZE 4
#define NEU_TAG_FLOAG_PRECISION_MAX 17
#define NEU_USER_PASSWORD_MIN_LEN 4
#define NEU_USER_PASSWORD_MAX_LEN 16
#define NEU_LOG_LEVEL_LEN 9
#define NEU_FILE_PATH_LEN 128
#define NEU_MSG_MAX_SIZE 2048
#define NEU_TAG_META_LENGTH 20
#define NEU_TAG_META_SIZE 3
#define NEU_LOG_LEVEL_DEBUG "debug"
#define NEU_LOG_LEVEL_INFO "info"
#define NEU_LOG_LEVEL_NOTICE "notice"
#define NEU_LOG_LEVEL_WARN "warn"
#define NEU_LOG_LEVEL_ERROR "error"
#define NEU_LOG_LEVEL_FATAL "fatal"
extern int default_log_level;
extern bool disable_jwt;
extern char host_port[32];
#define NEU_PLUGIN_LIBRARY_LEN 32
#define NEU_PLUGIN_DESCRIPTION_LEN 256
#define NEU_DRIVER_TAG_CACHE_EXPIRE_TIME 30
typedef enum neu_plugin_kind {
NEU_PLUGIN_KIND_STATIC = 0,
@@ -73,30 +38,23 @@ typedef enum neu_plugin_kind {
} neu_plugin_kind_e;
typedef enum {
NEU_NA_TYPE_DRIVER = 1,
NEU_NA_TYPE_APP = 2,
NEU_NA_TYPE_NDRIVER = 4,
NEU_NA_TYPE_DRIVER = 1,
NEU_NA_TYPE_APP = 2,
} neu_adapter_type_e,
neu_node_type_e;
typedef enum {
NEU_NODE_LINK_STATE_DISCONNECTED = 0,
NEU_NODE_LINK_STATE_CONNECTED = 1,
NEU_NODE_LINK_STATE_CONNECTING = 1,
NEU_NODE_LINK_STATE_CONNECTED = 2,
} neu_node_link_state_e;
typedef enum {
NEU_NODE_RUNNING_STATE_IDLE = 0,
NEU_NODE_RUNNING_STATE_INIT = 1,
NEU_NODE_RUNNING_STATE_READY = 2,
NEU_NODE_RUNNING_STATE_RUNNING = 3,
NEU_NODE_RUNNING_STATE_STOPPED = 4,
} neu_node_running_state_e;
typedef enum {
NEU_TAG_CACHE_TYPE_INTERVAL = 0,
NEU_TAG_CACHE_TYPE_NEVER,
} neu_tag_cache_type_e;
// forward declaration for neu_adapter_t
typedef struct neu_adapter neu_adapter_t;
#endif
+21 -64
View File
@@ -42,26 +42,16 @@ typedef enum {
NEU_ERR_INVALID_USER_OR_PASSWORD = 1009,
NEU_ERR_IS_BUSY = 1010,
NEU_ERR_FILE_NOT_EXIST = 1011,
NEU_ERR_INVALID_PASSWORD_LEN = 1012,
NEU_ERR_DUPLICATE_PASSWORD = 1013,
NEU_ERR_COMMAND_EXECUTION_FAILED = 1014,
NEU_ERR_IP_ADDRESS_INVALID = 1015,
NEU_ERR_IP_ADDRESS_IN_USE = 1016,
NEU_ERR_NODE_EXIST = 2002,
NEU_ERR_NODE_NOT_EXIST = 2003,
NEU_ERR_NODE_SETTING_INVALID = 2004,
NEU_ERR_NODE_SETTING_NOT_FOUND = 2005,
NEU_ERR_NODE_NOT_READY = 2006,
NEU_ERR_NODE_IS_RUNNING = 2007,
NEU_ERR_NODE_NOT_RUNNING = 2008,
NEU_ERR_NODE_IS_STOPED = 2009,
NEU_ERR_NODE_NAME_TOO_LONG = 2010,
NEU_ERR_NODE_NOT_ALLOW_DELETE = 2011,
NEU_ERR_NODE_NOT_ALLOW_SUBSCRIBE = 2012,
NEU_ERR_NODE_NOT_ALLOW_UPDATE = 2013,
NEU_ERR_NODE_NOT_ALLOW_MAP = 2014,
NEU_ERR_NODE_NAME_EMPTY = 2015,
NEU_ERR_NODE_EXIST = 2002,
NEU_ERR_NODE_NOT_EXIST = 2003,
NEU_ERR_NODE_SETTING_INVALID = 2004,
NEU_ERR_NODE_SETTING_NOT_FOUND = 2005,
NEU_ERR_NODE_NOT_READY = 2006,
NEU_ERR_NODE_IS_RUNNING = 2007,
NEU_ERR_NODE_NOT_RUNNING = 2008,
NEU_ERR_NODE_IS_STOPED = 2009,
NEU_ERR_NODE_NAME_TOO_LONG = 2010,
NEU_ERR_GROUP_ALREADY_SUBSCRIBED = 2101,
NEU_ERR_GROUP_NOT_SUBSCRIBE = 2102,
@@ -70,7 +60,6 @@ typedef enum {
NEU_ERR_GROUP_PARAMETER_INVALID = 2105,
NEU_ERR_GROUP_NOT_EXIST = 2106,
NEU_ERR_GROUP_NAME_TOO_LONG = 2107,
NEU_ERR_GROUP_MAX_GROUPS = 2108,
NEU_ERR_TAG_NOT_EXIST = 2201,
NEU_ERR_TAG_NAME_CONFLICT = 2202,
@@ -80,41 +69,20 @@ typedef enum {
NEU_ERR_TAG_NAME_TOO_LONG = 2206,
NEU_ERR_TAG_ADDRESS_TOO_LONG = 2207,
NEU_ERR_TAG_DESCRIPTION_TOO_LONG = 2208,
NEU_ERR_TAG_PRECISION_INVALID = 2209,
NEU_ERR_TAG_EXIST = 2210,
NEU_ERR_LIBRARY_NOT_FOUND = 2301,
NEU_ERR_LIBRARY_INFO_INVALID = 2302,
NEU_ERR_LIBRARY_NAME_CONFLICT = 2303,
NEU_ERR_LIBRARY_FAILED_TO_OPEN = 2304,
NEU_ERR_LIBRARY_MODULE_INVALID = 2305,
NEU_ERR_LIBRARY_SYSTEM_NOT_ALLOW_DEL = 2306,
NEU_ERR_LIBRARY_NOT_ALLOW_CREATE_INSTANCE = 2307,
NEU_ERR_LIBRARY_ARCH_NOT_SUPPORT = 2308,
NEU_ERR_LIBRARY_IN_USE = 2309,
NEU_ERR_LIBRARY_ADD_FAIL = 2310,
NEU_ERR_LIBRARY_MODULE_ALREADY_EXIST = 2311,
NEU_ERR_LIBRARY_MODULE_NOT_EXISTS = 2312,
NEU_ERR_LIBRARY_MODULE_KIND_NOT_SUPPORT = 2313,
NEU_ERR_LIBRARY_MODULE_VERSION_NOT_MATCH = 2314,
NEU_ERR_LIBRARY_NAME_NOT_CONFORM = 2315,
NEU_ERR_LIBRARY_CLIB_NOT_MATCH = 2316,
NEU_ERR_LIBRARY_UPDATE_FAIL = 2317,
NEU_ERR_LIBRARY_NOT_FOUND = 2301,
NEU_ERR_LIBRARY_INFO_INVALID = 2302,
NEU_ERR_LIBRARY_NAME_CONFLICT = 2303,
NEU_ERR_LIBRARY_FAILED_TO_OPEN = 2304,
NEU_ERR_LIBRARY_MODULE_INVALID = 2305,
NEU_ERR_LIBRARY_SYSTEM_NOT_ALLOW_DEL = 2306,
NEU_ERR_LICENSE_NOT_FOUND = 2400,
NEU_ERR_LICENSE_INVALID = 2401,
NEU_ERR_LICENSE_EXPIRED = 2402,
NEU_ERR_LICENSE_DISABLED = 2403,
NEU_ERR_LICENSE_MAX_NODES = 2404,
NEU_ERR_LICENSE_MAX_TAGS = 2405,
NEU_ERR_LICENSE_TOKEN_NOT_MATCH = 2406,
NEU_ERR_LICENSE_BAD_CLOCK = 2407,
NEU_ERR_LICENSE_MODULE_INVALID = 2408,
NEU_ERR_LICENSE_TOKEN_NOT_FOUND = 2409,
NEU_ERR_TEMPLATE_EXIST = 2500,
NEU_ERR_TEMPLATE_NOT_FOUND = 2501,
NEU_ERR_TEMPLATE_NAME_TOO_LONG = 2502,
NEU_ERR_LICENSE_NOT_FOUND = 2400,
NEU_ERR_LICENSE_INVALID = 2401,
NEU_ERR_LICENSE_EXPIRED = 2402,
NEU_ERR_LICENSE_DISABLED = 2403,
NEU_ERR_LICENSE_MAX_NODES = 2404,
NEU_ERR_LICENSE_MAX_TAGS = 2405,
// common error codes for plugins
NEU_ERR_PLUGIN_READ_FAILURE = 3000,
@@ -128,12 +96,6 @@ typedef enum {
NEU_ERR_PLUGIN_NOT_RUNNING = 3010,
NEU_ERR_PLUGIN_TAG_NOT_READY = 3011,
NEU_ERR_PLUGIN_PACKET_OUT_OF_ORDER = 3012,
NEU_ERR_PLUGIN_NAME_TOO_LONG = 3013,
NEU_ERR_PLUGIN_NOT_FOUND = 3014,
NEU_ERR_PLUGIN_DEVICE_NOT_RESPONSE = 3015,
NEU_ERR_PLUGIN_NOT_SUPPORT_TEMPLATE = 3016,
NEU_ERR_PLUGIN_NOT_SUPPORT_WRITE_TAGS = 3017,
NEU_ERR_PLUGIN_NOT_SUPPORT_READ_SYNC = 3018,
NEU_ERR_MQTT_FAILURE = 4000,
NEU_ERR_MQTT_NO_CERTFILESET = 4001,
@@ -153,11 +115,6 @@ typedef enum {
NEU_ERR_MQTT_SUSPENDED = 4015,
NEU_ERR_MQTT_PUBLISH_OVER_LENGTH = 4016,
NEU_ERR_STRING_TOO_LONG = 4100,
NEU_ERR_FILE_OPEN_FAILURE = 4101,
NEU_ERR_FILE_READ_FAILURE = 4102,
NEU_ERR_FILE_WRITE_FAILURE = 4103,
NEU_ERR_PLUGIN_ERROR_START = 10000,
NEU_ERR_PLUGIN_ERROR_END = 20000,
} neu_err_code_e;
+7 -65
View File
@@ -28,59 +28,21 @@ extern "C" {
typedef struct neu_events neu_events_t;
/**
* @brief Creat a new event.
* When an event is created, a corresponding thread is created, and both
* io_event and timer_event in this event are scheduled for processing in this
* thread.
* @return the newly created event.
*/
neu_events_t *neu_event_new(void);
/**
* @brief Close a event.
*
* @param[in] events
* @return 0 on successful shutdown.
*/
int neu_event_close(neu_events_t *events);
int neu_event_close(neu_events_t *events);
typedef struct neu_event_timer neu_event_timer_t;
typedef int (*neu_event_timer_callback)(void *usr_data);
typedef enum neu_event_timer_type {
NEU_EVENT_TIMER_BLOCK = 0,
NEU_EVENT_TIMER_NOBLOCK = 1,
} neu_event_timer_type_e;
typedef struct neu_event_timer_param {
// timer trigger period
int64_t second;
int64_t millisecond;
// Parameters passed to callback when timer fires
void *usr_data;
// Callback function that fires every time the timer fires
int64_t second;
int64_t millisecond;
void * usr_data;
neu_event_timer_callback cb;
neu_event_timer_type_e type;
} neu_event_timer_param_t;
/**
* @brief Add a timer to the event.
*
* @param[in] events
* @param[in] timer Parameters when creating timer.
* @return The added event timer.
*/
neu_event_timer_t *neu_event_add_timer(neu_events_t * events,
neu_event_timer_param_t timer);
/**
* @brief Remove timer from event.
*
* @param[in] events
* @param[in] timer
* @return 0 on success.
*/
int neu_event_del_timer(neu_events_t *events, neu_event_timer_t *timer);
enum neu_event_io_type {
@@ -93,33 +55,13 @@ typedef int (*neu_event_io_callback)(enum neu_event_io_type type, int fd,
void *usr_data);
typedef struct neu_event_io_param {
// fd that fires io_event.
int fd;
// Arguments passed to the neu_event_io_callback callback function when the
// io_event is fired.
void *usr_data;
// The neu_event_io_callback callback function is triggered when io_event is
// triggered.
int fd;
void * usr_data;
neu_event_io_callback cb;
} neu_event_io_param_t;
/**
* @brief Add io_event to the event.
*
* @param[in] events
* @param[in] io
* @return The added event io.
*/
neu_event_io_t *neu_event_add_io(neu_events_t *events, neu_event_io_param_t io);
/**
* @brief Delete io_event from event.
*
* @param[in] events
* @param[in] io
* @return 0 on success.
*/
int neu_event_del_io(neu_events_t *events, neu_event_io_t *io);
int neu_event_del_io(neu_events_t *events, neu_event_io_t *io);
#ifdef __cplusplus
}
+8 -23
View File
@@ -37,24 +37,17 @@ typedef enum neu_json_type {
NEU_JSON_FLOAT,
NEU_JSON_BOOL,
NEU_JSON_OBJECT,
NEU_JSON_BYTES,
NEU_JSON_VALUE = NEU_JSON_UNDEFINE
} neu_json_type_e;
typedef struct {
uint8_t *bytes;
uint8_t length;
} neu_json_value_bytes_t;
typedef union neu_json_value {
int64_t val_int;
uint8_t val_bit;
float val_float;
double val_double;
bool val_bool;
char * val_str;
void * val_object;
neu_json_value_bytes_t val_bytes;
int64_t val_int;
uint8_t val_bit;
float val_float;
double val_double;
bool val_bool;
char * val_str;
void * val_object;
} neu_json_value_u;
typedef enum neu_json_attribute {
@@ -67,7 +60,6 @@ typedef struct neu_json_elem {
char * name;
enum neu_json_type t;
union neu_json_value v;
uint8_t precision;
} neu_json_elem_t;
#define NEU_JSON_ELEM_SIZE(elems) sizeof(elems) / sizeof(neu_json_elem_t)
@@ -78,14 +70,12 @@ void *neu_json_array();
int neu_json_decode_by_json(void *json, int size, neu_json_elem_t *ele);
int neu_json_decode(char *buf, int size, neu_json_elem_t *ele);
int neu_json_decode_array_size_by_json(void *json, char *child);
int neu_json_decode_array_elem(void *json, int index, int size,
neu_json_elem_t *ele);
int neu_json_decode_array_by_json(void *json, char *name, int index, int size,
neu_json_elem_t *ele);
int neu_json_decode_array_size(char *buf, char *child);
int neu_json_decode_array(char *buf, char *name, int index, int size,
neu_json_elem_t *ele);
void *neu_json_decode_new(const char *buf);
void *neu_json_decode_new(char *buf);
void *neu_json_decode_newb(char *buf, size_t len);
void neu_json_decode_free(void *ob);
int neu_json_decode_value(void *object, neu_json_elem_t *ele);
@@ -97,11 +87,6 @@ void *neu_json_encode_array_value(void *array, neu_json_elem_t *t, int n);
int neu_json_encode_field(void *json_object, neu_json_elem_t *elem, int n);
int neu_json_encode(void *json_object, char **str);
int neu_json_dump_key(void *object, const char *key, char **const result,
bool must_exist);
int neu_json_load_key(void *object, const char *key, const char *input,
bool must_exist);
#ifdef __cplusplus
}
#endif
+2 -2
View File
@@ -26,8 +26,8 @@ extern "C" {
#include "json/json.h"
int neu_parse_param(const char *buf, char **err_param, int n,
neu_json_elem_t *ele, ...);
int neu_parse_param(char *buf, char **err_param, int n, neu_json_elem_t *ele,
...);
#ifdef __cplusplus
}
-66
View File
@@ -27,8 +27,6 @@
#include "json/json.h"
#include "tag.h"
#ifdef __cplusplus
extern "C" {
#endif
@@ -39,20 +37,11 @@ typedef struct {
uint64_t timestamp;
} neu_json_read_periodic_t;
typedef struct {
char * name;
enum neu_json_type t;
union neu_json_value value;
} neu_json_tag_meta_t;
typedef struct {
int64_t error;
char * name;
enum neu_json_type t;
union neu_json_value value;
uint8_t precision;
int n_meta;
neu_json_tag_meta_t *metas;
} neu_json_read_resp_tag_t;
typedef struct {
@@ -72,63 +61,11 @@ typedef struct {
} neu_json_write_req_t;
int neu_json_decode_write_req(char *buf, neu_json_write_req_t **result);
int neu_json_decode_write_req_json(void * json_obj,
neu_json_write_req_t **result);
void neu_json_decode_write_req_free(neu_json_write_req_t *req);
typedef struct {
char * tag;
enum neu_json_type t;
union neu_json_value value;
} neu_json_write_tags_elem_t;
typedef struct {
char * group;
char * node;
int n_tag;
neu_json_write_tags_elem_t *tags;
} neu_json_write_tags_req_t;
int neu_json_decode_write_tags_req(char * buf,
neu_json_write_tags_req_t **result);
int neu_json_decode_write_tags_req_json(void * json_obj,
neu_json_write_tags_req_t **result);
void neu_json_decode_write_tags_req_free(neu_json_write_tags_req_t *req);
typedef struct {
char * group;
int n_tag;
neu_json_write_tags_elem_t *tags;
} neu_json_write_gtags_elem_t;
typedef struct {
char *node;
int n_group;
neu_json_write_gtags_elem_t *groups;
} neu_json_write_gtags_req_t;
int neu_json_decode_write_gtags_req(char * buf,
neu_json_write_gtags_req_t **result);
int neu_json_decode_write_gtags_req_json(void * json_obj,
neu_json_write_gtags_req_t **result);
void neu_json_decode_write_gtags_req_free(neu_json_write_gtags_req_t *req);
typedef struct {
union {
neu_json_write_req_t single;
neu_json_write_tags_req_t plural;
};
bool singular;
} neu_json_write_t;
int neu_json_decode_write(char *buf, neu_json_write_t **result);
void neu_json_decode_write_free(neu_json_write_t *req);
typedef struct {
char *group;
char *node;
char *name;
char *desc;
bool sync;
} neu_json_read_req_t;
int neu_json_decode_read_req(char *buf, neu_json_read_req_t **result);
@@ -136,9 +73,6 @@ void neu_json_decode_read_req_free(neu_json_read_req_t *req);
int neu_json_encode_read_periodic_resp(void *json_object, void *param);
void neu_json_metas_to_json(neu_tag_meta_t *metas, int n_meta,
neu_json_read_resp_tag_t *json_tag);
#ifdef __cplusplus
}
#endif
-266
View File
@@ -1,266 +0,0 @@
/**
* NEURON IIoT System for Industry 4.0
* Copyright (C) 2020-2022 EMQ Technologies Co., Ltd All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
**/
#ifndef NEU_METRICS_H
#define NEU_METRICS_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include "define.h"
#include "type.h"
#include "utils/uthash.h"
typedef enum {
NEU_METRIC_TYPE_COUNTER,
NEU_METRIC_TYPE_GAUAGE,
NEU_METRIC_TYPE_COUNTER_SET,
} neu_metric_type_e;
// node running state
#define NEU_METRIC_RUNNING_STATE "running_state"
#define NEU_METRIC_RUNNING_STATE_TYPE NEU_METRIC_TYPE_GAUAGE
#define NEU_METRIC_RUNNING_STATE_HELP "Node running state"
// node link state
#define NEU_METRIC_LINK_STATE "link_state"
#define NEU_METRIC_LINK_STATE_TYPE NEU_METRIC_TYPE_GAUAGE
#define NEU_METRIC_LINK_STATE_HELP "Node link state"
// last round trip time in millisends
#define NEU_METRIC_LAST_RTT_MS "last_rtt_ms"
#define NEU_METRIC_LAST_RTT_MS_TYPE NEU_METRIC_TYPE_GAUAGE
#define NEU_METRIC_LAST_RTT_MS_HELP \
"Last request round trip time in milliseconds"
#define NEU_METRIC_LAST_RTT_MS_MAX 9999
// number of bytes sent
#define NEU_METRIC_SEND_BYTES "send_bytes"
#define NEU_METRIC_SEND_BYTES_TYPE NEU_METRIC_TYPE_COUNTER_SET
#define NEU_METRIC_SEND_BYTES_HELP "Total number of bytes sent"
// number of bytes received
#define NEU_METRIC_RECV_BYTES "recv_bytes"
#define NEU_METRIC_RECV_BYTES_TYPE NEU_METRIC_TYPE_COUNTER_SET
#define NEU_METRIC_RECV_BYTES_HELP "Total number of bytes received"
// maintained by neuron core
// number of tag read including errors
#define NEU_METRIC_TAG_READS_TOTAL "tag_reads_total"
#define NEU_METRIC_TAG_READS_TOTAL_TYPE NEU_METRIC_TYPE_COUNTER
#define NEU_METRIC_TAG_READS_TOTAL_HELP \
"Total number of tag reads including errors"
// maintained by neuron core
// number of tag read errors
#define NEU_METRIC_TAG_READ_ERRORS_TOTAL "tag_read_errors_total"
#define NEU_METRIC_TAG_READ_ERRORS_TOTAL_TYPE NEU_METRIC_TYPE_COUNTER
#define NEU_METRIC_TAG_READ_ERRORS_TOTAL_HELP "Total number of tag read errors"
// maintained by neuron core
// number of tags in group
#define NEU_METRIC_TAGS_TOTAL "tags_total"
#define NEU_METRIC_TAGS_TOTAL_TYPE NEU_METRIC_TYPE_GAUAGE
#define NEU_METRIC_TAGS_TOTAL_HELP "Total number of tags in the node"
// maintained by neuron core
// number of tags in group
#define NEU_METRIC_GROUP_TAGS_TOTAL "group_tags_total"
#define NEU_METRIC_GROUP_TAGS_TOTAL_TYPE NEU_METRIC_TYPE_GAUAGE
#define NEU_METRIC_GROUP_TAGS_TOTAL_HELP "Total number of tags in the group"
// number of messages sent in last group timer
#define NEU_METRIC_GROUP_LAST_SEND_MSGS "group_last_send_msgs"
#define NEU_METRIC_GROUP_LAST_SEND_MSGS_TYPE NEU_METRIC_TYPE_GAUAGE
#define NEU_METRIC_GROUP_LAST_SEND_MSGS_HELP \
"Number of messages sent on last group timer invocation"
// maintained by neuron core
// milliseconds consumed in last group timer invocation
#define NEU_METRIC_GROUP_LAST_TIMER_MS "group_last_timer_ms"
#define NEU_METRIC_GROUP_LAST_TIMER_MS_TYPE NEU_METRIC_TYPE_GAUAGE
#define NEU_METRIC_GROUP_LAST_TIMER_MS_HELP \
"Time in milliseconds consumed on last group timer invocation"
// maintained by neuron core
// group last error code
#define NEU_METRIC_GROUP_LAST_ERROR_CODE "group_last_error_code"
#define NEU_METRIC_GROUP_LAST_ERROR_CODE_TYPE NEU_METRIC_TYPE_GAUAGE
#define NEU_METRIC_GROUP_LAST_ERROR_CODE_HELP \
"Last encountered error code in group data acquisition"
// maintained by neuron core
// group last error timestamp
#define NEU_METRIC_GROUP_LAST_ERROR_TS "group_last_error_timestamp_ms"
#define NEU_METRIC_GROUP_LAST_ERROR_TS_TYPE NEU_METRIC_TYPE_GAUAGE
#define NEU_METRIC_GROUP_LAST_ERROR_TS_HELP \
"Timestamp (ms) of the last encountered error in group data acquisition"
// number of messages sent
#define NEU_METRIC_SEND_MSGS_TOTAL "send_msgs_total"
#define NEU_METRIC_SEND_MSGS_TOTAL_TYPE NEU_METRIC_TYPE_COUNTER
#define NEU_METRIC_SEND_MSGS_TOTAL_HELP "Total number of messages sent"
// number of errors encounter while sending messages
#define NEU_METRIC_SEND_MSG_ERRORS_TOTAL "send_msg_errors_total"
#define NEU_METRIC_SEND_MSG_ERRORS_TOTAL_TYPE NEU_METRIC_TYPE_COUNTER
#define NEU_METRIC_SEND_MSG_ERRORS_TOTAL_HELP \
"Total number of errors sending messages"
// number of messages received
#define NEU_METRIC_RECV_MSGS_TOTAL "recv_msgs_total"
#define NEU_METRIC_RECV_MSGS_TOTAL_TYPE NEU_METRIC_TYPE_COUNTER
#define NEU_METRIC_RECV_MSGS_TOTAL_HELP "Total number of messages received"
typedef enum {
NEU_METRICS_CATEGORY_GLOBAL,
NEU_METRICS_CATEGORY_DRIVER,
NEU_METRICS_CATEGORY_APP,
NEU_METRICS_CATEGORY_ALL,
} neu_metrics_category_e;
// metric entry
typedef struct {
const char * name; // NOTE: should points to string literal
const char * help; // NOTE: should points to string literal
neu_metric_type_e type; //
uint64_t value; //
UT_hash_handle hh; // ordered by name
} neu_metric_entry_t;
// group metrics
typedef struct {
char * name; // group name
neu_metric_entry_t *entries; // group metric entries
UT_hash_handle hh; // ordered by name
} neu_group_metrics_t;
// node metrics
typedef struct {
neu_node_type_e type; // node type
char * name; // node name
neu_metric_entry_t * entries; // node metric entries
neu_group_metrics_t *group_metrics; // group metrics
neu_adapter_t * adapter; //
UT_hash_handle hh; // ordered by name
} neu_node_metrics_t;
typedef struct {
char distro[32];
char kernel[32];
char machine[32];
char clib[32];
char clib_version[32];
unsigned cpu_percent;
unsigned cpu_cores;
size_t mem_total_bytes;
size_t mem_used_bytes;
size_t mem_cache_bytes;
size_t disk_size_gibibytes;
size_t disk_used_gibibytes;
size_t disk_avail_gibibytes;
bool core_dumped;
uint64_t license_max_tags;
uint64_t license_used_tags;
uint64_t uptime_seconds;
size_t north_nodes;
size_t north_running_nodes;
size_t north_disconnected_nodes;
size_t south_nodes;
size_t south_running_nodes;
size_t south_disconnected_nodes;
neu_node_metrics_t *node_metrics;
neu_metric_entry_t *registered_metrics;
} neu_metrics_t;
static inline const char *neu_metric_type_str(neu_metric_type_e type)
{
if (NEU_METRIC_TYPE_COUNTER == type) {
return "counter";
} else {
return "gauge";
}
}
int neu_metric_entries_add(neu_metric_entry_t **entries, const char *name,
const char *help, neu_metric_type_e type,
uint64_t init);
static inline void neu_metric_entry_free(neu_metric_entry_t *entry)
{
free(entry);
}
static inline void neu_group_metrics_free(neu_group_metrics_t *group_metrics)
{
if (NULL == group_metrics) {
return;
}
neu_metric_entry_t *e = NULL, *tmp = NULL;
HASH_ITER(hh, group_metrics->entries, e, tmp)
{
HASH_DEL(group_metrics->entries, e);
neu_metric_entry_free(e);
}
free(group_metrics->name);
free(group_metrics);
}
static inline void neu_node_metrics_free(neu_node_metrics_t *node_metrics)
{
if (NULL == node_metrics) {
return;
}
neu_metric_entry_t *e = NULL, *etmp = NULL;
HASH_ITER(hh, node_metrics->entries, e, etmp)
{
HASH_DEL(node_metrics->entries, e);
neu_metric_entry_free(e);
}
neu_group_metrics_t *g = NULL, *gtmp = NULL;
HASH_ITER(hh, node_metrics->group_metrics, g, gtmp)
{
HASH_DEL(node_metrics->group_metrics, g);
neu_group_metrics_free(g);
}
free(node_metrics);
}
void neu_metrics_init();
void neu_metrics_add_node(const neu_adapter_t *adapter);
void neu_metrics_del_node(const neu_adapter_t *adapter);
int neu_metrics_register_entry(const char *name, const char *help,
neu_metric_type_e type);
void neu_metrics_unregister_entry(const char *name);
typedef void (*neu_metrics_cb_t)(const neu_metrics_t *metrics, void *data);
void neu_metrics_visist(neu_metrics_cb_t cb, void *data);
#ifdef __cplusplus
}
#endif
#endif
-1145
View File
File diff suppressed because it is too large Load Diff
+1 -3
View File
@@ -37,15 +37,13 @@ extern "C" {
#include "utils/log.h"
#include "utils/zlog.h"
#include "utils/neu_jwt.h"
#include "utils/time.h"
#include "utils/utarray.h"
#include "utils/utextend.h"
#include "utils/uthash.h"
#include "utils/utlist.h"
#include "connection/mqtt_client_intf.h"
#include "connection/neu_connection.h"
#include "connection/neu_connection_eth.h"
#include "event/event.h"
#include "json/json.h"
-469
View File
@@ -1,469 +0,0 @@
/**
* NEURON IIoT System for Industry 4.0
* Copyright (C) 2020-2022 EMQ Technologies Co., Ltd All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
**/
#ifndef _NEU_PERSIST_PERSIST_
#define _NEU_PERSIST_PERSIST_
#ifdef __cplusplus
extern "C" {
#endif
#include <sqlite3.h>
#include "adapter_info.h"
#include "persist/json/persist_json_plugin.h"
typedef neu_json_plugin_req_plugin_t neu_persist_plugin_info_t;
typedef struct {
char *name;
int type;
char *plugin_name;
int state;
} neu_persist_node_info_t;
typedef struct {
uint32_t interval;
char * name;
} neu_persist_group_info_t;
typedef struct {
char *driver_name;
char *group_name;
char *params;
} neu_persist_subscription_info_t;
typedef struct {
char *name;
char *hash;
} neu_persist_user_info_t;
typedef struct {
char *name;
char *plugin_name;
} neu_persist_template_info_t;
static inline void neu_persist_plugin_infos_free(UT_array *plugin_infos)
{
utarray_free(plugin_infos);
}
static inline void neu_persist_node_info_fini(neu_persist_node_info_t *info)
{
free(info->name);
free(info->plugin_name);
}
static inline void neu_persist_group_info_fini(neu_persist_group_info_t *info)
{
free(info->name);
}
static inline void
neu_persist_subscription_info_fini(neu_persist_subscription_info_t *info)
{
free(info->driver_name);
free(info->group_name);
free(info->params);
}
static inline void neu_persist_user_info_fini(neu_persist_user_info_t *info)
{
free(info->name);
free(info->hash);
}
/**
* Create persister.
* @return 0 on success, -1 otherwise.
*/
int neu_persister_create(const char *schema_dir);
/**
* Destroy perister.
*/
void neu_persister_destroy();
sqlite3 *neu_persister_get_db();
int neu_persister_node_count();
int neu_persister_tag_count();
/**
* Persist nodes.
* @param node_info neu_persist_node_info_t.
* @return 0 on success, non-zero on failure
*/
int neu_persister_store_node(neu_persist_node_info_t *info);
/**
* Load node infos.
* @param[out] node_infos used to return pointer to heap allocated
* vector of neu_persist_node_info_t.
* @return 0 on success, none-zero on failure
*/
int neu_persister_load_nodes(UT_array **node_infos);
/**
* Delete node.
* @param node_name name of the node to delete.
* @return 0 on success, none-zero on failure
*/
int neu_persister_delete_node(const char *node_name);
/**
* Update node name.
* @param node_name name of the node to update.
* @param new_name new name of the adapter.
* @return 0 on success, none-zero on failure
*/
int neu_persister_update_node(const char *node_name, const char *new_name);
/**
* Update node state.
* @param node_name name of the node to update.
* @param state state of the adapter.
* @return 0 on success, none-zero on failure
*/
int neu_persister_update_node_state(const char *node_name, int state);
/**
* Persist plugins.
* @param plugin_infos vector of neu_persist_plugin_info_t.
* @return 0 on success, non-zero otherwise
*/
int neu_persister_store_plugins(UT_array *plugin_infos);
/**
* Load plugin infos.
* @param[out] plugin_infos used to return pointer to heap allocated
* vector of neu_persist_plugin_info_t.
* @return 0 on success, none-zero on failure
*/
int neu_persister_load_plugins(UT_array **plugin_infos);
/**
* Persist node tags.
* @param driver_name name of the driver who owns the tags
* @param group_name name of the group
* @param tag the tag to store
* @return 0 on success, non-zero otherwise
*/
int neu_persister_store_tag(const char *driver_name, const char *group_name,
const neu_datatag_t *tag);
int neu_persister_store_tags(const char *driver_name, const char *group_name,
const neu_datatag_t *tags, size_t n);
/**
* Load node tag infos.
* @param node_name name of the node who owns the tags
* @param group_name name of the group
* @param[out] tag_infos used to return pointer to heap allocated
* vector of neu_datatag_t
* @return 0 on success, non-zero otherwise
*/
int neu_persister_load_tags(const char *driver_name, const char *group_name,
UT_array **tag_infos);
/**
* Update node tags.
* @param driver_name name of the driver who owns the tags
* @param group_name name of the group
* @param tag the tag to update
* @return 0 on success, non-zero otherwise
*/
int neu_persister_update_tag(const char *driver_name, const char *group_name,
const neu_datatag_t *tag);
/**
* Update node tag value.
* @param driver_name name of the driver who owns the tags
* @param group_name name of the group
* @param tag the tag to update
* @return 0 on success, non-zero otherwise
*/
int neu_persister_update_tag_value(const char * driver_name,
const char * group_name,
const neu_datatag_t *tag);
/**
* Delete node tags.
* @param driver_name name of the driver who owns the tags
* @param group_name name of the group
* @param tag_name name of the tag
* @return 0 on success, non-zero otherwise
*/
int neu_persister_delete_tag(const char *driver_name, const char *group_name,
const char *tag_name);
/**
* Persist subscriptions.
* @param app_name name of the app node
* @param driver_name name of the driver node
* @param group_name name of the group
* @param params subscription params
* @return 0 on success, non-zero otherwise
*/
int neu_persister_store_subscription(const char *app_name,
const char *driver_name,
const char *group_name,
const char *params);
/**
* Update subscriptions.
* @param app_name name of the app node
* @param driver_name name of the driver node
* @param group_name name of the group
* @param params subscription params
* @return 0 on success, non-zero otherwise
*/
int neu_persister_update_subscription(const char *app_name,
const char *driver_name,
const char *group_name,
const char *params);
/**
* Load adapter subscriptions.
* @param app_name name of the app node
* @param[out] subscription_infos used to return pointer to heap allocated
* vector of neu_persist_subscription_info_t.
* @return 0 on success, non-zero otherwise
*/
int neu_persister_load_subscriptions(const char *app_name,
UT_array ** subscription_infos);
/**
* Persist subscriptions.
* @param app_name name of the app node
* @param driver_name name of the driver node
* @param group_name name of the group
* @return 0 on success, non-zero otherwise
*/
int neu_persister_delete_subscription(const char *app_name,
const char *driver_name,
const char *group_name);
/**
* Persist group config.
* @param driver_name name of the driver who owns the group
* @param group_info group info to persist.
* @return 0 on success, non-zero otherwise
*/
int neu_persister_store_group(const char * driver_name,
neu_persist_group_info_t *group_info);
/**
* Update group config.
* @param driver_name name of the driver who owns the group
* @param group_info group info to persist.
* @return 0 on success, non-zero otherwise
*/
int neu_persister_update_group(const char *driver_name, const char *group_name,
neu_persist_group_info_t *group_info);
/**
* Load all group config infos under an adapter.
* @param driver_name name of the driver who owns the group
* @param[out] group_infos used to return pointer to heap allocated
* vector of neu_persist_group_info_t.
* @return 0 on success, non-zero otherwise
*/
int neu_persister_load_groups(const char *driver_name, UT_array **group_infos);
/**
* Delete group config.
* @param driver_name name of the driver who owns the group
* @param group_name name of the group.
* @return 0 on success, none-zero on failure
*/
int neu_persister_delete_group(const char *driver_name, const char *group_name);
/**
* Persist node setting.
* @param adapter_name name of the adapter who owns the setting.
* @param setting node setting string.
* @return 0 on success, non-zero otherwise
*/
int neu_persister_store_node_setting(const char *node_name,
const char *setting);
/**
* Load node setting.
* @param node_name name of the node.
* @param[out] setting used to return node setting string.
* @return 0 on success, non-zero otherwise
*/
int neu_persister_load_node_setting(const char * node_name,
const char **const setting);
/**
* Delete node setting.
* @param node_name name of the node.
* @return 0 on success, none-zero on failure
*/
int neu_persister_delete_node_setting(const char *node_name);
/**
* Save user info.
* @param user user info
* @return 0 on success, none-zero on failure
*/
int neu_persister_store_user(const neu_persist_user_info_t *user);
/**
* Update user info.
* @param user user info
* @return 0 on success, none-zero on failure
*/
int neu_persister_update_user(const neu_persist_user_info_t *user);
/**
* Load user info.
* @param user_name name of the user.
* @param user_p output parameter of user info
* @return 0 on success, none-zero on failure
*/
int neu_persister_load_user(const char * user_name,
neu_persist_user_info_t **user_p);
/**
* Delete user info.
* @param user_name name of the user.
* @return 0 on success, none-zero on failure
*/
int neu_persister_delete_user(const char *user_name);
/**
* Persist templates.
* @param name template name
* @param plugin plugin name
* @return 0 on success, non-zero on failure
*/
int neu_persister_store_template(const char *name, const char *plugin);
/**
* Load template infos.
* @param[out] infos used to return pointer to heap allocated
* vector of neu_persist_template_info_t.
* @return 0 on success, none-zero on failure
*/
int neu_persister_load_templates(UT_array **infos);
/**
* Delete template.
* @param name template name
* @return 0 on success, none-zero on failure
*/
int neu_persister_delete_template(const char *name);
/**
* Delete all templates.
* @return 0 on success, none-zero on failure
*/
int neu_persister_clear_templates();
/**
* Persist template group.
* @param tmpl_name template name.
* @param group_info group info to persist.
* @return 0 on success, non-zero otherwise
*/
int neu_persister_store_template_group(const char * tmpl_name,
neu_persist_group_info_t *group_info);
/**
* Update template group.
* @param tmpl_name template name.
* @param group_name group name.
* @param group_info group info to persist.
* @return 0 on success, non-zero otherwise
*/
int neu_persister_update_template_group(const char * tmpl_name,
const char * group_name,
neu_persist_group_info_t *group_info);
/**
* Load all group infos of a template.
* @param tmpl_name template name.
* @param[out] group_infos used to return pointer to heap allocated
* vector of neu_persist_group_info_t.
* @return 0 on success, non-zero otherwise
*/
int neu_persister_load_template_groups(const char *tmpl_name,
UT_array ** group_infos);
/**
* Delete template group.
* @param tmpl_name template name.
* @param group_name name of the group.
* @return 0 on success, none-zero on failure
*/
int neu_persister_delete_template_group(const char *tmpl_name,
const char *group_name);
/**
* Persist template tags.
* @param tmpl_name name of the template
* @param group_name name of the group
* @param tags the tags to store
* @param n the number of tags
* @return 0 on success, non-zero otherwise
*/
int neu_persister_store_template_tags(const char * tmpl_name,
const char * group_name,
const neu_datatag_t *tags, size_t n);
/**
* Load template tag infos.
* @param tmpl_name name of the template
* @param group_name name of the group
* @param[out] tag_infos used to return pointer to heap allocated
* vector of neu_datatag_t
* @return 0 on success, non-zero otherwise
*/
int neu_persister_load_template_tags(const char *tmpl_name,
const char *group_name,
UT_array ** tag_infos);
/**
* Update template tags.
* @param tmpl_name name of the template
* @param group_name name of the group
* @param tags the tags to store
* @param n the number of tags
* @return 0 on success, non-zero otherwise
*/
int neu_persister_update_template_tags(const char * tmpl_name,
const char * group_name,
const neu_datatag_t *tags, size_t n);
/**
* Delete template tags.
* @param tmpl_name name of the template
* @param group_name name of the group
* @param tag_name name of the tag
* @return 0 on success, non-zero otherwise
*/
int neu_persister_delete_template_tags(const char * tmpl_name,
const char * group_name,
const char *const *tags, size_t n_tag);
char *neu_persister_save_file_tmp(const char *file_data, uint32_t len,
const char *suffix);
bool neu_persister_library_exists(const char *library);
#ifdef __cplusplus
}
#endif
#endif
+6 -60
View File
@@ -24,29 +24,25 @@
extern "C" {
#endif
#include "utils/utextend.h"
#include "utils/utarray.h"
#include "utils/zlog.h"
#include "event/event.h"
#include "adapter.h"
#include "define.h"
#include "type.h"
#define NEURON_PLUGIN_VER_1_0 \
NEU_VERSION(NEU_VERSION_MAJOR, NEU_VERSION_MINOR, NEU_VERSION_FIX)
extern int64_t global_timestamp;
#define NEURON_PLUGIN_VER_1_0 100
#define NEURON_PLUGIN_VER_2_0 200
typedef struct neu_plugin_common {
uint32_t magic;
neu_adapter_t * adapter;
const adapter_callbacks_t *adapter_callbacks;
char name[NEU_NODE_NAME_LEN];
neu_node_link_state_e link_state;
char log_level[NEU_LOG_LEVEL_LEN];
uint16_t tag_size;
int64_t timestamp;
zlog_category_t *log;
} neu_plugin_common_t;
@@ -63,17 +59,10 @@ struct neu_plugin_group {
neu_plugin_group_free group_free;
};
typedef int (*neu_plugin_tag_validator_t)(const neu_datatag_t *tag);
typedef struct {
neu_datatag_t *tag;
neu_value_u value;
} neu_plugin_tag_value_t;
typedef struct neu_plugin_intf_funs {
neu_plugin_t *(*open)(void);
int (*close)(neu_plugin_t *plugin);
int (*init)(neu_plugin_t *plugin, bool load);
int (*init)(neu_plugin_t *plugin);
int (*uninit)(neu_plugin_t *plugin);
int (*start)(neu_plugin_t *plugin);
int (*stop)(neu_plugin_t *plugin);
@@ -85,21 +74,8 @@ typedef struct neu_plugin_intf_funs {
struct {
int (*validate_tag)(neu_plugin_t *plugin, neu_datatag_t *tag);
int (*group_timer)(neu_plugin_t *plugin, neu_plugin_group_t *group);
int (*group_sync)(neu_plugin_t *plugin, neu_plugin_group_t *group);
int (*write_tag)(neu_plugin_t *plugin, void *req,
neu_datatag_t *tag, neu_value_u value);
int (*write_tags)(
neu_plugin_t *plugin, void *req,
UT_array *tag_values); // UT_array {neu_datatag_t, neu_value_u}
neu_plugin_tag_validator_t tag_validator;
int (*load_tags)(
neu_plugin_t *plugin, const char *group, neu_datatag_t *tags,
int n_tag); // create tags using data from the database
int (*add_tags)(neu_plugin_t *plugin, const char *group,
neu_datatag_t *tags,
int n_tag); // create tags by API
int (*del_tags)(neu_plugin_t *plugin, int n_tag);
} driver;
};
@@ -107,18 +83,11 @@ typedef struct neu_plugin_intf_funs {
typedef struct neu_plugin_module {
const uint32_t version;
const char * schema;
const char * module_name;
const char * module_descr;
const char * module_descr_zh;
const neu_plugin_intf_funs_t *intf_funs;
neu_node_type_e type;
neu_plugin_kind_e kind;
bool display;
bool single;
const char * single_name;
neu_event_timer_type_e timer_type;
neu_tag_cache_type_e cache_type;
} neu_plugin_module_t;
inline static neu_plugin_common_t *
@@ -127,32 +96,9 @@ neu_plugin_to_plugin_common(neu_plugin_t *plugin)
return (neu_plugin_common_t *) plugin;
}
/**
* @brief when creating a node, initialize the common parameter in
* the plugin.
*
* @param[in] common refers to common parameter in plugins.
*/
void neu_plugin_common_init(neu_plugin_common_t *common);
/**
* @brief Check the common parameter in the plugin.
*
* @param[in] plugin represents plugin information.
* @return Returns true if the check is correct,false otherwise.
*/
bool neu_plugin_common_check(neu_plugin_t *plugin);
/**
* @brief Encapsulate the request,convert the request into a message and send.
*
* @param[in] plugin
* @param[in] head the request header function.
* @param[in] data that different request headers correspond to different data.
*
* @return 0 for successful message processing, non-0 for message processing
* failure.
*/
int neu_plugin_op(neu_plugin_t *plugin, neu_reqresp_head_t head, void *data);
#ifdef __cplusplus
+18 -74
View File
@@ -23,27 +23,25 @@ config_ **/
#include <stdbool.h>
#include <stdint.h>
#include "define.h"
#include "type.h"
#include "utils/utextend.h"
#include "json/json.h"
#include "type.h"
#define NEU_TAG_META_SIZE 20
typedef enum {
NEU_ATTRIBUTE_READ = 1,
NEU_ATTRIBUTE_WRITE = 2,
NEU_ATTRIBUTE_SUBSCRIBE = 4,
NEU_ATTRIBUTE_STATIC = 8,
} neu_attribute_e;
typedef enum {
NEU_DATATAG_ENDIAN_L16 = 0, // #L 2,1
NEU_DATATAG_ENDIAN_B16 = 1, // #B 1,2
NEU_DATATAG_ENDIAN_LL32 = 2, // #LL 4,3,2,1
NEU_DATATAG_ENDIAN_LB32 = 3, // #LB 3,4,1,2
NEU_DATATAG_ENDIAN_BB32 = 4, // #BB 1,2,3,4
NEU_DATATAG_ENDIAN_BL32 = 5, // #BL 2,1,4,3
NEU_DATATAG_ENDIAN_L64 = 6, // #L 8,7,6,5,4,3,2,1
NEU_DATATAG_ENDIAN_B64 = 7, // #B 1,2,3,4,5,6,7,8
NEU_DATATAG_ENDIAN_L16 = 0, // #L
NEU_DATATAG_ENDIAN_B16 = 1, // #B
NEU_DATATAG_ENDIAN_LL32 = 2, // #LL
NEU_DATATAG_ENDIAN_LB32 = 3, // #LB
NEU_DATATAG_ENDIAN_BB32 = 4, // #BB
NEU_DATATAG_ENDIAN_BL32 = 5, // #BL
} neu_datatag_endian_e;
typedef enum {
@@ -60,18 +58,11 @@ typedef union {
struct {
neu_datatag_endian_e endian;
} value32;
struct {
neu_datatag_endian_e endian;
} value64;
struct {
uint16_t length;
neu_datatag_string_type_e type;
} string;
struct {
uint8_t length;
} bytes;
struct {
bool op;
uint8_t bit;
@@ -81,42 +72,22 @@ typedef union {
typedef struct {
char * name;
char * address;
char * description;
neu_attribute_e attribute;
neu_type_e type;
uint8_t precision;
double decimal;
char * description;
neu_datatag_addr_option_u option;
uint8_t meta[NEU_TAG_META_LENGTH];
uint8_t meta[NEU_TAG_META_SIZE];
} neu_datatag_t;
typedef struct neu_tag_meta {
char name[NEU_TAG_NAME_LEN];
neu_dvalue_t value;
} neu_tag_meta_t;
UT_icd *neu_tag_get_icd();
neu_datatag_t *neu_tag_dup(const neu_datatag_t *tag);
void neu_tag_copy(neu_datatag_t *tag, const neu_datatag_t *other);
void neu_tag_fini(neu_datatag_t *tag);
void neu_tag_free(neu_datatag_t *tag);
inline static bool neu_tag_attribute_test(const neu_datatag_t *tag,
neu_attribute_e attribute)
inline static bool neu_tag_attribute_test(neu_datatag_t * tag,
neu_attribute_e attribute)
{
return (tag->attribute & attribute) == attribute;
}
/**
* @brief Special usage of parsing tag address, e.g. setting length of string
* type, setting of endian.
*
* @param[in] datatag contains all the information about the tag.
* @param[in] option contain actions that the label can perform.
* @return 0 on success, -1 on failure.
*/
int neu_datatag_parse_addr_option(const neu_datatag_t * datatag,
UT_icd *neu_tag_get_icd();
int neu_datatag_parse_addr_option(neu_datatag_t * datatag,
neu_datatag_addr_option_u *option);
bool neu_datatag_string_is_utf8(char *data, int len);
@@ -130,31 +101,4 @@ int neu_datatag_string_dtoh(char *str, int len);
int neu_datatag_string_tod(char *str, int len, int buf_len);
int neu_datatag_string_toe(char *str, int len, int buf_len);
int neu_tag_get_static_value(const neu_datatag_t *tag, neu_value_u *value);
int neu_tag_set_static_value(neu_datatag_t *tag, const neu_value_u *value);
int neu_tag_get_static_value_json(neu_datatag_t *tag, neu_json_type_e *t,
neu_json_value_u *v);
int neu_tag_set_static_value_json(neu_datatag_t *tag, neu_json_type_e t,
const neu_json_value_u *v);
char *neu_tag_dump_static_value(const neu_datatag_t *tag);
int neu_tag_load_static_value(neu_datatag_t *tag, const char *s);
typedef struct {
char * name;
char * address;
neu_attribute_e attribute;
neu_type_e type;
char * params;
} neu_ndriver_tag_t;
UT_icd *neu_ndriver_tag_get_icd();
neu_datatag_t *neu_ndriver_tag_dup(const neu_ndriver_tag_t *tag);
void neu_ndriver_tag_copy(neu_ndriver_tag_t * tag,
const neu_ndriver_tag_t *other);
void neu_ndriver_tag_fini(neu_ndriver_tag_t *tag);
void neu_ndriver_tag_free(neu_ndriver_tag_t *tag);
#endif
#endif
-13
View File
@@ -55,22 +55,9 @@ typedef struct {
typedef bool (*neu_tag_sort_fn)(neu_tag_sort_t *sort, void *tag,
void *tag_to_be_sorted);
/**
* @brief Use sort and cmp to sort and classify tags.
*
* @param[in] tags The tags that needs to be processed.
* @param[in] sort Function for tag sort.
* @param[in] cmp Function for tags comparison.
* @return processed tags.
*/
neu_tag_sort_result_t *neu_tag_sort(UT_array *tags, neu_tag_sort_fn sort,
neu_tag_sort_cmp cmp);
/**
* @brief free the result.
*
* @param[in] result the tags result that needs to be relesed.
*/
void neu_tag_sort_free(neu_tag_sort_result_t *result);
#ifdef __cplusplus
+14 -242
View File
@@ -28,7 +28,6 @@ extern "C" {
#include <netinet/in.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
typedef enum {
NEU_TYPE_INT8 = 1,
@@ -46,10 +45,6 @@ typedef enum {
NEU_TYPE_STRING = 13,
NEU_TYPE_BYTES = 14,
NEU_TYPE_ERROR = 15,
NEU_TYPE_WORD = 16,
NEU_TYPE_DWORD = 17,
NEU_TYPE_LWORD = 18,
NEU_TYPE_PTR = 19,
} neu_type_e;
inline static const char *neu_type_string(neu_type_e type)
@@ -72,7 +67,7 @@ inline static const char *neu_type_string(neu_type_e type)
case NEU_TYPE_UINT64:
return "NEU_TYPE_UINT64";
case NEU_TYPE_FLOAT:
return "NEU_TYPE_FLOAT";
return "NEU_TYPE_FLOAt";
case NEU_TYPE_DOUBLE:
return "NEU_TYPE_DOUBLE";
case NEU_TYPE_BIT:
@@ -85,126 +80,31 @@ inline static const char *neu_type_string(neu_type_e type)
return "NEU_TYPE_BYTES";
case NEU_TYPE_ERROR:
return "NEU_TYPE_ERROR";
case NEU_TYPE_WORD:
return "NEU_TYPE_WORD";
case NEU_TYPE_DWORD:
return "NEU_TYPE_DWORD";
case NEU_TYPE_LWORD:
return "NEU_TYPE_LWORD";
case NEU_TYPE_PTR:
return "NEU_TYPE_PTR";
}
return "";
}
typedef struct {
neu_type_e type; // string or bytes
uint16_t length;
uint8_t * ptr;
} neu_value_ptr_t;
#define NEU_VALUE_SIZE 128
typedef struct {
uint8_t bytes[NEU_VALUE_SIZE];
uint8_t length;
} __attribute__((packed)) neu_value_bytes_t;
typedef union {
bool boolean;
int8_t i8;
uint8_t u8;
int16_t i16;
uint16_t u16;
int32_t i32;
uint32_t u32;
int64_t i64;
uint64_t u64;
float f32;
double d64;
char str[NEU_VALUE_SIZE];
neu_value_bytes_t bytes;
neu_value_ptr_t ptr;
bool boolean;
int8_t i8;
uint8_t u8;
int16_t i16;
uint16_t u16;
int32_t i32;
uint32_t u32;
int64_t i64;
uint64_t u64;
float f32;
double d64;
char str[NEU_VALUE_SIZE];
uint8_t bytes[NEU_VALUE_SIZE];
} neu_value_u;
static inline char *neu_value_str(neu_type_e type, neu_value_u value)
{
static __thread char str[32] = { 0 };
switch (type) {
case NEU_TYPE_INT8:
snprintf(str, sizeof(str), "type: %s, value: %i", neu_type_string(type),
value.i8);
break;
case NEU_TYPE_UINT8:
snprintf(str, sizeof(str), "type: %s, value: %u", neu_type_string(type),
value.u8);
break;
case NEU_TYPE_INT16:
snprintf(str, sizeof(str), "type: %s, value: %i", neu_type_string(type),
value.i16);
break;
case NEU_TYPE_WORD:
case NEU_TYPE_UINT16:
snprintf(str, sizeof(str), "type: %s, value: %u", neu_type_string(type),
value.u16);
break;
case NEU_TYPE_INT32:
snprintf(str, sizeof(str), "type: %s, value: %i", neu_type_string(type),
value.i32);
break;
case NEU_TYPE_DWORD:
case NEU_TYPE_UINT32:
snprintf(str, sizeof(str), "type: %s, value: %u", neu_type_string(type),
value.u32);
break;
case NEU_TYPE_INT64: {
long long int i = value.i64;
snprintf(str, sizeof(str), "type: %s, value: %lld",
neu_type_string(type), i);
break;
}
case NEU_TYPE_LWORD:
case NEU_TYPE_UINT64: {
long long unsigned int i = value.u64;
snprintf(str, sizeof(str), "type: %s, value: %llu",
neu_type_string(type), i);
break;
}
case NEU_TYPE_FLOAT:
snprintf(str, sizeof(str), "type: %s, value: %f", neu_type_string(type),
value.f32);
break;
case NEU_TYPE_DOUBLE:
snprintf(str, sizeof(str), "type: %s, value: %f", neu_type_string(type),
value.d64);
break;
case NEU_TYPE_BIT:
snprintf(str, sizeof(str), "type: %s, value: %u", neu_type_string(type),
value.u8);
break;
case NEU_TYPE_BOOL:
snprintf(str, sizeof(str), "type: %s, value: %u", neu_type_string(type),
value.boolean);
break;
case NEU_TYPE_STRING: {
snprintf(str, sizeof(str), "type: %s, value: %c%c%c",
neu_type_string(type), value.str[0], value.str[1],
value.str[2]);
break;
}
default:
break;
}
return str;
}
typedef struct {
neu_type_e type;
neu_value_u value;
uint8_t precision;
} neu_dvalue_t;
typedef union neu_value8 {
uint8_t value;
@@ -533,134 +433,6 @@ static inline void neu_htons_p(uint16_t *pu)
neu_ntohs_p(pu);
}
static inline uint16_t neu_get_u16(uint8_t *bytes)
{
uint16_t ret = 0;
uint8_t *t = NULL;
t = (uint8_t *) &ret;
t[0] = bytes[0];
t[1] = bytes[1];
return ret;
}
static inline int16_t neu_get_i16(uint8_t *bytes)
{
int16_t ret = 0;
uint8_t *t = NULL;
t = (uint8_t *) &ret;
t[0] = bytes[0];
t[1] = bytes[1];
return ret;
}
static inline uint32_t neu_get_u32(uint8_t *bytes)
{
uint32_t ret = 0;
uint8_t *t = NULL;
t = (uint8_t *) &ret;
t[0] = bytes[0];
t[1] = bytes[1];
t[2] = bytes[2];
t[3] = bytes[3];
return ret;
}
static inline int32_t neu_get_i32(uint8_t *bytes)
{
int32_t ret = 0;
uint8_t *t = NULL;
t = (uint8_t *) &ret;
t[0] = bytes[0];
t[1] = bytes[1];
t[2] = bytes[2];
t[3] = bytes[3];
return ret;
}
static inline float neu_get_f32(uint8_t *bytes)
{
float ret = 0;
uint8_t *t = NULL;
t = (uint8_t *) &ret;
t[0] = bytes[0];
t[1] = bytes[1];
t[2] = bytes[2];
t[3] = bytes[3];
return ret;
}
static inline uint64_t neu_get_u64(uint8_t *bytes)
{
uint64_t ret = 0;
uint8_t *t = NULL;
t = (uint8_t *) &ret;
t[0] = bytes[0];
t[1] = bytes[1];
t[2] = bytes[2];
t[3] = bytes[3];
t[4] = bytes[4];
t[5] = bytes[5];
t[6] = bytes[6];
t[7] = bytes[7];
return ret;
}
static inline int64_t neu_get_i64(uint8_t *bytes)
{
int64_t ret = 0;
uint8_t *t = NULL;
t = (uint8_t *) &ret;
t[0] = bytes[0];
t[1] = bytes[1];
t[2] = bytes[2];
t[3] = bytes[3];
t[4] = bytes[4];
t[5] = bytes[5];
t[6] = bytes[6];
t[7] = bytes[7];
return ret;
}
static inline double neu_get_f64(uint8_t *bytes)
{
double ret = 0;
uint8_t *t = NULL;
t = (uint8_t *) &ret;
t[0] = bytes[0];
t[1] = bytes[1];
t[2] = bytes[2];
t[3] = bytes[3];
t[4] = bytes[4];
t[5] = bytes[5];
t[6] = bytes[6];
t[7] = bytes[7];
return ret;
}
#ifdef __cplusplus
}
#endif
+1 -46
View File
@@ -30,61 +30,16 @@ typedef bool (*neu_async_queue_expire)(void *elem);
typedef void (*neu_async_queue_free)(void *elem);
typedef bool (*neu_async_queue_filter)(void *filter_elem, void *elem);
/**
* @brief Create a new asynchronous queue.
*
* @param[in] key_fn Calculate the key of the element.
* @param[in] expire_fn Element invalidation check function in queue.
* @param[in] free_fn Release expired elements and elements that exceed the
* queue length.
* @param[in] max_size Maximum length of the queue.
* @return a created async queue.
*/
neu_async_queue_t *neu_async_queue_new(neu_async_queue_key key_fn,
neu_async_queue_expire expire_fn,
neu_async_queue_free free_fn,
uint16_t max_size);
/**
* @brief destroy queue.
*
* @param[in] q the queue that needs to be destroyed.
*/
void neu_async_queue_destroy(neu_async_queue_t *q);
/**
* @brief Add element at the end of the queue.
*
* @param[in] q the queue that requires an operation.
* @param[in] elem that needs to be added at the end of the queue.
*/
void neu_async_queue_push(neu_async_queue_t *q, void *elem);
int neu_async_queue_pop(neu_async_queue_t *q, uint64_t key, void **elem);
/**
* @brief Pop the element corrseponding to key in the queue.
*
* @param[in] q the queue that requires an operation.
* @param[in] key
* @param[out] elem that needs to be deleted at the end of the queue.
* @return 0 for success, -1 for failure.
*/
int neu_async_queue_pop(neu_async_queue_t *q, uint64_t key, void **elem);
/**
* @brief remove some elements from the queue.
*
* @param[in] q the queue that requires an operation.
* @param[in] filter element comparison function.
* @param[in] filter_elem
*/
void neu_async_queue_remove(neu_async_queue_t *q, neu_async_queue_filter filter,
void *filter_elem);
/**
* @brief remove all elements from the queue.
*
* @param[in] q the queue that requires an operation.
*/
void neu_async_queue_clean(neu_async_queue_t *q);
#endif
+1 -17
View File
@@ -24,23 +24,7 @@
extern "C" {
#endif
/**
* @brief base64 encoding.
*
* @param[in] input Data to be encoded.
* @param[in] length Length of data to be encoded.
* @return Encoded data.
*/
char *neu_encode64(const unsigned char *input, int length);
/**
* @brief base64 decoding.
*
* @param[out] length Pointer to the length of the decoded data.
* @param[in] input Data to be decoded.
* @return The decoded data.
*/
char * neu_encode64(const unsigned char *input, int length);
unsigned char *neu_decode64(int *length, const char *input);
#ifdef __cplusplus
-114
View File
@@ -1,114 +0,0 @@
/**
* NEURON IIoT System for Industry 4.0
* Copyright (C) 2020-2022 EMQ Technologies Co., Ltd All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
**/
#ifndef _NEU_HTTP_HANDLER_H_
#define _NEU_HTTP_HANDLER_H_
#include <stdlib.h>
#include <nng/nng.h>
#include <nng/supplemental/http/http.h>
#include "utils/neu_jwt.h"
#include "json/neu_json_error.h"
#define NEU_PROCESS_HTTP_REQUEST(aio, req_type, decode_fun, func) \
{ \
char * req_data = NULL; \
size_t req_data_size = 0; \
req_type *req = NULL; \
\
if (neu_http_get_body((aio), (void **) &req_data, &req_data_size) == \
0 && \
decode_fun(req_data, &req) == 0) { \
{ func }; \
decode_fun##_free(req); \
} else { \
neu_http_bad_request(aio, "{\"error\": 1002}"); \
} \
free(req_data); \
}
#define NEU_PROCESS_HTTP_REQUEST_VALIDATE_JWT(aio, req_type, decode_fun, func) \
{ \
if (!disable_jwt) { \
char *jwt = \
(char *) neu_http_get_header(aio, (char *) "Authorization"); \
\
NEU_JSON_RESPONSE_ERROR(neu_jwt_validate(jwt), { \
if (error_code.error != NEU_ERR_SUCCESS) { \
neu_http_response(aio, error_code.error, result_error); \
free(result_error); \
return; \
} \
}) \
} \
NEU_PROCESS_HTTP_REQUEST(aio, req_type, decode_fun, func); \
}
#define NEU_VALIDATE_JWT(aio) \
{ \
if (!disable_jwt) { \
char *jwt = \
(char *) neu_http_get_header(aio, (char *) "Authorization"); \
\
NEU_JSON_RESPONSE_ERROR(neu_jwt_validate(jwt), { \
if (error_code.error != NEU_ERR_SUCCESS) { \
neu_http_response(aio, error_code.error, result_error); \
free(result_error); \
return; \
} \
}); \
} \
}
enum neu_http_method {
NEU_HTTP_METHOD_UNDEFINE = 0x0,
NEU_HTTP_METHOD_GET,
NEU_HTTP_METHOD_POST,
NEU_HTTP_METHOD_PUT,
NEU_HTTP_METHOD_DELETE,
NEU_HTTP_METHOD_OPTIONS
};
enum neu_http_handler_type {
NEU_HTTP_HANDLER_FUNCTION = 0x0,
NEU_HTTP_HANDLER_DIRECTORY,
NEU_HTTP_HANDLER_PROXY,
NEU_HTTP_HANDLER_REDIRECT,
};
struct neu_http_handler {
enum neu_http_method method;
char * url;
enum neu_http_handler_type type;
union neu_http_handler_value {
void *handler;
char *path;
char *dst_url;
} value;
};
int neu_http_add_handler(nng_http_server * server,
const struct neu_http_handler *http_handler);
void neu_http_handle_cors(nng_aio *aio);
int neu_http_proxy_handler(const struct neu_http_handler *http_handler,
nng_http_handler ** handler);
#endif
+39 -72
View File
@@ -21,36 +21,11 @@ config_ **/
#define _NEU_LOG_H_
#include <inttypes.h>
#include <memory.h>
#include "utils/zlog.h"
#include "define.h"
extern zlog_category_t *neuron;
inline static const char *log_level_to_str(int level)
{
switch (level) {
case ZLOG_LEVEL_FATAL:
return NEU_LOG_LEVEL_FATAL;
case ZLOG_LEVEL_ERROR:
return NEU_LOG_LEVEL_ERROR;
case ZLOG_LEVEL_WARN:
return NEU_LOG_LEVEL_WARN;
case ZLOG_LEVEL_NOTICE:
return NEU_LOG_LEVEL_NOTICE;
case ZLOG_LEVEL_INFO:
return NEU_LOG_LEVEL_INFO;
case ZLOG_LEVEL_DEBUG:
return NEU_LOG_LEVEL_DEBUG;
default:
return "UNKNOWN";
}
}
#define nlog_level_change(level) zlog_level_switch(neuron, level)
#define nlog_fatal(...) \
zlog(neuron, __FILE__, sizeof(__FILE__) - 1, __func__, \
sizeof(__func__) - 1, __LINE__, ZLOG_LEVEL_FATAL, __VA_ARGS__)
@@ -89,54 +64,46 @@ inline static const char *log_level_to_str(int level)
zlog((plugin)->common.log, __FILE__, sizeof(__FILE__) - 1, __func__, \
sizeof(__func__) - 1, __LINE__, ZLOG_LEVEL_DEBUG, __VA_ARGS__)
enum neu_protocol_log_type {
NEU_PROTOCOL_SEND,
NEU_PROTOCOL_RECV,
};
#define plog_send_protocol(plugin, bytes, n_byte) \
static __thread char log_protocol_buf[65535] = { 0 }; \
int log_offset = 0; \
uint16_t tmp_n_byte = n_byte; \
memset(log_protocol_buf, 0, sizeof(log_protocol_buf)); \
log_offset = snprintf(log_protocol_buf, sizeof(log_protocol_buf), \
">>(%d)", tmp_n_byte); \
for (int i = 0; i < n_byte; i++) { \
log_offset += snprintf(log_protocol_buf + log_offset, \
sizeof(log_protocol_buf) - log_offset, \
" 0x%02hhX", (bytes)[i]); \
} \
plog_debug(plugin, "%s", log_protocol_buf);
inline static void zlog_protocol(zlog_category_t *log, uint8_t *bytes,
uint16_t n_byte,
enum neu_protocol_log_type type)
{
static __thread char buf[2048] = { 0 };
int offset = 0;
#define plog_recv_protocol(plugin, bytes, n_byte) \
static __thread char log_protocol_buf[65535] = { 0 }; \
int log_offset = 0; \
uint16_t tmp_n_byte = n_byte; \
memset(log_protocol_buf, 0, sizeof(log_protocol_buf)); \
log_offset = snprintf(log_protocol_buf, sizeof(log_protocol_buf), \
"<<(%d)", tmp_n_byte); \
for (int i = 0; i < n_byte; i++) { \
log_offset += snprintf(log_protocol_buf + log_offset, \
sizeof(log_protocol_buf) - log_offset, \
" 0x%02hhX", (bytes)[i]); \
} \
plog_debug(plugin, "%s", log_protocol_buf);
memset(buf, 0, sizeof(buf));
if (type == NEU_PROTOCOL_SEND) {
offset = snprintf(buf, sizeof(buf) - 1, ">>(%d)", n_byte);
} else {
offset = snprintf(buf, sizeof(buf) - 1, "<<(%d)", n_byte);
}
for (int i = 0; i < n_byte; i++) {
if (sizeof(buf) > (size_t) offset && sizeof(buf) - offset > 10) {
int s_ret = snprintf(buf + offset, sizeof(buf) - offset - 1,
" 0x%02hhX", bytes[i]);
if (s_ret > 0) {
offset += s_ret;
} else {
break;
}
} else {
break;
}
}
zlog_debug(log, "%s", buf);
}
#define zlog_send_protocol(log, bytes, n_byte) \
zlog_protocol(log, (uint8_t *) bytes, n_byte, NEU_PROTOCOL_SEND)
#define zlog_recv_protocol(log, bytes, n_byte) \
zlog_protocol(log, (uint8_t *) bytes, n_byte, NEU_PROTOCOL_RECV)
#define plog_recv_protocol(plugin, bytes, n_byte) \
zlog_recv_protocol((plugin)->common.log, bytes, n_byte)
#define plog_send_protocol(plugin, bytes, n_byte) \
zlog_send_protocol((plugin)->common.log, bytes, n_byte)
void remove_logs(const char *node);
#define zlog_recv_protocol(log, bytes, n_byte) \
static __thread char log_protocol_buf[65535] = { 0 }; \
int log_offset = 0; \
uint16_t tmp_n_byte = n_byte; \
memset(log_protocol_buf, 0, sizeof(log_protocol_buf)); \
log_offset = snprintf(log_protocol_buf, sizeof(log_protocol_buf), \
"<<(%d)", tmp_n_byte); \
for (int i = 0; i < n_byte; i++) { \
log_offset += snprintf(log_protocol_buf + log_offset, \
sizeof(log_protocol_buf) - log_offset, \
" 0x%02hhX", (bytes)[i]); \
} \
zlog_debug(log, "%s", log_protocol_buf);
#endif
-26
View File
@@ -35,13 +35,6 @@ typedef struct {
uint16_t offset;
} neu_protocol_buf_t, neu_protocol_pack_buf_t, neu_protocol_unpack_buf_t;
/**
* @brief Initialization of protocol_pack_buf.
*
* @param[in] buf neu_protocol_pack_buf_t to be initialized.
* @param[in] base Memory used in protocol_pack_buf.
* @param[in] size Size of base memory.
*/
inline static void neu_protocol_pack_buf_init(neu_protocol_pack_buf_t *buf,
uint8_t *base, uint16_t size)
{
@@ -50,13 +43,6 @@ inline static void neu_protocol_pack_buf_init(neu_protocol_pack_buf_t *buf,
buf->offset = size;
}
/**
* @brief Initialization of protocol_unpack_buf.
*
* @param[in] buf neu_protocol_unpack_buf_t to be initialized.
* @param[in] base Memory used in protocol_unpack_buf.
* @param[in] size Size of base memory.
*/
inline static void neu_protocol_unpack_buf_init(neu_protocol_unpack_buf_t *buf,
uint8_t *base, uint16_t size)
{
@@ -192,16 +178,4 @@ neu_protocol_unpack_buf_used_size(neu_protocol_unpack_buf_t *buf)
return buf->offset;
}
inline static void
neu_protocol_unpack_buf_use_all(neu_protocol_unpack_buf_t *buf)
{
buf->offset = buf->size;
}
inline static uint16_t
neu_protocol_unpack_buf_size(neu_protocol_unpack_buf_t *buf)
{
return buf->size;
}
#endif
-51
View File
@@ -1,51 +0,0 @@
/**
* NEURON IIoT System for Industry 4.0
* Copyright (C) 2020-2022 EMQ Technologies Co., Ltd All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
**/
#ifndef __NEU_TIME_H__
#define __NEU_TIME_H__
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <stdlib.h>
#include <sys/time.h>
#include <time.h>
static inline int64_t neu_time_ms()
{
struct timeval tv = { 0 };
gettimeofday(&tv, NULL);
return (int64_t) tv.tv_sec * 1000 + (int64_t) tv.tv_usec / 1000;
}
static inline void neu_msleep(unsigned msec)
{
struct timespec tv = {
.tv_sec = msec / 1000,
.tv_nsec = (msec % 1000) * 1000000,
};
nanosleep(&tv, NULL);
}
#ifdef __cplusplus
}
#endif
#endif
+3 -36
View File
@@ -33,25 +33,12 @@ static inline UT_array *utarray_clone(UT_array *array)
result->i = array->i;
result->n = array->n;
result->icd = array->icd;
if (array->n > 0) {
result->d = (char *) calloc(1, array->n * array->icd.sz);
memcpy(result->d, array->d, array->n * array->icd.sz);
} else {
result->d = NULL;
}
result->d = (char *) calloc(1, array->n * array->icd.sz);
memcpy(result->d, array->d, array->n * array->icd.sz);
return result;
}
static inline void *utarray_steal(UT_array *array)
{
void *data = array->d;
array->i = 0;
array->n = 0;
array->d = NULL;
return data;
}
#define utarray_foreach(array, type, elem) \
for (type elem = (type) utarray_front(array); elem != NULL; \
elem = (type) utarray_next(array, elem))
@@ -71,24 +58,4 @@ static inline void *utarray_steal(UT_array *array)
#define DL_REVERSE_FOREACH_END(head, tail, el) \
while (((el) = (el)->prev) != (head))
#ifdef NO_DECLTYPE
#define HASH_LOOP(hh, head, el) \
for ((el) = (head); (el) != NULL; \
(*(char **) (&(el))) = (char *) (el)->hh.next)
#else
#define HASH_LOOP(hh, head, el) \
for ((el) = (head); (el) != NULL; (el) = DECLTYPE(el)((el)->hh.next))
#endif
static inline UT_array *utarray_deep_clone(UT_array *array)
{
UT_array *result = NULL;
utarray_new(result, &array->icd);
utarray_foreach(array, void *, elem) { utarray_push_back(result, elem); }
return result;
}
#endif
#endif
Executable
+86
View File
@@ -0,0 +1,86 @@
#!/bin/bash
set -e
compiler_prefix="x86_64-linux-gnu"
dir="/usr/local/"
install_dir=
arch=x86_64
while getopts ":c:d:a:" OPT; do
case ${OPT} in
a)
arch=$OPTARG
;;
c)
compiler_prefix=$OPTARG
;;
d)
dir=$OPTARG
;;
esac
done
install_dir=${dir}/${compiler_prefix}
#$1 rep
#$2 tag
#$3 compile option
function compile_source() {
git clone https://github.com/$1 tmp
cd tmp
git checkout -b br $2
mkdir build && cd build
cmake .. -DCMAKE_C_COMPILER=${compiler_prefix}-gcc \
-DCMAKE_CXX_COMPILER=${compiler_prefix}-g++ \
-DCMAKE_STAGING_PREFIX=${install_dir} \
-DCMAKE_PREFIX_PATH=${install_dir} \
$3
# github-hosted runners has 2 core
make -j4 && sudo make install
cd ../../
rm -rf tmp
}
function build_openssl() {
echo "Installing openssl (1.1.1)"
if [ $compiler_prefix == "x86_64-linux-gnu" ]; then
sudo apt-get install -y openssl libssl-dev
else
git clone -b OpenSSL_1_1_1 https://github.com/openssl/openssl.git
cd openssl
mkdir -p ${install_dir}/openssl/ssl
./Configure linux-${arch} no-asm shared \
--prefix=${install_dir}/ \
--openssldir=${install_dir}/openssl/ssl \
--cross-compile-prefix=${compiler_prefix}-
make clean
make -j4
make install_sw
make clean
cd ../
fi
}
function build_zlog() {
git clone -b 1.2.15 https://github.com/HardySimpson/zlog.git
cd zlog
make CC=${compiler_prefix}-gcc
if [ $compiler_prefix == "x86_64-linux-gnu" ]; then
sudo make install
sudo make PREFIX=${install_dir} install
else
sudo make PREFIX=${install_dir} install
fi
}
build_zlog
compile_source akheron/jansson.git v2.14 "-DJANSSON_BUILD_DOCS=OFF -DJANSSON_EXAMPLES=OFF"
build_openssl
compile_source neugates/nng.git HEAD "-DBUILD_SHARED_LIBS=OFF -DNNG_TESTS=OFF"
compile_source benmcollins/libjwt.git v1.13.1 "-DENABLE_PIC=ON -DBUILD_SHARED_LIBS=OFF"
compile_source neugates/MQTT-C.git HEAD "-DCMAKE_POSITION_INDEPENDENT_CODE=ON -DMQTT_C_OpenSSL_SUPPORT=ON -DMQTT_C_EXAMPLES=OFF"
if [ $compiler_prefix == "x86_64-linux-gnu" ]; then
compile_source google/googletest.git release-1.11.0
fi
Executable
+398
View File
@@ -0,0 +1,398 @@
#!/usr/bin/env python3
import argparse
import os
import re
import sqlite3
import operator
import json
VERBOSE = False
def log(message):
if VERBOSE:
print(message)
def parse_args():
"""Parse command line arguments."""
parser = argparse.ArgumentParser()
parser.add_argument("-v", "--verbose", action="count", help="verbosity")
parser.add_argument("-d", "--data_dir", type=str, help="data directory")
subparsers = parser.add_subparsers(
dest="subcommand", help="supported subcommands"
)
show_parser = subparsers.add_parser("show")
import_parser = subparsers.add_parser("import")
up_parser = subparsers.add_parser("up")
return parser.parse_args()
class Migration:
def __init__(self, database_dir="persistence", database_name="sqlite.db"):
try:
database_path = os.path.join(database_dir, database_name)
conn = sqlite3.connect(database_path)
except Exception as e:
log("Connecting database `{}` fail, {}".format(database_path, e))
raise e
self.conn_ = conn
self.cursor_ = self.conn_.cursor()
self.database_dir_ = database_dir
self.database_name_ = database_name
log("Creating migrations table if not exists")
self.ensure_migrations_table_exists()
def ensure_migrations_table_exists(self):
"""Create migration table if not exists."""
self.cursor_.execute(
"""
CREATE TABLE IF NOT EXISTS migrations (
migration_id INTEGER PRIMARY KEY,
version TEXT NOT NULL UNIQUE,
description TEXT NOT NULL,
dirty INTEGER NOT NULL,
created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP)
"""
)
def head(self):
"""Read the current version from the database"""
log("Reading migration head version")
self.cursor_.execute(
"SELECT version, description, dirty, created_at FROM migrations"
" ORDER BY migration_id DESC LIMIT 1"
)
row = self.cursor_.fetchone()
if not row:
return {
"version": None,
"description": None,
"dirty": None,
"created_at": None,
}
return {
"version": row[0],
"description": row[1],
"dirty": row[2],
"created_at": row[3],
}
def print_head(self):
head = self.head()
if not head["version"]:
print("No version.")
return
print(
"Version: {}, ({} {})".format(
head["version"], head["created_at"], head["description"]
)
)
if head["dirty"]:
print("Warning: the migration database is dirty")
def get_migration_info(self, file_name):
"""Extract the migration info from migration file name."""
match = re.search(
"(?P<version>[^_]*)_?(?P<description>.*)\\.sql",
file_name,
re.IGNORECASE,
)
if not match:
return {"version": None, "description": None}
return {
"version": match.group("version"),
"description": match.group("description"),
}
def should_apply(self, migration_filename: str, target_version=None):
"""Check whether to apply the migration file."""
head = self.head()
current_version = head["version"] or ""
if target_version and target_version == current_version:
# already on the target version, don't apply the migration
return False
# extract the proposed version from the migration filename
proposed_version = self.get_migration_info(migration_filename)[
"version"
]
if not proposed_version:
# does not have a valid version in the name
return False
if proposed_version <= current_version:
return False
if target_version and proposed_version > target_version:
return False
return True
def apply(self):
"""Migrate to the latest state."""
head = self.head()
if head["dirty"]:
print("Latest version is dirty, please tune manually.")
return
migration_filenames = list(
filter(self.should_apply, os.listdir(self.database_dir_))
)
# Sort the migrations based on the version encoded in the filename
migration_filenames.sort()
for migration_filename in migration_filenames:
print("Applying migration " + migration_filename)
info = self.get_migration_info(migration_filename)
self.cursor_.execute(
"""INSERT INTO migrations (version, description, dirty)
VALUES (?, ?, 1)""",
(
info["version"],
info["description"],
),
)
self.conn_.commit()
with open(
os.path.join(self.database_dir_, migration_filename), "r"
) as f:
sql = f.read()
self.cursor_.executescript(sql)
self.cursor_.execute(
"UPDATE migrations SET dirty = 0 WHERE migration_id = ?",
(self.cursor_.lastrowid,),
)
self.conn_.commit()
def import_json(self):
node_group_names = self.find_json_importable_node_and_group_names()
node_names = self.find_json_importable_node_names()
# 1.
# self.import_plugins_json()
# 2.
self.import_nodes_json(node_names)
# 3.
self.import_settings_json(node_names)
# 4.
self.import_groups_json(node_group_names)
# 5.
self.import_tags_json(node_group_names)
# 6.
self.import_subscritions_json(node_names)
def import_plugins_json(self):
"""Import data from persistence JSON files."""
plugin_file = os.path.join(self.database_dir_, "plugins.json")
if not os.path.exists(plugin_file):
return
data = json.load(open(plugin_file, "r"))
for library in data["plugins"]:
log("Import library {}".format(library))
self.cursor_.execute(
"INSERT INTO plugins (library) VALUES (?)", (library,)
)
self.conn_.commit()
def import_nodes_json(self, node_names):
"""Import nodes data from persistence JSON files."""
adapter_file = os.path.join(self.database_dir_, "adapters.json")
if os.path.exists(adapter_file):
data = json.load(open(adapter_file, "r"))
for node in data["nodes"]:
log("Import node {}".format(node))
self.cursor_.execute(
"""INSERT INTO nodes (name, type, state, plugin_name)
VALUES (?, ?, ?, ?)""",
(
node["name"],
node["type"],
node["state"],
node["plugin_name"],
),
)
self.conn_.commit()
for node_name in node_names:
adapter_file = os.path.join(
self.database_dir_, "adapters", node_name, "adapter.json"
)
if not os.path.exists(adapter_file):
continue
data = json.load(open(adapter_file, "r"))
log("Import node {}".format(data))
self.cursor_.execute(
"""INSERT INTO nodes (name, type, state, plugin_name)
VALUES (?, ?, ?, ?)""",
(
data["name"],
data["type"],
data["state"],
data["plugin_name"],
),
)
self.conn_.commit()
def import_settings_json(self, node_names):
"""Import node settings from persistence JSON files."""
for node_name in node_names:
settings_file = os.path.join(
self.database_dir_, "adapters", node_name, "settings.json"
)
if not os.path.exists(settings_file):
continue
data = open(settings_file, "r").read()
log("Import setting {}".format(data))
self.cursor_.execute(
"INSERT INTO settings (node_name, setting) VALUES(?, ?)",
(node_name, data),
)
self.conn_.commit()
def import_groups_json(self, node_group_names):
"""Import node groups from persistence JSON files."""
for node_name, group_name in node_group_names:
group_file = os.path.join(
self.database_dir_,
"adapters",
node_name,
"groups",
group_name,
"config.json",
)
if not os.path.exists(group_file):
continue
data = json.load(open(group_file, "r"))
log("Import group {}".format(data))
self.cursor_.execute(
"""INSERT INTO groups (driver_name, name, interval)
VALUES (?, ?, ?)""",
(node_name, group_name, data["read_interval"]),
)
self.conn_.commit()
def import_tags_json(self, node_group_names):
"""Import node tags from persistence JSON files."""
for node_name, group_name in node_group_names:
tags_file = os.path.join(
self.database_dir_,
"adapters",
node_name,
"groups",
group_name,
"datatags.json",
)
if not os.path.exists(tags_file):
continue
data = json.load(open(tags_file, "r"))
for tag in data["tags"]:
log("Import tag {}".format(tag))
self.cursor_.execute(
"""INSERT INTO tags (driver_name, group_name, name, address,
attribute, type, description)
VALUES (?, ?, ?, ?, ?, ?, ?)""",
(
node_name,
group_name,
tag["name"],
tag["address"],
tag["attribute"],
tag["type"],
tag.get("description", ""),
),
)
self.conn_.commit()
def import_subscritions_json(self, node_names):
"""Import subscriptions from persistence JSON files."""
for node_name in node_names:
subscription_file = os.path.join(
self.database_dir_, "adapters", node_name, "subscriptions.json"
)
if not os.path.exists(subscription_file):
continue
data = json.load(open(subscription_file, "r"))
for subscription in data["subscriptions"]:
log("Import subscription {}".format(subscription))
self.cursor_.execute(
"""INSERT INTO subscriptions (
app_name, driver_name, group_name
) VALUES(?, ?, ?)""",
(
subscription["sub_adapter_name"],
subscription["src_adapter_name"],
subscription["group_config_name"],
),
)
self.conn_.commit()
def find_json_importable_node_names(self):
"""Find node names from persistence directory."""
adapters_dir = os.path.join(self.database_dir_, "adapters")
return (
list(os.listdir(adapters_dir))
if os.path.exists(adapters_dir)
else []
)
def find_json_importable_node_and_group_names(self):
"""Find node names and group names from persistence directory."""
res = []
adapters_dir = os.path.join(self.database_dir_, "adapters")
if not os.path.exists(adapters_dir):
return res
for adapter_name in os.listdir(adapters_dir):
groups_dir = os.path.join(adapters_dir, adapter_name, "groups")
if not os.path.exists(groups_dir):
continue
for group_name in os.listdir(groups_dir):
res.append((adapter_name, group_name))
return res
if __name__ == "__main__":
args = parse_args()
VERBOSE = args.verbose
migrations = Migration(database_dir=args.data_dir)
if args.subcommand == "import":
migrations.import_json()
elif args.subcommand == "show":
migrations.print_head()
elif args.subcommand == "up":
migrations.apply()
-7
View File
@@ -1,7 +0,0 @@
{
"ip": "0.0.0.0",
"port": 7000,
"disable_auth": 0,
"syslog_host": "",
"syslog_port": 541
}
+1 -13
View File
@@ -35,39 +35,27 @@ mkdir -p $package_name/lib
mkdir -p $package_name/config
mkdir -p $package_name/plugins/schema
cp sdk-install.sh ${package_name}/
cp neuron.conf ${package_name}/
cp cmake/neuron-config.cmake ${package_name}/
cp -r include/* ${package_name}/include/
cp -r build/dist ${package_name}/
cp build/neuron ${package_name}
cp build/libneuron-base.so ${package_name}/lib
cp /usr/local/lib/libzlog.so.1.2 ${package_name}/lib
cp zlog/src/libzlog.so.1.2 ${package_name}/lib
cp persistence/*.sql ${package_name}/config/
cp sdk-zlog.conf ${package_name}/config/
cp zlog.conf ${package_name}/config/
cp dev.conf ${package_name}/config/
cp neuron.key ${package_name}/config/
cp neuron.pem ${package_name}/config/
cp default_plugins.json ${package_name}/config/
cp neuron.json ${package_name}/config/
cp build/plugins/schema/ekuiper.json \
build/plugins/schema/monitor.json \
build/plugins/schema/mqtt.json \
build/plugins/schema/modbus-tcp.json \
build/plugins/schema/file.json \
${package_name}/plugins/schema/
cp build/plugins/libplugin-ekuiper.so \
build/plugins/libplugin-monitor.so \
build/plugins/libplugin-mqtt.so \
build/plugins/libplugin-modbus-tcp.so \
build/plugins/libplugin-file.so \
${package_name}/plugins/
tar czf ${package_name}-${arch}.tar.gz ${package_name}/
@@ -17,61 +17,60 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
**/
--- Add plugins table ---
CREATE TABLE IF NOT EXISTS
CREATE TABLE
plugins (library TEXT PRIMARY KEY check(length(library) <= 32));
--- Add adapters table ---
CREATE TABLE IF NOT EXISTS
CREATE TABLE
nodes (
name TEXT PRIMARY KEY check(length(name) <= 32),
type integer(1) NOT NULL check(type IN (1, 2)),
state integer(1) NOT NULL check(state BETWEEN 1 AND 4),
type integer(1) NOT NULL check(TYPE IN (1, 2)),
state integer(1) NOT NULL check(state BETWEEN 0 AND 4),
plugin_name TEXT NOT NULL check(length(plugin_name) <= 32)
);
--- Add settings table ---
CREATE TABLE IF NOT EXISTS
CREATE TABLE
settings (
node_name TEXT NOT NULL,
setting TEXT NOT NULL,
UNIQUE (node_name),
FOREIGN KEY (node_name) REFERENCES nodes (name) ON UPDATE CASCADE ON DELETE CASCADE
);
--- Add groups table ---
CREATE TABLE IF NOT EXISTS
CREATE TABLE
groups (
driver_name TEXT NOT NULL,
name TEXT NULL check(length(name) <= 32),
name NOT NULL check(length(name) <= 32),
interval INTEGER NOT NULL check(interval >= 100),
UNIQUE (driver_name, name),
FOREIGN KEY (driver_name) REFERENCES nodes (name) ON UPDATE CASCADE ON DELETE CASCADE
);
--- Add tags table ---
CREATE TABLE IF NOT EXISTS
CREATE TABLE
tags (
driver_name TEXT NOT NULL,
group_name TEXT NOT NULL,
name TEXT NULL check(length(name) <= 32),
address TEXT NULL check(length(address) <= 64),
name NOT NULL UNIQUE check(length(name) <= 32),
address NOT NULL check(length(address) <= 64),
attribute INTEGER NOT NULL check(attribute BETWEEN 0 AND 7),
precision INTEGER NOT NULL check(precision BETWEEN 0 AND 17),
decimal REAL NOT NULL,
type INTEGER NOT NULL check(type BETWEEN 0 AND 15),
description TEXT NULL check(length(description) <= 128),
description NOT NULL check(length(description) <= 128),
UNIQUE (driver_name, group_name, name),
FOREIGN KEY (driver_name, group_name) REFERENCES groups (driver_name, name) ON UPDATE CASCADE ON DELETE CASCADE
FOREIGN KEY (driver_name) REFERENCES nodes (name) ON UPDATE CASCADE ON DELETE CASCADE,
FOREIGN KEY (group_name) REFERENCES groups (name) ON UPDATE CASCADE ON DELETE CASCADE
);
--- Add subscriptions table ---
CREATE TABLE IF NOT EXISTS
CREATE TABLE
subscriptions (
app_name TEXT NOT NULL,
driver_name TEXT NOT NULL,
group_name TEXT NOT NULL,
group_name INTEGER NOT NULL,
CHECK (app_name != driver_name),
UNIQUE (app_name, driver_name, group_name),
FOREIGN KEY (app_name) REFERENCES nodes (name) ON UPDATE CASCADE ON DELETE CASCADE,
FOREIGN KEY (driver_name, group_name) REFERENCES groups (driver_name, name) ON UPDATE CASCADE ON DELETE CASCADE
FOREIGN KEY (driver_name) REFERENCES nodes (name) ON UPDATE CASCADE ON DELETE CASCADE,
FOREIGN KEY (group_name) REFERENCES groups (name) ON UPDATE CASCADE ON DELETE CASCADE
);
-103
View File
@@ -1,103 +0,0 @@
/**
* NEURON IIoT System for Industry 4.0
* Copyright (C) 2020-2022 EMQ Technologies Co., Ltd All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
**/
--- Add users table ---
CREATE TABLE
IF NOT EXISTS users (
name TEXT PRIMARY KEY check(length(name) <= 32),
password TEXT NOT NULL
);
--- Default admin user ---
INSERT INTO
users (name, password)
VALUES
(
"admin",
"$5$PwFeXpBBIBZuZdZl$fP8fFPWCLoaWcnVXVSR.3Xi8TEqCvX92gjhowNNn6S4"
);
BEGIN TRANSACTION;
ALTER TABLE nodes RENAME TO old_nodes;
CREATE TABLE
nodes (
name TEXT PRIMARY KEY check(length(name) <= 128),
type integer(1) NOT NULL check(type IN (1, 2)),
state integer(1) NOT NULL check(state BETWEEN 1 AND 4),
plugin_name TEXT NOT NULL check(length(plugin_name) <= 32)
);
INSERT INTO nodes SELECT * FROM old_nodes;
ALTER TABLE groups RENAME TO old_groups;
CREATE TABLE IF NOT EXISTS
groups (
driver_name TEXT NOT NULL,
name TEXT NULL check(length(name) <= 128),
interval INTEGER NOT NULL check(interval >= 100),
UNIQUE (driver_name, name),
FOREIGN KEY (driver_name) REFERENCES nodes (name) ON UPDATE CASCADE ON DELETE CASCADE
);
INSERT INTO groups SELECT * FROM old_groups;
ALTER TABLE tags RENAME TO old_tags;
CREATE TABLE IF NOT EXISTS
tags (
driver_name TEXT NOT NULL,
group_name TEXT NOT NULL,
name TEXT NULL check(length(name) <= 64),
address TEXT NULL check(length(address) <= 128),
attribute INTEGER NOT NULL check(attribute BETWEEN 0 AND 7),
precision INTEGER NOT NULL check(precision BETWEEN 0 AND 17),
decimal REAL NOT NULL,
type INTEGER NOT NULL check(type BETWEEN 0 AND 19),
description TEXT NULL check(length(description) <= 128),
UNIQUE (driver_name, group_name, name),
FOREIGN KEY (driver_name, group_name) REFERENCES groups (driver_name, name) ON UPDATE CASCADE ON DELETE CASCADE
);
INSERT INTO tags SELECT * FROM old_tags;
ALTER TABLE subscriptions RENAME TO old_subscriptions;
CREATE TABLE IF NOT EXISTS
subscriptions (
app_name TEXT NOT NULL,
driver_name TEXT NOT NULL,
group_name TEXT NOT NULL,
CHECK (app_name != driver_name),
UNIQUE (app_name, driver_name, group_name),
FOREIGN KEY (app_name) REFERENCES nodes (name) ON UPDATE CASCADE ON DELETE CASCADE,
FOREIGN KEY (driver_name, group_name) REFERENCES groups (driver_name, name) ON UPDATE CASCADE ON DELETE CASCADE
);
INSERT INTO subscriptions SELECT * FROM old_subscriptions;
ALTER TABLE settings RENAME TO old_settings;
CREATE TABLE IF NOT EXISTS
settings (
node_name TEXT NOT NULL,
setting TEXT NOT NULL,
UNIQUE (node_name),
FOREIGN KEY (node_name) REFERENCES nodes (name) ON UPDATE CASCADE ON DELETE CASCADE
);
INSERT INTO settings SELECT * FROM old_settings;
CREATE TABLE IF NOT EXISTS
node_cache (
node_name TEXT NOT NULL,
cache TEXT NOT NULL
);
COMMIT;
-36
View File
@@ -1,36 +0,0 @@
/**
* NEURON IIoT System for Industry 4.0
* Copyright (C) 2020-2023 EMQ Technologies Co., Ltd All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
**/
--- fix primary key ---
BEGIN;
DROP TABLE IF EXISTS old_node_cache;
ALTER TABLE node_cache RENAME TO old_node_cache;
CREATE TABLE IF NOT EXISTS node_cache (
node_name TEXT PRIMARY KEY,
CACHE TEXT NOT NULL,
FOREIGN KEY (node_name) REFERENCES nodes (name) ON UPDATE CASCADE ON DELETE CASCADE
);
INSERT OR REPLACE INTO node_cache SELECT * FROM old_node_cache;
DROP TABLE old_node_cache;
COMMIT;
@@ -1,53 +0,0 @@
/**
* NEURON IIoT System for Industry 4.0
* Copyright (C) 2020-2023 EMQ Technologies Co., Ltd All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
**/
BEGIN TRANSACTION;
DROP TABLE
IF EXISTS old_subscriptions;
ALTER TABLE
subscriptions RENAME TO old_subscriptions;
-- add column params for subscription parameters
CREATE TABLE
IF NOT EXISTS subscriptions (
app_name TEXT NOT NULL,
driver_name TEXT NOT NULL,
group_name TEXT NOT NULL,
params TEXT DEFAULT NULL,
CHECK (app_name != driver_name),
UNIQUE (app_name, driver_name, group_name),
FOREIGN KEY (app_name) REFERENCES nodes (name) ON UPDATE CASCADE ON DELETE CASCADE,
FOREIGN KEY (driver_name, group_name) REFERENCES groups (driver_name, name) ON UPDATE CASCADE ON DELETE CASCADE
);
INSERT INTO
subscriptions
SELECT
app_name,
driver_name,
group_name,
NULL
FROM
old_subscriptions;
DROP TABLE
old_subscriptions;
COMMIT;
-64
View File
@@ -1,64 +0,0 @@
/**
* NEURON IIoT System for Industry 4.0
* Copyright (C) 2020-2023 EMQ Technologies Co., Ltd All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
**/
BEGIN TRANSACTION;
DROP TABLE
IF EXISTS old_tags;
ALTER TABLE
tags RENAME TO old_tags;
-- alter attribute column constraint for static tags
-- add value column
CREATE TABLE
IF NOT EXISTS tags (
driver_name TEXT NOT NULL,
group_name TEXT NOT NULL,
name TEXT NULL check(length(name) <= 64),
address TEXT NULL check(length(address) <= 128),
attribute INTEGER NOT NULL check(attribute BETWEEN 0 AND 15),
PRECISION INTEGER NOT NULL check(PRECISION BETWEEN 0 AND 17),
decimal REAL NOT NULL,
TYPE INTEGER NOT NULL check(TYPE BETWEEN 0 AND 19),
description TEXT NULL check(length(description) <= 128),
value TEXT DEFAULT NULL,
UNIQUE (driver_name, group_name, name),
FOREIGN KEY (driver_name, group_name) REFERENCES groups (driver_name, name) ON UPDATE CASCADE ON DELETE CASCADE
);
INSERT INTO
tags
SELECT
driver_name,
group_name,
name,
address,
attribute,
PRECISION,
decimal,
TYPE,
description,
NULL
FROM
old_tags;
DROP TABLE
old_tags;
COMMIT;
-48
View File
@@ -1,48 +0,0 @@
/**
* NEURON IIoT System for Industry 4.0
* Copyright (C) 2020-2023 EMQ Technologies Co., Ltd All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
**/
BEGIN TRANSACTION;
-- from neuron version 2.4.0, eKuiper plugin is no more singleton
-- remove default data-stream-processing node if not in use
DELETE FROM
nodes
WHERE
name = 'data-stream-processing'
AND name NOT in (
SELECT
node_name
FROM
settings
)
AND name NOT in (
SELECT
app_name
FROM
subscriptions
);
-- fix data-stream-processing node plugin name
UPDATE
nodes
SET
plugin_name = 'eKuiper'
where
name = 'data-stream-processing';
COMMIT;
-110
View File
@@ -1,110 +0,0 @@
/**
* NEURON IIoT System for Industry 4.0
* Copyright (C) 2020-2023 EMQ Technologies Co., Ltd All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
**/
BEGIN TRANSACTION;
UPDATE nodes
SET plugin_name = 'MQTT'
WHERE plugin_name = 'mqtt';
UPDATE nodes
SET plugin_name = 'eKuiper'
WHERE plugin_name = 'ekuiper';
UPDATE nodes
SET plugin_name = 'SparkPlugB'
WHERE plugin_name = 'sparkplugb';
UPDATE nodes
SET plugin_name = 'Beckhoff ADS'
WHERE plugin_name = 'ads';
UPDATE nodes
SET plugin_name = 'Modbus TCP'
WHERE plugin_name = 'modbus-tcp';
UPDATE nodes
SET plugin_name = 'Modbus RTU'
WHERE plugin_name = 'modbus-rtu';
UPDATE nodes
SET plugin_name = 'Modbus TCP'
WHERE plugin_name = 'modbus-plus-tcp';
UPDATE nodes
SET plugin_name = 'Modbus TCP QH'
WHERE plugin_name = 'modbus-qh-tcp';
UPDATE nodes
SET plugin_name = 'Siemens S7 ISOTCP'
WHERE plugin_name = 's7comm';
UPDATE nodes
SET plugin_name = 'Siemens S7 ISOTCP for 300/400'
WHERE plugin_name = 's7comm_for_300';
UPDATE nodes
SET plugin_name = 'OPC UA'
WHERE plugin_name = 'opcua';
UPDATE nodes
SET plugin_name = 'Omron FINS TCP'
WHERE plugin_name = 'fins';
UPDATE nodes
SET plugin_name = 'Mitsubishi 3E'
WHERE plugin_name = 'qna3e';
UPDATE nodes
SET plugin_name = 'Mitsubishi 1E'
WHERE plugin_name = 'a1e';
UPDATE nodes
SET plugin_name = 'IEC60870-5-104'
WHERE plugin_name = 'iec104';
UPDATE nodes
SET plugin_name = 'BACnet/IP'
WHERE plugin_name = 'bacnet';
UPDATE nodes
SET plugin_name = 'KNXnet/IP'
WHERE plugin_name = 'knx';
UPDATE nodes
SET plugin_name = 'DLT645-2007'
WHERE plugin_name = 'dlt645';
UPDATE nodes
SET plugin_name = 'NON A11'
WHERE plugin_name = 'nona11';
UPDATE nodes
SET plugin_name = 'EtherNet/IP(CIP)'
WHERE plugin_name = 'EtherNet-IP';
UPDATE nodes
SET plugin_name = 'Fanuc Focas Ethernet'
WHERE plugin_name = 'focas';
UPDATE nodes
SET plugin_name = 'File'
WHERE plugin_name = 'file';
COMMIT;
@@ -1,59 +0,0 @@
/**
* NEURON IIoT System for Industry 4.0
* Copyright (C) 2020-2023 EMQ Technologies Co., Ltd All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
**/
BEGIN TRANSACTION;
-- for backward compatibility with version 2.3,
-- migrate MQTT plugin upload-topic to subscription parameters.
WITH
topics AS (
SELECT
name AS app,
json_extract(json(setting), '$.params.upload-topic') AS topic
FROM
nodes
JOIN settings
WHERE
name = node_name
AND plugin_name = 'MQTT'
)
UPDATE
subscriptions
SET
params = (
SELECT
json_object('params', json_object('topic', topic)) AS params
FROM
topics
WHERE
topics.app = subscriptions.app_name
AND topics.topic NOT NULL
)
WHERE
EXISTS (
SELECT
topic
FROM
topics
WHERE
topics.app = subscriptions.app_name
AND topics.topic NOT NULL
AND subscriptions.params IS NULL
);
COMMIT;
-52
View File
@@ -1,52 +0,0 @@
/**
* NEURON IIoT System for Industry 4.0
* Copyright (C) 2020-2023 EMQ Technologies Co., Ltd All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
**/
BEGIN TRANSACTION;
CREATE TABLE
IF NOT EXISTS templates (
name TEXT PRIMARY KEY check(length(name) <= 128),
plugin_name TEXT NOT NULL check(length(plugin_name) <= 32)
);
CREATE TABLE
IF NOT EXISTS template_groups (
tmpl_name TEXT NOT NULL,
name TEXT NULL check(length(name) <= 128),
interval INTEGER NOT NULL check(interval >= 100),
UNIQUE (tmpl_name, name),
FOREIGN KEY (tmpl_name) REFERENCES templates (name) ON UPDATE CASCADE ON DELETE CASCADE
);
CREATE TABLE
IF NOT EXISTS template_tags (
tmpl_name TEXT NOT NULL,
group_name TEXT NOT NULL,
name TEXT NULL check(length(name) <= 64),
address TEXT NULL check(length(address) <= 128),
attribute INTEGER NOT NULL check(attribute BETWEEN 0 AND 15),
PRECISION INTEGER NOT NULL check(PRECISION BETWEEN 0 AND 17),
decimal REAL NOT NULL,
TYPE INTEGER NOT NULL check(TYPE BETWEEN 0 AND 19),
description TEXT NULL check(length(description) <= 128),
value TEXT DEFAULT NULL,
UNIQUE (tmpl_name, group_name, name),
FOREIGN KEY (tmpl_name, group_name) REFERENCES template_groups (tmpl_name, name) ON UPDATE CASCADE ON DELETE CASCADE
);
COMMIT;
-57
View File
@@ -1,57 +0,0 @@
/**
* NEURON IIoT System for Industry 4.0
* Copyright (C) 2020-2023 EMQ Technologies Co., Ltd All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
**/
BEGIN TRANSACTION;
-- For backward compatibility before version 2.5,
-- add parameters to modbus plugin.
UPDATE settings
SET setting = JSON_SET(json(setting), '$.params.transport_mode', 0)
FROM nodes
WHERE
settings.node_name = nodes.name
AND JSON_EXTRACT(json(setting), '$.params.transport_mode') IS NULL
AND (nodes.plugin_name='modbus-qh-tcp' OR nodes.plugin_name='modbus-plus-tcp' OR nodes.plugin_name='modbus-tcp' OR nodes.plugin_name='Modbus TCP' OR nodes.plugin_name='Modbus TCP QH');
UPDATE settings
SET setting = JSON_SET(json(setting), '$.params.connection_mode', 0)
FROM nodes
WHERE
settings.node_name = nodes.name
AND JSON_EXTRACT(json(setting), '$.params.connection_mode') IS NULL
AND (nodes.plugin_name='modbus-qh-tcp' OR nodes.plugin_name='modbus-plus-tcp' OR nodes.plugin_name='modbus-rtu' OR nodes.plugin_name='modbus-tcp' OR nodes.plugin_name='Modbus TCP' OR nodes.plugin_name='Modbus RTU' OR nodes.plugin_name='Modbus TCP QH');
UPDATE settings
SET setting = JSON_SET(json(setting), '$.params.group_interval', 1000)
FROM nodes
WHERE
settings.node_name = nodes.name
AND JSON_EXTRACT(json(setting), '$.params.group_interval') IS NULL
AND (nodes.plugin_name='modbus-qh-tcp' OR nodes.plugin_name='modbus-plus-tcp' OR nodes.plugin_name='modbus-rtu' OR nodes.plugin_name='modbus-tcp' OR nodes.plugin_name='Modbus TCP' OR nodes.plugin_name='Modbus RTU' OR nodes.plugin_name='Modbus TCP QH');
UPDATE settings
SET setting = JSON_SET(json(setting), '$.params.interval', 20)
FROM nodes
WHERE
settings.node_name = nodes.name
AND JSON_EXTRACT(json(setting), '$.params.interval') IS NULL
AND (nodes.plugin_name='modbus-qh-tcp' OR nodes.plugin_name='modbus-plus-tcp' OR nodes.plugin_name='modbus-rtu' OR nodes.plugin_name='modbus-tcp' OR nodes.plugin_name='Modbus TCP' OR nodes.plugin_name='Modbus RTU' OR nodes.plugin_name='Modbus TCP QH');
COMMIT;
-26
View File
@@ -1,26 +0,0 @@
/**
* NEURON IIoT System for Industry 4.0
* Copyright (C) 2020-2023 EMQ Technologies Co., Ltd All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
**/
BEGIN TRANSACTION;
UPDATE nodes
SET plugin_name = 'Mitsubishi FX'
WHERE plugin_name = 'Mitsabishi FX';
COMMIT;
@@ -1,24 +0,0 @@
/**
* NEURON IIoT System for Industry 4.0
* Copyright (C) 2020-2023 EMQ Technologies Co., Ltd All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
**/
BEGIN;
CREATE TABLE
IF NOT EXISTS virtual_license (license TEXT NOT NULL);
COMMIT;
+81
View File
@@ -0,0 +1,81 @@
{
"tag_type": [
4,
5,
6,
7,
8,
9,
10,
11,
14
],
"params": [
"host",
"port",
"mode",
"baud_rate",
"real_param"
],
"host": {
"name": "host",
"description": "host",
"type": "string",
"default": "127.0.0.1",
"valid": {
"length": 30
}
},
"port": {
"name": "port",
"description": "port",
"type": "int",
"default": 502,
"valid": {
"min": 1024,
"max": 65535
}
},
"mode": {
"name": "mode",
"description": "mode",
"type": "bool",
"default": false,
"valid": {}
},
"baud_rate": {
"name": "baud rate",
"description": "port",
"type": "int",
"default": 9600,
"valid": {
"value": [
9600,
112800
]
}
},
"real_param": {
"name": "real param",
"description": "real",
"type": "real",
"default": 11.22,
"valid": {
"min": 1.1,
"max": 20.2
}
},
"ca": {
"name": "ca",
"description": "",
"attribute": "optional",
"type": "file",
"condition": {
"field": "mode",
"value": true
},
"valid": {
"length": 1024
}
}
}
+1 -27
View File
@@ -1,27 +1 @@
{
"host": {
"name": "Local IP Address",
"name_zh": "本地IP地址",
"description": "IP address to listen for connections from eKuiper",
"description_zh": "绑定本地IP地址,等待eKuiper连接",
"attribute": "required",
"type": "string",
"default": "0.0.0.0",
"valid": {
"length": 255
}
},
"port": {
"name": "Local Port",
"name_zh": "本地端口",
"description": "TCP port number to listen for connections from eKuiper",
"description_zh": "绑定本地端口,等待eKuiper连接",
"attribute": "required",
"type": "int",
"default": 7081,
"valid": {
"min": 1024,
"max": 65535
}
}
}
{}
+93 -55
View File
@@ -25,6 +25,81 @@
#include "json_rw.h"
#include "plugin_ekuiper.h"
int wrap_tag_data(neu_json_read_resp_tag_t *json_tag,
neu_resp_tag_value_t * tag_value)
{
if (NULL == json_tag || NULL == tag_value) {
return -1;
}
json_tag->name = tag_value->tag;
json_tag->error = NEU_ERR_SUCCESS;
switch (tag_value->value.type) {
case NEU_TYPE_INT8:
json_tag->t = NEU_JSON_INT;
json_tag->value.val_int = tag_value->value.value.i8;
break;
case NEU_TYPE_UINT8:
json_tag->t = NEU_JSON_INT;
json_tag->value.val_int = tag_value->value.value.u8;
break;
case NEU_TYPE_INT16:
json_tag->t = NEU_JSON_INT;
json_tag->value.val_int = tag_value->value.value.i16;
break;
case NEU_TYPE_UINT16:
json_tag->t = NEU_JSON_INT;
json_tag->value.val_int = tag_value->value.value.u16;
break;
case NEU_TYPE_INT32:
json_tag->t = NEU_JSON_INT;
json_tag->value.val_int = tag_value->value.value.i32;
break;
case NEU_TYPE_UINT32:
json_tag->t = NEU_JSON_INT;
json_tag->value.val_int = tag_value->value.value.u32;
break;
case NEU_TYPE_INT64:
json_tag->t = NEU_JSON_INT;
json_tag->value.val_int = tag_value->value.value.i64;
break;
case NEU_TYPE_UINT64:
json_tag->t = NEU_JSON_INT;
json_tag->value.val_int = tag_value->value.value.u64;
break;
case NEU_TYPE_FLOAT:
json_tag->t = NEU_JSON_FLOAT;
json_tag->value.val_float = tag_value->value.value.f32;
break;
case NEU_TYPE_DOUBLE:
json_tag->t = NEU_JSON_DOUBLE;
json_tag->value.val_double = tag_value->value.value.d64;
break;
case NEU_TYPE_BIT:
json_tag->t = NEU_JSON_BIT;
json_tag->value.val_bit = tag_value->value.value.u8;
break;
case NEU_TYPE_BOOL:
json_tag->t = NEU_JSON_BOOL;
json_tag->value.val_bool = tag_value->value.value.boolean;
break;
case NEU_TYPE_STRING:
json_tag->t = NEU_JSON_STR;
json_tag->value.val_str = tag_value->value.value.str;
break;
case NEU_TYPE_ERROR:
json_tag->t = NEU_JSON_INT;
json_tag->value.val_int = tag_value->value.value.i32;
json_tag->error = tag_value->value.value.i32;
break;
default:
break;
}
return 0;
}
int json_encode_read_resp_header(void *json_object, void *param)
{
int ret = 0;
@@ -59,90 +134,53 @@ int json_encode_read_resp_tags(void *json_object, void *param)
neu_reqresp_trans_data_t *trans_data = resp->trans_data;
void * values_object = NULL;
void * errors_object = NULL;
void * metas_object = NULL;
metas_object = neu_json_encode_new();
if (NULL == metas_object) {
plog_error(plugin, "ekuiper cannot allocate json object");
return -1;
}
values_object = neu_json_encode_new();
if (NULL == values_object) {
plog_error(plugin, "ekuiper cannot allocate json object");
json_decref(metas_object);
return -1;
}
errors_object = neu_json_encode_new();
if (NULL == errors_object) {
plog_error(plugin, "ekuiper cannot allocate json object");
json_decref(values_object);
json_decref(metas_object);
return -1;
}
utarray_foreach(trans_data->tags, neu_resp_tag_value_meta_t *, tag_value)
{
for (int i = 0; i < trans_data->n_tag; i++) {
neu_json_read_resp_tag_t json_tag = { 0 };
neu_tag_value_to_json(tag_value, &json_tag);
if (0 != wrap_tag_data(&json_tag, &trans_data->tags[i])) {
continue; // ignore
}
neu_json_elem_t tag_elem = {
.name = json_tag.name,
.t = json_tag.t,
.v = json_tag.value,
.precision = tag_value->value.precision,
.name = json_tag.name,
.t = json_tag.t,
.v = json_tag.value,
};
if (json_tag.n_meta > 0) {
void *meta = neu_json_encode_new();
for (int k = 0; k < json_tag.n_meta; k++) {
neu_json_elem_t meta_elem = {
.name = json_tag.metas[k].name,
.t = json_tag.metas[k].t,
.v = json_tag.metas[k].value,
};
neu_json_encode_field(meta, &meta_elem, 1);
}
neu_json_elem_t meta_elem = {
.name = json_tag.name,
.t = NEU_JSON_OBJECT,
.v.val_object = meta,
};
neu_json_encode_field(metas_object, &meta_elem, 1);
free(json_tag.metas);
}
ret = neu_json_encode_field((0 != json_tag.error) ? errors_object
: values_object,
&tag_elem, 1);
if (0 != ret) {
json_decref(errors_object);
json_decref(values_object);
json_decref(metas_object);
return ret;
}
}
neu_json_elem_t resp_elems[] = {
{
.name = "values",
.t = NEU_JSON_OBJECT,
.v.val_object = values_object,
},
{
.name = "errors",
.t = NEU_JSON_OBJECT,
.v.val_object = errors_object,
neu_json_elem_t resp_elems[] = { {
.name = "values",
.t = NEU_JSON_OBJECT,
.v.val_object = values_object,
},
{
.name = "errors",
.t = NEU_JSON_OBJECT,
.v.val_object = errors_object,
},
{
.name = "metas",
.t = NEU_JSON_OBJECT,
.v.val_object = metas_object,
},
};
} };
// steals `values_object` and `errors_object`
ret = neu_json_encode_field(json_object, resp_elems,
NEU_JSON_ELEM_SIZE(resp_elems));
@@ -159,7 +197,7 @@ int json_encode_read_resp(void *json_object, void *param)
json_read_resp_header_t header = { .group_name = trans_data->group,
.node_name = trans_data->driver,
.timestamp = global_timestamp };
.timestamp = plugin->common.timestamp };
ret = json_encode_read_resp_header(json_object, &header);
if (0 != ret) {
+2 -2
View File
@@ -38,8 +38,8 @@ typedef struct {
uint64_t timestamp;
} json_read_resp_header_t;
int wrap_tag_data(neu_json_read_resp_tag_t * json_tag,
neu_resp_tag_value_meta_t *tag_value);
int wrap_tag_data(neu_json_read_resp_tag_t *json_tag,
neu_resp_tag_value_t * tag_value);
typedef struct {
neu_plugin_t * plugin;
+37 -186
View File
@@ -17,18 +17,12 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
**/
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include "errcodes.h"
#include "neuron.h"
#include "utils/asprintf.h"
#include "plugin_ekuiper.h"
#include "read_write.h"
#define EKUIPER_PLUGIN_URL "tcp://127.0.0.1:7081"
#define EKUIPER_PLUGIN_URL "ipc:///tmp/neuron-ekuiper.ipc"
const neu_plugin_module_t neu_plugin_module;
@@ -38,8 +32,8 @@ static neu_plugin_t *ekuiper_plugin_open(void)
neu_plugin_common_init(&plugin->common);
zlog_notice(neuron, "success to create plugin: %s",
neu_plugin_module.module_name);
zlog_info(neuron, "success to create plugin: %s",
neu_plugin_module.module_name);
return plugin;
}
@@ -48,8 +42,8 @@ static int ekuiper_plugin_close(neu_plugin_t *plugin)
int rv = 0;
free(plugin);
zlog_notice(neuron, "success to free plugin: %s",
neu_plugin_module.module_name);
zlog_info(neuron, "success to free plugin: %s",
neu_plugin_module.module_name);
return rv;
}
@@ -73,9 +67,8 @@ static void pipe_rm_cb(nng_pipe p, nng_pipe_ev ev, void *arg)
nng_mtx_unlock(plugin->mtx);
}
static int ekuiper_plugin_init(neu_plugin_t *plugin, bool load)
static int ekuiper_plugin_init(neu_plugin_t *plugin)
{
(void) load;
int rv = 0;
nng_aio *recv_aio = NULL;
@@ -89,14 +82,12 @@ static int ekuiper_plugin_init(neu_plugin_t *plugin, bool load)
rv = nng_aio_alloc(&recv_aio, recv_data_callback, plugin);
if (rv < 0) {
plog_error(plugin, "cannot allocate recv_aio: %s", nng_strerror(rv));
nng_mtx_free(plugin->mtx);
plugin->mtx = NULL;
return rv;
}
plugin->recv_aio = recv_aio;
plog_notice(plugin, "plugin initialized");
plog_info(plugin, "plugin initialized");
return rv;
}
@@ -104,20 +95,16 @@ static int ekuiper_plugin_uninit(neu_plugin_t *plugin)
{
int rv = 0;
nng_close(plugin->sock);
nng_aio_free(plugin->recv_aio);
nng_mtx_free(plugin->mtx);
free(plugin->host);
free(plugin->url);
plog_notice(plugin, "plugin uninitialized");
plog_info(plugin, "plugin uninitialized");
return rv;
}
static int ekuiper_plugin_start(neu_plugin_t *plugin)
{
int rv = 0;
char *url = plugin->url ? plugin->url : EKUIPER_PLUGIN_URL; // default url
int rv = 0;
rv = nng_pair0_open(&plugin->sock);
if (rv != 0) {
@@ -127,24 +114,13 @@ static int ekuiper_plugin_start(neu_plugin_t *plugin)
nng_pipe_notify(plugin->sock, NNG_PIPE_EV_ADD_POST, pipe_add_cb, plugin);
nng_pipe_notify(plugin->sock, NNG_PIPE_EV_REM_POST, pipe_rm_cb, plugin);
nng_socket_set_int(plugin->sock, NNG_OPT_SENDBUF, 2048);
nng_socket_set_int(plugin->sock, NNG_OPT_RECVBUF, 2048);
if ((rv = nng_listen(plugin->sock, url, NULL, 0)) != 0) {
if ((rv = nng_listen(plugin->sock, EKUIPER_PLUGIN_URL, NULL, 0)) != 0) {
plog_error(plugin, "nng_listen: %s", nng_strerror(rv));
nng_close(plugin->sock);
if (NNG_EADDRINVAL == rv) {
rv = NEU_ERR_IP_ADDRESS_INVALID;
} else if (NNG_EADDRINUSE == rv) {
rv = NEU_ERR_IP_ADDRESS_IN_USE;
} else {
rv = NEU_ERR_EINTERNAL;
}
return rv;
return NEU_ERR_EINTERNAL;
}
nng_recv_aio(plugin->sock, plugin->recv_aio);
plugin->started = true;
plog_notice(plugin, "start successfully");
return NEU_ERR_SUCCESS;
@@ -153,132 +129,18 @@ static int ekuiper_plugin_start(neu_plugin_t *plugin)
static int ekuiper_plugin_stop(neu_plugin_t *plugin)
{
nng_close(plugin->sock);
plugin->started = false;
plog_notice(plugin, "stop successfully");
return NEU_ERR_SUCCESS;
}
static int parse_config(neu_plugin_t *plugin, const char *setting,
char **host_p, uint16_t *port_p)
static int ekuiper_plugin_config(neu_plugin_t *plugin, const char *configs)
{
char * err_param = NULL;
neu_json_elem_t host = { .name = "host", .t = NEU_JSON_STR };
neu_json_elem_t port = { .name = "port", .t = NEU_JSON_INT };
int rv = 0;
if (0 != neu_parse_param(setting, &err_param, 2, &host, &port)) {
plog_error(plugin, "parsing setting fail, key: `%s`", err_param);
goto error;
}
(void) plugin;
(void) configs;
// host, required
if (0 == strlen(host.v.val_str)) {
plog_error(plugin, "setting invalid host: `%s`", host.v.val_str);
goto error;
}
struct in_addr addr;
if (0 == inet_aton(host.v.val_str, &addr)) {
plog_error(plugin, "inet_aton fail: %s", host.v.val_str);
goto error;
}
// port, required
if (0 == port.v.val_int || port.v.val_int > 65535) {
plog_error(plugin, "setting invalid port: %" PRIi64, port.v.val_int);
goto error;
}
*host_p = host.v.val_str;
*port_p = port.v.val_int;
plog_notice(plugin, "config host:%s port:%" PRIu16, *host_p, *port_p);
return 0;
error:
free(err_param);
free(host.v.val_str);
return -1;
}
static inline int check_url_listenable(neu_plugin_t *plugin, const char *url,
const char *host, uint16_t port)
{
if (NULL != plugin->host && // already configured and
port == plugin->port && // port is the same, then if
(0 == strcmp(plugin->host, host) // 1. host is the same
|| 0 == strcmp("0.0.0.0", host) // 2. to bind to any address
|| 0 == strcmp("0.0.0.0", plugin->host) // 3. bound to any address
)) {
// early return, no need check url is listenable
return 0;
}
nng_socket sock = NNG_SOCKET_INITIALIZER;
int rv = nng_pair0_open(&sock);
if (0 != rv) {
plog_error(plugin, "nng_pair0_open: %s", nng_strerror(rv));
return NEU_ERR_EINTERNAL;
}
if (0 != (rv = nng_listen(sock, url, NULL, 0))) {
plog_error(plugin, "nng_listen: %s", nng_strerror(rv));
if (NNG_EADDRINVAL == rv) {
rv = NEU_ERR_IP_ADDRESS_INVALID;
} else if (NNG_EADDRINUSE == rv) {
rv = NEU_ERR_IP_ADDRESS_IN_USE;
} else {
rv = NEU_ERR_EINTERNAL;
}
}
nng_close(sock);
return rv;
}
static int ekuiper_plugin_config(neu_plugin_t *plugin, const char *setting)
{
int rv = 0;
char * url = NULL;
char * host = NULL;
uint16_t port = 0;
if (0 != parse_config(plugin, setting, &host, &port)) {
rv = NEU_ERR_NODE_SETTING_INVALID;
goto error;
}
neu_asprintf(&url, "tcp://%s:%" PRIu16, host, port);
if (NULL == url) {
plog_error(plugin, "create url fail");
rv = NEU_ERR_EINTERNAL;
goto error;
}
if (0 != (rv = check_url_listenable(plugin, url, host, port))) {
goto error;
}
plog_notice(plugin, "config success");
free(plugin->host);
plugin->host = host;
plugin->port = port;
free(plugin->url);
plugin->url = url;
if (plugin->started) {
// restart service
ekuiper_plugin_stop(plugin);
ekuiper_plugin_start(plugin);
}
return rv;
error:
free(url);
free(host);
plog_error(plugin, "config failure");
plog_info(plugin, "config success");
return rv;
}
@@ -287,45 +149,38 @@ static int ekuiper_plugin_request(neu_plugin_t * plugin,
{
bool disconnected = false;
plog_debug(plugin, "handling request type: %d", header->type);
plog_info(plugin, "handling request type: %d", header->type);
nng_mtx_lock(plugin->mtx);
disconnected =
NEU_NODE_LINK_STATE_DISCONNECTED == plugin->common.link_state;
nng_mtx_unlock(plugin->mtx);
if (disconnected) {
plog_notice(plugin, "not connected");
return -1;
}
switch (header->type) {
case NEU_RESP_ERROR: {
neu_resp_error_t *error = (neu_resp_error_t *) data;
plog_debug(plugin, "receive resp errcode: %d", error->error);
plog_info(plugin, "receive resp errcode: %d", error->error);
break;
}
case NEU_REQRESP_TRANS_DATA: {
neu_reqresp_trans_data_t *trans_data = data;
send_data(plugin, trans_data);
break;
}
case NEU_RESP_APP_SUBSCRIBE_GROUP: {
neu_resp_app_subscribe_group_t *sub =
(neu_resp_app_subscribe_group_t *) data;
if (disconnected) {
plog_debug(plugin, "not connected");
} else {
send_data(plugin, trans_data);
}
utarray_free(sub->tags);
break;
}
case NEU_REQ_UPDATE_NODE: {
break;
}
case NEU_REQ_UPDATE_GROUP: {
break;
}
case NEU_REQ_SUBSCRIBE_GROUP:
case NEU_REQ_UPDATE_SUBSCRIBE_GROUP: {
neu_req_subscribe_t *sub_info = data;
free(sub_info->params);
break;
}
case NEU_REQ_UNSUBSCRIBE_GROUP:
break;
default:
plog_warn(plugin, "unsupported request type: %d", header->type);
plog_notice(plugin, "unsupported request type: %d", header->type);
break;
}
@@ -344,14 +199,10 @@ static const neu_plugin_intf_funs_t plugin_intf_funs = {
};
const neu_plugin_module_t neu_plugin_module = {
.version = NEURON_PLUGIN_VER_1_0,
.schema = "ekuiper",
.module_name = "eKuiper",
.module_descr = "LF Edge eKuiper integration plugin",
.module_descr_zh = "LF Edge eKuiper 一体化插件",
.intf_funs = &plugin_intf_funs,
.kind = NEU_PLUGIN_KIND_SYSTEM,
.type = NEU_NA_TYPE_APP,
.display = true,
.single = false,
.version = NEURON_PLUGIN_VER_1_0,
.module_name = "ekuiper",
.module_descr = "Neuron and LF Edge eKuiper integration plugin",
.intf_funs = &plugin_intf_funs,
.kind = NEU_PLUGIN_KIND_SYSTEM,
.type = NEU_NA_TYPE_APP,
};
-6
View File
@@ -20,8 +20,6 @@
#ifndef NEURON_PLUGIN_EKUIPER_H
#define NEURON_PLUGIN_EKUIPER_H
#include <stdint.h>
#include <nng/nng.h>
#include <nng/protocol/pair0/pair.h>
#include <nng/supplemental/util/platform.h>
@@ -36,11 +34,7 @@ struct neu_plugin {
neu_plugin_common_t common;
nng_socket sock;
nng_mtx * mtx;
bool started;
nng_aio * recv_aio;
char * host;
uint16_t port;
char * url;
};
#ifdef __cplusplus

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