├── .github
├── CONTRIBUTING.md
├── FUNDING.yml
├── ISSUE_TEMPLATE
│ ├── bugs.yaml
│ └── features.yaml
├── PULL_REQUEST_TEMPLATE.md
├── dependabot.yml
└── workflows
│ ├── build.yml
│ ├── codeql-analysis.yml
│ ├── greet-collaborators.yml
│ ├── snyk-analysis.yml
│ ├── stale.yml
│ └── summary.yml
├── .gitignore
├── .gitlab-ci.yml
├── .gitpod.yml
├── .istanbul.yml
├── .jsinspectrc
├── .npmignore
├── .nvmrc
├── .travis.yml
├── CHANGELOG.md
├── LICENSE
├── README.md
├── TODO.md
├── _config.yml
├── badges
├── badge-branches.svg
├── badge-functions.svg
├── badge-lines.svg
└── badge-statements.svg
├── clean.sh
├── create_certificates.js
├── examples
├── SDM630
│ └── SDM630toOPCUA.json
├── all-in-one.json
├── client
│ ├── aso-browse-crawle.json
│ ├── browser-listen-group.json
│ ├── browser-read.json
│ ├── browser-to-listener.json
│ ├── browser.json
│ ├── crawler.json
│ ├── event-listener.json
│ ├── flex-connector-jwt.json
│ ├── flex-connector.json
│ ├── grouped-listener.json
│ ├── listener.json
│ ├── method-call.json
│ ├── read-history.json
│ ├── read-structure.json
│ ├── read-write.json
│ ├── read.json
│ ├── response.json
│ ├── result-filter.json
│ ├── write-read.json
│ └── write.json
├── external
│ ├── codesys-pi-sl.json
│ ├── prosys-simulator.json
│ └── ua-cpp-demo-server.json
└── server
│ ├── program-server-with-context.json
│ ├── programmable-server.json
│ ├── server-ISA95.json
│ ├── server-aso-types.json
│ ├── server-demo-users.json
│ └── server-demo.json
├── gulpfile.js
├── images
├── icon.png
├── icon.psd
├── listener-example-subv220.png
├── listener-flow-examplev220.png
├── logoISA88blue.png
├── logoISA95blue.png
├── logoISA95blue.xcf
├── logoISA95blue2.png
├── logoISA99blue.png
├── logoRAMI40blue.png
├── method-caller-examplev220.png
├── opcua-icon-small.png
├── opcua-icon-small.xcf
├── opcua-iiot-logo-glass.png
├── opcua-iiot-logo-white.png
├── opcua-iiot-logo.png
├── opcua-iiot-logo64-glass.png
├── opcua-iiot-logo64-white.png
├── opcua-iiot-logo64.png
├── opcua-iiot-logo6464.png
├── opcua.png
├── opcua64.png
├── read-examplev220.png
├── server-aso-type-examplev220.png
├── wiki
│ ├── ASOTestVariablesUAExpert.png
│ ├── Node-RED-Menu-Examples.png
│ ├── browser-flow3.png
│ ├── browser-listener-flow3-active.png
│ ├── browser-listener-flow3.png
│ ├── browserResultMessageJustValue.png
│ ├── browserResultMessageToListener.png
│ ├── browserResultMessageToRead.png
│ ├── certificateTrustedUAExpert.png
│ ├── certificateUntrustedUAExpert.png
│ ├── crawler.png
│ ├── discoveryExampleUAExpert.png
│ ├── example-menu31.png
│ ├── flex-connector-flow31.png
│ ├── flexServerAddressSapceExample.png
│ ├── flexServerAddressSapceExamplev3.png
│ ├── iiot-nodes-v3.png
│ ├── injectMessage.png
│ ├── listenerChangedMessage.png
│ ├── listenerResultMessageChanged.png
│ ├── method-call3-active.png
│ ├── read-history3-active.png
│ ├── read-write-flow.png
│ ├── readResultMessage.png
│ ├── server-aso-flow3.png
│ ├── write-flow3-active.png
│ ├── write-read-flow.png
│ ├── write-read-flow2.png
│ ├── write-read-flow3.png
│ ├── writeInputMessage.png
│ └── writeMessage.png
└── write-examplev220.png
├── index.js
├── jest.config.js
├── npm-update.sh
├── npm-upgrade.sh
├── package-lock.json
├── package.json
├── scripts
└── JestOutputToSummary.js
├── src
├── core
│ ├── opcua-iiot-core-browser.ts
│ ├── opcua-iiot-core-client.ts
│ ├── opcua-iiot-core-connector.ts
│ ├── opcua-iiot-core-discovery.ts
│ ├── opcua-iiot-core-filter.ts
│ ├── opcua-iiot-core-inject.ts
│ ├── opcua-iiot-core-listener.ts
│ ├── opcua-iiot-core-method.ts
│ ├── opcua-iiot-core-response.ts
│ ├── opcua-iiot-core-server.ts
│ └── opcua-iiot-core.ts
├── helpers
│ ├── alarms-and-conditions-demo.ts
│ └── isa95_demo_address_space.ts
├── icons
│ ├── OPCUA-IIoT-Logo.png
│ ├── icon.png
│ ├── isa95-icon-blue-1024.png
│ ├── isa95-icon-blue-128.png
│ ├── isa95-icon-blue-64.png
│ ├── isa95-icon-blue.png
│ └── opcuaiiot.png
├── locales
│ ├── de-DE
│ │ ├── messages.json
│ │ ├── opcua-iiot-browser.json
│ │ ├── opcua-iiot-connector.json
│ │ ├── opcua-iiot-event.json
│ │ ├── opcua-iiot-flex-server.json
│ │ ├── opcua-iiot-inject.json
│ │ ├── opcua-iiot-listener.json
│ │ ├── opcua-iiot-method-caller.json
│ │ ├── opcua-iiot-node.json
│ │ ├── opcua-iiot-read.json
│ │ ├── opcua-iiot-response.json
│ │ ├── opcua-iiot-result-filter.json
│ │ ├── opcua-iiot-server-aso.json
│ │ ├── opcua-iiot-server-cmd.json
│ │ ├── opcua-iiot-server.json
│ │ └── opcua-iiot-write.json
│ └── en-US
│ │ ├── messages.json
│ │ ├── opcua-iiot-browser.json
│ │ ├── opcua-iiot-connector.json
│ │ ├── opcua-iiot-crawler.json
│ │ ├── opcua-iiot-discovery.json
│ │ ├── opcua-iiot-event.json
│ │ ├── opcua-iiot-flex-connector.json
│ │ ├── opcua-iiot-flex-server.json
│ │ ├── opcua-iiot-inject.json
│ │ ├── opcua-iiot-listener.json
│ │ ├── opcua-iiot-method-caller.json
│ │ ├── opcua-iiot-node.json
│ │ ├── opcua-iiot-read.json
│ │ ├── opcua-iiot-response.json
│ │ ├── opcua-iiot-result-filter.json
│ │ ├── opcua-iiot-server-aso.json
│ │ ├── opcua-iiot-server-cmd.json
│ │ ├── opcua-iiot-server.json
│ │ └── opcua-iiot-write.json
├── opcua-iiot-browser.html
├── opcua-iiot-browser.ts
├── opcua-iiot-connector.html
├── opcua-iiot-connector.ts
├── opcua-iiot-crawler.html
├── opcua-iiot-crawler.ts
├── opcua-iiot-discovery.html
├── opcua-iiot-discovery.ts
├── opcua-iiot-event.html
├── opcua-iiot-event.ts
├── opcua-iiot-flex-connector.html
├── opcua-iiot-flex-connector.ts
├── opcua-iiot-flex-server.html
├── opcua-iiot-flex-server.ts
├── opcua-iiot-inject.html
├── opcua-iiot-inject.ts
├── opcua-iiot-listener.html
├── opcua-iiot-listener.ts
├── opcua-iiot-method-caller.html
├── opcua-iiot-method-caller.ts
├── opcua-iiot-node.html
├── opcua-iiot-node.ts
├── opcua-iiot-read.html
├── opcua-iiot-read.ts
├── opcua-iiot-response.html
├── opcua-iiot-response.ts
├── opcua-iiot-result-filter.html
├── opcua-iiot-result-filter.ts
├── opcua-iiot-server-aso.html
├── opcua-iiot-server-aso.ts
├── opcua-iiot-server-cmd.html
├── opcua-iiot-server-cmd.ts
├── opcua-iiot-server.html
├── opcua-iiot-server.ts
├── opcua-iiot-write.html
├── opcua-iiot-write.ts
├── public
│ ├── vendor
│ │ ├── harting
│ │ │ ├── 10_di.xml
│ │ │ ├── 20_autoid.xml
│ │ │ └── 30_aim.xml
│ │ └── opc-foundation
│ │ │ ├── binary
│ │ │ ├── OPC.ISA95.Types.bsd.xml
│ │ │ ├── Opc.Ua.Adi.Types.bsd.xml
│ │ │ ├── Opc.Ua.Di.Types.bsd.xml
│ │ │ ├── Opc.Ua.Gds.Types.bsd.xml
│ │ │ └── Opc.Ua.Types.bsd.xml
│ │ │ ├── csv
│ │ │ ├── AttributeIds.csv
│ │ │ ├── NodeIds.csv
│ │ │ ├── Opc.Ua.StatusCodes.csv
│ │ │ ├── OpcUaGdsModel.csv
│ │ │ ├── ServerCapabilities.csv
│ │ │ ├── ServerCapabilityIdentifiers.csv
│ │ │ ├── StatusCode.csv
│ │ │ └── StatusCodes.csv
│ │ │ ├── schema
│ │ │ ├── OPC.ISA95.Types.xsd
│ │ │ ├── OPCBinarySchema.xsd
│ │ │ ├── Opc.Ua.Types.xsd
│ │ │ ├── SecuredApplication.xsd
│ │ │ └── UANodeSet.xsd
│ │ │ └── xml
│ │ │ ├── OPC.ISA95.NodeSet2.Nov52013.xml
│ │ │ ├── Opc.ISA95.NodeSet2.xml
│ │ │ ├── Opc.Ua.Adi.NodeSet2.xml
│ │ │ ├── Opc.Ua.Adi.Types.bsd.xml
│ │ │ ├── Opc.Ua.Adi.Types.xsd
│ │ │ ├── Opc.Ua.Di.NodeSet2.xml
│ │ │ ├── Opc.Ua.Di.Types.bsd.xml
│ │ │ ├── Opc.Ua.Di.Types.xsd
│ │ │ ├── Opc.Ua.Gds.NodeSet.xml
│ │ │ ├── Opc.Ua.Gds.NodeSet2.xml
│ │ │ ├── Opc.Ua.Gds.Types.bsd.xml
│ │ │ ├── Opc.Ua.Gds.Types.xsd
│ │ │ ├── Opc.Ua.NodeSet-2.xml
│ │ │ ├── Opc.Ua.NodeSet-3.xml
│ │ │ ├── Opc.Ua.NodeSet.xml
│ │ │ ├── Opc.Ua.NodeSet2.Part10.xml
│ │ │ ├── Opc.Ua.NodeSet2.Part11.xml
│ │ │ ├── Opc.Ua.NodeSet2.Part12.xml
│ │ │ ├── Opc.Ua.NodeSet2.Part13.xml
│ │ │ ├── Opc.Ua.NodeSet2.Part3.xml
│ │ │ ├── Opc.Ua.NodeSet2.Part4.xml
│ │ │ ├── Opc.Ua.NodeSet2.Part5.xml
│ │ │ ├── Opc.Ua.NodeSet2.Part8.xml
│ │ │ ├── Opc.Ua.NodeSet2.Part9.xml
│ │ │ ├── Opc.Ua.NodeSet2.Part999.xml
│ │ │ ├── Opc.Ua.NodeSet2.xml
│ │ │ └── Opc.Ua.PredefinedNodes.xml
│ └── xmlsets.txt
└── types
│ ├── assertion.ts
│ ├── helpers.ts
│ ├── payloads.ts
│ └── placeholders.ts
├── test
├── .gitignore
├── core
│ ├── opcua-iiot-core-browser.test.js
│ ├── opcua-iiot-core-client.test.js
│ ├── opcua-iiot-core-connector.test.js
│ ├── opcua-iiot-core-listener.test.js
│ ├── opcua-iiot-core-method.test.js
│ ├── opcua-iiot-core-server.test.js
│ └── opcua-iiot-core.test.js
├── e2e
│ ├── flows
│ │ ├── browser-e2e-flows.js
│ │ ├── browser-recursive-e2e-flows.js
│ │ ├── connector-e2e-flows.js
│ │ ├── crawler-e2e-flows.js
│ │ ├── event-listener-e2e-flows.js
│ │ ├── flex-connector-e2e-flows.js
│ │ ├── flex-server-e2e-flows.js
│ │ ├── listener-browser-e2e-flows.js
│ │ ├── listener-e2e-flows.js
│ │ ├── method-caller-e2e-flow.js
│ │ ├── node-e2e-flows.js
│ │ ├── read-e2e-flows.js
│ │ ├── response-e2e-flows.js
│ │ ├── result-filter-e2e-flows.js
│ │ ├── server-aso-e2e-flows.js
│ │ ├── server-cmd-e2e-flows.js
│ │ └── write-e2e-flows.js
│ ├── opcua-iiot-browser-e2e.test.js
│ ├── opcua-iiot-browser-recursive-e2e.test.js
│ ├── opcua-iiot-connector-e2e.test.js
│ ├── opcua-iiot-crawler-e2e.test.js
│ ├── opcua-iiot-event-listener-e2e.test.js
│ ├── opcua-iiot-flex-connector-e2e.test.js
│ ├── opcua-iiot-flex-server.test.js
│ ├── opcua-iiot-listener-browser-e2e.test.js
│ ├── opcua-iiot-listener-e2e.test.js
│ ├── opcua-iiot-method-caller-e2e.test.js
│ ├── opcua-iiot-node-e2e.test.js
│ ├── opcua-iiot-read-e2e.test.js
│ ├── opcua-iiot-response-e2e.test.js
│ ├── opcua-iiot-result-filter-e2e.test.js
│ ├── opcua-iiot-server-aso-e2e.test.js
│ ├── opcua-iiot-server-cmd-e2e.test.js
│ └── opcua-iiot-write-e2e.test.js
├── helper
│ ├── receive.js
│ └── test-helper-extensions.js
└── units
│ ├── flows
│ ├── browser-flows.js
│ ├── connector-flows.js
│ ├── crawler-flows.js
│ ├── discovery-flows.js
│ ├── event-flows.js
│ ├── flex-connector-flows.js
│ ├── flex-server-flows.js
│ ├── inject-flows.js
│ ├── listener-flows.js
│ ├── method-caller-flows.js
│ ├── node-flows.js
│ ├── read-flows.js
│ ├── response-flows.js
│ ├── response-status-flows.js
│ ├── result-filter-flows.js
│ ├── server-aso-flows.js
│ ├── server-cmd-flows.js
│ ├── server-flows.js
│ └── write-flows.js
│ ├── opcua-iiot-browser.test.js
│ ├── opcua-iiot-connector.test.js
│ ├── opcua-iiot-crawler.test.js
│ ├── opcua-iiot-discovery.test.js
│ ├── opcua-iiot-event.test.js
│ ├── opcua-iiot-flex-connector.test.js
│ ├── opcua-iiot-flex-server.test.js
│ ├── opcua-iiot-inject.test.js
│ ├── opcua-iiot-listener.test.js
│ ├── opcua-iiot-method-caller.test.js
│ ├── opcua-iiot-node.test.js
│ ├── opcua-iiot-read.test.js
│ ├── opcua-iiot-reponse-status.test.js
│ ├── opcua-iiot-response.test.js
│ ├── opcua-iiot-result-filter.test.js
│ ├── opcua-iiot-server-aso.test.js
│ ├── opcua-iiot-server-cmd.test.js
│ ├── opcua-iiot-server.test.js
│ └── opcua-iiot-write.test.js
└── tsconfig.json
/.github/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing to node-red-contrib-iiot-opcua
2 |
3 | As in Node-RED we have some guidelines for the OPC UA IIoT contribution package.
4 | We welcome contributions, but request you follow these guidelines.
5 |
6 | - [Coding rules](#coding-rules)
7 | - [Raising issues](#raising-issues)
8 | - [Feature requests](#feature-requests)
9 | - [Pull-Requests](#pull-requests)
10 |
11 | ## How to start
12 |
13 | 1. install node-red global without the IIoT OPC UA package
14 | 2. run the shell script: ./clean.sh
15 | 3. run command: npm run dev-link
16 | 4. start node-red and see the IIoT OPC UA nodes for testing
17 | 5. start your test and develop life cycle
18 | 6. Create a new version via 'npm run release & npm run rewrite-changelog'
19 |
20 | You can unlink via 'npm run dev-unlink' and test via 'npm test'.
21 | Check the coverage state before and after your development via 'npm run coverage'!
22 |
23 | ## Coding rules
24 |
25 | 1. Code for one another, and use tools to perform mechanical optimizations.
26 | 2. Keep it simple; compactness != succinctness.
27 | 3. Just because you can doesn’t mean you should.
28 | 4. Utilize familiar paradigms and patterns.
29 | 5. Consistency is king.
30 | 6. Lay good foundations. Be mindful of evolutionary complexity.
31 | 7. Write tests and check the coverage of your code.
32 |
33 | ## Raising issues
34 |
35 | Please raise any bug reports on the relevant project's issue tracker.
36 | Be sure to search the list to see if your issue has already been raised.
37 |
38 | A good bug report is one that make it easy for us to understand what you were
39 | trying to do and what went wrong.
40 |
41 | Provide as much context as possible so we can try to recreate the issue.
42 | If possible, include the relevant part of your flow. To do this, select the
43 | relevant nodes, press Ctrl-E and copy the flow data from the Export dialog.
44 |
45 | At a minimum, please include:
46 |
47 | - Version of node.js? (should be >= 16)
48 | - Version of Node-RED? (should be >= 3)
49 | - Version of node-red-contrib-iiot-opcua? (should be >= 4)
50 |
51 | - What is your platform? (Linux, macOS, ...)
52 | - What does `DEBUG=opcuaIIoT:* node-red -v` say? (log files are welcome)
53 |
54 | - What is your platform? (Linux, macOS, ...)
55 | - What does `DEBUG=opcuaIIoT:* node-red -v` say? (log files are welcome)
56 |
57 | ## Feature requests
58 |
59 | For feature requests, please raise them on the relevant project's issue tracker.
60 |
61 | ## Pull-Requests
62 |
63 | Please, send your PRs to the **develop** branch!
64 | If you want to raise a pull-request with a new feature, or a refactoring
65 | of existing code, it may well get rejected if you haven't discussed it on the relevant project's issue tracker first.
66 |
67 | ### Coding standards
68 |
69 | Please ensure you follow the coding standards used through-out the existing code base.
70 |
71 | Some basic rules include:
72 |
73 | - all files must have the BSD 3-Clause license in the header.
74 | - indent with 2-spaces, no tabs. No arguments.
75 | - follow ES6 or above coding standards
76 | - follow standard.js coding standards
77 |
78 | Some style suggestions to follow when possible:
79 |
80 | - Arrow functions should be prioritized over the function keyword.
81 | - Assign types as narrowly as possible
82 | - Using the `any` type should be avoided unless a variable's type truly doesn't matter.
83 | - If it is very difficult to deduce an object's type, use the `Todo` type from `src/types/placeholders.ts` instead
84 | of `any`.
85 | - When writing new code, use functional programming principles when possible.
86 | - Modifying objects makes the code more complex and harder to read, so favor creating a new object instead.
87 | - A lot of the existing code doesn't follow this, so use your best judgement.
88 |
89 | ### Update
90 |
91 | ### Upgrade
92 |
93 | ### Return of Code Investment
94 |
95 | Please, make pull requests!
96 | If you are not sure how to do this, then ask for help please!
97 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 | custom: ["https://github.com/sponsors/BiancoRoyal", "https://bianco-royal.space/supporter/", "https://opencollective.com/node-red-contrib-modbus", "https://www.noderedplus.de/"]
3 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bugs.yaml:
--------------------------------------------------------------------------------
1 | name: "Bug Report"
2 | description: Report a bug or unexpected behavior encountered.
3 | labels:
4 | - bug
5 | body:
6 | - type: "input"
7 | id: "version"
8 | attributes:
9 | label: Which node-red-contrib-iiot-opcua version are you using?
10 | description: |
11 | Please check the `package.json` file in your Node-RED data directory (default: `$HOME/.node-red/`).
12 | validations:
13 | required: true
14 | - type: textarea
15 | id: descriptions
16 | attributes:
17 | label: What happened?
18 | description: |
19 | Please provide a clear and thorough description of what happened.
20 | validations:
21 | required: true
22 | - type: dropdown
23 | id: server
24 | attributes:
25 | label: Server
26 | description: |
27 | Which type of OPC UA Server are you connected to?
28 | multiple: false
29 | options:
30 | - OPCUA-IIoT-Server Node
31 | - OPCUA-IIoT-Flex-Server Node (Please attach AddressSpaceScript to the next section)
32 | - Other/External server
33 | - None/This is related to a node that doesn't connect to a server
34 | validations:
35 | required: true
36 | - type: textarea
37 | id: reproduction
38 | attributes:
39 | label: How can this be reproduced?
40 | description: |
41 | Please provide a step-by-step description of how to reproduce this behavior.
42 | Please attach relevant flows as a `.json` file. (In the top-right menu, click `Export`)
43 | validations:
44 | required: true
45 | - type: textarea
46 | id: expected
47 | attributes:
48 | label: What did you expect to happen?
49 | description: |
50 | Describe the expected behavior and how the actual behavior differed.
51 | validations:
52 | required: false
53 |
54 | - type: textarea
55 | id: other
56 | attributes:
57 | label: Other Information
58 | description: |
59 | Please provide any other information you feel is relevant, such as Node-RED or NodeJS versions.
60 | validations:
61 | required: false
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/features.yaml:
--------------------------------------------------------------------------------
1 | name: "Feature Request"
2 | description: Request a new feature
3 | labels:
4 | - feature
5 | body:
6 | - type: textarea
7 | id: description
8 | attributes:
9 | label: Describe the requested feature
10 | description: |
11 | Describe the feature you would like to see added.
12 | Feel free to attach diagrams or screenshots.
13 | validations:
14 | required: true
15 | - type: textarea
16 | id: motivation
17 | attributes:
18 | label: Motivation
19 | description: |
20 | Describe why you would like to see this feature or the use-case for the feature.
21 | validations:
22 | required: true
23 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 |
7 |
8 | **Which issues are addressed by this Pull Request?**
9 |
10 | **What does this Pull Request change?**
11 |
12 | **Does this Pull Request introduce any potentially breaking changes?**
13 |
18 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: 'npm'
4 | directory: '/'
5 | target-branch: "develop"
6 | schedule:
7 | interval: "weekly"
8 | allow:
9 | - dependency-type: "production"
10 | ignore:
11 | - dependency-name: "node-opcua*"
--------------------------------------------------------------------------------
/.github/workflows/build.yml:
--------------------------------------------------------------------------------
1 | name: Build and publish
2 | on:
3 | pull_request:
4 | types:
5 | - opened
6 | push:
7 | branches:
8 | - develop
9 | - development
10 | - alpha
11 | - beta
12 | - master
13 | - main
14 | jobs:
15 | build:
16 | runs-on: ubuntu-20.04
17 | strategy:
18 | matrix:
19 | node: [14, 16, 18]
20 | steps:
21 | - uses: actions/checkout@v3
22 | - uses: actions/setup-node@v3
23 | with:
24 | node-version: ${{ matrix.node }}
25 | - run: npm install
26 | - run: npm run build
27 | - run: tar -czvf distrib.tar.gz opcuaIIoT examples package.json create_certificates.js docs index.js README.md CHANGELOG.md
28 | - uses: actions/upload-artifact@v3
29 | with:
30 | name: build-folders
31 | path: distrib.tar.gz
32 |
33 | publish:
34 | runs-on: ubuntu-20.04
35 | needs: build
36 | if: github.ref == 'refs/heads/master'
37 | steps:
38 | - uses: actions/checkout@v3
39 | - uses: actions/setup-node@v3
40 | with:
41 | node-version: 16
42 | - run: npm install
43 | - uses: JS-DevTools/npm-publish@v1
44 | with:
45 | token: ${{ secrets.NPM_TOKEN }}
46 |
--------------------------------------------------------------------------------
/.github/workflows/codeql-analysis.yml:
--------------------------------------------------------------------------------
1 | # For most projects, this workflow file will not need changing; you simply need
2 | # to commit it to your repository.
3 | #
4 | # You may wish to alter this file to override the set of languages analyzed,
5 | # or to provide custom queries or build logic.
6 | #
7 | # ******** NOTE ********
8 | # We have attempted to detect the languages in your repository. Please check
9 | # the `language` matrix defined below to confirm you have the correct set of
10 | # supported CodeQL languages.
11 | #
12 | name: "CodeQL"
13 |
14 | on:
15 | push:
16 | branches:
17 | - main
18 | - master
19 | - development
20 | - develop
21 | pull_request:
22 | # The branches below must be a subset of the branches above
23 | branches:
24 | - develop
25 | schedule:
26 | - cron: '39 20 * * 0'
27 |
28 | jobs:
29 | analyze:
30 | name: Analyze
31 | runs-on: ubuntu-latest
32 | permissions:
33 | actions: read
34 | contents: read
35 | security-events: write
36 |
37 | strategy:
38 | fail-fast: false
39 | matrix:
40 | language: [ 'javascript' ]
41 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
42 | # Learn more about CodeQL language support at https://git.io/codeql-language-support
43 |
44 | steps:
45 | - name: Checkout repository
46 | uses: actions/checkout@v2
47 |
48 | # Initializes the CodeQL tools for scanning.
49 | - name: Initialize CodeQL
50 | uses: github/codeql-action/init@v2
51 | with:
52 | languages: ${{ matrix.language }}
53 | # If you wish to specify custom queries, you can do so here or in a config file.
54 | # By default, queries listed here will override any specified in a config file.
55 | # Prefix the list here with "+" to use these queries and those in the config file.
56 | # queries: ./path/to/local/query, your-org/your-repo/queries@main
57 |
58 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
59 | # If this step fails, then you should remove it and run the build manually (see below)
60 | - name: Autobuild
61 | uses: github/codeql-action/autobuild@v2
62 |
63 | # ℹ️ Command-line programs to run using the OS shell.
64 | # 📚 https://git.io/JvXDl
65 |
66 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
67 | # and modify them (or add more) to build your code if your project
68 | # uses a compiled language
69 |
70 | #- run: |
71 | # make bootstrap
72 | # make release
73 |
74 | - name: Perform CodeQL Analysis
75 | uses: github/codeql-action/analyze@v2
76 |
--------------------------------------------------------------------------------
/.github/workflows/greet-collaborators.yml:
--------------------------------------------------------------------------------
1 | name: "Greet Contributors"
2 | on:
3 | pull_request:
4 | types: [opened, synchronize]
5 |
6 | jobs:
7 | GreetCommitter:
8 | runs-on: ubuntu-latest
9 | steps:
10 | - name: "Greet Contributor"
11 | uses: ibakshay/greet-contributors-action@v3
12 | env:
13 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
--------------------------------------------------------------------------------
/.github/workflows/snyk-analysis.yml:
--------------------------------------------------------------------------------
1 | name: "Snyk Vulnerability Analysis"
2 | on:
3 | push:
4 | branches:
5 | - 6-additional-github-actions
6 | - main
7 | pull_request:
8 | types:
9 | - synchronize
10 | - opened
11 | jobs:
12 | snyk:
13 | runs-on: ubuntu-latest
14 | steps:
15 | - uses: actions/checkout@v2
16 | - name: Run Snyk vulnerability scan
17 | uses: snyk/actions/node@master
18 | env:
19 | SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
20 | with:
21 | command: monitor
22 |
--------------------------------------------------------------------------------
/.github/workflows/stale.yml:
--------------------------------------------------------------------------------
1 | name: 'Close stale issues and PRs'
2 | on:
3 | schedule:
4 | - cron: '30 1 * * *'
5 |
6 | jobs:
7 | stale:
8 | runs-on: ubuntu-latest
9 | steps:
10 | - uses: actions/stale@v4
11 | with:
12 | stale-issue-message: 'This issue is stale because it has been open 60 days with no activity. It will be closed in 15 days, but can be saved by removing the stale label or commenting.'
13 | days-before-stale: 60
14 | days-before-close: 15
--------------------------------------------------------------------------------
/.github/workflows/summary.yml:
--------------------------------------------------------------------------------
1 | # This workflow will do a clean installation of node dependencies, cache/restore them, build the source code and run tests across different versions of node
2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
3 |
4 | name: "Generate Summary"
5 |
6 | on:
7 | - push
8 | - pull_request
9 |
10 | jobs:
11 | tests:
12 | runs-on: ubuntu-latest
13 | strategy:
14 | matrix:
15 | node-version:
16 | - 12
17 | - 14
18 | - 16
19 | - 18
20 | # See supported Node.js release schedule at https://nodejs.org/en/about/releases/
21 | steps:
22 | - uses: actions/checkout@v3
23 | - name: Use Node.js ${{ matrix.node-version }}
24 | uses: actions/setup-node@v3
25 | with:
26 | node-version: ${{ matrix.node-version }}
27 | cache: 'npm'
28 | - run: npm install
29 | - run: npm run summary
30 | - run: echo Test results for NodeJS version ${{ matrix.node-version }} >> $GITHUB_STEP_SUMMARY
31 | - run: cat summary.md >> $GITHUB_STEP_SUMMARY
32 | - uses: actions/upload-artifact@v3
33 | with:
34 | name: badges
35 | path: badges
36 | badgeUpdate:
37 | name: "Update badges"
38 | runs-on: ubuntu-latest
39 | needs: tests
40 | if: github.ref == 'refs/heads/master' || github.ref == 'refs/heads/develop'
41 | steps:
42 | - uses: actions/checkout@v3
43 | - uses: actions/download-artifact@v3
44 | with:
45 | name: badges
46 | path: badges
47 | - run: |
48 | git config user.name "$(git log -n 1 --pretty=format:%an)"
49 | git config user.email "$(git log -n 1 --pretty=format:%ae)"
50 | - run: git add badges
51 | - run: git commit -m "Automatically update coverage badges"
52 | - run: git push --force
53 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | scripts/out*
2 |
3 | .idea/
4 | *.iml
5 | code/
6 | node_modules/
7 | opcuaIIoT/
8 | *leifert*
9 | error*.txt
10 | .DS_Store
11 | maps/
12 | docs/gen/
13 | coverage/
14 | .coverage/
15 | pki/
16 | .vscode/
17 | jcoverage/
18 |
19 | \.jsinspect-results\.json
20 |
21 | certificates/
22 |
23 | dist/
24 |
25 | *.log
26 | *.bak
--------------------------------------------------------------------------------
/.gitlab-ci.yml:
--------------------------------------------------------------------------------
1 | image: node:14
2 |
3 | before_script:
4 | - npm install
5 | stages:
6 | - test
7 | npm_test:
8 | stage: test
9 | script:
10 | - npm run build
11 | - echo "test TBD" # npm test
12 |
--------------------------------------------------------------------------------
/.gitpod.yml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/.istanbul.yml:
--------------------------------------------------------------------------------
1 | verbose: false
2 | instrumentation:
3 | globals: ['expect']
4 | root: ./src
5 | default-excludes: true
6 | excludes: ['src/public']
7 | include-all-sources: true
8 | include-pid: false
9 | es-modules: true
10 | ignoreLeaks: false
11 | ui: bdd
12 | embed-source: false
13 | variable: __coverage__
14 | compact: true
15 | preserve-comments: false
16 | complete-copy: false
17 | save-baseline: false
18 | baseline-file: ./coverage/coverage-baseline.json
19 | reporting:
20 | print: both
21 | reports:
22 | - lcov
23 | - html
24 | - cobertura
25 | - clover
26 | dir: ./coverage
27 | watermarks:
28 | statements: [50, 80]
29 | lines: [50, 80]
30 | functions: [50, 80]
31 | branches: [50, 80]
32 | hooks:
33 | hook-run-in-context: false
34 | post-require-hook: null
35 | handle-sigint: false
36 | check:
37 | global:
38 | statements: 0
39 | lines: 0
40 | branches: 0
41 | functions: 0
42 | excludes: []
43 | each:
44 | statements: 0
45 | lines: 0
46 | branches: 0
47 | functions: 0
48 | excludes: []
--------------------------------------------------------------------------------
/.jsinspectrc:
--------------------------------------------------------------------------------
1 | {
2 | "threshold": 50,
3 | "identifiers": true,
4 | "literals": true,
5 | "color": true,
6 | "minInstances": 2,
7 | "ignore": "test/|spec|mock≤|public/",
8 | "reporter": "json",
9 | "truncate": 100
10 | }
11 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | .git
2 | .idea
3 | test
4 | code/
5 | node_modules
6 | .gitignore
7 | *.iml
8 | Example.png
9 | *EXAMPLE.png
10 | *.conf.js
11 | *.log
12 | maps/
13 | pki/
14 | .vscode/
15 | jcoverage/
16 |
--------------------------------------------------------------------------------
/.nvmrc:
--------------------------------------------------------------------------------
1 | v14.19.1
2 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | matrix:
3 | include:
4 | - node_js: "lts/*"
5 | - node_js: 18
6 | - node_js: 16
7 | - node_js: 14
8 | allow_failures:
9 | - node_js: 16
10 | - node_js: 18
11 | install:
12 | - npm install
13 | - npm install --only=dev
14 | script:
15 | - npm run coverage:ci
16 | - npm run coverage:upload
17 | cache:
18 | directories:
19 | - "pki"
20 | branches:
21 | only:
22 | - master
23 | - develop
24 | - LTS
25 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | BSD 3-Clause License
2 |
3 | Copyright (c) 2022 DATATRONiQ GmbH (https://datatroniq.com)
4 | Copyright (c) 2016,2017,2018,2019,2020,2021,2022 Klaus Landsdorf (https://bianco-royal.space/)
5 | Copyright (c) 2015, 2016, Mika Karaila, Valmet Automation Inc. (node-red-contrib-opcua)
6 | All rights reserved.
7 | node-red-contrib-iiot-opcua
8 |
9 | Redistribution and use in source and binary forms, with or without
10 | modification, are permitted provided that the following conditions are met:
11 |
12 | * Redistributions of source code must retain the above copyright notice, this
13 | list of conditions and the following disclaimer.
14 |
15 | * Redistributions in binary form must reproduce the above copyright notice,
16 | this list of conditions and the following disclaimer in the documentation
17 | and/or other materials provided with the distribution.
18 |
19 | * Neither the name of the copyright holder nor the names of its
20 | contributors may be used to endorse or promote products derived from
21 | this software without specific prior written permission.
22 |
23 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
27 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 |
--------------------------------------------------------------------------------
/TODO.md:
--------------------------------------------------------------------------------
1 | ## OPC UA IIoT for Node-RED
2 |
3 | ## Known Issues
4 |
5 | * Result Filter does not filter correctly in every case (Will be fixed in v5.x)
6 | * Read after browse in browse example does not work
7 | * No output and no error
8 | * Browse-Listener and grouped-listener example top browse/listen will throw following error
9 |
10 | ```
11 | Error: encodeObject Error: [Error] Value: {
12 | payload: 'Monitored Item Error',
13 | monitoredItem: ClientMonitoredItemImpl {
14 | _events: {
15 | initialized: [Function (anonymous)],
16 | changed: [Function (anonymous)],
17 | err: [Function (anonymous)],
18 | terminated: [Function (anonymous)]
19 | },
20 | _eventsCount: 4,
21 | _maxListeners: undefined,
22 | statusCode: ConstantStatusCode {
23 | _value: 2150957056,
24 | _description: 'The attribute is not supported for the specified Node.',
25 | _name: 'BadAttributeIdInvalid'
26 | },
27 | subscription: ClientSubscriptionImpl {
28 | _events: [Object],
29 | _eventsCount: 4,
30 | _maxListeners: undefined,
31 | monitoredItemGroups: [],
32 | timeoutHint: 14000,
33 | _nextClientHandle: 26,
34 | publishEngine: [ClientSidePublishEngine],
35 | lastSequenceNumber: 10,
36 | publishingInterval: 200,
37 | lifetimeCount: 18000,
38 | maxKeepAliveCount: 60,
39 | maxNotificationsPerPublish: 100,
40 | publishingEnabled: true,
41 | priority: 10,
42 | ```
43 | Removing the catch node will bring the following error messages
44 | ```
45 | "{"name":"Error","message":"ns=0;i=2253: BadAttributeIdInvalid (0x80350000)"}"
46 | ```
47 | Maybe that happens because the browser browses the root object recursively and returns also
48 | nodes of the server that aren't allowed to be listened
49 | * Event Listener monitoring the basic opc ua events will always return an empty array of values
50 | * Discovered following error: Expected data is unavailable for the requested time range due to an
51 | un-mounted volume, an off-line archive or tape, or similar reason for temporary unavailability.
52 | (Will be fixed in v5.x)
53 |
54 |
55 | ### Features
56 |
57 | #### ASO and Servers
58 |
59 | * adding variables
60 | * adding folders/objects
61 | * adding complex structures
62 | * adding arrays
63 | * adding methods
64 |
65 | ----
66 |
67 | ### Worked before
68 |
69 | #### Listener
70 |
71 | * Events cannot be monitored (error node-opcua maxAge)
72 |
--------------------------------------------------------------------------------
/_config.yml:
--------------------------------------------------------------------------------
1 | theme: jekyll-theme-modernist
--------------------------------------------------------------------------------
/badges/badge-branches.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/badges/badge-functions.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/badges/badge-lines.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/badges/badge-statements.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/clean.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | node -v
4 |
5 | rm -rf node_modules/
6 |
7 | rm -rf opcuaIIoT/
8 |
9 | rm -rf code/
10 |
11 | rm -rf certificates/
12 |
13 | rm -rf coverage/
14 |
15 | rm -rf docs/gen
16 |
17 | rm package-lock.json
18 |
19 | npm cache verify
20 |
21 | npm install
22 |
23 | npm i --only=dev
24 |
25 | npm run test:clearCache
26 |
27 | npm test
28 |
29 | npm run coverage
30 |
31 | npm run build
32 |
33 | npm run rewrite-changelog
34 |
35 | node -v
36 |
37 | npm audit
38 |
--------------------------------------------------------------------------------
/create_certificates.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | require('node-opcua-pki/bin/crypto_create_CA')
3 |
--------------------------------------------------------------------------------
/examples/client/event-listener.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "id": "b3974c60.a56ab8",
4 | "type": "tab",
5 | "label": "IIoT OPC UA Events",
6 | "disabled": false,
7 | "info": ""
8 | },
9 | {
10 | "id": "d9bca212.ee7d3",
11 | "type": "debug",
12 | "z": "b3974c60.a56ab8",
13 | "name": "",
14 | "active": true,
15 | "tosidebar": true,
16 | "console": false,
17 | "tostatus": false,
18 | "complete": "true",
19 | "targetType": "full",
20 | "statusVal": "",
21 | "statusType": "auto",
22 | "x": 730,
23 | "y": 120,
24 | "wires": []
25 | },
26 | {
27 | "id": "cbc425f4.8b596",
28 | "type": "OPCUA-IIoT-Event",
29 | "z": "b3974c60.a56ab8",
30 | "eventType": "BaseEventType",
31 | "eventTypeLabel": "BaseEventType (i=2041)",
32 | "resultType": "basic",
33 | "queueSize": "1000",
34 | "usingListener": true,
35 | "name": "Base Events",
36 | "showStatusActivities": false,
37 | "showErrors": false,
38 | "x": 420,
39 | "y": 120,
40 | "wires": [
41 | [
42 | "d4e7bb7a.8ba54"
43 | ]
44 | ]
45 | },
46 | {
47 | "id": "99ea348a.48cfd8",
48 | "type": "OPCUA-IIoT-Inject",
49 | "z": "b3974c60.a56ab8",
50 | "injectType": "listen",
51 | "payload": "200",
52 | "payloadType": "num",
53 | "topic": "",
54 | "repeat": "",
55 | "crontab": "",
56 | "once": true,
57 | "startDelay": "",
58 | "name": "listen with 200 ms",
59 | "addressSpaceItems": [
60 | {
61 | "name": "Tanks",
62 | "nodeId": "ns=1;i=1000",
63 | "datatypeName": ""
64 | },
65 | {
66 | "name": "Server",
67 | "nodeId": "ns=0;i=2253",
68 | "datatypeName": ""
69 | }
70 | ],
71 | "x": 230,
72 | "y": 120,
73 | "wires": [
74 | [
75 | "cbc425f4.8b596"
76 | ]
77 | ]
78 | },
79 | {
80 | "id": "d4e7bb7a.8ba54",
81 | "type": "OPCUA-IIoT-Listener",
82 | "z": "b3974c60.a56ab8",
83 | "connector": "fe9e7411.128358",
84 | "action": "events",
85 | "queueSize": "100",
86 | "name": "",
87 | "topic": "",
88 | "justValue": true,
89 | "useGroupItems": false,
90 | "showStatusActivities": false,
91 | "showErrors": true,
92 | "x": 580,
93 | "y": 120,
94 | "wires": [
95 | [
96 | "d9bca212.ee7d3"
97 | ]
98 | ]
99 | },
100 | {
101 | "id": "193736fe173d5219",
102 | "type": "comment",
103 | "z": "b3974c60.a56ab8",
104 | "name": "Use Demo Server Example",
105 | "info": "Please use the Demo Server example for this example to work.\nImport that with strg+i -> Examples -> opcuaIIoT -> Server -> Demo Server",
106 | "x": 250,
107 | "y": 62,
108 | "wires": []
109 | },
110 | {
111 | "id": "fe9e7411.128358",
112 | "type": "OPCUA-IIoT-Connector",
113 | "z": "b3974c60.a56ab8",
114 | "discoveryUrl": "",
115 | "endpoint": "opc.tcp://localhost:55388/",
116 | "endpointMustExist": false,
117 | "keepSessionAlive": true,
118 | "loginEnabled": false,
119 | "name": "LOCAL EVENT SERVER",
120 | "showErrors": false,
121 | "securityPolicy": "None",
122 | "securityMode": "None",
123 | "individualCerts": false,
124 | "publicCertificateFile": "",
125 | "privateKeyFile": "",
126 | "defaultSecureTokenLifetime": "",
127 | "autoSelectRightEndpoint": false,
128 | "strategyMaxRetry": "",
129 | "strategyInitialDelay": "",
130 | "strategyMaxDelay": "",
131 | "strategyRandomisationFactor": "",
132 | "requestedSessionTimeout": "",
133 | "connectionStartDelay": "",
134 | "reconnectDelay": "",
135 | "maxBadSessionRequests": ""
136 | }
137 | ]
--------------------------------------------------------------------------------
/examples/client/read-write.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "id": "f49a0646.6b54a8",
4 | "type": "tab",
5 | "label": "IIoT OPC UA Read Write",
6 | "disabled": false,
7 | "info": ""
8 | },
9 | {
10 | "id": "68b2953e.23fe94",
11 | "type": "OPCUA-IIoT-Write",
12 | "z": "f49a0646.6b54a8",
13 | "connector": "7316e0da.4324d",
14 | "name": "",
15 | "justValue": false,
16 | "showStatusActivities": false,
17 | "showErrors": true,
18 | "x": 550,
19 | "y": 80,
20 | "wires": [
21 | [
22 | "13fe0f0e.0ca0e9"
23 | ]
24 | ]
25 | },
26 | {
27 | "id": "51907704.7ca4d",
28 | "type": "OPCUA-IIoT-Inject",
29 | "z": "f49a0646.6b54a8",
30 | "injectType": "read",
31 | "payload": "",
32 | "payloadType": "date",
33 | "topic": "",
34 | "repeat": "120",
35 | "crontab": "",
36 | "once": true,
37 | "startDelay": "",
38 | "name": "inject",
39 | "addressSpaceItems": [
40 | {
41 | "name": "TestReadWrite",
42 | "nodeId": "ns=1;s=TestReadWrite",
43 | "datatypeName": "Double"
44 | }
45 | ],
46 | "x": 140,
47 | "y": 80,
48 | "wires": [
49 | [
50 | "d4817dc5.a09168"
51 | ]
52 | ]
53 | },
54 | {
55 | "id": "d4817dc5.a09168",
56 | "type": "OPCUA-IIoT-Read",
57 | "z": "f49a0646.6b54a8",
58 | "attributeId": "13",
59 | "maxAge": 1,
60 | "depth": 1,
61 | "connector": "7316e0da.4324d",
62 | "name": "",
63 | "justValue": true,
64 | "showStatusActivities": false,
65 | "showErrors": true,
66 | "parseStrings": false,
67 | "historyDays": "",
68 | "x": 270,
69 | "y": 80,
70 | "wires": [
71 | [
72 | "30116e36.369d22"
73 | ]
74 | ]
75 | },
76 | {
77 | "id": "13fe0f0e.0ca0e9",
78 | "type": "OPCUA-IIoT-Response",
79 | "z": "f49a0646.6b54a8",
80 | "name": "",
81 | "compressStructure": false,
82 | "showStatusActivities": false,
83 | "showErrors": false,
84 | "activateUnsetFilter": false,
85 | "activateFilters": false,
86 | "negateFilter": false,
87 | "filters": [],
88 | "x": 680,
89 | "y": 80,
90 | "wires": [
91 | [
92 | "afa379a1.804f18"
93 | ]
94 | ]
95 | },
96 | {
97 | "id": "afa379a1.804f18",
98 | "type": "debug",
99 | "z": "f49a0646.6b54a8",
100 | "name": "",
101 | "active": true,
102 | "tosidebar": true,
103 | "console": false,
104 | "tostatus": false,
105 | "complete": "true",
106 | "targetType": "full",
107 | "statusVal": "",
108 | "statusType": "auto",
109 | "x": 810,
110 | "y": 80,
111 | "wires": []
112 | },
113 | {
114 | "id": "30116e36.369d22",
115 | "type": "function",
116 | "z": "f49a0646.6b54a8",
117 | "name": "toWriteMsg",
118 | "func": "msg.payload.nodetype = 'inject';\nmsg.payload.injectType = 'write'\nmsg.payload.valuesToWrite = [16.04]\nreturn msg;",
119 | "outputs": 1,
120 | "noerr": 0,
121 | "initialize": "",
122 | "finalize": "",
123 | "libs": [],
124 | "x": 410,
125 | "y": 80,
126 | "wires": [
127 | [
128 | "68b2953e.23fe94"
129 | ]
130 | ]
131 | },
132 | {
133 | "id": "f1ed16b147240f8d",
134 | "type": "comment",
135 | "z": "f49a0646.6b54a8",
136 | "name": "Use Demo Server Example!",
137 | "info": "Import Demo Server example with\nstrg+i -> Example -> opcuaIIoT -> Server -> Demo Server",
138 | "x": 200,
139 | "y": 32,
140 | "wires": []
141 | },
142 | {
143 | "id": "7316e0da.4324d",
144 | "type": "OPCUA-IIoT-Connector",
145 | "z": "f49a0646.6b54a8",
146 | "discoveryUrl": "",
147 | "endpoint": "opc.tcp://localhost:55388",
148 | "endpointMustExist": false,
149 | "keepSessionAlive": true,
150 | "loginEnabled": false,
151 | "name": "LOCAL DEMO SERVER",
152 | "showErrors": false,
153 | "securityPolicy": "None",
154 | "securityMode": "None",
155 | "individualCerts": false,
156 | "publicCertificateFile": "",
157 | "privateKeyFile": "",
158 | "defaultSecureTokenLifetime": "60000",
159 | "autoSelectRightEndpoint": false,
160 | "strategyMaxRetry": "",
161 | "strategyInitialDelay": "",
162 | "strategyMaxDelay": "",
163 | "strategyRandomisationFactor": "",
164 | "requestedSessionTimeout": "",
165 | "connectionStartDelay": "",
166 | "reconnectDelay": "",
167 | "maxBadSessionRequests": ""
168 | }
169 | ]
--------------------------------------------------------------------------------
/examples/server/server-ISA95.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "id": "ade2bb45.1c9a2",
4 | "type": "tab",
5 | "label": "IIoT OPC UA Server ISA95",
6 | "disabled": false,
7 | "info": ""
8 | },
9 | {
10 | "id": "2b0a9d8f.fda952",
11 | "type": "comment",
12 | "z": "ade2bb45.1c9a2",
13 | "name": "information",
14 | "info": "Clients to browse\n\nUA-Expert: https://www.unified-automation.com/products/development-tools/uaexpert.html\nOPCUA-Commander: https://github.com/node-opcua/opcua-commander\nNode-RED: use the browse examples to start browsing the server via Node-RED\n\nHappy wiring!\nKlaus Landsdorf\nhttp://bianco-royal.de/",
15 | "x": 210,
16 | "y": 60,
17 | "wires": []
18 | },
19 | {
20 | "id": "4088e400.34f28c",
21 | "type": "comment",
22 | "z": "ade2bb45.1c9a2",
23 | "name": "ISA95",
24 | "info": "Some links\nhttps://opcfoundation.org/markets-collaboration/isa-95/\n\n\nhttps://opcfoundation.org/developer-tools/specifications-unified-architecture/isa-95-common-object-model/\n\n56 min video by Paul Hunkar\n“OPC UA for ISA-95 Common Object Model Companion Specification”\nhttps://youtu.be/OobhzbQoUnA",
25 | "x": 350,
26 | "y": 60,
27 | "wires": []
28 | },
29 | {
30 | "id": "cd0b3a6a.197f18",
31 | "type": "OPCUA-IIoT-Server",
32 | "z": "ade2bb45.1c9a2",
33 | "port": "55395",
34 | "endpoint": "",
35 | "acceptExternalCommands": true,
36 | "maxAllowedSessionNumber": "",
37 | "maxConnectionsPerEndpoint": "",
38 | "maxAllowedSubscriptionNumber": "",
39 | "alternateHostname": "",
40 | "name": "ISA95 Server",
41 | "showStatusActivities": false,
42 | "showErrors": true,
43 | "asoDemo": true,
44 | "allowAnonymous": true,
45 | "individualCerts": false,
46 | "isAuditing": false,
47 | "serverDiscovery": true,
48 | "users": [],
49 | "xmlsets": [
50 | {
51 | "name": "ISA95",
52 | "path": "public/vendor/opc-foundation/xml/Opc.ISA95.NodeSet2.xml"
53 | }
54 | ],
55 | "publicCertificateFile": "",
56 | "privateCertificateFile": "",
57 | "registerServerMethod": "1",
58 | "discoveryServerEndpointUrl": "",
59 | "capabilitiesForMDNS": "",
60 | "maxNodesPerRead": "",
61 | "maxNodesPerBrowse": "",
62 | "delayToClose": "",
63 | "x": 200,
64 | "y": 100,
65 | "wires": [
66 | []
67 | ]
68 | }
69 | ]
--------------------------------------------------------------------------------
/gulpfile.js:
--------------------------------------------------------------------------------
1 | /*
2 | The BSD 3-Clause License
3 |
4 | Copyright (c) 2018-2022 Klaus Landsdorf (http://node-red.plus/)
5 | All rights reserved.
6 | node-red-contrib-iiot-opcua
7 | */
8 |
9 | 'use strict'
10 |
11 | const gulp = require('gulp')
12 | const { series, parallel } = require('gulp')
13 | const htmlmin = require('gulp-htmlmin')
14 | const jsdoc = require('gulp-jsdoc3')
15 | const clean = require('gulp-clean')
16 | const sourcemaps = require('gulp-sourcemaps')
17 | const changelog = require('gulp-conventional-changelog')
18 |
19 | function icons () {
20 | return gulp.src('src/icons/**/*').pipe(gulp.dest('opcuaIIoT/icons'))
21 | }
22 |
23 | function docIcons () {
24 | return gulp.src('src/icons/**/*').pipe(gulp.dest('docs/gen/icons'))
25 | }
26 |
27 | function docImages () {
28 | return gulp.src('images/**/*').pipe(gulp.dest('docs/gen/images'))
29 | }
30 |
31 | function locale () {
32 | return gulp.src('src/locales/**/*').pipe(gulp.dest('opcuaIIoT/locales'))
33 | }
34 |
35 | function publics () {
36 | return gulp.src('src/public/**/*').pipe(gulp.dest('opcuaIIoT/public'))
37 | }
38 |
39 | function maps () {
40 | return gulp.src('maps/**/*').pipe(gulp.dest('opcuaIIoT/maps'))
41 | }
42 |
43 | function wipe () {
44 | return gulp.src(['opcuaIIoT', 'docs/gen', 'maps', 'code', 'coverage', 'jcoverage', 'suite/jcoverage', 'pki', 'suite/pki', 'test/pki'], { allowEmpty: true })
45 | .pipe(clean({ force: true }))
46 | }
47 |
48 | function changelogUpdate () {
49 | return gulp.src('CHANGELOG.md')
50 | .pipe(changelog({
51 | // conventional-changelog options go here
52 | preset: 'angular',
53 | releaseCount: 0
54 | }, {
55 | // context goes here
56 | }, {
57 | // git-raw-commits options go here
58 | }, {
59 | // conventional-commits-parser options go here
60 | }, {
61 | // conventional-changelog-writer options go here
62 | }))
63 | .pipe(gulp.dest('./'))
64 | }
65 |
66 | function web () {
67 | return gulp.src('src/*.htm*')
68 | .pipe(htmlmin({
69 | minifyJS: false,
70 | minifyCSS: true,
71 | minifyURLs: true,
72 | maxLineLength: 120,
73 | preserveLineBreaks: false,
74 | collapseWhitespace: true,
75 | collapseInlineTagWhitespace: true,
76 | conservativeCollapse: true,
77 | processScripts: ['text/x-red'],
78 | quoteCharacter: "'"
79 | }))
80 | .pipe(gulp.dest('opcuaIIoT'))
81 | }
82 |
83 | function ts () {
84 | const ts = require('gulp-typescript')
85 | const tsProject = ts.createProject('tsconfig.json')
86 | return gulp.src('src/**/*.ts')
87 | .pipe(sourcemaps.init({ loadMaps: true }))
88 | .pipe(tsProject())
89 | .pipe(sourcemaps.write(''))
90 | .pipe(gulp.dest('opcuaIIoT'))
91 | }
92 |
93 | function doc (cb) {
94 | return gulp.src(['README.md', 'src/**/*.ts'], { read: false })
95 | .pipe(jsdoc(cb))
96 | }
97 |
98 | // function code () {
99 | // return gulp.src('src/**/*.ts')
100 | // .pipe(babel({ presets: ['@babel/env'] }))
101 | // .pipe(gulp.dest('code'))
102 | // }
103 |
104 | const docs = series(doc, docIcons, docImages)
105 | const build = series(wipe, web, ts, locale, publics, icons)
106 |
107 | exports.docs = docs
108 | exports.clean = wipe
109 | exports.build = build
110 | exports.changelog = changelogUpdate
111 | exports.publish = parallel(build, maps, docs, changelogUpdate)
112 |
--------------------------------------------------------------------------------
/images/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiancoRoyal/node-red-contrib-iiot-opcua/40cf83b46abbed92b9b8f11ebb6eecfc28d2b6a7/images/icon.png
--------------------------------------------------------------------------------
/images/icon.psd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiancoRoyal/node-red-contrib-iiot-opcua/40cf83b46abbed92b9b8f11ebb6eecfc28d2b6a7/images/icon.psd
--------------------------------------------------------------------------------
/images/listener-example-subv220.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiancoRoyal/node-red-contrib-iiot-opcua/40cf83b46abbed92b9b8f11ebb6eecfc28d2b6a7/images/listener-example-subv220.png
--------------------------------------------------------------------------------
/images/listener-flow-examplev220.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiancoRoyal/node-red-contrib-iiot-opcua/40cf83b46abbed92b9b8f11ebb6eecfc28d2b6a7/images/listener-flow-examplev220.png
--------------------------------------------------------------------------------
/images/logoISA88blue.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiancoRoyal/node-red-contrib-iiot-opcua/40cf83b46abbed92b9b8f11ebb6eecfc28d2b6a7/images/logoISA88blue.png
--------------------------------------------------------------------------------
/images/logoISA95blue.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiancoRoyal/node-red-contrib-iiot-opcua/40cf83b46abbed92b9b8f11ebb6eecfc28d2b6a7/images/logoISA95blue.png
--------------------------------------------------------------------------------
/images/logoISA95blue.xcf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiancoRoyal/node-red-contrib-iiot-opcua/40cf83b46abbed92b9b8f11ebb6eecfc28d2b6a7/images/logoISA95blue.xcf
--------------------------------------------------------------------------------
/images/logoISA95blue2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiancoRoyal/node-red-contrib-iiot-opcua/40cf83b46abbed92b9b8f11ebb6eecfc28d2b6a7/images/logoISA95blue2.png
--------------------------------------------------------------------------------
/images/logoISA99blue.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiancoRoyal/node-red-contrib-iiot-opcua/40cf83b46abbed92b9b8f11ebb6eecfc28d2b6a7/images/logoISA99blue.png
--------------------------------------------------------------------------------
/images/logoRAMI40blue.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiancoRoyal/node-red-contrib-iiot-opcua/40cf83b46abbed92b9b8f11ebb6eecfc28d2b6a7/images/logoRAMI40blue.png
--------------------------------------------------------------------------------
/images/method-caller-examplev220.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiancoRoyal/node-red-contrib-iiot-opcua/40cf83b46abbed92b9b8f11ebb6eecfc28d2b6a7/images/method-caller-examplev220.png
--------------------------------------------------------------------------------
/images/opcua-icon-small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiancoRoyal/node-red-contrib-iiot-opcua/40cf83b46abbed92b9b8f11ebb6eecfc28d2b6a7/images/opcua-icon-small.png
--------------------------------------------------------------------------------
/images/opcua-icon-small.xcf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiancoRoyal/node-red-contrib-iiot-opcua/40cf83b46abbed92b9b8f11ebb6eecfc28d2b6a7/images/opcua-icon-small.xcf
--------------------------------------------------------------------------------
/images/opcua-iiot-logo-glass.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiancoRoyal/node-red-contrib-iiot-opcua/40cf83b46abbed92b9b8f11ebb6eecfc28d2b6a7/images/opcua-iiot-logo-glass.png
--------------------------------------------------------------------------------
/images/opcua-iiot-logo-white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiancoRoyal/node-red-contrib-iiot-opcua/40cf83b46abbed92b9b8f11ebb6eecfc28d2b6a7/images/opcua-iiot-logo-white.png
--------------------------------------------------------------------------------
/images/opcua-iiot-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiancoRoyal/node-red-contrib-iiot-opcua/40cf83b46abbed92b9b8f11ebb6eecfc28d2b6a7/images/opcua-iiot-logo.png
--------------------------------------------------------------------------------
/images/opcua-iiot-logo64-glass.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiancoRoyal/node-red-contrib-iiot-opcua/40cf83b46abbed92b9b8f11ebb6eecfc28d2b6a7/images/opcua-iiot-logo64-glass.png
--------------------------------------------------------------------------------
/images/opcua-iiot-logo64-white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiancoRoyal/node-red-contrib-iiot-opcua/40cf83b46abbed92b9b8f11ebb6eecfc28d2b6a7/images/opcua-iiot-logo64-white.png
--------------------------------------------------------------------------------
/images/opcua-iiot-logo64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiancoRoyal/node-red-contrib-iiot-opcua/40cf83b46abbed92b9b8f11ebb6eecfc28d2b6a7/images/opcua-iiot-logo64.png
--------------------------------------------------------------------------------
/images/opcua-iiot-logo6464.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiancoRoyal/node-red-contrib-iiot-opcua/40cf83b46abbed92b9b8f11ebb6eecfc28d2b6a7/images/opcua-iiot-logo6464.png
--------------------------------------------------------------------------------
/images/opcua.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiancoRoyal/node-red-contrib-iiot-opcua/40cf83b46abbed92b9b8f11ebb6eecfc28d2b6a7/images/opcua.png
--------------------------------------------------------------------------------
/images/opcua64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiancoRoyal/node-red-contrib-iiot-opcua/40cf83b46abbed92b9b8f11ebb6eecfc28d2b6a7/images/opcua64.png
--------------------------------------------------------------------------------
/images/read-examplev220.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiancoRoyal/node-red-contrib-iiot-opcua/40cf83b46abbed92b9b8f11ebb6eecfc28d2b6a7/images/read-examplev220.png
--------------------------------------------------------------------------------
/images/server-aso-type-examplev220.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiancoRoyal/node-red-contrib-iiot-opcua/40cf83b46abbed92b9b8f11ebb6eecfc28d2b6a7/images/server-aso-type-examplev220.png
--------------------------------------------------------------------------------
/images/wiki/ASOTestVariablesUAExpert.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiancoRoyal/node-red-contrib-iiot-opcua/40cf83b46abbed92b9b8f11ebb6eecfc28d2b6a7/images/wiki/ASOTestVariablesUAExpert.png
--------------------------------------------------------------------------------
/images/wiki/Node-RED-Menu-Examples.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiancoRoyal/node-red-contrib-iiot-opcua/40cf83b46abbed92b9b8f11ebb6eecfc28d2b6a7/images/wiki/Node-RED-Menu-Examples.png
--------------------------------------------------------------------------------
/images/wiki/browser-flow3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiancoRoyal/node-red-contrib-iiot-opcua/40cf83b46abbed92b9b8f11ebb6eecfc28d2b6a7/images/wiki/browser-flow3.png
--------------------------------------------------------------------------------
/images/wiki/browser-listener-flow3-active.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiancoRoyal/node-red-contrib-iiot-opcua/40cf83b46abbed92b9b8f11ebb6eecfc28d2b6a7/images/wiki/browser-listener-flow3-active.png
--------------------------------------------------------------------------------
/images/wiki/browser-listener-flow3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiancoRoyal/node-red-contrib-iiot-opcua/40cf83b46abbed92b9b8f11ebb6eecfc28d2b6a7/images/wiki/browser-listener-flow3.png
--------------------------------------------------------------------------------
/images/wiki/browserResultMessageJustValue.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiancoRoyal/node-red-contrib-iiot-opcua/40cf83b46abbed92b9b8f11ebb6eecfc28d2b6a7/images/wiki/browserResultMessageJustValue.png
--------------------------------------------------------------------------------
/images/wiki/browserResultMessageToListener.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiancoRoyal/node-red-contrib-iiot-opcua/40cf83b46abbed92b9b8f11ebb6eecfc28d2b6a7/images/wiki/browserResultMessageToListener.png
--------------------------------------------------------------------------------
/images/wiki/browserResultMessageToRead.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiancoRoyal/node-red-contrib-iiot-opcua/40cf83b46abbed92b9b8f11ebb6eecfc28d2b6a7/images/wiki/browserResultMessageToRead.png
--------------------------------------------------------------------------------
/images/wiki/certificateTrustedUAExpert.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiancoRoyal/node-red-contrib-iiot-opcua/40cf83b46abbed92b9b8f11ebb6eecfc28d2b6a7/images/wiki/certificateTrustedUAExpert.png
--------------------------------------------------------------------------------
/images/wiki/certificateUntrustedUAExpert.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiancoRoyal/node-red-contrib-iiot-opcua/40cf83b46abbed92b9b8f11ebb6eecfc28d2b6a7/images/wiki/certificateUntrustedUAExpert.png
--------------------------------------------------------------------------------
/images/wiki/crawler.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiancoRoyal/node-red-contrib-iiot-opcua/40cf83b46abbed92b9b8f11ebb6eecfc28d2b6a7/images/wiki/crawler.png
--------------------------------------------------------------------------------
/images/wiki/discoveryExampleUAExpert.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiancoRoyal/node-red-contrib-iiot-opcua/40cf83b46abbed92b9b8f11ebb6eecfc28d2b6a7/images/wiki/discoveryExampleUAExpert.png
--------------------------------------------------------------------------------
/images/wiki/example-menu31.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiancoRoyal/node-red-contrib-iiot-opcua/40cf83b46abbed92b9b8f11ebb6eecfc28d2b6a7/images/wiki/example-menu31.png
--------------------------------------------------------------------------------
/images/wiki/flex-connector-flow31.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiancoRoyal/node-red-contrib-iiot-opcua/40cf83b46abbed92b9b8f11ebb6eecfc28d2b6a7/images/wiki/flex-connector-flow31.png
--------------------------------------------------------------------------------
/images/wiki/flexServerAddressSapceExample.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiancoRoyal/node-red-contrib-iiot-opcua/40cf83b46abbed92b9b8f11ebb6eecfc28d2b6a7/images/wiki/flexServerAddressSapceExample.png
--------------------------------------------------------------------------------
/images/wiki/flexServerAddressSapceExamplev3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiancoRoyal/node-red-contrib-iiot-opcua/40cf83b46abbed92b9b8f11ebb6eecfc28d2b6a7/images/wiki/flexServerAddressSapceExamplev3.png
--------------------------------------------------------------------------------
/images/wiki/iiot-nodes-v3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiancoRoyal/node-red-contrib-iiot-opcua/40cf83b46abbed92b9b8f11ebb6eecfc28d2b6a7/images/wiki/iiot-nodes-v3.png
--------------------------------------------------------------------------------
/images/wiki/injectMessage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiancoRoyal/node-red-contrib-iiot-opcua/40cf83b46abbed92b9b8f11ebb6eecfc28d2b6a7/images/wiki/injectMessage.png
--------------------------------------------------------------------------------
/images/wiki/listenerChangedMessage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiancoRoyal/node-red-contrib-iiot-opcua/40cf83b46abbed92b9b8f11ebb6eecfc28d2b6a7/images/wiki/listenerChangedMessage.png
--------------------------------------------------------------------------------
/images/wiki/listenerResultMessageChanged.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiancoRoyal/node-red-contrib-iiot-opcua/40cf83b46abbed92b9b8f11ebb6eecfc28d2b6a7/images/wiki/listenerResultMessageChanged.png
--------------------------------------------------------------------------------
/images/wiki/method-call3-active.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiancoRoyal/node-red-contrib-iiot-opcua/40cf83b46abbed92b9b8f11ebb6eecfc28d2b6a7/images/wiki/method-call3-active.png
--------------------------------------------------------------------------------
/images/wiki/read-history3-active.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiancoRoyal/node-red-contrib-iiot-opcua/40cf83b46abbed92b9b8f11ebb6eecfc28d2b6a7/images/wiki/read-history3-active.png
--------------------------------------------------------------------------------
/images/wiki/read-write-flow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiancoRoyal/node-red-contrib-iiot-opcua/40cf83b46abbed92b9b8f11ebb6eecfc28d2b6a7/images/wiki/read-write-flow.png
--------------------------------------------------------------------------------
/images/wiki/readResultMessage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiancoRoyal/node-red-contrib-iiot-opcua/40cf83b46abbed92b9b8f11ebb6eecfc28d2b6a7/images/wiki/readResultMessage.png
--------------------------------------------------------------------------------
/images/wiki/server-aso-flow3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiancoRoyal/node-red-contrib-iiot-opcua/40cf83b46abbed92b9b8f11ebb6eecfc28d2b6a7/images/wiki/server-aso-flow3.png
--------------------------------------------------------------------------------
/images/wiki/write-flow3-active.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiancoRoyal/node-red-contrib-iiot-opcua/40cf83b46abbed92b9b8f11ebb6eecfc28d2b6a7/images/wiki/write-flow3-active.png
--------------------------------------------------------------------------------
/images/wiki/write-read-flow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiancoRoyal/node-red-contrib-iiot-opcua/40cf83b46abbed92b9b8f11ebb6eecfc28d2b6a7/images/wiki/write-read-flow.png
--------------------------------------------------------------------------------
/images/wiki/write-read-flow2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiancoRoyal/node-red-contrib-iiot-opcua/40cf83b46abbed92b9b8f11ebb6eecfc28d2b6a7/images/wiki/write-read-flow2.png
--------------------------------------------------------------------------------
/images/wiki/write-read-flow3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiancoRoyal/node-red-contrib-iiot-opcua/40cf83b46abbed92b9b8f11ebb6eecfc28d2b6a7/images/wiki/write-read-flow3.png
--------------------------------------------------------------------------------
/images/wiki/writeInputMessage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiancoRoyal/node-red-contrib-iiot-opcua/40cf83b46abbed92b9b8f11ebb6eecfc28d2b6a7/images/wiki/writeInputMessage.png
--------------------------------------------------------------------------------
/images/wiki/writeMessage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiancoRoyal/node-red-contrib-iiot-opcua/40cf83b46abbed92b9b8f11ebb6eecfc28d2b6a7/images/wiki/writeMessage.png
--------------------------------------------------------------------------------
/images/write-examplev220.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiancoRoyal/node-red-contrib-iiot-opcua/40cf83b46abbed92b9b8f11ebb6eecfc28d2b6a7/images/write-examplev220.png
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | /*
2 | The BSD 3-Clause License
3 |
4 | Copyright (c) 2018-2022 Klaus Landsdorf (http://node-red.plus/)
5 | All rights reserved.
6 | node-red-contrib-iiot-opcua
7 | */
8 | 'use strict'
9 |
--------------------------------------------------------------------------------
/npm-update.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | npm cache verify
4 |
5 | npm outdated --depth=0
6 |
7 | npm install
8 |
--------------------------------------------------------------------------------
/npm-upgrade.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | # this sh is to upgrade all package dependencies from NPM
4 | # you need to install before: npm i -g npm-check-updates
5 |
6 | rm package-lock.json
7 |
8 | npm cache verify
9 |
10 | npm outdated --depth=0
11 |
12 | ncu -u
13 |
14 | npm i
15 |
16 | npm i --only=dev
17 |
18 | npm install
19 |
20 | npm test
21 |
22 | npm run build
23 |
--------------------------------------------------------------------------------
/scripts/JestOutputToSummary.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs')
2 | const path = require('path')
3 |
4 | const read = async (outfilepath) => {
5 | const result = new Promise((resolve, reject) => {
6 | fs.readFile(path.join(__dirname, outfilepath || 'out.json'), 'utf8', function (err, data) {
7 | if (err) {
8 | reject(err)
9 | return
10 | }
11 | resolve(JSON.parse(data))
12 | })
13 | }
14 | )
15 |
16 | await result
17 |
18 | if (result instanceof Error) {
19 | console.log('Error reading output file: ' + result.message)
20 | process.exit(1)
21 | }
22 |
23 | return result
24 | }
25 |
26 | const write = async () => {
27 | const results = await read()
28 |
29 | const {
30 | numTotalTestSuites,
31 | numTotalTests,
32 | numPassedTestSuites,
33 | numPassedTests,
34 | success,
35 | testResults
36 | } = results
37 |
38 | if (!success) {
39 | console.log('Jest failed')
40 | process.exit(1)
41 | }
42 |
43 | writeMarkdown({
44 | 'Test Suite Completion': (numPassedTestSuites / numTotalTestSuites * 100) + '% (' + numPassedTestSuites + ' / ' + numTotalTestSuites + ')',
45 | 'Test Completion': (numPassedTests / numTotalTests * 100) + '% (' + numPassedTests + ' / ' + numTotalTests + ')'
46 | }, 'Overall Results', ['Measure', 'Status'])
47 |
48 | const detailedResults = {}
49 | testResults.forEach((singleResult) => {
50 | const name = singleResult.name.split('/test/')[1]
51 | detailedResults[name] = singleResult.status
52 | })
53 |
54 | writeMarkdown(detailedResults, 'Detailed Results ', ['Test', 'Status'])
55 | }
56 |
57 | const writeMarkdown = (obj, title, columns) => {
58 | if (title) console.log('### ' + title)
59 |
60 | const entries = (typeof obj[Object.keys(obj)[0]] === 'string' ? 1 : obj[Object.keys(obj)[0]].length || 1) + 1
61 |
62 | const header = [...Array(entries)].map((item, index) => {
63 | if (index <= columns.length) {
64 | return columns[index]
65 | } else {
66 | return ' '
67 | }
68 | })
69 | const seperator = [...Array(entries)].map((item) => ':---:')
70 |
71 | console.log()
72 | writeRow(header)
73 | writeRow(seperator)
74 |
75 | Object.keys(obj).forEach((key) => {
76 | if (typeof obj[key] !== 'string' && obj[key].length) {
77 | writeRow(key + obj[key])
78 | } else {
79 | writeRow([key, obj[key]])
80 | }
81 | })
82 | console.log()
83 | }
84 |
85 | const writeRow = (array) => {
86 | const output = array.join(' | ')
87 | console.log('| ' + output + ' | ')
88 | }
89 |
90 | write()
91 |
--------------------------------------------------------------------------------
/src/core/opcua-iiot-core-discovery.ts:
--------------------------------------------------------------------------------
1 | /**
2 | The BSD 3-Clause License
3 |
4 | Copyright 2022 - DATATRONiQ GmbH (https://datatroniq.com)
5 | Copyright (c) 2018-2022 Klaus Landsdorf (http://node-red.plus/)
6 | All rights reserved.
7 | node-red-contrib-iiot-opcua
8 | */
9 | 'use strict'
10 | // SOURCE-MAP-REQUIRED
11 |
12 | import debug from 'debug'
13 |
14 | const internalDebugLog = debug('opcuaIIoT:discovery') // eslint-disable-line no-use-before-define
15 | const detailDebugLog = debug('opcuaIIoT:discovery:details') // eslint-disable-line no-use-before-define
16 | const DEFAULT_OPCUA_DISCOVERY_PORT = 4840 // eslint-disable-line no-use-before-define
17 |
18 | const coreDiscovery = {
19 | internalDebugLog,
20 | detailDebugLog,
21 | DEFAULT_OPCUA_DISCOVERY_PORT,
22 | }
23 |
24 | export default coreDiscovery
25 |
--------------------------------------------------------------------------------
/src/core/opcua-iiot-core-filter.ts:
--------------------------------------------------------------------------------
1 | /**
2 | The BSD 3-Clause License
3 |
4 | Copyright 2022 - DATATRONiQ GmbH (https://datatroniq.com)
5 | Copyright (c) 2018-2022 Klaus Landsdorf (http://node-red.plus/)
6 | All rights reserved.
7 | node-red-contrib-iiot-opcua
8 | */
9 | 'use strict'
10 | // SOURCE-MAP-REQUIRED
11 |
12 |
13 | import debug from 'debug';
14 |
15 | const coreFilter = {
16 | internalDebugLog: debug('opcuaIIoT:filter:internal'),
17 | }
18 |
19 | export default coreFilter
20 |
--------------------------------------------------------------------------------
/src/core/opcua-iiot-core-inject.ts:
--------------------------------------------------------------------------------
1 | /**
2 | The BSD 3-Clause License
3 |
4 | Copyright 2022 - DATATRONiQ GmbH (https://datatroniq.com)
5 | Copyright (c) 2018-2022 Klaus Landsdorf (http://node-red.plus/)
6 | All rights reserved.
7 | node-red-contrib-iiot-opcua
8 | */
9 | 'use strict'
10 | // SOURCE-MAP-REQUIRED
11 |
12 | import debug from 'debug';
13 |
14 | const internalDebugLog = debug('opcuaIIoT:inject') // eslint-disable-line no-use-before-define
15 | const detailDebugLog = debug('opcuaIIoT:inject:details') // eslint-disable-line no-use-before-define
16 |
17 | const coreInject = {
18 | internalDebugLog,
19 | detailDebugLog
20 | }
21 |
22 | export default coreInject
23 |
--------------------------------------------------------------------------------
/src/helpers/isa95_demo_address_space.ts:
--------------------------------------------------------------------------------
1 | /*
2 | The MIT License (MIT)
3 |
4 | Copyright (c) 2022 DATATRONiQ GmbH
5 | Copyright (c) 2017-2022 Klaus Landsdorf (http://node-red.plus/)
6 | Copyright (c) 2014-2017 Etienne Rossignon
7 |
8 | Permission is hereby granted, free of charge, to any person obtaining a copy of
9 | this software and associated documentation files (the "Software"), to deal in
10 | the Software without restriction, including without limitation the rights to
11 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
12 | the Software, and to permit persons to whom the Software is furnished to do so,
13 | subject to the following conditions:
14 |
15 | The above copyright notice and this permission notice shall be included in all
16 | copies or substantial portions of the Software.
17 |
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
20 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
21 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
22 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 | */
25 | 'use strict'
26 |
--------------------------------------------------------------------------------
/src/icons/OPCUA-IIoT-Logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiancoRoyal/node-red-contrib-iiot-opcua/40cf83b46abbed92b9b8f11ebb6eecfc28d2b6a7/src/icons/OPCUA-IIoT-Logo.png
--------------------------------------------------------------------------------
/src/icons/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiancoRoyal/node-red-contrib-iiot-opcua/40cf83b46abbed92b9b8f11ebb6eecfc28d2b6a7/src/icons/icon.png
--------------------------------------------------------------------------------
/src/icons/isa95-icon-blue-1024.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiancoRoyal/node-red-contrib-iiot-opcua/40cf83b46abbed92b9b8f11ebb6eecfc28d2b6a7/src/icons/isa95-icon-blue-1024.png
--------------------------------------------------------------------------------
/src/icons/isa95-icon-blue-128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiancoRoyal/node-red-contrib-iiot-opcua/40cf83b46abbed92b9b8f11ebb6eecfc28d2b6a7/src/icons/isa95-icon-blue-128.png
--------------------------------------------------------------------------------
/src/icons/isa95-icon-blue-64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiancoRoyal/node-red-contrib-iiot-opcua/40cf83b46abbed92b9b8f11ebb6eecfc28d2b6a7/src/icons/isa95-icon-blue-64.png
--------------------------------------------------------------------------------
/src/icons/isa95-icon-blue.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiancoRoyal/node-red-contrib-iiot-opcua/40cf83b46abbed92b9b8f11ebb6eecfc28d2b6a7/src/icons/isa95-icon-blue.png
--------------------------------------------------------------------------------
/src/icons/opcuaiiot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BiancoRoyal/node-red-contrib-iiot-opcua/40cf83b46abbed92b9b8f11ebb6eecfc28d2b6a7/src/icons/opcuaiiot.png
--------------------------------------------------------------------------------
/src/locales/de-DE/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "opcua-iiot-contrib": {
3 | "common": {
4 | "label": {
5 | "type": "Typ",
6 | "showActivities": "Zeige Aktivitäten",
7 | "showErrors": "Zeige Fehler"
8 | },
9 | "response": {
10 | },
11 | "getter": {
12 | },
13 | "read": {
14 | },
15 | "write": {
16 | },
17 | "server": {
18 | },
19 | "client": {
20 | }
21 | }
22 | }
23 | }
--------------------------------------------------------------------------------
/src/locales/de-DE/opcua-iiot-browser.json:
--------------------------------------------------------------------------------
1 | {
2 | "opcua-iiot-contrib": {
3 | "tabs-label":{
4 | "settings": "Einstellungen"
5 | },
6 | "label": {
7 | "connector": "Verbindung",
8 | "justValue": "Sende nur Werte",
9 | "sendNodesToRead": "Ergebnisliste für Read",
10 | "sendNodesToListener": "Ergebnisliste für Listener",
11 | "sendNodesToBrowser": "Ergebnisliste für Browser",
12 | "Multiple Outputs": "Separate Ergebnisse",
13 | "lookupUseHint": "Das Browsen funktioniert via Auswahl und erneutem Klick auf Suche.",
14 | "showActivities": "Zeige Aktivitäten",
15 | "showErrors": "Zeige Fehler"
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/locales/de-DE/opcua-iiot-connector.json:
--------------------------------------------------------------------------------
1 | {
2 | "opcua-iiot-contrib": {
3 | "label": {
4 | "type": "Typ",
5 | "connector": "Verbindung",
6 | "credentials": "Verwende Login",
7 | "user": "Benutzer",
8 | "password": "Kennwort",
9 | "keepSessionAlive": "Halte Session aktiv",
10 | "publicCertificateFile": "Öffentlich",
11 | "privateKeyFile": "Privat",
12 | "certificateFiles": "Zertifikatdateien",
13 | "endpointMustExist": "Endpoint muss exakt sein",
14 | "autoSelectRightEndpoint": "Automatische Endpoint-Auswahl",
15 | "showErrors": "Zeige Fehler",
16 | "individualCerts": "Nutze individuelle Zertifikate"
17 | },
18 | "tabs-label": {
19 | "settings": "Einstellungen",
20 | "security": "Sicherheit",
21 | "strategy": "Strategie"
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/locales/de-DE/opcua-iiot-event.json:
--------------------------------------------------------------------------------
1 | {
2 | "opcua-iiot-contrib": {
3 | "label": {
4 | "eventType": "Event Typ",
5 | "queueSize": "Queue Umfang",
6 | "showActivities": "Zeige Aktivitäten",
7 | "showErrors": "Zeige Fehler",
8 | "parseStrings": "Parse Daten",
9 | "lookupUseHint": "Die Eventauswahl funktioniert via Auswahl und erneutem Klick auf Suche."
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/locales/de-DE/opcua-iiot-flex-server.json:
--------------------------------------------------------------------------------
1 | {
2 | "opcua-iiot-contrib": {
3 | "label": {
4 | "showActivities": "Zeige Aktivitäten",
5 | "showErrors": "Zeige Fehler",
6 | "stateLogEnabled": "Log Aktiv",
7 | "addButton": "Neu",
8 | "removeButton": "Entfernen",
9 | "maxConnectionsPerEndpoint": "Max Verbindungen/Endpoint",
10 | "alternateHostname": "Alternativer Hostname",
11 | "allowAnonymous": "Erlaube Anonymous",
12 | "publicCertificateFile": "Öffentlich",
13 | "privateCertificateFile": "Privat",
14 | "certificateFiles": "Zertifikatdateien",
15 | "users": "Benutzer",
16 | "individualCerts": "Nutze individuelle Zertifikate"
17 | },
18 | "tabs-label": {
19 | "users": "Benutzer & Sets",
20 | "settings": "Einstellungen",
21 | "security": "Sicherheit"
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/locales/de-DE/opcua-iiot-inject.json:
--------------------------------------------------------------------------------
1 | {
2 | "opcuaiiotinject": {
3 | "opcuaiiotinject": "inject",
4 | "inject": "inject",
5 | "injectType": "Typ",
6 | "repeat": "repeat = __repeat__",
7 | "crontab": "crontab = __crontab__",
8 | "stopped": "stopped",
9 | "failed": "Inject failed: __error__",
10 | "label": {
11 | "repeat": "Wiederholung"
12 | },
13 | "timestamp": "Zeitstempel",
14 | "none": "keine",
15 | "interval": "Interval",
16 | "interval-time": "Zeitinterval",
17 | "time": "bestimmter Zeitpunkt",
18 | "seconds": "Sekunden",
19 | "minutes": "Minuten",
20 | "hours": "Stunden",
21 | "between": "zwischen",
22 | "previous": "previous value",
23 | "at": "an",
24 | "and": "und",
25 | "every": "jede",
26 | "days": [
27 | "Montag",
28 | "Dienstag",
29 | "Mittwoch",
30 | "Donnerstag",
31 | "Freitag",
32 | "Samstag",
33 | "Sonntag"
34 | ],
35 | "on": "um",
36 | "onstart": "Inject beim Start?",
37 | "tip": "Note: \"interval between times\" and \"at a specific time\" will use cron.
See info box for details.",
38 | "success": "Erfolgreich injected: __label__",
39 | "errors": {
40 | "failed": "inject failed, see log for details"
41 | },
42 | "startDelay": "Delay beim Start",
43 | "startDelayAddon": "Sek. und dann"
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/locales/de-DE/opcua-iiot-listener.json:
--------------------------------------------------------------------------------
1 | {
2 | "opcua-iiot-contrib": {
3 | "label": {
4 | "connector": "Verbindung",
5 | "showActivities": "Zeige Aktivitäten",
6 | "showErrors": "Zeige Fehler",
7 | "actiontype": "Actionstyp",
8 | "attributeId": "Attribut Id",
9 | "queueSize": "Queue Umfang",
10 | "justValue": "Sende nur Werte",
11 | "useGroupItems": "Nutze Gruppierung"
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/locales/de-DE/opcua-iiot-method-caller.json:
--------------------------------------------------------------------------------
1 | {
2 | "opcua-iiot-contrib": {
3 | "tabs-label":{
4 | "settings": "Einstellungen",
5 | "argument": "Argumente"
6 | },
7 | "label": {
8 | "connector": "Verbindung",
9 | "methodType": "Methodentyp",
10 | "value": "Wert",
11 | "showActivities": "Zeige Aktivitäten",
12 | "showErrors": "Zeige Fehler",
13 | "addButton": "Neu",
14 | "removeButton": "Entfernen",
15 | "justValue": "Sende nur Werte"
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/locales/de-DE/opcua-iiot-node.json:
--------------------------------------------------------------------------------
1 | {
2 | "opcua-iiot-contrib": {
3 | "label": {
4 | "nodeId": "Node-Id",
5 | "datatype": "Datentyp",
6 | "value": "Wert",
7 | "injectType": "Typ",
8 | "showActivities": "Zeige Aktivitäten",
9 | "showErrors": "Zeige Fehler"
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/locales/de-DE/opcua-iiot-read.json:
--------------------------------------------------------------------------------
1 | {
2 | "opcua-iiot-contrib": {
3 | "label": {
4 | "connector": "Verbindung",
5 | "showActivities": "Zeige Aktivitäten",
6 | "showErrors": "Zeige Fehler",
7 | "attributeId": "Attribut Id",
8 | "maxAge": "Max. Alter",
9 | "depth": "Tiefe",
10 | "justValue": "Sende nur Werte",
11 | "parseStrings": "Parse Daten"
12 | }
13 | }
14 | }
--------------------------------------------------------------------------------
/src/locales/de-DE/opcua-iiot-response.json:
--------------------------------------------------------------------------------
1 | {
2 | "opcua-iiot-contrib": {
3 | "label": {
4 | "compressStructure": "Vereinfache Daten",
5 | "showActivities": "Zeige Aktivitäten",
6 | "showErrors": "Zeige Fehler"
7 | }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/locales/de-DE/opcua-iiot-result-filter.json:
--------------------------------------------------------------------------------
1 | {
2 | "opcua-iiot-contrib": {
3 | "tabs-label":{
4 | "settings": "Einstellungen",
5 | "convert": "Umwandlung"
6 | },
7 | "label": {
8 | "datatype": "Datentyp",
9 | "withPrecision": "Max Stellen",
10 | "precision": "Stellen",
11 | "fixedValue": "Nachkommastellen",
12 | "fixPoint": "Anzahl",
13 | "entry": "Array Eintrag",
14 | "justValue": "Sende nur Werte",
15 | "withValueCheck": "Wertprüfung",
16 | "minvalue": "Min Wert",
17 | "maxvalue": "Max Wert",
18 | "defaultvalue": "Default Wert",
19 | "showActivities": "Zeige Aktivitäten",
20 | "showErrors": "Zeige Fehler"
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/locales/de-DE/opcua-iiot-server-aso.json:
--------------------------------------------------------------------------------
1 | {
2 | "opcua-iiot-contrib": {
3 | "label": {
4 | "objecttype": "Objekttyp",
5 | "referencetype": "Referenztyp",
6 | "referenceNodeId": "Referenz-Id",
7 | "datatype": "Datentyp",
8 | "value": "Wert",
9 | "showActivities": "Zeige Aktivitäten",
10 | "showErrors": "Zeige Fehler",
11 | "displayname": "Anzeigename",
12 | "browsename": "Browse-Name"
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/locales/de-DE/opcua-iiot-server-cmd.json:
--------------------------------------------------------------------------------
1 | {
2 | "opcua-iiot-contrib": {
3 | "label": {
4 | "commandtype": "Kommandotype",
5 | "showActivities": "Zeige Aktivitäten",
6 | "showErrors": "Zeige Fehler"
7 | }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/locales/de-DE/opcua-iiot-server.json:
--------------------------------------------------------------------------------
1 | {
2 | "opcua-iiot-contrib": {
3 | "label": {
4 | "showActivities": "Zeige Aktivitäten",
5 | "showErrors": "Zeige Fehler",
6 | "stateLogEnabled": "Log Aktiv",
7 | "addButton": "Neu",
8 | "removeButton": "Entfernen",
9 | "maxConnectionsPerEndpoint": "Max Verbindungen/Endpoint",
10 | "alternateHostname": "Alternativer Hostname",
11 | "allowAnonymous": "Erlaube Anonymous",
12 | "publicCertificateFile": "Öffentlich",
13 | "privateCertificateFile": "Privat",
14 | "certificateFiles": "Zertifikatdateien",
15 | "users": "Benutzer",
16 | "individualCerts": "Nutze individuelle Zertifikate"
17 | },
18 | "tabs-label": {
19 | "users": "Benutzer & Sets",
20 | "settings": "Einstellungen",
21 | "security": "Sicherheit"
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/locales/de-DE/opcua-iiot-write.json:
--------------------------------------------------------------------------------
1 | {
2 | "opcua-iiot-contrib": {
3 | "label": {
4 | "connector": "Verbindung",
5 | "justValue": "Sende nur Werte",
6 | "showActivities": "Zeige Aktivitäten",
7 | "showErrors": "Zeige Fehler"
8 | }
9 | }
10 | }
--------------------------------------------------------------------------------
/src/locales/en-US/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "common": {
3 | "label": {
4 | "payload": "Payload",
5 | "topic": "Topic",
6 | "name": "Name",
7 | "username": "Username",
8 | "password": "Password"
9 | },
10 | "status": {
11 | "connected": "connected",
12 | "not-connected": "not connected",
13 | "disconnected": "disconnected",
14 | "connecting": "connecting",
15 | "error": "error",
16 | "ok": "OK"
17 | },
18 | "notification": {
19 | "error": "Error: __message__",
20 | "errors": {
21 | "not-deployed": "node not deployed",
22 | "no-response": "no response from server",
23 | "unexpected": "unexpected error (__status__) __message__"
24 | }
25 | },
26 | "errors": {
27 | "nooverride": "Warning: msg properties can no longer override set node properties. See bit.ly/nr-override-msg-props"
28 | }
29 | },
30 | "opcua-iiot-contrib": {
31 | "common": {
32 | "label": {
33 | "type": "Type",
34 | "server": "Server",
35 | "timeout": "Timeout",
36 | "name": "Name",
37 | "endpoint": "Endpoint",
38 | "connector": "Connector",
39 | "topic": "Topic",
40 | "user": "User",
41 | "password": "Password",
42 | "showActivities": "Show Activities",
43 | "showErrors": "Show Errors"
44 | },
45 | "response": {
46 | },
47 | "getter": {
48 | },
49 | "read": {
50 | },
51 | "write": {
52 | },
53 | "server": {
54 | },
55 | "client": {
56 | }
57 | }
58 | }
59 | }
--------------------------------------------------------------------------------
/src/locales/en-US/opcua-iiot-browser.json:
--------------------------------------------------------------------------------
1 | {
2 | "opcua-iiot-contrib": {
3 | "tabs-label":{
4 | "settings": "Settings",
5 | "browser": "Browser"
6 | },
7 | "label": {
8 | "connector": "Connector",
9 | "browseAll": "Browse All",
10 | "justValue": "Send Just Values",
11 | "sendNodesToRead": "Results To Read",
12 | "sendNodesToListener": "Results To Listener",
13 | "sendNodesToBrowser": "Results To Browser",
14 | "multipleOutputs": "Multiple Outputs",
15 | "showActivities": "Show Activities",
16 | "showErrors": "Show Errors",
17 | "topic": "Topic",
18 | "nodeId": "Node-Id",
19 | "lookupUseHint": "Start browsing with the lookup button! Select and lookup again to go deeper in hierarchy. Restart at root by deleting the input content.",
20 | "recursiveBrowse": "Recursive",
21 | "recursiveDepth": "Depth",
22 | "delayPerMessage": "Delay msg"
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/locales/en-US/opcua-iiot-connector.json:
--------------------------------------------------------------------------------
1 | {
2 | "opcua-iiot-contrib": {
3 | "label": {
4 | "discoveryUrl": "Discovery",
5 | "endpoint": "Endpoint",
6 | "connector": "Connector",
7 | "showErrors": "Show Errors",
8 | "type": "Type",
9 | "host": "Host",
10 | "port": "Port",
11 | "securityPolicy": "Security Policy",
12 | "securityMode": "Security Mode",
13 | "user": "User",
14 | "password": "Password",
15 | "credentials": "Use Login",
16 | "keepSessionAlive": "Keep Session Alive",
17 | "publicCertificateFile": "Public",
18 | "privateKeyFile": "Private",
19 | "defaultSecureTokenLifetime": "Secure TLT",
20 | "certificateFiles": "Certificate Files",
21 | "endpointMustExist": "Endpoint Must Exist",
22 | "autoSelectRightEndpoint": "Auto Select Endpoint",
23 | "strategyMaxRetry": "Max. Retry",
24 | "strategyInitialDelay": "Initial Delay",
25 | "strategyMaxDelay": "Max. Delay",
26 | "strategyRandomisationFactor": "Random Factor",
27 | "requestedSessionTimeout": "Requested Timeout",
28 | "connectionStartDelay": "Start",
29 | "reconnectDelay": "Reconnect",
30 | "connectionStopDelay": "Stop",
31 | "serverConnectionDelays": "Server Connection Delays",
32 | "maxBadSessionRequests": "Max. BadSession Requests",
33 | "individualCerts": "Use individual Certificate Files"
34 | },
35 | "tabs-label": {
36 | "settings": "Settings",
37 | "security": "Security",
38 | "strategy": "Strategy"
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/locales/en-US/opcua-iiot-crawler.json:
--------------------------------------------------------------------------------
1 | {
2 | "opcua-iiot-contrib": {
3 | "tabs-label":{
4 | "settings": "Settings",
5 | "filter": "Filter"
6 | },
7 | "label": {
8 | "activateUnsetFilter": "Unset filtering",
9 | "activateFilters": "Activate filters",
10 | "negateFilter": "Negate filter",
11 | "filters": "Filter List",
12 | "connector": "Connector",
13 | "justValue": "Remove References",
14 | "singleResult": "Single Request",
15 | "showActivities": "Show Activities",
16 | "showErrors": "Show Errors",
17 | "topic": "Topic",
18 | "nodeId": "Node-Id",
19 | "lookupUseHint": "You can crawl with the lookup by select and lookup agian.",
20 | "delayPerMessage": "Delay Between Messages",
21 | "timeout": "Crawler Timeout"
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/locales/en-US/opcua-iiot-discovery.json:
--------------------------------------------------------------------------------
1 | {
2 | "opcua-iiot-contrib": {
3 | "label": {
4 | "showActivities": "Show Activities",
5 | "showErrors": "Show Errors"
6 | }
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/src/locales/en-US/opcua-iiot-event.json:
--------------------------------------------------------------------------------
1 | {
2 | "opcua-iiot-contrib": {
3 | "label": {
4 | "eventType": "Event Type",
5 | "resultType": "Result Type",
6 | "queueSize": "Queue Size",
7 | "usingListener": "Listener",
8 | "showActivities": "Show Activities",
9 | "showErrors": "Show Errors",
10 | "parseStrings": "Parse Output",
11 | "lookupUseHint": "You can use the lookup or give a NodeId of your event."
12 | },
13 | "resulttype": {
14 | "label": {
15 | "basic": "basic",
16 | "condition": "condition",
17 | "state": "state",
18 | "all": "all"
19 | }
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/locales/en-US/opcua-iiot-flex-connector.json:
--------------------------------------------------------------------------------
1 | {
2 | "opcua-iiot-contrib": {
3 | "label": {
4 | "connector": "Connector",
5 | "showActivities": "Show Activities",
6 | "showErrors": "Show Errors"
7 | }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/locales/en-US/opcua-iiot-flex-server.json:
--------------------------------------------------------------------------------
1 | {
2 | "opcua-iiot-contrib": {
3 | "label": {
4 | "port": "Port",
5 | "endpoint": "Endpoint",
6 | "showActivities": "Show Activities",
7 | "showErrors": "Show Errors",
8 | "stateLogEnabled": "Log State",
9 | "statusLog": "Log Status",
10 | "securityPolicy": "Security Policies",
11 | "securityMode": "Security Modes",
12 | "addButton": "Add",
13 | "removeButton": "Remove",
14 | "maxAllowedSessionNumber": "Max Sessions",
15 | "maxConnectionsPerEndpoint": "Max Connections Per Endpoint",
16 | "maxAllowedSubscriptionNumber": "Max Subscriptions",
17 | "alternateHostname": "Alternate Hostname",
18 | "allowAnonymous": "Allow Anonymous",
19 | "isAuditing": "Auditing",
20 | "function": "Address Space Script",
21 | "publicCertificateFile": "Public",
22 | "privateCertificateFile": "Private",
23 | "certificateFiles": "Certificate Files",
24 | "users": "Users",
25 | "xmlsets": "XML-Sets",
26 | "serverDiscovery": "Discovery",
27 | "maxNodesPerRead": "Max per Read",
28 | "maxNodesPerBrowse": "Max per Browse",
29 | "registerServerMethod": "Register Server Method",
30 | "discoveryServerEndpointUrl": "Endpoint Url",
31 | "capabilitiesForMDNS": "MDNS capabilities",
32 | "delayToClose": "Delay On Close",
33 | "individualCerts": "Use individual Certificate Files"
34 | },
35 | "tabs-label": {
36 | "users": "Users & Sets",
37 | "settings": "Settings",
38 | "security": "Security",
39 | "ass": "Address Space",
40 | "discovery": "Discovery",
41 | "limits": "Limits"
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/locales/en-US/opcua-iiot-inject.json:
--------------------------------------------------------------------------------
1 | {
2 | "opcuaiiotinject": {
3 | "injectTypeListener": "Listener Inject",
4 | "inject": "inject",
5 | "opcuaiiotinject": "inject",
6 | "injectType": "Type",
7 | "repeat": "repeat = __repeat__",
8 | "crontab": "crontab = __crontab__",
9 | "stopped": "stopped",
10 | "failed": "Inject failed: __error__",
11 | "label": {
12 | "payload": "Payload",
13 | "interval": "Interval",
14 | "repeat": "Repeat",
15 | "datatype": "Data Type",
16 | "nodeid": "Node-Id",
17 | "injectType": "Type"
18 | },
19 | "timestamp": "timestamp",
20 | "none": "none",
21 | "interval": "interval",
22 | "interval-time": "interval between times",
23 | "time": "at a specific time",
24 | "milliseconds": "milliseconds",
25 | "seconds": "seconds",
26 | "minutes": "minutes",
27 | "hours": "hours",
28 | "between": "between",
29 | "previous": "previous value",
30 | "at": "at",
31 | "and": "and",
32 | "every": "every",
33 | "days": [
34 | "Monday",
35 | "Tuesday",
36 | "Wednesday",
37 | "Thursday",
38 | "Friday",
39 | "Saturday",
40 | "Sunday"
41 | ],
42 | "on": "on",
43 | "onstart": "Delay before starting",
44 | "tip": "Note: \"interval between times\" and \"at a specific time\" will use cron.
See info box for details.",
45 | "success": "Successfully injected: __label__",
46 | "errors": {
47 | "failed": "inject failed, see log for details"
48 | },
49 | "startDelay": "Delay at start",
50 | "startDelayAddon": "sec. then",
51 | "addButton": "Add",
52 | "tabs-label": {
53 | "addressSpaceItems": "OPC UA Nodes",
54 | "settings": "Settings",
55 | "security": "Security"
56 | },
57 | "type-label":{
58 | "inject": "inject",
59 | "read": "read",
60 | "write": "write",
61 | "listen": "listen"
62 | }
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/src/locales/en-US/opcua-iiot-listener.json:
--------------------------------------------------------------------------------
1 | {
2 | "opcua-iiot-contrib": {
3 | "label": {
4 | "connector": "Connector",
5 | "actiontype": "Action Type",
6 | "interval": "Interval",
7 | "showActivities": "Show Activities",
8 | "showErrors": "Show Errors",
9 | "attributeId": "Attribute Id",
10 | "queueSize": "Queue Size",
11 | "justValue": "Send Just Values",
12 | "useGroupItems": "Group Items"
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/locales/en-US/opcua-iiot-method-caller.json:
--------------------------------------------------------------------------------
1 | {
2 | "opcua-iiot-contrib": {
3 | "tabs-label":{
4 | "settings": "Settings",
5 | "argument": "Input-Arguments"
6 | },
7 | "label": {
8 | "connector": "Connector",
9 | "objectId": "Object-Id",
10 | "methodId": "Method-Id",
11 | "methodType": "Method Type",
12 | "value": "Value",
13 | "showActivities": "Show Activities",
14 | "showErrors": "Show Errors",
15 | "addButton": "Add",
16 | "removeButton": "Remove",
17 | "justValue": "Send Just Values"
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/locales/en-US/opcua-iiot-node.json:
--------------------------------------------------------------------------------
1 | {
2 | "opcua-iiot-contrib": {
3 | "label": {
4 | "nodeId": "Node-Id",
5 | "datatype": "Data Type",
6 | "value": "Value",
7 | "topic": "Topic",
8 | "injectType": "Type",
9 | "showActivities": "Show Activities",
10 | "showErrors": "Show Errors"
11 | },
12 | "type-label":{
13 | "inject": "inject",
14 | "read": "read",
15 | "write": "write",
16 | "listen": "listen"
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/locales/en-US/opcua-iiot-read.json:
--------------------------------------------------------------------------------
1 | {
2 | "opcua-iiot-contrib": {
3 | "label": {
4 | "connector": "Connector",
5 | "showActivities": "Show Activities",
6 | "showErrors": "Show Errors",
7 | "attributeId": "Attribute Id",
8 | "maxAge": "Max. Age",
9 | "depth": "Depth",
10 | "justValue": "Send Just Values",
11 | "parseStrings": "Parse Result",
12 | "historyDays": "History Days"
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/locales/en-US/opcua-iiot-response.json:
--------------------------------------------------------------------------------
1 | {
2 | "opcua-iiot-contrib": {
3 | "tabs-label":{
4 | "settings": "Settings",
5 | "filter": "Filter"
6 | },
7 | "label": {
8 | "activateUnsetFilter": "Unset filtering",
9 | "negateFilter": "Negate filter",
10 | "activateFilters": "Activate filters",
11 | "compressStructure": "Simplify results",
12 | "showActivities": "Show Activities",
13 | "showErrors": "Show Errors"
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/locales/en-US/opcua-iiot-result-filter.json:
--------------------------------------------------------------------------------
1 | {
2 | "opcua-iiot-contrib": {
3 | "tabs-label":{
4 | "settings": "Settings",
5 | "convert": "Converts"
6 | },
7 | "label": {
8 | "nodeId": "Node-Id",
9 | "datatype": "Data Type",
10 | "withPrecision": "With Precision",
11 | "precision": "Precision",
12 | "fixedValue": "Fixed Value",
13 | "fixPoint": "Fix",
14 | "entry": "Array Entry",
15 | "justValue": "Send Just Values",
16 | "withValueCheck": "With Value Check",
17 | "minvalue": "Min Value",
18 | "maxvalue": "Max Value",
19 | "defaultvalue": "Default Value",
20 | "usingListener": "Listener",
21 | "showActivities": "Show Activities",
22 | "showErrors": "Show Errors"
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/locales/en-US/opcua-iiot-server-aso.json:
--------------------------------------------------------------------------------
1 | {
2 | "opcua-iiot-contrib": {
3 | "label": {
4 | "nodeId": "Node-Id",
5 | "objecttype": "Object Type",
6 | "referencetype": "Reference Type",
7 | "referenceNodeId": "Reference Id",
8 | "datatype": "Data Type",
9 | "value": "Value",
10 | "showActivities": "Show Activities",
11 | "showErrors": "Show Errors",
12 | "displayname": "Display Name",
13 | "browsename": "Browse Name"
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/locales/en-US/opcua-iiot-server-cmd.json:
--------------------------------------------------------------------------------
1 | {
2 | "opcua-iiot-contrib": {
3 | "label": {
4 | "nodeId": "Node-Id",
5 | "commandtype": "Command Type",
6 | "showActivities": "Show Activities",
7 | "showErrors": "Show Errors"
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/locales/en-US/opcua-iiot-server.json:
--------------------------------------------------------------------------------
1 | {
2 | "opcua-iiot-contrib": {
3 | "label": {
4 | "port": "Port",
5 | "endpoint": "Endpoint",
6 | "showActivities": "Show Activities",
7 | "showErrors": "Show Errors",
8 | "stateLogEnabled": "Log State",
9 | "statusLog": "Log Status",
10 | "securityPolicy": "Security Policies",
11 | "securityMode": "Security Modes",
12 | "addButton": "Add",
13 | "removeButton": "Remove",
14 | "maxAllowedSessionNumber": "Max Sessions",
15 | "maxConnectionsPerEndpoint": "Max Connections Per Endpoint",
16 | "maxAllowedSubscriptionNumber": "Max Subscriptions",
17 | "alternateHostname": "Alternate Hostname",
18 | "allowAnonymous": "Allow Anonymous",
19 | "isAuditing": "Auditing",
20 | "publicCertificateFile": "Public",
21 | "privateCertificateFile": "Private",
22 | "certificateFiles": "Certificate Files",
23 | "xmlsets": "XML-Sets",
24 | "asoDemo": "ASO Demo",
25 | "serverDiscovery": "Discovery",
26 | "maxNodesPerRead": "Max per Read",
27 | "maxNodesPerBrowse": "Max per Browse",
28 | "registerServerMethod": "Register Server Method",
29 | "discoveryServerEndpointUrl": "Endpoint Url",
30 | "capabilitiesForMDNS": "MDNS capabilities",
31 | "delayToClose": "Delay On Close",
32 | "individualCerts": "Use individual Certificate Files"
33 | },
34 | "tabs-label": {
35 | "users": "Users & Sets",
36 | "settings": "Settings",
37 | "security": "Security",
38 | "discovery": "Discovery",
39 | "limits": "Limits"
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/locales/en-US/opcua-iiot-write.json:
--------------------------------------------------------------------------------
1 | {
2 | "opcua-iiot-contrib": {
3 | "label": {
4 | "connector": "Connector",
5 | "justValue": "Send Just Values",
6 | "showActivities": "Show Activities",
7 | "showErrors": "Show Errors"
8 | }
9 | }
10 | }
--------------------------------------------------------------------------------
/src/opcua-iiot-discovery.html:
--------------------------------------------------------------------------------
1 |
10 |
11 |
31 |
32 |
42 |
43 |
53 |
--------------------------------------------------------------------------------
/src/opcua-iiot-flex-connector.html:
--------------------------------------------------------------------------------
1 |
9 |
10 |
35 |
36 |
57 |
58 |
104 |
--------------------------------------------------------------------------------
/src/opcua-iiot-flex-connector.ts:
--------------------------------------------------------------------------------
1 | /*
2 | The BSD 3-Clause License
3 |
4 | Copyright 2022 - DATATRONiQ GmbH (https://datatroniq.com)
5 | Copyright (c) 2018-2022 Klaus Landsdorf (http://node-red.plus/)
6 | All rights reserved.
7 | node-red-contrib-iiot-opcua
8 | */
9 | 'use strict'
10 | import * as nodered from "node-red";
11 | import {NodeMessage, NodeStatus} from "node-red";
12 | import {TodoTypeAny} from "./types/placeholders";
13 | import coreConnector from "./core/opcua-iiot-core-connector";
14 | import {deregisterToConnector, registerToConnector, resetIiotNode} from "./core/opcua-iiot-core";
15 | import {NodeMessageInFlow} from "@node-red/registry";
16 |
17 | export interface OPCUAIIoTFlexConnector extends nodered.Node {
18 | showStatusActivities: boolean
19 | showErrors: boolean
20 | connector: any
21 | iiot?: TodoTypeAny
22 | }
23 |
24 | interface OPCUAIIoTFlexConnectorConfigurationDef extends nodered.NodeDef {
25 | showStatusActivities: boolean
26 | showErrors: boolean
27 | connector: any
28 | }
29 |
30 | /**
31 | * Event Node-RED node.
32 | *
33 | * @param RED
34 | */
35 | module.exports = function (RED: nodered.NodeAPI) {
36 | // SOURCE-MAP-REQUIRED
37 |
38 | function OPCUAIIoTFlexConnector(this: OPCUAIIoTFlexConnector, config: OPCUAIIoTFlexConnectorConfigurationDef) {
39 | RED.nodes.createNode(this, config)
40 | this.name = config.name
41 | this.showStatusActivities = config.showStatusActivities
42 | this.showErrors = config.showErrors
43 | this.connector = RED.nodes.getNode(config.connector)
44 |
45 | let self = this;
46 | self.iiot = {}
47 |
48 | this.status({fill: 'blue', shape: 'ring', text: 'new'})
49 |
50 | this.on('input', (msg: NodeMessageInFlow) => {
51 | coreConnector.internalDebugLog('connector change request input')
52 |
53 | const payload: TodoTypeAny = msg.payload
54 |
55 | if (self.connector) {
56 | if (payload.endpoint && payload.endpoint.includes('opc.tcp:')) {
57 | coreConnector.internalDebugLog('connector change possible')
58 | coreConnector.internalDebugLog(payload)
59 | self.connector.functions.restartWithNewSettings(payload, () => {
60 | coreConnector.internalDebugLog('connector change injected')
61 | this.send(msg)
62 | })
63 | } else {
64 | coreConnector.internalDebugLog('Connector Change Not Possible - Wrong Endpoint')
65 | this.error(new Error('Connector Change Not Possible - Wrong Endpoint'), msg)
66 | }
67 | } else {
68 | coreConnector.internalDebugLog('Connector Change Not Possible - No Connector')
69 | this.error(new Error('Connector Change Not Possible - No Connector'), msg)
70 | }
71 | })
72 |
73 | const statusHandler = (status: string | NodeStatus) => {
74 | this.status(status)
75 | }
76 |
77 | const errorHandler = (err: Error, msg: NodeMessage) => {
78 | this.error(err, msg)
79 | }
80 |
81 | const onAlias = (event: string, callback: () => void) => {
82 | // @ts-ignore
83 | this.on(event, callback)
84 | }
85 |
86 | registerToConnector(this, statusHandler, onAlias, errorHandler)
87 |
88 | this.on('close', (done: () => void) => {
89 | self.removeAllListeners()
90 |
91 | deregisterToConnector(this as TodoTypeAny, () => {
92 | resetIiotNode(this)
93 | done()
94 | })
95 | })
96 | }
97 |
98 | RED.nodes.registerType('OPCUA-IIoT-Flex-Connector', OPCUAIIoTFlexConnector)
99 | }
100 |
--------------------------------------------------------------------------------
/src/opcua-iiot-node.ts:
--------------------------------------------------------------------------------
1 | /*
2 | The BSD 3-Clause License
3 |
4 | Copyright 2022 - DATATRONiQ GmbH (https://datatroniq.com)
5 | Copyright (c) 2018-2022 Klaus Landsdorf (http://node-red.plus/)
6 | Copyright 2015,2016 - Mika Karaila, Valmet Automation Inc. (node-red-contrib-opcua)
7 | All rights reserved.
8 | node-red-contrib-iiot-opcua
9 | */
10 | 'use strict'
11 |
12 | import * as nodered from "node-red";
13 | import {TodoTypeAny} from "./types/placeholders";
14 | import {NodeMessageInFlow} from "@node-red/registry";
15 | import {convertDataValueByDataType} from "./core/opcua-iiot-core";
16 | import {logger} from "./core/opcua-iiot-core-connector";
17 | import _ from "underscore";
18 |
19 | interface OPCUAIIoTNode extends nodered.Node {
20 | nodeId: string
21 | datatype: string
22 | value: string
23 | topic: string
24 | name: string
25 | injectType: string
26 | showErrors: string
27 | }
28 |
29 | interface OPCUAIIoTNodeDef extends nodered.NodeDef {
30 | nodeId: string
31 | datatype: string
32 | value: string
33 | topic: string
34 | name: string
35 | injectType: string
36 | showErrors: string
37 | }
38 |
39 | /**
40 | * OPC UA node representation for Node-RED OPC UA IIoT nodes.
41 | *
42 | * @param RED
43 | */
44 | module.exports = (RED: nodered.NodeAPI) => {
45 | // SOURCE-MAP-REQUIRED
46 |
47 | function OPCUAIIoTNode(this: OPCUAIIoTNode, config: OPCUAIIoTNodeDef) {
48 | RED.nodes.createNode(this, config)
49 | this.nodeId = config.nodeId
50 | this.datatype = config.datatype
51 | this.value = config.value
52 | this.topic = config.topic
53 | this.name = config.name
54 | this.injectType = config.injectType
55 | this.showErrors = config.showErrors
56 |
57 | let self: TodoTypeAny = this
58 | self.iiot = {}
59 |
60 | self.iiot.subscribed = false
61 | self.status({fill: 'blue', shape: 'ring', text: 'new'})
62 |
63 | self.toggleNodeStatusSymbol = () => {
64 | self.iiot.subscribed = !self.iiot.subscribed
65 |
66 | if (self.injectType === 'listen') {
67 | if (self.iiot.subscribed) {
68 | self.status({fill: 'blue', shape: 'dot', text: 'subscribed'})
69 | } else {
70 | self.status({fill: 'blue', shape: 'ring', text: 'not subscribed'})
71 | }
72 | } else {
73 | self.status({fill: 'blue', shape: 'dot', text: 'injected'})
74 | }
75 | }
76 |
77 | this.on('input', (msg: NodeMessageInFlow) => {
78 |
79 | self.toggleNodeStatusSymbol();
80 |
81 | const topic = msg.topic || self.topic
82 | const payload = msg.payload as TodoTypeAny
83 | const value: TodoTypeAny = payload?.value ? payload.value : msg.payload;
84 | const valuesToWrite = payload.valuesToWrite || []
85 | const addressSpaceItems = payload.addressSpaceItems || []
86 |
87 | if (self.injectType === 'write') {
88 | addressSpaceItems.push({name: self.name, nodeId: self.nodeId, datatypeName: self.datatype})
89 | try {
90 | if(typeof self.value !== "string"){
91 | self.value = self.value.toString()
92 | }
93 | valuesToWrite.push(convertDataValueByDataType( (_.isEmpty(self.value)) ? value : self.value, self.datatype))
94 | } catch (err) {
95 | logger.internalDebugLog(err)
96 | if (self.showErrors) {
97 | this.error(err, msg)
98 | }
99 | }
100 | } else {
101 | addressSpaceItems.push({name: self.name, nodeId: self.nodeId, datatypeName: self.datatype})
102 | }
103 |
104 | const outputPayload = {
105 | nodetype: "node",
106 | injectType: self.injectType || payload.injectType,
107 | addressSpaceItems,
108 | valuesToWrite,
109 | value,
110 | }
111 |
112 | const outputMessage = {
113 | payload: outputPayload,
114 | topic,
115 | _msgid: msg._msgid
116 | }
117 | logger.internalDebugLog('node msg stringified: ' + JSON.stringify(msg))
118 | this.send(outputMessage)
119 | })
120 |
121 | }
122 |
123 | RED.nodes.registerType('OPCUA-IIoT-Node', OPCUAIIoTNode)
124 | }
125 |
--------------------------------------------------------------------------------
/src/opcua-iiot-server-aso.ts:
--------------------------------------------------------------------------------
1 | /*
2 | The BSD 3-Clause License
3 |
4 | Copyright 2022 - DATATRONiQ GmbH (https://datatroniq.com)
5 | Copyright (c) 2018-2022 Klaus Landsdorf (http://node-red.plus/)
6 | All rights reserved.
7 | node-red-contrib-iiot-opcua
8 | */
9 | 'use strict'
10 |
11 | import * as nodered from "node-red";
12 | import {TodoTypeAny} from "./types/placeholders";
13 | import {NodeMessageInFlow} from "node-red";
14 | import {OBJECTS_ROOT, resetIiotNode} from "./core/opcua-iiot-core";
15 | import {ReferenceTypeIds} from "node-opcua";
16 | import {logger} from "./core/opcua-iiot-core-connector";
17 | import internalDebugLog = logger.internalDebugLog;
18 |
19 | interface OPCUAIIoTASO extends nodered.Node {
20 | nodeId: string
21 | browsename: string
22 | displayname: string
23 | objecttype: string
24 | referencetype: string
25 | referenceNodeId: string
26 | datatype: string
27 | value: string
28 | name: string
29 |
30 | }
31 |
32 | interface OPCUAIIoTCMDASO extends nodered.NodeDef {
33 | nodeId: string
34 | browsename: string
35 | displayname: string
36 | objecttype: string
37 | referencetype: string
38 | referenceNodeId: string
39 | datatype: string
40 | value: string
41 | name: string
42 | }
43 |
44 | /**
45 | * Address space object Node-RED node.
46 | *
47 | * @param RED
48 | */
49 | module.exports = (RED: nodered.NodeAPI) => {
50 | // SOURCE-MAP-REQUIRED
51 |
52 | function OPCUAIIoTASO(this: OPCUAIIoTASO, config: OPCUAIIoTCMDASO) {
53 | RED.nodes.createNode(this, config)
54 | this.nodeId = config.nodeId
55 | this.browsename = config.browsename
56 | this.displayname = config.displayname
57 | this.objecttype = config.objecttype
58 | this.referencetype = config.referencetype
59 | this.referenceNodeId = config.referenceNodeId
60 | this.datatype = config.datatype
61 | this.value = config.value
62 | this.name = config.name
63 |
64 | let self = this
65 | internalDebugLog('Open ASO Node')
66 |
67 | this.on('input', (msg: NodeMessageInFlow | TodoTypeAny) => {
68 | if (msg.payload.nodetype === 'inject') {
69 | self.nodeId = msg.payload.topic || self.nodeId
70 | self.datatype = msg.payload.datatype || self.datatype
71 | self.value = msg.payload.payload || self.value
72 | }
73 | const value = self.value || msg.payload.value;
74 | msg = {payload: {}} // clean message
75 | msg.topic = 'ServerAddressSpaceObject'
76 | msg.payload.nodetype = 'inject'
77 | msg.payload.injectType = 'ASO'
78 |
79 | if (self.nodeId.includes('i=') || self.nodeId.includes('s=') || self.nodeId.includes('b=')) {
80 | msg.payload.nodeId = self.nodeId
81 | msg.payload.browsename = self.browsename
82 | msg.payload.displayname = self.displayname
83 | msg.payload.objecttype = self.objecttype
84 | msg.payload.datatype = self.datatype
85 | msg.payload.value = value
86 |
87 | msg.payload.referenceNodeId = self.referenceNodeId || OBJECTS_ROOT
88 | msg.payload.referencetype = self.referencetype || ReferenceTypeIds.Organizes
89 |
90 | internalDebugLog('node msg stringified: ' + JSON.stringify(msg))
91 | this.send(msg)
92 | } else {
93 | /* istanbul ignore next */
94 | this.error(new Error('ASO NodeId Is Not Valid'), msg)
95 | }
96 | })
97 |
98 | this.on('close', (done: () => void) => {
99 | internalDebugLog('Close ASO Node')
100 | resetIiotNode(self)
101 | done()
102 | })
103 | }
104 |
105 | RED.nodes.registerType('OPCUA-IIoT-Server-ASO', OPCUAIIoTASO)
106 | }
107 |
--------------------------------------------------------------------------------
/src/opcua-iiot-server-cmd.html:
--------------------------------------------------------------------------------
1 |
9 |
10 |
45 |
46 |
64 |
65 |
70 |
--------------------------------------------------------------------------------
/src/opcua-iiot-server-cmd.ts:
--------------------------------------------------------------------------------
1 | /*
2 | The BSD 3-Clause License
3 |
4 | Copyright 2022 - DATATRONiQ GmbH (https://datatroniq.com)
5 | Copyright (c) 2018-2022 Klaus Landsdorf (http://node-red.plus/)
6 | All rights reserved.
7 | node-red-contrib-iiot-opcua
8 | */
9 | 'use strict'
10 |
11 | import * as nodered from "node-red";
12 | import {NodeMessageInFlow} from "node-red";
13 | import {TodoTypeAny} from "./types/placeholders";
14 | import {logger} from "./core/opcua-iiot-core-connector";
15 | import {resetIiotNode} from "./core/opcua-iiot-core";
16 | import internalDebugLog = logger.internalDebugLog;
17 |
18 | interface OPCUAIIoTCMD extends nodered.Node {
19 | commandtype: string
20 | nodeId: string
21 | name: string
22 |
23 | }
24 |
25 | interface OPCUAIIoTCMDDef extends nodered.NodeDef {
26 | commandtype: string
27 | nodeId: string
28 | name: string
29 | }
30 |
31 | /**
32 | * Address space object Node-RED node.
33 | *
34 | * @param RED
35 | */
36 |
37 | module.exports = (RED: nodered.NodeAPI) => {
38 | // SOURCE-MAP-REQUIRED
39 |
40 | function OPCUAIIoTCMD(this: OPCUAIIoTCMD, config: OPCUAIIoTCMDDef) {
41 | RED.nodes.createNode(this, config)
42 | this.commandtype = config.commandtype
43 | this.nodeId = config.nodeId
44 | this.name = config.name
45 |
46 | let self = this
47 |
48 | this.on('input', (msg: NodeMessageInFlow | TodoTypeAny) => {
49 | let returnPayload: TodoTypeAny = {};
50 |
51 | returnPayload.nodetype = 'inject'
52 | returnPayload.injectType = 'CMD'
53 | returnPayload.commandType = self.commandtype
54 |
55 | if (msg.payload.addressSpaceItems && msg.payload.addressSpaceItems.length > 0) {
56 | let addressSpaceItem
57 | for (addressSpaceItem of msg.payload.addressSpaceItems) {
58 | returnPayload.nodeId = addressSpaceItem.nodeId
59 | }
60 | if (returnPayload.nodeId) {
61 | this.send({
62 | ...msg,
63 | payload: returnPayload
64 | })
65 | }
66 | } else {
67 | if (self.nodeId) {
68 | returnPayload.nodeId = self.nodeId
69 | }
70 | this.send({...msg, payload: returnPayload})
71 | }
72 | })
73 |
74 | this.on('close', (done: () => void) => {
75 | internalDebugLog('Close CMD Node')
76 | resetIiotNode(self)
77 | done()
78 | })
79 | }
80 |
81 | RED.nodes.registerType('OPCUA-IIoT-Server-Command', OPCUAIIoTCMD)
82 | }
83 |
--------------------------------------------------------------------------------
/src/opcua-iiot-write.html:
--------------------------------------------------------------------------------
1 |
10 |
11 |
34 |
35 |
62 |
63 |
107 |
--------------------------------------------------------------------------------
/src/public/vendor/opc-foundation/binary/Opc.Ua.Adi.Types.bsd.xml:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 | Structure defining the information for auxiliary axis for array type variables.
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 | Identify on which type of axis the data shall be displayed.
53 |
54 |
55 |
56 |
57 |
58 |
59 | Structure defining XY value like a list of peaks.
60 |
61 |
62 |
63 |
64 |
65 | Structure defining double IEEE 32 bits complex value
66 |
67 |
68 |
69 |
70 |
71 | Structure defining double IEEE 64 bits complex value
72 |
73 |
74 |
75 |
76 |
--------------------------------------------------------------------------------
/src/public/vendor/opc-foundation/binary/Opc.Ua.Di.Types.bsd.xml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/public/vendor/opc-foundation/binary/Opc.Ua.Gds.Types.bsd.xml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/src/public/vendor/opc-foundation/csv/AttributeIds.csv:
--------------------------------------------------------------------------------
1 | NodeId,1
2 | NodeClass,2
3 | BrowseName,3
4 | DisplayName,4
5 | Description,5
6 | WriteMask,6
7 | UserWriteMask,7
8 | IsAbstract,8
9 | Symmetric,9
10 | InverseName,10
11 | ContainsNoLoops,11
12 | EventNotifier,12
13 | Value,13
14 | DataType,14
15 | ValueRank,15
16 | ArrayDimensions,16
17 | AccessLevel,17
18 | UserAccessLevel,18
19 | MinimumSamplingInterval,19
20 | Historizing,20
21 | Executable,21
22 | UserExecutable,22
23 |
--------------------------------------------------------------------------------
/src/public/vendor/opc-foundation/csv/ServerCapabilities.csv:
--------------------------------------------------------------------------------
1 | NA, No capability information is available. Cannot be used in combination with any other capability.
2 | DA, Provides current data.
3 | HD, Provides historical data.
4 | AC, Provides alarms and conditions that may require operator interaction.
5 | HE, Provides historical alarms and events.
6 | GDS, Supports the Global Discovery Server information model.
7 | LDS, Only supports the Discovery Services. Cannot be used in combination with any other capability.
8 | DI, Supports the Device Integration (DI) information model.
9 | ADI, Supports the Analyser Device Integration (ADI) information model.
10 | FDI, Supports the Field Device Integration (FDI) information model.
11 | FDIC, Supports the Field Device Integration (FDI) Communication Server information model.
12 | PLC, Supports the PLCopen information model.
13 | S95, Supports the ISA95 information model.
--------------------------------------------------------------------------------
/src/public/vendor/opc-foundation/csv/ServerCapabilityIdentifiers.csv:
--------------------------------------------------------------------------------
1 | NA, No capability information is available. Cannot be used in combination with any other capability.
2 | DA, Provides current data.
3 | HD, Provides historical data.
4 | AC, Provides alarms and conditions that may require operator interaction.
5 | HE, Provides historical alarms and events.
6 | GDS, Supports the Global Discovery Server information model.
7 | LDS, Only supports the Discovery Services. Cannot be used in combination with any other capability.
8 | DI, Supports the Device Integration (DI) information model.
9 | ADI, Supports the Analyser Device Integration (ADI) information model.
10 | FDI, Supports the Field Device Integration (FDI) information model.
11 | FDIC, Supports the Field Device Integration (FDI) Communication Server information model.
12 | PLC, Supports the PLCopen information model.
13 | S95, Supports the ISA95 information model.
--------------------------------------------------------------------------------
/src/public/vendor/opc-foundation/xml/Opc.Ua.Adi.Types.bsd.xml:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 | Structure defining the information for auxiliary axis for array type variables.
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 | Identify on which type of axis the data shall be displayed.
53 |
54 |
55 |
56 |
57 |
58 |
59 | Structure defining XY value like a list of peaks.
60 |
61 |
62 |
63 |
64 |
65 | Structure defining double IEEE 32 bits complex value
66 |
67 |
68 |
69 |
70 |
71 | Structure defining double IEEE 64 bits complex value
72 |
73 |
74 |
75 |
76 |
--------------------------------------------------------------------------------
/src/public/vendor/opc-foundation/xml/Opc.Ua.Di.Types.bsd.xml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/public/vendor/opc-foundation/xml/Opc.Ua.Di.Types.xsd:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/src/public/vendor/opc-foundation/xml/Opc.Ua.Gds.Types.bsd.xml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/src/public/vendor/opc-foundation/xml/Opc.Ua.Gds.Types.xsd:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/src/public/xmlsets.txt:
--------------------------------------------------------------------------------
1 | public/vendor/opc-foundation/xml/Opc.Ua.NodeSet2.xml (Standard)
2 |
3 |
4 | (Extras)
5 |
6 | public/vendor/opc-foundation/xml/Opc.ISA95.NodeSet2.xml
7 |
8 | public/vendor/opc-foundation/xml/Opc.Ua.Adi.NodeSet2.xml
9 |
10 | public/vendor/opc-foundation/xml/Opc.Ua.Gds.NodeSet2.xml
11 |
12 | public/vendor/opc-foundation/xml/Opc.Ua.Di.NodeSet2.xml
13 |
14 | (Harting Mica)
15 |
16 | public/vendor/harting/10_di.xml
17 | public/vendor/harting/20_autoid.xml
18 | public/vendor/harting/30_aim.xml
--------------------------------------------------------------------------------
/src/types/assertion.ts:
--------------------------------------------------------------------------------
1 | /**
2 | The BSD 3-Clause License
3 |
4 | Copyright 2022 - DATATRONiQ GmbH (https://datatroniq.com)
5 | All rights reserved.
6 | node-red-contrib-iiot-opcua
7 | */
8 |
9 |
10 | /**
11 | * Asserts that the object is undefined or null
12 | */
13 | export const isNotDefined = (object: any): object is undefined => {
14 | return typeof object === 'undefined' || object === null;
15 | }
16 |
17 | /**
18 | * Asserts that the given object is an array of type .
19 | */
20 | export const isArray = (object: any): object is Array => {
21 | return Array.isArray(object)
22 | }
23 |
--------------------------------------------------------------------------------
/src/types/helpers.ts:
--------------------------------------------------------------------------------
1 | /**
2 | The BSD 3-Clause License
3 |
4 | Copyright 2022 - DATATRONiQ GmbH (https://datatroniq.com)
5 | All rights reserved.
6 | node-red-contrib-iiot-opcua
7 | */
8 |
9 | import {TodoTypeAny} from "./placeholders";
10 | import {AttributeIds, DataType, DataValue, NodeId, NodeIdType, StatusCode} from "node-opcua";
11 | import {NodeMessageInFlow} from "node-red";
12 |
13 | export type TimeUnits =
14 | 'ms' |
15 | 's' |
16 | 'm' |
17 | 'h';
18 |
19 | export type TimeUnitNames =
20 | 'msec.' |
21 | 'sec.' |
22 | 'min.' |
23 | 'h.' |
24 | '';
25 |
26 | export type WriteMessage = {
27 | addressSpaceItems: AddressSpaceItem[]
28 | payload: {
29 | nodesToWrite: NodeToWrite[],
30 | }
31 | valuesToWrite?: TodoTypeAny[]
32 | }
33 |
34 | export type AddressSpaceItem = {
35 | nodeId: string
36 | browseName: string
37 | displayName: string
38 | nodeClass: string
39 | datatypeName: string
40 | }
41 |
42 | export type BrowseMessage = {
43 | 'topic': string
44 | 'nodeId': string
45 | 'browseName': string
46 | 'nodeClassType': string
47 | 'typeDefinition': string
48 | 'payload': ''
49 | }
50 |
51 | export type NodeToWrite = {
52 | nodeId: NodeId
53 | attributeId: AttributeIds.Value
54 | indexRange: null
55 | value: DataValue
56 | }
57 |
58 | export type DataTypeInput = DataType | string;
59 |
60 | export type NodeIdentifier = NodeIdentifierNumeric | NodeIdentifierString;
61 |
62 | type NodeIdentifierNumeric = {
63 | identifier: number
64 | type: NodeIdType.NUMERIC
65 | }
66 |
67 | type NodeIdentifierString = {
68 | identifier: string
69 | type: Exclude
70 | }
71 |
72 | /**
73 | * Creates a copy of type , except that all keys are optional.
74 | */
75 | export type Like = {
76 | [key in keyof T]?: T[key]
77 | }
78 |
79 | /**
80 | * Get a list of enum keys from an enum
81 | */
82 | export const getEnumKeys = (obj: O): K[] => {
83 | return Object.keys(obj).filter(k => Number.isNaN(+k)) as K[];
84 | }
85 |
86 | /**
87 | * Give a type to NodeMessageInFlow to voerwrite the unknown type
88 | */
89 | export type TypedNodeMessage = NodeMessageInFlow & {
90 | payload: T
91 | }
92 |
93 | /**
94 | * A type used to represent anything that might have status codes
95 | */
96 | export type StatusInput = {
97 | statusCodes?: StatusCode[]
98 | statusCode?: StatusCode
99 | };
--------------------------------------------------------------------------------
/src/types/payloads.ts:
--------------------------------------------------------------------------------
1 | /**
2 | The BSD 3-Clause License
3 |
4 | Copyright 2022 - DATATRONiQ GmbH (https://datatroniq.com)
5 | All rights reserved.
6 | node-red-contrib-iiot-opcua
7 | */
8 |
9 | import {CrawlerPayload} from "../opcua-iiot-crawler";
10 | import {BrowserPayload} from "../opcua-iiot-browser";
11 | import {ListenPayload} from "../opcua-iiot-listener";
12 | import {ReadPayload} from "../opcua-iiot-read";
13 | import {MethodPayload} from "../opcua-iiot-method-caller";
14 | import {WritePayload} from "../opcua-iiot-write";
15 |
16 | export type AnyPayload = CrawlerPayload |
17 | BrowserPayload |
18 | ReadPayload |
19 | WritePayload |
20 | ListenPayload |
21 | MethodPayload;
22 |
--------------------------------------------------------------------------------
/src/types/placeholders.ts:
--------------------------------------------------------------------------------
1 | /**
2 | The BSD 3-Clause License
3 |
4 | Copyright 2022 - DATATRONiQ GmbH (https://datatroniq.com)
5 | All rights reserved.
6 | node-red-contrib-iiot-opcua
7 | */
8 |
9 | export type TodoTypeAny = any;
10 | export type TodoVoidFunction = (...args: any) => void;
11 |
--------------------------------------------------------------------------------
/test/.gitignore:
--------------------------------------------------------------------------------
1 | *.txt
2 | *.log
3 | *.zip
--------------------------------------------------------------------------------
/test/core/opcua-iiot-core-browser.test.js:
--------------------------------------------------------------------------------
1 | /*
2 | The BSD 3-Clause License
3 |
4 | Copyright 2022 - DATATRONiQ GmbH (https://datatroniq.com)
5 | Copyright (c) 2018-2022 Klaus Landsdorf (http://node-red.plus/)
6 | All rights reserved.
7 | node-red-contrib-iiot-opcua
8 | */
9 | 'use strict'
10 |
11 | // jest.setTimeout(30000)
12 |
13 | describe('OPC UA Core Browser', function () {
14 | let { default: coreBrowser } = require('../../src/core/opcua-iiot-core-browser')
15 | let { OBJECTS_ROOT } = require('../../src/core/opcua-iiot-core')
16 | const events = require('events')
17 |
18 | let testingOpcUaPort = 0
19 |
20 | beforeAll(() => {
21 | testingOpcUaPort = 50220
22 | })
23 |
24 | describe('Core Browser unit test', function () {
25 |
26 | it('should return the objects root nodeId', function (done) {
27 | expect(coreBrowser.browseToRoot()).toBe(OBJECTS_ROOT)
28 | done()
29 | })
30 |
31 | it('should return the default objects nodeId without root in payload request', function (done) {
32 | expect(coreBrowser.extractNodeIdFromTopic({}, {})).toBe(null)
33 | done()
34 | })
35 |
36 | it('should return the default objects nodeId with empty root in payload request', function (done) {
37 | expect(coreBrowser.extractNodeIdFromTopic({ actiontype: 'browse', root: {} }, {})).toBe(OBJECTS_ROOT)
38 | done()
39 | })
40 |
41 | it('should return the nodeId from root in payload request', function (done) {
42 | expect(coreBrowser.extractNodeIdFromTopic({
43 | actiontype: 'browse',
44 | root: { nodeId: 'ns=1;s=MyDemo' }
45 | }, {})).toBe('ns=1;s=MyDemo')
46 | done()
47 | })
48 |
49 | it('should handle browse error', function (done) {
50 | let statusText = 'idle'
51 | let node = {
52 | showErrors: true,
53 | showStatusActivities: true,
54 | statusText,
55 | status: (state) => { statusText = state.text },
56 | error: (err, msg) => { coreBrowser.internalDebugLog(err.message) }
57 | }
58 | const statusHandler = (status) => {
59 | node.statusText = status.text || status
60 | }
61 | coreBrowser.browseErrorHandling(node, new Error('Error'), { payload: {} }, [], (err, msg) => {return}, statusHandler, 'idle')
62 | expect(node.statusText).toBe('error')
63 | done()
64 | })
65 |
66 | it('should return JSON from transformToEntry call', function (done) {
67 | expect(coreBrowser.transformToEntry({})).toBeDefined()
68 | done()
69 | })
70 |
71 | it('should return reference strings from transformToEntry call', function (done) {
72 | expect(coreBrowser.transformToEntry({
73 | referenceTypeId: { toString: () => { return '1234' } },
74 | isForward: true,
75 | nodeId: { toString: () => { return 'ns=1;s=MyDemo' } },
76 | browseName: { toString: () => { return '1:MyDemo' } },
77 | displayName: { toString: () => { return 'MyDemo' } },
78 | nodeClass: { toString: () => { return 'Object' } },
79 | typeDefinition: { toString: () => { return 'ns=1;i=68' } }
80 | })).toEqual({
81 | referenceTypeId: '1234',
82 | isForward: true,
83 | nodeId: 'ns=1;s=MyDemo',
84 | browseName: '1:MyDemo',
85 | displayName: 'MyDemo',
86 | nodeClass: 'Object',
87 | typeDefinition: 'ns=1;i=68'
88 | })
89 | done()
90 | })
91 | })
92 | })
93 |
--------------------------------------------------------------------------------
/test/core/opcua-iiot-core-server.test.js:
--------------------------------------------------------------------------------
1 | /*
2 | The BSD 3-Clause License
3 |
4 | Copyright 2022 - DATATRONiQ GmbH (https://datatroniq.com)
5 | Copyright (c) 2018-2022 Klaus Landsdorf (http://node-red.plus/)
6 | All rights reserved.
7 | node-red-contrib-iiot-opcua
8 | */
9 | 'use strict'
10 |
11 | // jest.setTimeout(30000)
12 |
13 | let { default: coreServer } = require('../../src/core/opcua-iiot-core-server')
14 | const { OPCUAServer } = require('node-opcua')
15 | const portHelper = require('../helper/test-helper-extensions')
16 |
17 | let opcuaServer = null
18 |
19 | describe('OPC UA Core Server', function () {
20 |
21 | let testingOpcUaPort = 0
22 |
23 | beforeAll(() => {
24 | testingOpcUaPort = 51220
25 | })
26 |
27 | beforeEach(function (done) {
28 | opcuaServer = null
29 |
30 | testingOpcUaPort = portHelper.getPort(testingOpcUaPort)
31 | const port = testingOpcUaPort
32 |
33 | opcuaServer = new OPCUAServer({
34 | port,
35 | resourcePath: '/UA/MyLittleTestServer',
36 | buildInfo: {
37 | productName: 'MyTestServer1',
38 | buildNumber: '7658',
39 | buildDate: new Date()
40 | }
41 | })
42 | done()
43 | })
44 |
45 | afterEach(function (done) {
46 | opcuaServer.shutdown(function () {
47 | coreServer.destructAddressSpace(done)
48 | })
49 | })
50 |
51 | afterAll(function (done) {
52 | opcuaServer = null
53 | coreServer = null
54 | done()
55 | })
56 |
57 | describe('core server functions', function () {
58 | it('should work on server initialize callback', function (done) {
59 | const run = async () => {
60 | await opcuaServer.initialize()
61 | coreServer.constructAddressSpace(opcuaServer, true).then(() => {
62 | done()
63 | })
64 | }
65 | run()
66 | })
67 |
68 | it('should reset count server timeInterval on maxTimeInterval', function (done) {
69 | opcuaServer.initialize(function () {
70 | const run = async () => {
71 | coreServer.constructAddressSpace(opcuaServer, true).then(function () {
72 | coreServer.timeInterval = coreServer.maxTimeInterval
73 | coreServer.simulateVariation({})
74 | expect(coreServer.timeInterval).toBe(500000)
75 | done()
76 | })
77 | }
78 | run()
79 | })
80 | })
81 |
82 | it('should catch error on start with empty server', function (done) {
83 | coreServer.start(null, null).then().catch(function (err) {
84 | if (err) {
85 | expect(err.message).toBe('Server Not Valid To Start')
86 | done()
87 | }
88 | })
89 | })
90 |
91 | it('should catch error on start with empty node', function (done) {
92 | opcuaServer.initialize(function () {
93 | coreServer.constructAddressSpace(opcuaServer, true).then(function () {
94 | coreServer.start(opcuaServer, null).then().catch(function (err) {
95 | if (err) {
96 | expect(err.message).toBe('Node Not Valid To Start')
97 | done()
98 | }
99 | })
100 | })
101 | })
102 | })
103 |
104 | it('should work on server start callback', function (done) {
105 | opcuaServer.initialize(function () {
106 | coreServer.constructAddressSpace(opcuaServer, true).then(function () {
107 | let node = { iiot: { initialized: false } }
108 | coreServer.start(opcuaServer, node).then(function () {
109 | expect(node.iiot.initialized).toBe(true)
110 | done()
111 | })
112 | })
113 | })
114 | })
115 | })
116 | })
117 |
--------------------------------------------------------------------------------
/test/e2e/opcua-iiot-browser-recursive-e2e.test.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Original Work Copyright 2014 IBM Corp.
3 | * node-red
4 | *
5 | * Copyright (c) 2022 DATATRONiQ GmbH (https://datatroniq.com)
6 | * Copyright (c) 2018-2022 Klaus Landsdorf (http://node-red.plus/)
7 | * All rights reserved.
8 | * node-red-contrib-iiot-opcua
9 | *
10 | **/
11 |
12 | 'use strict'
13 |
14 | // jest.setTimeout(30000)
15 |
16 | var injectNode = require('../../src/opcua-iiot-inject')
17 | var connectorNode = require('../../src/opcua-iiot-connector')
18 | var inputNode = require('../../src/opcua-iiot-browser')
19 | var listenerNode = require('../../src/opcua-iiot-listener')
20 | var asoNode = require('../../src/opcua-iiot-server-aso')
21 | var serverNode = require('../../src/opcua-iiot-server')
22 | var responseNode = require('../../src/opcua-iiot-response')
23 | var resultFilterNode = require('../../src/opcua-iiot-result-filter')
24 |
25 | var helper = require('node-red-node-test-helper')
26 | var portHelper = require('./../helper/test-helper-extensions')
27 | helper.init(require.resolve('node-red'))
28 |
29 | var browseRecursiveNodesToLoad = [injectNode, asoNode, listenerNode, connectorNode, resultFilterNode, inputNode, serverNode, responseNode]
30 |
31 | var testFlows = require('./flows/browser-recursive-e2e-flows')
32 |
33 | let testingOpcUaPort = 0
34 |
35 | describe('OPC UA Browser recursive with ASO nodes e2e Testing', function () {
36 |
37 | beforeAll(() => {
38 | testingOpcUaPort = 52300
39 | })
40 |
41 | beforeEach(function (done) {
42 | helper.startServer(function () {
43 | done()
44 | })
45 | })
46 |
47 | afterEach(function (done) {
48 | helper.unload().then(function () {
49 | helper.stopServer(function () {
50 | done()
51 | })
52 | }).catch(function () {
53 | helper.stopServer(function () {
54 | done()
55 | })
56 | })
57 | })
58 |
59 | describe('Browser Recursive node', function () {
60 | it('should verify browser items as result of a recursive browse', function (done) {
61 | const flow = Array.from(testFlows.testBrowseRecursiveASOFlow)
62 | testingOpcUaPort = portHelper.getPort(testingOpcUaPort)
63 | const port = testingOpcUaPort
64 | flow[3].port = port
65 | flow[24].endpoint = 'opc.tcp://localhost:' + port
66 | helper.load(browseRecursiveNodesToLoad, flow, function () {
67 | let n1 = helper.getNode('helperNode')
68 | n1.on('input', function (msg) {
69 | expect(msg.payload.browserResults).toBeDefined()
70 | expect(msg.payload.browserResults).toBeInstanceOf(Array)
71 | expect(msg.payload.browserResults.length).toBe(11)
72 | done()
73 | })
74 | })
75 | })
76 | })
77 | })
78 |
--------------------------------------------------------------------------------
/test/e2e/opcua-iiot-flex-server.test.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Original Work Copyright 2014 IBM Corp.
3 | * node-red
4 | *
5 | * Copyright (c) 2022 DATATRONiQ GmbH (https://datatroniq.com)
6 | * Copyright (c) 2018-2022 Klaus Landsdorf (http://node-red.plus/)
7 | * All rights reserved.
8 | * node-red-contrib-iiot-opcua
9 | *
10 | **/
11 |
12 | 'use strict'
13 |
14 | // jest.setTimeout(30000)
15 |
16 | var injectNode = require('@node-red/nodes/core/common/20-inject')
17 | var connectorNode = require('../../src/opcua-iiot-connector')
18 | var readNode = require('../../src/opcua-iiot-read')
19 | var serverNode = require('../../src/opcua-iiot-flex-server')
20 | var nodeNode = require('../../src/opcua-iiot-node')
21 | var writeNode = require('../../src/opcua-iiot-write')
22 |
23 | var nodesToLoad = [injectNode, connectorNode, readNode, serverNode, nodeNode, writeNode]
24 |
25 | var helper = require('node-red-node-test-helper')
26 | var portHelper = require('./../helper/test-helper-extensions')
27 | helper.init(require.resolve('node-red'))
28 |
29 | const testFlows = require("./flows/flex-server-e2e-flows")
30 |
31 | let testingOpcUaPort
32 |
33 | describe("OPC UA Flex Server Node E2E testing", () => {
34 | beforeAll(() => {
35 | testingOpcUaPort = 56600
36 | })
37 |
38 | beforeEach(function (done) {
39 | helper.startServer(function () {
40 | done()
41 | })
42 | })
43 |
44 | afterEach(function (done) {
45 | helper.unload().then(function () {
46 | helper.stopServer(function () {
47 | done()
48 | })
49 | }).catch(function () {
50 | helper.stopServer(function () {
51 | done()
52 | })
53 | })
54 | })
55 |
56 | describe("Flex Server Node", () => {
57 | it("should write 1 then 0 and read 0", (done) => {
58 | const flow = Array.from(testFlows.testFlexServerWriteZeroFlow)
59 | const port = portHelper.getPort(testingOpcUaPort)
60 | flow[1].port = port
61 | flow[11].endpoint = "opc.tcp://localhost:" + port
62 |
63 | helper.load(nodesToLoad, flow, () => {
64 | const helperWrite = helper.getNode("fe3c32681ca3545d")
65 | const helperRead = helper.getNode("f82a189319618699")
66 | let writeCounter = 0;
67 | helperWrite.on('input', (msg) => {
68 | writeCounter++
69 | expect(msg.payload).toBeDefined()
70 | expect(msg.payload.injectType).toBeDefined()
71 | expect(msg.payload.value).toBeDefined()
72 | expect(msg.payload.valuesToWrite).toBeDefined()
73 | expect(msg.payload.addressSpaceItems).toBeDefined()
74 | expect(msg.payload.value.statusCodes).toBeDefined()
75 | expect(msg.payload.injectType).toBe("write")
76 | expect(msg.payload.value.statusCodes[0].value).toBe(0)
77 | expect(msg.payload.valuesToWrite.length).toBe(1)
78 |
79 | if(writeCounter === 1){
80 | expect(msg.payload.valuesToWrite[0]).toBe(1)
81 | } else if(writeCounter === 2) {
82 | expect(msg.payload.valuesToWrite[0]).toBe(0)
83 | }
84 | })
85 | helperRead.on('input', (msg) => {
86 | expect(msg.payload).toBeDefined()
87 | expect(msg.payload.injectType).toBeDefined()
88 | expect(msg.payload.value).toBeDefined()
89 | expect(typeof(msg.payload.value)).toBe(typeof [])
90 | expect(msg.payload.addressSpaceItems).toBeDefined()
91 | expect(msg.payload.value[0].statusCode).toBeDefined()
92 | expect(msg.payload.value[0].statusCode.value).toBe(0)
93 | expect(msg.payload.value[0].value?.value).toBeDefined()
94 | expect(msg.payload.value[0].value?.value).toBe(0)
95 | expect(msg.payload.value[0].value?.dataType).toBe("Double")
96 | expect(msg.payload.injectType).toBe("read")
97 | done()
98 | })
99 | })
100 | })
101 | })
102 | })
103 |
--------------------------------------------------------------------------------
/test/e2e/opcua-iiot-node-e2e.test.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Original Work Copyright 2014 IBM Corp.
3 | * node-red
4 | *
5 | * Copyright (c) 2022 DATATRONiQ GmbH (https://datatroniq.com)
6 | * Copyright (c) 2018-2022 Klaus Landsdorf (http://node-red.plus/)
7 | * All rights reserved.
8 | * node-red-contrib-iiot-opcua
9 | *
10 | **/
11 |
12 | 'use strict'
13 |
14 | // jest.setTimeout(30000)
15 |
16 | var injectNode = require('@node-red/nodes/core/common/20-inject')
17 |
18 | // iiot opc ua nodes
19 |
20 | var serverNode = require('../../src/opcua-iiot-server')
21 | var responseNode = require('../../src/opcua-iiot-response')
22 | var connectorNode = require('../../src/opcua-iiot-connector')
23 | var listenerNode = require('../../src/opcua-iiot-listener')
24 | var inputNode = require('../../src/opcua-iiot-node')
25 | var resultFilterNode = require('../../src/opcua-iiot-result-filter')
26 |
27 | var helper = require('node-red-node-test-helper')
28 | var portHelper = require('./../helper/test-helper-extensions')
29 | helper.init(require.resolve('node-red'))
30 |
31 | var nodeNodesToLoad = [injectNode, inputNode, connectorNode, listenerNode, responseNode, serverNode, resultFilterNode]
32 |
33 | var testFlows = require('./flows/node-e2e-flows')
34 |
35 | let testingOpcUaPort = 0
36 |
37 | describe('OPC UA Node node e2e Testing', function () {
38 |
39 | beforeAll(() => {
40 | testingOpcUaPort = 54700
41 | })
42 |
43 | beforeEach(function (done) {
44 | helper.startServer(function () {
45 | done()
46 | })
47 | })
48 |
49 | afterEach(function (done) {
50 | helper.unload().then(function () {
51 | helper.stopServer(function () {
52 | done()
53 | })
54 | }).catch(function () {
55 | helper.stopServer(function () {
56 | done()
57 | })
58 | })
59 | })
60 |
61 | describe('Node node', function () {
62 | let msgCounter = 0
63 |
64 | it('should get two messages with payload and value after inject on subscribe with listener', function (done) {
65 | const flow = Array.from(testFlows.testNodeFlow)
66 | testingOpcUaPort = portHelper.getPort(testingOpcUaPort)
67 | const port = testingOpcUaPort
68 | flow[9].port = port
69 | flow[16].endpoint = 'opc.tcp://localhost:' + port
70 |
71 | helper.load(nodeNodesToLoad, flow, function () {
72 | msgCounter = 0
73 | let n2 = helper.getNode('9902563b094d0417')
74 | // let n2 = helper.getNode('53aa4e70.57ae7')
75 | n2.on('input', function (msg) {
76 | msgCounter++
77 | if (msgCounter === 1) {
78 | expect(msg.payload).toBeDefined()
79 | expect(msg.payload.value).toBeDefined()
80 | }
81 | if (msgCounter === 2) {
82 | expect(msg.payload).toBeDefined()
83 | expect(msg.payload.value).toBeDefined()
84 | done()
85 | }
86 | })
87 | })
88 | })
89 |
90 | it('should get two messages with payload and a value after inject with local value on write', function (done) {
91 | const flow = Array.from(testFlows.testWithValueFromNode)
92 |
93 | helper.load(nodeNodesToLoad, flow, function () {
94 | msgCounter = 0
95 | let n2 = helper.getNode('91ffe73f63f8e590')
96 | n2.on('input', function (msg) {
97 | msgCounter++
98 | if (msgCounter === 1) {
99 | expect(msg.payload).toBeDefined()
100 | expect(msg.payload.value).toBeDefined()
101 | expect(msg.payload.valuesToWrite).toBeDefined()
102 | expect(msg.payload.valuesToWrite.length).toBe(1)
103 | expect(msg.payload.valuesToWrite[0]).toBe(39)
104 | }
105 | if (msgCounter === 2) {
106 | expect(msg.payload).toBeDefined()
107 | expect(msg.payload.value).toBeDefined()
108 | expect(msg.payload.valuesToWrite).toBeDefined()
109 | expect(msg.payload.valuesToWrite.length).toBe(1)
110 | expect(msg.payload.valuesToWrite[0]).toBe(39)
111 | done()
112 | }
113 | })
114 | })
115 | })
116 | })
117 | })
118 |
--------------------------------------------------------------------------------
/test/helper/receive.js:
--------------------------------------------------------------------------------
1 | const receive = (node) => {
2 | node.receive({ payload: { value: 'defaultPayload' } })
3 | }
4 |
5 | module.exports = receive
--------------------------------------------------------------------------------
/test/helper/test-helper-extensions.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Original Work Copyright 2014 IBM Corp.
3 | * node-red
4 | *
5 | * Copyright (c) 2022 Klaus Landsdorf (http://node-red.plus/)
6 | * All rights reserved.
7 | * node-red-contrib-iiot-opcua
8 | *
9 | **/
10 |
11 | 'use strict'
12 |
13 | const net = require('net')
14 |
15 | const isPortTaken = (port) => {
16 | const server = net.createServer()
17 | let result
18 | server.on('error', (err) => {
19 | result = true
20 | }).on('listening', () => {
21 | result = false
22 | server.close()
23 | })
24 |
25 | server.listen(port)
26 |
27 | return result
28 | }
29 |
30 | module.exports = {
31 |
32 | cleanNodePositionData: (item) => {
33 | let newObject = JSON.parse(JSON.stringify(item))
34 |
35 | if (newObject.type === 'helper') {
36 | newObject = { 'id': newObject.id, 'type': 'helper', wires: newObject.wires }
37 | } else {
38 | delete newObject['x']
39 | delete newObject['y']
40 | delete newObject['z']
41 | }
42 |
43 | return newObject
44 | },
45 |
46 | cleanFlowPositionData: (jsonFlow) => {
47 | let cleanFlow = []
48 | // flow is an array of JSON objects with x,y,z from the Node-RED export
49 | jsonFlow.forEach((item, index, array) => {
50 | let newObject = JSON.parse(JSON.stringify(item))
51 | if (newObject.type === 'helper') {
52 | cleanFlow.push({ 'id': newObject.id, 'type': 'helper', wires: newObject.wires })
53 | } else {
54 | delete newObject['x']
55 | delete newObject['y']
56 | delete newObject['z']
57 | cleanFlow.push(newObject)
58 | }
59 | })
60 |
61 | return cleanFlow
62 | },
63 |
64 | getPort: (portOffset) => {
65 | let testPort = portOffset
66 |
67 | do {
68 | testPort++
69 | } while (isPortTaken(testPort))
70 |
71 | return testPort
72 | }
73 | }
--------------------------------------------------------------------------------
/test/units/flows/browser-flows.js:
--------------------------------------------------------------------------------
1 |
2 | const helperExtensions = require('../../helper/test-helper-extensions')
3 |
4 | module.exports = {
5 |
6 | "testUnitBrowseFlow": helperExtensions.cleanFlowPositionData([
7 | {
8 | "id": "e41e66b2c57b1657",
9 | "type": "tab",
10 | "label": "Test Unit Browse Flow",
11 | "disabled": false,
12 | "info": "",
13 | "env": []
14 | },
15 | {
16 | "id": "4ac0b7c8.bebe18",
17 | "type": "OPCUA-IIoT-Browser",
18 | "z": "e41e66b2c57b1657",
19 | "connector": "",
20 | "nodeId": "ns=1;i=1234",
21 | "name": "TestNameBrowser",
22 | "justValue": true,
23 | "sendNodesToRead": false,
24 | "sendNodesToListener": false,
25 | "sendNodesToBrowser": false,
26 | "multipleOutputs": false,
27 | "recursiveBrowse": false,
28 | "recursiveDepth": "",
29 | "delayPerMessage": "",
30 | "showStatusActivities": false,
31 | "showErrors": false,
32 | "x": 190,
33 | "y": 140,
34 | "wires": [
35 | [
36 | "059bc7271eb02b9d"
37 | ]
38 | ]
39 | },
40 | {
41 | "id": "059bc7271eb02b9d",
42 | "type": "helper",
43 | "z": "e41e66b2c57b1657",
44 | "name": "helper 1",
45 | "active": true,
46 | "tosidebar": true,
47 | "console": false,
48 | "tostatus": false,
49 | "complete": "payload",
50 | "targetType": "msg",
51 | "statusVal": "",
52 | "statusType": "auto",
53 | "x": 440,
54 | "y": 140,
55 | "wires": []
56 | }
57 | ])
58 | }
--------------------------------------------------------------------------------
/test/units/flows/connector-flows.js:
--------------------------------------------------------------------------------
1 |
2 | const helperExtensions = require('../../helper/test-helper-extensions')
3 |
4 | module.exports = {
5 |
6 | "testUnitConnectorFlow": helperExtensions.cleanFlowPositionData([
7 | {
8 | "id": "b79fdf68790c5ed2",
9 | "type": "tab",
10 | "label": "testUnitConnectorFlow",
11 | "disabled": false,
12 | "info": "",
13 | "env": []
14 | },
15 | {
16 | "id": "n4",
17 | "type": "OPCUA-IIoT-Connector",
18 | "z": "b79fdf68790c5ed2",
19 | "discoveryUrl": "",
20 | "endpoint": "",
21 | "keepSessionAlive": false,
22 | "loginEnabled": false,
23 | "securityPolicy": "None",
24 | "securityMode": "None",
25 | "name": "TESTSERVER",
26 | "showErrors": false,
27 | "individualCerts": false,
28 | "publicCertificateFile": "",
29 | "privateKeyFile": "",
30 | "defaultSecureTokenLifetime": "60000",
31 | "endpointMustExist": false,
32 | "autoSelectRightEndpoint": false,
33 | "strategyMaxRetry": "",
34 | "strategyInitialDelay": "",
35 | "strategyMaxDelay": "",
36 | "strategyRandomisationFactor": "",
37 | "requestedSessionTimeout": "",
38 | "connectionStartDelay": "",
39 | "reconnectDelay": "",
40 | "maxBadSessionRequests": ""
41 | }
42 | ]),
43 |
44 | "testUnitConnectorDefaultsFlow": helperExtensions.cleanFlowPositionData([
45 | {
46 | "id": "b79fdf68790c5ed2",
47 | "type": "tab",
48 | "label": "testUnitConnectorDefaultsFlow",
49 | "disabled": false,
50 | "info": "",
51 | "env": []
52 | },
53 | {
54 | "id": "n4",
55 | "type": "OPCUA-IIoT-Connector",
56 | "z": "b79fdf68790c5ed2",
57 | "discoveryUrl": "",
58 | "endpoint": "opc.tcp://localhost:55388/",
59 | "keepSessionAlive": true,
60 | "loginEnabled": false,
61 | "securityPolicy": "None",
62 | "securityMode": "None",
63 | "name": "LOCAL SERVER",
64 | "showErrors": false,
65 | "individualCerts": false,
66 | "publicCertificateFile": "",
67 | "privateKeyFile": "",
68 | "defaultSecureTokenLifetime": "",
69 | "endpointMustExist": false,
70 | "autoSelectRightEndpoint": false,
71 | "strategyMaxRetry": "",
72 | "strategyInitialDelay": "",
73 | "strategyMaxDelay": "",
74 | "strategyRandomisationFactor": "",
75 | "requestedSessionTimeout": "",
76 | "connectionStartDelay": "",
77 | "connectionStopDelay": "",
78 | "reconnectDelay": "",
79 | "maxBadSessionRequests": 10
80 | }
81 | ]),
82 |
83 | "testUnitConnectorGeneratedDefaultsFlow": helperExtensions.cleanFlowPositionData([
84 | {
85 | "id": "b79fdf68790c5ed2",
86 | "type": "tab",
87 | "label": "testUnitConnectorDefaultFlowFlow",
88 | "disabled": false,
89 | "info": "",
90 | "env": []
91 | },
92 | {
93 | "id": "7291451d5224efde",
94 | "type": "OPCUA-IIoT-Read",
95 | "z": "b79fdf68790c5ed2",
96 | "attributeId": 0,
97 | "maxAge": 1,
98 | "depth": 1,
99 | "connector": "594b2860fa40bda5",
100 | "name": "",
101 | "justValue": true,
102 | "showStatusActivities": false,
103 | "showErrors": false,
104 | "parseStrings": false,
105 | "historyDays": 1,
106 | "x": 440,
107 | "y": 250,
108 | "wires": [
109 | []
110 | ]
111 | },
112 | {
113 | "id": "594b2860fa40bda5",
114 | "type": "OPCUA-IIoT-Connector",
115 | "discoveryUrl": "",
116 | "endpoint": "opc.tcp://localhost:44840/",
117 | "keepSessionAlive": true,
118 | "loginEnabled": false,
119 | "securityPolicy": "None",
120 | "securityMode": "None",
121 | "name": "LOCAL SERVER",
122 | "showErrors": false,
123 | "individualCerts": false,
124 | "publicCertificateFile": "",
125 | "privateKeyFile": "",
126 | "defaultSecureTokenLifetime": "",
127 | "endpointMustExist": false,
128 | "autoSelectRightEndpoint": false,
129 | "strategyMaxRetry": "",
130 | "strategyInitialDelay": "",
131 | "strategyMaxDelay": "",
132 | "strategyRandomisationFactor": "",
133 | "requestedSessionTimeout": "",
134 | "connectionStartDelay": "",
135 | "reconnectDelay": "",
136 | "maxBadSessionRequests": 10
137 | }
138 | ])
139 | }
--------------------------------------------------------------------------------
/test/units/flows/crawler-flows.js:
--------------------------------------------------------------------------------
1 |
2 | const helperExtensions = require('../../helper/test-helper-extensions')
3 |
4 | module.exports = {
5 |
6 | "testUnitCrawlerFlow": helperExtensions.cleanFlowPositionData([
7 | {
8 | "id": "4d6ae11544766677",
9 | "type": "tab",
10 | "label": "Test Crawler Flow",
11 | "disabled": false,
12 | "info": "",
13 | "env": []
14 | },
15 | {
16 | "id": "13e5e190.e34516",
17 | "type": "OPCUA-IIoT-Crawler",
18 | "z": "4d6ae11544766677",
19 | "connector": "",
20 | "name": "TestNameCrawler",
21 | "justValue": true,
22 | "singleResult": false,
23 | "showStatusActivities": false,
24 | "showErrors": false,
25 | "activateUnsetFilter": true,
26 | "activateFilters": false,
27 | "negateFilter": false,
28 | "filters": [
29 | {
30 | "name": "Organizes",
31 | "value": ""
32 | },
33 | {
34 | "name": "GeneratesEvent",
35 | "value": ""
36 | },
37 | {
38 | "name": "References",
39 | "value": ""
40 | }
41 | ],
42 | "delayPerMessage": "",
43 | "timeout": "",
44 | "x": 370,
45 | "y": 160,
46 | "wires": [
47 | []
48 | ]
49 | }
50 | ]),
51 | "testUnitDefaultCrawlerFlow" : helperExtensions.cleanFlowPositionData([
52 | {
53 | "id": "4d6ae11544766677",
54 | "type": "tab",
55 | "label": "Test Unit Default Crawler Flow",
56 | "disabled": false,
57 | "info": "",
58 | "env": []
59 | },
60 | {
61 | "id": "4bf9f1cbd3fe98bc",
62 | "type": "OPCUA-IIoT-Crawler",
63 | "z": "4d6ae11544766677",
64 | "connector": "",
65 | "name": "",
66 | "justValue": true,
67 | "singleResult": false,
68 | "showStatusActivities": false,
69 | "showErrors": false,
70 | "activateUnsetFilter": false,
71 | "activateFilters": false,
72 | "negateFilter": false,
73 | "filters": [],
74 | "delayPerMessage": 0.2,
75 | "timeout": 30,
76 | "x": 220,
77 | "y": 180,
78 | "wires": [
79 | [
80 | "647418b9eaf63928"
81 | ]
82 | ]
83 | },
84 | {
85 | "id": "647418b9eaf63928",
86 | "type": "helper",
87 | "z": "4d6ae11544766677",
88 | "name": "helper 1",
89 | "active": true,
90 | "tosidebar": true,
91 | "console": false,
92 | "tostatus": false,
93 | "complete": "false",
94 | "statusVal": "",
95 | "statusType": "auto",
96 | "x": 420,
97 | "y": 180,
98 | "wires": []
99 | }
100 | ])
101 | }
--------------------------------------------------------------------------------
/test/units/flows/discovery-flows.js:
--------------------------------------------------------------------------------
1 |
2 | const helperExtensions = require('../../helper/test-helper-extensions')
3 |
4 | module.exports = {
5 |
6 | "testUnitDiscoveryFlow": helperExtensions.cleanFlowPositionData([
7 | {
8 | "id": "86a4cc825a400180",
9 | "type": "tab",
10 | "label": "testUnitDiscoveryFlow",
11 | "disabled": false,
12 | "info": "",
13 | "env": []
14 | },
15 | {
16 | "id": "d9db5e281fac4a0c",
17 | "type": "OPCUA-IIoT-Discovery",
18 | "z": "86a4cc825a400180",
19 | "name": "TestName",
20 | "discoveryPort": "",
21 | "x": 360,
22 | "y": 220,
23 | "wires": [
24 | [
25 | "7d54598b282a3ed9"
26 | ]
27 | ]
28 | },
29 | {
30 | "id": "7d54598b282a3ed9",
31 | "type": "helper",
32 | "z": "86a4cc825a400180",
33 | "name": "",
34 | "tosidebar": true,
35 | "console": false,
36 | "tostatus": false,
37 | "complete": "payload",
38 | "targetType": "msg",
39 | "statusVal": "",
40 | "statusType": "auto",
41 | "x": 380,
42 | "y": 340,
43 | "wires": []
44 | }
45 | ]),
46 | "testUnitDiscoveryNullPortFlow": helperExtensions.cleanFlowPositionData([
47 | {
48 | "id": "b79fdf68790c5ed2",
49 | "type": "tab",
50 | "label": "testUnitDiscoveryNullPortFlow",
51 | "disabled": false,
52 | "info": "",
53 | "env": []
54 | },
55 | {
56 | "id": "n1dsf2",
57 | "type": "OPCUA-IIoT-Discovery",
58 | "z": "b79fdf68790c5ed2",
59 | "name": "TestName",
60 | "discoveryPort": "",
61 | "x": 370,
62 | "y": 210,
63 | "wires": [
64 | [
65 | "n2dsf1"
66 | ]
67 | ]
68 | },
69 | {
70 | "id": "n2dsf1",
71 | "type": "helper",
72 | "z": "b79fdf68790c5ed2",
73 | "name": "",
74 | "tosidebar": true,
75 | "console": false,
76 | "tostatus": false,
77 | "complete": "payload",
78 | "targetType": "msg",
79 | "statusVal": "",
80 | "statusType": "auto",
81 | "x": 390,
82 | "y": 160,
83 | "wires": []
84 | }
85 | ]),
86 | "testUnitDiscoveryNullPortAndInjectFlow": helperExtensions.cleanFlowPositionData([
87 | {
88 | "id": "b79fdf68790c5ed2",
89 | "type": "tab",
90 | "label": "testUnitDiscoveryNullPortAndInjectFlow",
91 | "disabled": false,
92 | "info": "",
93 | "env": []
94 | },
95 | {
96 | "id": "n1edf1",
97 | "type": "inject",
98 | "z": "b79fdf68790c5ed2",
99 | "name": "",
100 | "props": [
101 | {
102 | "p": "payload"
103 | },
104 | {
105 | "p": "topic",
106 | "vt": "str"
107 | }
108 | ],
109 | "repeat": "",
110 | "crontab": "",
111 | "once": true,
112 | "onceDelay": "4",
113 | "topic": "TestTopic",
114 | "payload": "",
115 | "payloadType": "date",
116 | "x": 290,
117 | "y": 320,
118 | "wires": [
119 | [
120 | "n2edf1",
121 | "n3edf1"
122 | ]
123 | ]
124 | },
125 | {
126 | "id": "n2edf1",
127 | "type": "helper",
128 | "z": "b79fdf68790c5ed2",
129 | "name": "",
130 | "tosidebar": true,
131 | "console": false,
132 | "tostatus": false,
133 | "complete": "payload",
134 | "targetType": "msg",
135 | "statusVal": "",
136 | "statusType": "auto",
137 | "x": 450,
138 | "y": 440,
139 | "wires": []
140 | },
141 | {
142 | "id": "n3edf1",
143 | "type": "OPCUA-IIoT-Discovery",
144 | "z": "b79fdf68790c5ed2",
145 | "name": "TestName",
146 | "discoveryPort": "",
147 | "x": 180,
148 | "y": 170,
149 | "wires": [
150 | [
151 | "n4edf1"
152 | ]
153 | ]
154 | },
155 | {
156 | "id": "n4edf1",
157 | "type": "helper",
158 | "z": "b79fdf68790c5ed2",
159 | "name": "",
160 | "tosidebar": true,
161 | "console": false,
162 | "tostatus": false,
163 | "complete": "payload",
164 | "targetType": "msg",
165 | "statusVal": "",
166 | "statusType": "auto",
167 | "x": 390,
168 | "y": 100,
169 | "wires": []
170 | }
171 | ])
172 | }
--------------------------------------------------------------------------------
/test/units/flows/event-flows.js:
--------------------------------------------------------------------------------
1 |
2 | const helperExtensions = require('../../helper/test-helper-extensions')
3 |
4 | module.exports = {
5 |
6 | "testUnitEventFlow": helperExtensions.cleanFlowPositionData([
7 | {
8 | "id": "b79fdf68790c5ed2",
9 | "type": "tab",
10 | "label": "testUnitEventFlow",
11 | "disabled": false,
12 | "info": "",
13 | "env": []
14 | },
15 | {
16 | "id": "n1evf1",
17 | "type": "inject",
18 | "z": "b79fdf68790c5ed2",
19 | "name": "",
20 | "props": [
21 | {
22 | "p": "payload"
23 | },
24 | {
25 | "p": "topic",
26 | "vt": "str"
27 | }
28 | ],
29 | "repeat": "",
30 | "crontab": "",
31 | "once": true,
32 | "onceDelay": "4",
33 | "topic": "TestTopic",
34 | "payload": "{\"value\":1000}",
35 | "payloadType": "json",
36 | "x": 470,
37 | "y": 400,
38 | "wires": [
39 | [
40 | "n2evf1",
41 | "n3evf1"
42 | ]
43 | ]
44 | },
45 | {
46 | "id": "n2evf1",
47 | "type": "helper",
48 | "z": "b79fdf68790c5ed2",
49 | "name": "",
50 | "tosidebar": true,
51 | "console": false,
52 | "tostatus": false,
53 | "complete": "payload",
54 | "targetType": "msg",
55 | "statusVal": "",
56 | "statusType": "auto",
57 | "x": 700,
58 | "y": 660,
59 | "wires": []
60 | },
61 | {
62 | "id": "n3evf1",
63 | "type": "OPCUA-IIoT-Event",
64 | "z": "b79fdf68790c5ed2",
65 | "eventType": "i=2041",
66 | "eventTypeLabel": "BaseTypeEvent",
67 | "queueSize": 10,
68 | "usingListener": true,
69 | "name": "TestName",
70 | "showStatusActivities": false,
71 | "showErrors": false,
72 | "x": 830,
73 | "y": 300,
74 | "wires": [
75 | [
76 | "n4evf1"
77 | ]
78 | ]
79 | },
80 | {
81 | "id": "n4evf1",
82 | "type": "helper",
83 | "z": "b79fdf68790c5ed2",
84 | "name": "",
85 | "tosidebar": true,
86 | "console": false,
87 | "tostatus": false,
88 | "complete": "payload",
89 | "targetType": "msg",
90 | "statusVal": "",
91 | "statusType": "auto",
92 | "x": 480,
93 | "y": 180,
94 | "wires": []
95 | }
96 | ])
97 | }
--------------------------------------------------------------------------------
/test/units/flows/flex-connector-flows.js:
--------------------------------------------------------------------------------
1 |
2 | const helperExtensions = require('../../helper/test-helper-extensions')
3 |
4 | module.exports = {
5 |
6 | "testUnitFlexConnectorFlow": helperExtensions.cleanFlowPositionData([
7 | {
8 | "id": "b79fdf68790c5ed2",
9 | "type": "tab",
10 | "label": "testUnitFlexConnectorFlow",
11 | "disabled": false,
12 | "info": "",
13 | "env": []
14 | },
15 | {
16 | "id": "14d54403.f94f04",
17 | "type": "OPCUA-IIoT-Flex-Connector",
18 | "z": "b79fdf68790c5ed2",
19 | "name": "TestFlexConnector",
20 | "showStatusActivities": false,
21 | "showErrors": false,
22 | "connector": "",
23 | "x": 510,
24 | "y": 260,
25 | "wires": [
26 | []
27 | ]
28 | }
29 | ]),
30 |
31 | "testUnitFlexConnectorShowActivitiesFlow": helperExtensions.cleanFlowPositionData([
32 | {
33 | "id": "b79fdf68790c5ed2",
34 | "type": "tab",
35 | "label": "testUnitFlexConnectorShowActivitiesFlow",
36 | "disabled": false,
37 | "info": "",
38 | "env": []
39 | },
40 | {
41 | "id": "14d54403.f94f05",
42 | "type": "OPCUA-IIoT-Flex-Connector",
43 | "z": "b79fdf68790c5ed2",
44 | "name": "TestFlexConnector2",
45 | "showStatusActivities": true,
46 | "showErrors": false,
47 | "connector": "",
48 | "x": 440,
49 | "y": 260,
50 | "wires": [
51 | []
52 | ]
53 | }
54 | ])
55 | }
--------------------------------------------------------------------------------
/test/units/flows/listener-flows.js:
--------------------------------------------------------------------------------
1 |
2 | const helperExtensions = require('../../helper/test-helper-extensions')
3 |
4 | module.exports = {
5 |
6 | "testUnitListenerFlow": helperExtensions.cleanFlowPositionData([
7 | {
8 | "id": "b79fdf68790c5ed2",
9 | "type": "tab",
10 | "label": "testUnitListenerFlow",
11 | "disabled": false,
12 | "info": "",
13 | "env": []
14 | },
15 | {
16 | "id": "bee3e3b0.ca1a08",
17 | "type": "OPCUA-IIoT-Listener",
18 | "z": "b79fdf68790c5ed2",
19 | "connector": "",
20 | "action": "subscribe",
21 | "queueSize": 10,
22 | "name": "TestListener",
23 | "topic": "",
24 | "justValue": true,
25 | "useGroupItems": false,
26 | "showStatusActivities": false,
27 | "showErrors": false,
28 | "x": 470,
29 | "y": 240,
30 | "wires": [
31 | []
32 | ]
33 | }
34 | ])
35 | }
--------------------------------------------------------------------------------
/test/units/flows/method-caller-flows.js:
--------------------------------------------------------------------------------
1 |
2 | const helperExtensions = require('../../helper/test-helper-extensions')
3 |
4 | module.exports = {
5 |
6 | "testUnitMethodCallerFlow": helperExtensions.cleanFlowPositionData([
7 | {
8 | "id": "b79fdf68790c5ed2",
9 | "type": "tab",
10 | "label": "testUnitMethodCallerFlow",
11 | "disabled": false,
12 | "info": "",
13 | "env": []
14 | },
15 | {
16 | "id": "706d43c1.90baac",
17 | "type": "OPCUA-IIoT-Method-Caller",
18 | "z": "b79fdf68790c5ed2",
19 | "connector": "",
20 | "objectId": "ns=1;i=1234",
21 | "methodId": "ns=1;i=12345",
22 | "methodType": "basic",
23 | "value": "",
24 | "justValue": false,
25 | "name": "TestName",
26 | "showStatusActivities": false,
27 | "showErrors": true,
28 | "inputArguments": [
29 | {
30 | "name": "barks",
31 | "dataType": "UInt32",
32 | "value": "3"
33 | },
34 | {
35 | "name": "volume",
36 | "dataType": "UInt32",
37 | "value": "6"
38 | }
39 | ],
40 | "x": 480,
41 | "y": 230,
42 | "wires": [
43 | []
44 | ]
45 | }
46 | ]),
47 |
48 | "testUnitMethodCallerNotConfiguredFlow": helperExtensions.cleanFlowPositionData([
49 | {
50 | "id": "b79fdf68790c5ed2",
51 | "type": "tab",
52 | "label": "testUnitMethodCallerNotConfiguredFlow",
53 | "disabled": false,
54 | "info": "",
55 | "env": []
56 | },
57 | {
58 | "id": "706d43c1.90babc",
59 | "type": "OPCUA-IIoT-Method-Caller",
60 | "z": "b79fdf68790c5ed2",
61 | "connector": "",
62 | "objectId": "",
63 | "methodId": "",
64 | "methodType": "basic",
65 | "value": "",
66 | "justValue": false,
67 | "name": "TestName",
68 | "showStatusActivities": false,
69 | "showErrors": true,
70 | "inputArguments": [],
71 | "x": 440,
72 | "y": 250,
73 | "wires": [
74 | []
75 | ]
76 | }
77 | ])
78 | }
--------------------------------------------------------------------------------
/test/units/flows/read-flows.js:
--------------------------------------------------------------------------------
1 |
2 | const helperExtensions = require('../../helper/test-helper-extensions')
3 |
4 | module.exports = {
5 |
6 | "testUnitReadFlow": helperExtensions.cleanFlowPositionData([
7 | {
8 | "id": "b79fdf68790c5ed2",
9 | "type": "tab",
10 | "label": "testUnitReadFlow",
11 | "disabled": false,
12 | "info": "",
13 | "env": []
14 | },
15 | {
16 | "id": "41cb29d.1ab50d8",
17 | "type": "OPCUA-IIoT-Read",
18 | "z": "b79fdf68790c5ed2",
19 | "attributeId": 0,
20 | "maxAge": 1,
21 | "depth": 1,
22 | "connector": "",
23 | "name": "ReadAll",
24 | "justValue": true,
25 | "showStatusActivities": false,
26 | "showErrors": false,
27 | "parseStrings": false,
28 | "historyDays": "",
29 | "x": 400,
30 | "y": 170,
31 | "wires": [
32 | [
33 | "508385cc4a0a910b"
34 | ]
35 | ]
36 | },
37 | {
38 | "id": "508385cc4a0a910b",
39 | "type": "helper",
40 | "z": "b79fdf68790c5ed2",
41 | "name": "helper 1",
42 | "active": true,
43 | "tosidebar": true,
44 | "console": false,
45 | "tostatus": false,
46 | "complete": "false",
47 | "statusVal": "",
48 | "statusType": "auto",
49 | "x": 600,
50 | "y": 170,
51 | "wires": []
52 | }
53 | ])
54 | }
--------------------------------------------------------------------------------
/test/units/flows/server-aso-flows.js:
--------------------------------------------------------------------------------
1 |
2 | const helperExtensions = require('../../helper/test-helper-extensions')
3 |
4 | module.exports = {
5 |
6 | "testUnitServerASOFlow": helperExtensions.cleanFlowPositionData([
7 | {
8 | "id": "628990c93a2db9aa",
9 | "type": "tab",
10 | "label": "Test Unit Server ASO Flow",
11 | "disabled": false,
12 | "info": "",
13 | "env": []
14 | },
15 | {
16 | "id": "7cb85115.7635",
17 | "type": "OPCUA-IIoT-Server-ASO",
18 | "z": "628990c93a2db9aa",
19 | "nodeId": "ns=1;s=TestVariables",
20 | "browsename": "TestVariables",
21 | "displayname": "Test Variables",
22 | "objecttype": "FolderType",
23 | "datatype": "Double",
24 | "value": "1.0",
25 | "referenceNodeId": "ns=0;i=85",
26 | "referencetype": "Organizes",
27 | "name": "Folder",
28 | "x": 210,
29 | "y": 280,
30 | "wires": [
31 | [
32 | "a51de437b1ecc2f5"
33 | ]
34 | ]
35 | },
36 | {
37 | "id": "a51de437b1ecc2f5",
38 | "type": "helper",
39 | "z": "628990c93a2db9aa",
40 | "name": "helper 1",
41 | "active": true,
42 | "tosidebar": true,
43 | "console": false,
44 | "tostatus": false,
45 | "complete": "payload",
46 | "targetType": "msg",
47 | "statusVal": "",
48 | "statusType": "auto",
49 | "x": 380,
50 | "y": 280,
51 | "wires": []
52 | }
53 | ])
54 | }
--------------------------------------------------------------------------------
/test/units/flows/server-cmd-flows.js:
--------------------------------------------------------------------------------
1 |
2 | const helperExtensions = require('../../helper/test-helper-extensions')
3 |
4 | module.exports = {
5 |
6 | "testUnitServerCommandFlow": helperExtensions.cleanFlowPositionData([
7 | {
8 | "id": "b79fdf68790c5ed2",
9 | "type": "tab",
10 | "label": "testUnitServerCommandFlow",
11 | "disabled": false,
12 | "info": "",
13 | "env": []
14 | },
15 | {
16 | "id": "n3cmdf1",
17 | "type": "OPCUA-IIoT-Server-Command",
18 | "z": "b79fdf68790c5ed2",
19 | "commandtype": "restart",
20 | "nodeId": "",
21 | "name": "TestName",
22 | "x": 130,
23 | "y": 200,
24 | "wires": [
25 | []
26 | ]
27 | }
28 | ])
29 | }
--------------------------------------------------------------------------------
/test/units/flows/server-flows.js:
--------------------------------------------------------------------------------
1 |
2 | const helperExtensions = require('../../helper/test-helper-extensions')
3 |
4 | module.exports = {
5 |
6 | "testUnitServerWithDemoFlow": helperExtensions.cleanFlowPositionData([
7 | {
8 | "id": "b233bdeab126bfd4",
9 | "type": "tab",
10 | "label": "Test Server Demo Flow",
11 | "disabled": false,
12 | "info": "",
13 | "env": []
14 | },
15 | {
16 | "id": "6ec4ef50.86dc1",
17 | "type": "OPCUA-IIoT-Server",
18 | "z": "b233bdeab126bfd4",
19 | "port": "51250",
20 | "endpoint": "",
21 | "acceptExternalCommands": true,
22 | "maxAllowedSessionNumber": "",
23 | "maxConnectionsPerEndpoint": "",
24 | "maxAllowedSubscriptionNumber": "",
25 | "alternateHostname": "",
26 | "name": "DEMOSERVER",
27 | "showStatusActivities": false,
28 | "showErrors": false,
29 | "asoDemo": true,
30 | "allowAnonymous": true,
31 | "individualCerts": false,
32 | "isAuditing": false,
33 | "serverDiscovery": false,
34 | "users": [],
35 | "xmlsets": [],
36 | "publicCertificateFile": "",
37 | "privateCertificateFile": "",
38 | "registerServerMethod": 1,
39 | "discoveryServerEndpointUrl": "",
40 | "capabilitiesForMDNS": "",
41 | "maxNodesPerRead": 1000,
42 | "maxNodesPerBrowse": 2000,
43 | "delayToClose": 200,
44 | "x": 380,
45 | "y": 200,
46 | "wires": [
47 | []
48 | ]
49 | }
50 | ]),
51 |
52 | "testUnitServerWithoutDemoFlow": helperExtensions.cleanFlowPositionData([
53 | {
54 | "id": "4a4f0ffea30b6dcb",
55 | "type": "tab",
56 | "label": "Test Server Flow",
57 | "disabled": false,
58 | "info": "",
59 | "env": []
60 | },
61 | {
62 | "id": "6ec4ef50.86dc2",
63 | "type": "OPCUA-IIoT-Server",
64 | "z": "4a4f0ffea30b6dcb",
65 | "port": "51201",
66 | "endpoint": "",
67 | "acceptExternalCommands": true,
68 | "maxAllowedSessionNumber": "",
69 | "maxConnectionsPerEndpoint": "",
70 | "maxAllowedSubscriptionNumber": "",
71 | "alternateHostname": "",
72 | "name": "DEMOSERVER",
73 | "showStatusActivities": false,
74 | "showErrors": false,
75 | "asoDemo": false,
76 | "allowAnonymous": true,
77 | "individualCerts": false,
78 | "isAuditing": false,
79 | "serverDiscovery": true,
80 | "users": [],
81 | "xmlsets": [],
82 | "publicCertificateFile": "",
83 | "privateCertificateFile": "",
84 | "registerServerMethod": 1,
85 | "discoveryServerEndpointUrl": "",
86 | "capabilitiesForMDNS": "",
87 | "maxNodesPerRead": 1000,
88 | "maxNodesPerBrowse": 2000,
89 | "delayToClose": "",
90 | "x": 460,
91 | "y": 140,
92 | "wires": [
93 | []
94 | ]
95 | }
96 | ])
97 | }
--------------------------------------------------------------------------------
/test/units/flows/write-flows.js:
--------------------------------------------------------------------------------
1 |
2 | const helperExtensions = require('../../helper/test-helper-extensions')
3 |
4 | module.exports = {
5 |
6 | "testUnitWriteFlow": helperExtensions.cleanFlowPositionData([
7 | {
8 | "id": "b79fdf68790c5ed2",
9 | "type": "tab",
10 | "label": "testUnitWriteFlow",
11 | "disabled": false,
12 | "info": "",
13 | "env": []
14 | },
15 | {
16 | "id": "34d2c6bc.43275b",
17 | "type": "OPCUA-IIoT-Write",
18 | "z": "b79fdf68790c5ed2",
19 | "connector": "",
20 | "name": "TestWrite",
21 | "justValue": false,
22 | "showStatusActivities": false,
23 | "showErrors": true,
24 | "x": 220,
25 | "y": 170,
26 | "wires": [
27 | []
28 | ]
29 | }
30 | ])
31 | }
--------------------------------------------------------------------------------
/test/units/opcua-iiot-browser.test.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Original Work Copyright 2014 IBM Corp.
3 | * node-red
4 | *
5 | * Copyright (c) 2022 DATATRONiQ GmbH (https://datatroniq.com)
6 | * Copyright (c) 2018-2022 Klaus Landsdorf (http://node-red.plus/)
7 | * All rights reserved.
8 | * node-red-contrib-iiot-opcua
9 | *
10 | **/
11 |
12 | 'use strict'
13 |
14 | // jest.setTimeout(30000)
15 |
16 | var functionNode = require('@node-red/nodes/core/function/10-function')
17 | var injectNode = require('@node-red/nodes/core/common/20-inject')
18 | var browserNode = require('../../src/opcua-iiot-browser')
19 |
20 | var helper = require('node-red-node-test-helper')
21 | var portHelper = require('./../helper/test-helper-extensions')
22 | helper.init(require.resolve('node-red'))
23 |
24 | var browseNodesToLoad = [injectNode, functionNode, browserNode]
25 |
26 | var testFlows = require('./flows/browser-flows')
27 |
28 | let testingOpcUaPort = 0
29 |
30 | describe('OPC UA Browser node Unit Testing', function () {
31 |
32 | beforeAll(() => {
33 | testingOpcUaPort = 57050
34 | })
35 |
36 | beforeEach(function (done) {
37 | helper.startServer(function () {
38 | done()
39 | })
40 | })
41 |
42 | afterEach(function (done) {
43 | helper.unload().then(function () {
44 | helper.stopServer(function () {
45 | done()
46 | })
47 | }).catch(function () {
48 | helper.stopServer(function () {
49 | done()
50 | })
51 | })
52 | })
53 |
54 | describe('Browser node', function () {
55 | it('should be loaded with correct defaults', function (done) {
56 | const flow = Array.from(testFlows.testUnitBrowseFlow)
57 |
58 | helper.load(browseNodesToLoad, flow,
59 | function () {
60 | let nodeUnderTest = helper.getNode('4ac0b7c8.bebe18')
61 | expect(nodeUnderTest.nodeId).toBe('ns=1;i=1234')
62 | expect(nodeUnderTest.name).toBe('TestNameBrowser')
63 | expect(nodeUnderTest.justValue).toBe(true)
64 | expect(nodeUnderTest.sendNodesToRead).toBe(false)
65 | expect(nodeUnderTest.sendNodesToListener).toBe(false)
66 | expect(nodeUnderTest.sendNodesToBrowser).toBe(false)
67 | expect(nodeUnderTest.multipleOutputs).toBe(false)
68 | expect(nodeUnderTest.recursiveBrowse).toBe(false)
69 | expect(nodeUnderTest.recursiveDepth).toBe(1)
70 | expect(nodeUnderTest.delayPerMessage).toBe(0.2)
71 | expect(nodeUnderTest.showStatusActivities).toBe(false)
72 | expect(nodeUnderTest.showErrors).toBe(false)
73 | setTimeout(done, 3000)
74 | })
75 | })
76 | })
77 | })
78 |
--------------------------------------------------------------------------------
/test/units/opcua-iiot-crawler.test.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Original Work Copyright 2014 IBM Corp.
3 | * node-red
4 | *
5 | * Copyright (c) 2022 DATATRONiQ GmbH (https://datatroniq.com)
6 | * Copyright (c) 2018-2022 Klaus Landsdorf (http://node-red.plus/)
7 | * All rights reserved.
8 | * node-red-contrib-iiot-opcua
9 | *
10 | **/
11 |
12 | 'use strict'
13 |
14 | // jest.setTimeout(30000)
15 |
16 | var injectNode = require('@node-red/nodes/core/common/20-inject')
17 | var functionNode = require('@node-red/nodes/core/function/10-function')
18 | var inputNode = require('../../src/opcua-iiot-crawler')
19 |
20 | var helper = require('node-red-node-test-helper')
21 | var portHelper = require('./../helper/test-helper-extensions')
22 | helper.init(require.resolve('node-red'))
23 |
24 | var crawlerNodesToLoad = [injectNode, functionNode, inputNode]
25 |
26 | var testFlows = require('./flows/crawler-flows')
27 |
28 | let testingOpcUaPort = 0
29 |
30 | describe('OPC UA Crawler node Unit Testing', function () {
31 |
32 | beforeAll(() => {
33 | testingOpcUaPort = 57250
34 | })
35 |
36 | beforeEach(function (done) {
37 | helper.startServer(function () {
38 | done()
39 | })
40 | })
41 |
42 | afterEach(function (done) {
43 | helper.unload().then(function () {
44 | helper.stopServer(function () {
45 | done()
46 | })
47 | }).catch(function () {
48 | helper.stopServer(function () {
49 | done()
50 | })
51 | })
52 | })
53 |
54 | describe('Crawler node', function () {
55 | it('should be loaded', function (done) {
56 | helper.load(crawlerNodesToLoad, testFlows.testUnitCrawlerFlow,
57 | function () {
58 | let nodeUnderTest = helper.getNode('13e5e190.e34516')
59 | expect(nodeUnderTest.name).toBe('TestNameCrawler')
60 | expect(nodeUnderTest.justValue).toBe(true)
61 | expect(nodeUnderTest.singleResult).toBe(false)
62 | expect(nodeUnderTest.showStatusActivities).toBe(false)
63 | expect(nodeUnderTest.showErrors).toBe(false)
64 | done()
65 | })
66 | })
67 |
68 | it('should be loaded with default settings', function (done) {
69 | helper.load(crawlerNodesToLoad, testFlows.testUnitDefaultCrawlerFlow,
70 | function () {
71 | let nodeUnderTest = helper.getNode('4bf9f1cbd3fe98bc')
72 | expect(nodeUnderTest.name).toBe('')
73 | expect(nodeUnderTest.justValue).toBe(true)
74 | expect(nodeUnderTest.singleResult).toBe(false)
75 | expect(nodeUnderTest.showStatusActivities).toBe(false)
76 | expect(nodeUnderTest.showErrors).toBe(false)
77 | expect(nodeUnderTest.activateUnsetFilter).toBe(false)
78 | expect(nodeUnderTest.activateFilters).toBe(false)
79 | expect(nodeUnderTest.negateFilter).toBe(false)
80 | expect(nodeUnderTest.filters).toBeInstanceOf(Array)
81 | expect(nodeUnderTest.filters.length).toBe(0)
82 | expect(nodeUnderTest.delayPerMessage).toBe(0.2)
83 | expect(nodeUnderTest.timeout).toBe(30)
84 | done()
85 | })
86 | })
87 |
88 | })
89 | })
90 |
--------------------------------------------------------------------------------
/test/units/opcua-iiot-discovery.test.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Original Work Copyright 2014 IBM Corp.
3 | * node-red
4 | *
5 | * Copyright (c) 2022 DATATRONiQ GmbH (https://datatroniq.com)
6 | * Copyright (c) 2018-2022 Klaus Landsdorf (http://node-red.plus/)
7 | * All rights reserved.
8 | * node-red-contrib-iiot-opcua
9 | *
10 | **/
11 |
12 | 'use strict'
13 |
14 | // jest.setTimeout(30000)
15 |
16 | var injectNode = require('@node-red/nodes/core/common/20-inject')
17 | var inputNode = require('../../src/opcua-iiot-discovery')
18 |
19 | var helper = require('node-red-node-test-helper')
20 | var portHelper = require('./../helper/test-helper-extensions')
21 | helper.init(require.resolve('node-red'))
22 |
23 | var testFlows = require('./flows/discovery-flows')
24 |
25 | let testingOpcUaPort = 0
26 |
27 | describe('OPC UA Discovery node Unit Testing', function () {
28 |
29 | beforeAll(() => {
30 | testingOpcUaPort = 57350
31 | })
32 |
33 | beforeEach(function (done) {
34 | helper.startServer(function () {
35 | done()
36 | })
37 | })
38 |
39 | afterEach(function (done) {
40 | helper.unload().then(function () {
41 | helper.stopServer(function () {
42 | done()
43 | })
44 | }).catch(function () {
45 | helper.stopServer(function () {
46 | done()
47 | })
48 | })
49 | })
50 |
51 | describe('Discovery node', function () {
52 | it('should be loaded', function (done) {
53 | helper.load(
54 | [inputNode], testFlows.testUnitDiscoveryFlow,
55 | () => {
56 | let nodeUnderTest = helper.getNode('d9db5e281fac4a0c')
57 | expect(nodeUnderTest.type).toBe('OPCUA-IIoT-Discovery')
58 | expect(nodeUnderTest.name).toBe('TestName')
59 | setTimeout(done, 2000)
60 | })
61 | })
62 |
63 | it('should be loaded with default port', function (done) {
64 | helper.load(
65 | [inputNode], testFlows.testUnitDiscoveryNullPortFlow,
66 | function () {
67 | let nodeUnderTest = helper.getNode('n1dsf2')
68 | expect(nodeUnderTest.type).toBe('OPCUA-IIoT-Discovery')
69 | expect(nodeUnderTest.name).toBe('TestName')
70 | setTimeout(done, 2000)
71 | })
72 | })
73 |
74 | it('should be loaded with default port and send msg after inject', function (done) {
75 | helper.load(
76 | [injectNode, inputNode], testFlows.testUnitDiscoveryNullPortAndInjectFlow,
77 | function () {
78 | let nodeUnderTest = helper.getNode('n4edf1')
79 | nodeUnderTest.on('input', (msg) => {
80 | expect(msg.payload.discoveryUrls).toBeDefined()
81 | expect(msg.payload.endpoints).toBeDefined()
82 | setTimeout(done, 2000)
83 | })
84 | })
85 | })
86 | })
87 | })
88 |
--------------------------------------------------------------------------------
/test/units/opcua-iiot-event.test.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Original Work Copyright 2014 IBM Corp.
3 | * node-red
4 | *
5 | * Copyright (c) 2022 DATATRONiQ GmbH (https://datatroniq.com)
6 | * Copyright (c) 2018-2022 Klaus Landsdorf (http://node-red.plus/)
7 | * All rights reserved.
8 | * node-red-contrib-iiot-opcua
9 | *
10 | **/
11 |
12 | 'use strict'
13 |
14 | // jest.setTimeout(30000)
15 |
16 | var injectNode = require('@node-red/nodes/core/common/20-inject')
17 | var inputNode = require('../../src/opcua-iiot-event')
18 |
19 | var helper = require('node-red-node-test-helper')
20 | var portHelper = require('./../helper/test-helper-extensions')
21 | helper.init(require.resolve('node-red'))
22 |
23 | var testFlows = require('./flows/event-flows')
24 |
25 | let testingOpcUaPort = 0
26 |
27 | describe('OPC UA Event node Unit Testing', function () {
28 |
29 | beforeAll(() => {
30 | testingOpcUaPort = 57450
31 | })
32 |
33 | beforeEach(function (done) {
34 | helper.startServer(function () {
35 | done()
36 | })
37 | })
38 |
39 | afterEach(function (done) {
40 | helper.unload().then(function () {
41 | helper.stopServer(function () {
42 | done()
43 | })
44 | }).catch(function () {
45 | helper.stopServer(function () {
46 | done()
47 | })
48 | })
49 | })
50 |
51 | describe('Event node', function () {
52 | it('should load with basic settings', function (done) {
53 | helper.load(
54 | [injectNode, inputNode],
55 | testFlows.testUnitEventFlow,
56 | function () {
57 | let nodeUnderTest = helper.getNode('n3evf1')
58 | expect(nodeUnderTest.name).toBe('TestName')
59 | expect(nodeUnderTest.eventTypeLabel).toBe('BaseTypeEvent')
60 | expect(nodeUnderTest.eventType).toBe('i=2041')
61 | expect(nodeUnderTest.usingListener).toBe(true)
62 | expect(nodeUnderTest.queueSize).toBe(10)
63 | done()
64 | })
65 | })
66 |
67 | it('should get a message with payload', function (done) {
68 | helper.load([injectNode, inputNode], testFlows.testUnitEventFlow, function () {
69 | let n2 = helper.getNode('n2evf1')
70 | n2.on('input', function (msg) {
71 | expect(msg.payload).toBeDefined()
72 | done()
73 | })
74 | })
75 | })
76 |
77 | it('should verify a message for event parameters', function (done) {
78 | helper.load([injectNode, inputNode], testFlows.testUnitEventFlow, function () {
79 | let n4 = helper.getNode('n4evf1')
80 | n4.on('input', function (msg) {
81 | expect(msg.payload.eventType).toBeDefined()
82 | expect(msg.payload.uaEventFilter).toBeDefined()
83 | expect(msg.payload.uaEventFields).toBeDefined()
84 | expect(msg.payload.queueSize).toBe(10)
85 | expect(msg.payload.interval).toBe(1000)
86 | /* payload: { eventType: 'i=2041',
87 | eventFilter: EventFilter { selectClauses: [Array], whereClause: [ContentFilter] }, eventFields: [ 'EventId', 'SourceName', 'Message', 'ReceiveTime' ],
88 | queueSize: 10,
89 | interval: 1000 }) */
90 | done()
91 | })
92 | })
93 | })
94 | })
95 | })
96 |
--------------------------------------------------------------------------------
/test/units/opcua-iiot-flex-connector.test.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Original Work Copyright 2014 IBM Corp.
3 | * node-red
4 | *
5 | * Copyright (c) 2022 DATATRONiQ GmbH (https://datatroniq.com)
6 | * Copyright (c) 2018-2022 Klaus Landsdorf (http://node-red.plus/)
7 | * All rights reserved.
8 | * node-red-contrib-iiot-opcua
9 | *
10 | **/
11 |
12 | 'use strict'
13 |
14 | // jest.setTimeout(30000)
15 |
16 | var inputNode = require('../../src/opcua-iiot-flex-connector')
17 |
18 | var helper = require('node-red-node-test-helper')
19 | var portHelper = require('./../helper/test-helper-extensions')
20 | helper.init(require.resolve('node-red'))
21 |
22 | var testFlows = require('./flows/flex-connector-flows')
23 |
24 | let testingOpcUaPort = 0
25 |
26 | describe('OPC UA Flex Connector node Unit Testing', function () {
27 |
28 | beforeAll(() => {
29 | testingOpcUaPort = 57550
30 | })
31 |
32 | beforeEach(function (done) {
33 | helper.startServer(function () {
34 | done()
35 | })
36 | })
37 |
38 | afterEach(function (done) {
39 | helper.unload().then(function () {
40 | helper.stopServer(function () {
41 | done()
42 | })
43 | }).catch(function () {
44 | helper.stopServer(function () {
45 | done()
46 | })
47 | })
48 | })
49 |
50 | describe('Flex Connector node', function () {
51 | it('should be loaded without connector', function (done) {
52 | helper.load([inputNode], testFlows.testUnitFlexConnectorFlow,
53 | function () {
54 | let nodeUnderTest = helper.getNode('14d54403.f94f04')
55 | expect(nodeUnderTest).toBeDefined()
56 | expect(nodeUnderTest.name).toBe('TestFlexConnector')
57 | done()
58 | })
59 | })
60 |
61 | it('should be loaded without connector and showing activities', function (done) {
62 | helper.load([inputNode], testFlows.testUnitFlexConnectorShowActivitiesFlow,
63 | function () {
64 | let nodeUnderTest = helper.getNode('14d54403.f94f05')
65 | expect(nodeUnderTest).toBeDefined()
66 | expect(nodeUnderTest.name).toBe('TestFlexConnector2')
67 | done()
68 | })
69 | })
70 | })
71 | })
72 |
--------------------------------------------------------------------------------
/test/units/opcua-iiot-flex-server.test.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Original Work Copyright 2014 IBM Corp.
3 | * node-red
4 | *
5 | * Copyright (c) 2022 DATATRONiQ GmbH (https://datatroniq.com)
6 | * Copyright (c) 2018-2022 Klaus Landsdorf (http://node-red.plus/)
7 | * All rights reserved.
8 | * node-red-contrib-iiot-opcua
9 | *
10 | **/
11 |
12 | 'use strict'
13 |
14 | // jest.setTimeout(30000)
15 |
16 | var injectNode = require('@node-red/nodes/core/common/20-inject')
17 | var functionNode = require('@node-red/nodes/core/function/10-function')
18 | var flexServerNode = require('../../src/opcua-iiot-flex-server')
19 |
20 | var flexServerFlowNodes = [injectNode, functionNode, flexServerNode]
21 |
22 | var helper = require('node-red-node-test-helper')
23 | var portHelper = require('./../helper/test-helper-extensions')
24 | helper.init(require.resolve('node-red'))
25 |
26 | var testFlows = require('./flows/flex-server-flows')
27 |
28 | let testingOpcUaPort = 0
29 |
30 | describe('OPC UA Flex Server node Unit Testing', function () {
31 |
32 | beforeAll(() => {
33 | testingOpcUaPort = 57650
34 | })
35 |
36 | beforeEach(function (done) {
37 | helper.startServer(function () {
38 | done()
39 | })
40 | })
41 |
42 | afterEach(function (done) {
43 | helper.unload().then(function () {
44 | helper.stopServer(function () {
45 | done()
46 | })
47 | }).catch(function () {
48 | helper.stopServer(function () {
49 | done()
50 | })
51 | })
52 | })
53 |
54 | describe('Flex Server node', function () {
55 | it('should be loaded', function (done) {
56 | helper.load(flexServerFlowNodes, testFlows.testUnitFlexServerFlow,
57 | () => {
58 | let nodeUnderTest = helper.getNode('85d5edb0.385143')
59 | // expect(nodeUnderTest).toBeDefined()
60 | nodeUnderTest.on('server_running', () => {
61 | expect(nodeUnderTest.name).toBe('DEMOSERVER')
62 | expect(nodeUnderTest.maxAllowedSessionNumber).toBe(10)
63 | expect(nodeUnderTest.maxNodesPerRead).toBe(1000)
64 | expect(nodeUnderTest.maxNodesPerBrowse).toBe(2000)
65 | setTimeout(done, 4000)
66 | })
67 | }
68 | )
69 | })
70 |
71 | it('should be loaded with user and ISA95 NodeSet XML', function (done) {
72 | helper.load(flexServerFlowNodes, testFlows.testUnitFlexServerWithUserAndISA95Flow,
73 | () => {
74 | let nodeUnderTest = helper.getNode('16093040.5dab23')
75 | expect(nodeUnderTest).toBeDefined()
76 | nodeUnderTest.on('server_running', () => {
77 | expect(nodeUnderTest.name).toBe('DEMOSERVERWITHUSERANDISA95')
78 | expect(nodeUnderTest.maxAllowedSessionNumber).toBe(10)
79 | expect(nodeUnderTest.maxNodesPerRead).toBe(1000)
80 | expect(nodeUnderTest.maxNodesPerBrowse).toBe(2000)
81 | setTimeout(done, 4000)
82 | })
83 | }
84 | )
85 | })
86 | })
87 | })
88 |
--------------------------------------------------------------------------------
/test/units/opcua-iiot-server-aso.test.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Original Work Copyright 2014 IBM Corp.
3 | * node-red
4 | *
5 | * Copyright (c) 2022 DATATRONiQ GmbH (https://datatroniq.com)
6 | * Copyright (c) 2018-2022 Klaus Landsdorf (http://node-red.plus/)
7 | * All rights reserved.
8 | * node-red-contrib-iiot-opcua
9 | *
10 | **/
11 |
12 | 'use strict'
13 |
14 | // jest.setTimeout(30000)
15 |
16 | var injectNode = require('@node-red/nodes/core/common/20-inject')
17 | var functionNode = require('@node-red/nodes/core/function/10-function')
18 | var serverAsoNode = require('../../src/opcua-iiot-server-aso')
19 |
20 | var serverAsoFlowNodes = [injectNode, functionNode, serverAsoNode]
21 |
22 | var testFlows = require('./flows/server-aso-flows')
23 |
24 | var helper = require('node-red-node-test-helper')
25 | var portHelper = require('./../helper/test-helper-extensions')
26 | helper.init(require.resolve('node-red'))
27 |
28 | let testingOpcUaPort = 0
29 |
30 | describe('OPC UA Server ASO node Unit Testing', function () {
31 |
32 | beforeAll(() => {
33 | testingOpcUaPort = 58350
34 | })
35 |
36 | beforeEach(function (done) {
37 | helper.startServer(function () {
38 | done()
39 | })
40 | })
41 |
42 | afterEach(function (done) {
43 | helper.unload().then(function () {
44 | helper.stopServer(function () {
45 | done()
46 | })
47 | }).catch(function () {
48 | helper.stopServer(function () {
49 | done()
50 | })
51 | })
52 | })
53 |
54 | describe('Address Space Operation node Unit Testing', function () {
55 | it('should be loaded', function (done) {
56 | helper.load(serverAsoFlowNodes, testFlows.testUnitServerASOFlow,
57 | function () {
58 | let nodeUnderTest = helper.getNode('7cb85115.7635')
59 | expect(nodeUnderTest.name).toBe('Folder')
60 | expect(nodeUnderTest.nodeId.toString()).toBe('ns=1;s=TestVariables')
61 | expect(nodeUnderTest.datatype).toBe('Double')
62 | expect(nodeUnderTest.value).toBe('1.0')
63 | expect(nodeUnderTest.browsename).toBe('TestVariables')
64 | expect(nodeUnderTest.displayname).toBe('Test Variables')
65 | done()
66 | })
67 | })
68 | })
69 | })
70 |
--------------------------------------------------------------------------------
/test/units/opcua-iiot-server-cmd.test.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Original Work Copyright 2014 IBM Corp.
3 | * node-red
4 | *
5 | * Copyright (c) 2022 DATATRONiQ GmbH (https://datatroniq.com)
6 | * Copyright (c) 2018-2022 Klaus Landsdorf (http://node-red.plus/)
7 | * All rights reserved.
8 | * node-red-contrib-iiot-opcua
9 | *
10 | **/
11 |
12 | 'use strict'
13 |
14 | // jest.setTimeout(30000)
15 |
16 | var injectNode = require('@node-red/nodes/core/common/20-inject')
17 | var functionNode = require('@node-red/nodes/core/function/10-function')
18 | var serverCmdNode = require('../../src/opcua-iiot-server-cmd')
19 |
20 | var serverCmdNodes = [injectNode, functionNode, serverCmdNode]
21 |
22 | var helper = require('node-red-node-test-helper')
23 | var portHelper = require('./../helper/test-helper-extensions')
24 | helper.init(require.resolve('node-red'))
25 |
26 | var testFlows = require('./flows/server-cmd-flows')
27 |
28 | let testingOpcUaPort = 0
29 |
30 | describe('OPC UA Server Command node Unit Testing', function () {
31 |
32 | beforeAll(() => {
33 | testingOpcUaPort = 58350
34 | })
35 |
36 | beforeEach(function (done) {
37 | helper.startServer(function () {
38 | done()
39 | })
40 | })
41 |
42 | afterEach(function (done) {
43 | helper.unload().then(function () {
44 | helper.stopServer(function () {
45 | done()
46 | })
47 | }).catch(function () {
48 | helper.stopServer(function () {
49 | done()
50 | })
51 | })
52 | })
53 |
54 | describe('Command node', function () {
55 | it('should be loaded', function (done) {
56 | helper.load(serverCmdNodes, testFlows.testUnitServerCommandFlow,
57 | function () {
58 | let nodeUnderTest = helper.getNode('n3cmdf1')
59 | expect(nodeUnderTest.name).toBe('TestName')
60 | expect(nodeUnderTest.commandtype).toBe('restart')
61 | expect(nodeUnderTest.nodeId).toBe('')
62 | done()
63 | })
64 | })
65 | })
66 | })
67 |
--------------------------------------------------------------------------------
/test/units/opcua-iiot-server.test.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Original Work Copyright 2014 IBM Corp.
3 | * node-red
4 | *
5 | * Copyright (c) 2022 DATATRONiQ GmbH (https://datatroniq.com)
6 | * Copyright (c) 2018-2022 Klaus Landsdorf (http://node-red.plus/)
7 | * All rights reserved.
8 | * node-red-contrib-iiot-opcua
9 | *
10 | **/
11 |
12 | 'use strict'
13 |
14 | // jest.setTimeout(30000)
15 |
16 | var serverNode = require('../../src/opcua-iiot-server')
17 |
18 | var helper = require('node-red-node-test-helper')
19 | var portHelper = require('./../helper/test-helper-extensions')
20 | helper.init(require.resolve('node-red'))
21 |
22 | var testFlows = require('./flows/server-flows')
23 |
24 | let testingOpcUaPort = 0
25 |
26 | describe('OPC UA Server node Unit Testing', function () {
27 |
28 | beforeAll(() => {
29 | testingOpcUaPort = 58250
30 | })
31 |
32 | beforeEach(function (done) {
33 | helper.startServer(function () {
34 | done()
35 | })
36 | })
37 |
38 | afterEach(function (done) {
39 | helper.unload().then(function () {
40 | helper.stopServer(function () {
41 | done()
42 | })
43 | }).catch(function () {
44 | helper.stopServer(function () {
45 | done()
46 | })
47 | })
48 | })
49 |
50 | describe('Server node', function () {
51 | it('should be loaded with demo address-space', function (done) {
52 | const flow = Array.from(testFlows.testUnitServerWithDemoFlow)
53 | testingOpcUaPort = portHelper.getPort(testingOpcUaPort)
54 | const port = testingOpcUaPort
55 | flow[1].port = port
56 | helper.load(serverNode, flow,
57 | function () {
58 | let nodeUnderTest = helper.getNode('6ec4ef50.86dc1')
59 | // expect(nodeUnderTest).toBeDefined()
60 | nodeUnderTest.on('server_running', () => {
61 | expect(nodeUnderTest.name).toBe('DEMOSERVER')
62 | expect(nodeUnderTest.maxAllowedSessionNumber).toBe(10)
63 | expect(nodeUnderTest.maxNodesPerRead).toBe(1000)
64 | expect(nodeUnderTest.maxNodesPerBrowse).toBe(2000)
65 | setTimeout(done, 3000)
66 | })
67 | // done()
68 | })
69 | })
70 |
71 | it('should be loaded with discovery and without demo address-space', function (done) {
72 | const flow = Array.from(testFlows.testUnitServerWithoutDemoFlow)
73 | testingOpcUaPort = portHelper.getPort(testingOpcUaPort)
74 | const port = testingOpcUaPort
75 | flow[1].port = port
76 | helper.load(serverNode, flow,
77 | function () {
78 | let nodeUnderTest = helper.getNode('6ec4ef50.86dc2')
79 | expect(nodeUnderTest).toBeDefined()
80 | nodeUnderTest.on('server_running', () => {
81 | expect(nodeUnderTest.name).toBe('DEMOSERVER')
82 | expect(nodeUnderTest.maxAllowedSessionNumber).toBe(10)
83 | expect(nodeUnderTest.maxNodesPerRead).toBe(1000)
84 | expect(nodeUnderTest.maxNodesPerBrowse).toBe(2000)
85 | setTimeout(done, 3000)
86 | })
87 | done()
88 | })
89 | })
90 | })
91 | })
92 |
--------------------------------------------------------------------------------
/test/units/opcua-iiot-write.test.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Original Work Copyright 2014 IBM Corp.
3 | * node-red
4 | *
5 | * Copyright (c) 2022 DATATRONiQ GmbH (https://datatroniq.com)
6 | * Copyright (c) 2018-2022 Klaus Landsdorf (http://node-red.plus/)
7 | * All rights reserved.
8 | * node-red-contrib-iiot-opcua
9 | *
10 | **/
11 |
12 | 'use strict'
13 |
14 | process.env.TEST = 'true'
15 |
16 | // jest.setTimeout(30000)
17 |
18 | var injectNodeRedNode = require('@node-red/nodes/core/common/20-inject')
19 | var functionNodeRedNode = require('@node-red/nodes/core/function/10-function')
20 |
21 | // iiot opcua
22 | var inputNode = require('../../src/opcua-iiot-write')
23 |
24 | var helper = require('node-red-node-test-helper')
25 | var portHelper = require('./../helper/test-helper-extensions')
26 | helper.init(require.resolve('node-red'))
27 |
28 | var writeNodesToLoad = [injectNodeRedNode, functionNodeRedNode, inputNode]
29 |
30 | var testFlows = require('./flows/write-flows')
31 |
32 | let testingOpcUaPort = 0
33 |
34 | describe('OPC UA Write node Unit Testing', function () {
35 |
36 | beforeAll(() => {
37 | testingOpcUaPort = 58350
38 | })
39 |
40 | beforeEach(function (done) {
41 | helper.startServer(function () {
42 | done()
43 | })
44 | })
45 |
46 | afterEach(function (done) {
47 | helper.unload().then(function () {
48 | helper.stopServer(function () {
49 | done()
50 | })
51 | }).catch(function () {
52 | helper.stopServer(function () {
53 | done()
54 | })
55 | })
56 | })
57 |
58 | describe('Write node', function () {
59 | it('should be loaded', function (done) {
60 | helper.load(writeNodesToLoad, testFlows.testUnitWriteFlow,
61 | function () {
62 | let nodeUnderTest = helper.getNode('34d2c6bc.43275b')
63 | expect(nodeUnderTest.name).toBe('TestWrite')
64 | expect(nodeUnderTest.showErrors).toBe(true)
65 | expect(nodeUnderTest.justValue).toBe(false)
66 | done()
67 | })
68 | })
69 |
70 | it('should be loaded and handle error', function (done) {
71 | helper.load(writeNodesToLoad, testFlows.testUnitWriteFlow, () => {
72 | let n1 = helper.getNode('34d2c6bc.43275b')
73 | if (n1) {
74 | n1.functions.handleWriteError(new Error('Testing Error To Handle'), { payload: {} })
75 | done()
76 | }
77 | })
78 | })
79 | })
80 | })
81 |
--------------------------------------------------------------------------------