@things-factory/integration-modbus 8.0.0 → 9.0.0-beta.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@things-factory/integration-modbus",
3
- "version": "8.0.0",
3
+ "version": "9.0.0-beta.3",
4
4
  "main": "dist-server/index.js",
5
5
  "browser": "client/index.js",
6
6
  "things-factory": true,
@@ -23,11 +23,11 @@
23
23
  "clean": "npm run clean:server"
24
24
  },
25
25
  "dependencies": {
26
- "@things-factory/integration-base": "^8.0.0",
26
+ "@things-factory/integration-base": "^9.0.0-beta.3",
27
27
  "jsmodbus": "^4.0.2",
28
28
  "p-queue": "^6.4.0",
29
29
  "promise-socket": "^7.0.0",
30
30
  "serialport": "^9.0.2"
31
31
  },
32
- "gitHead": "07ef27d272dd9a067a9648ac7013748510556a18"
32
+ "gitHead": "1d7e0dd4c88f3c3f3bd311c00e4b1d1542d53634"
33
33
  }
@@ -1,2 +0,0 @@
1
- import './modbus-tcp-server'
2
- import './modbus-tcp'
@@ -1,50 +0,0 @@
1
- import { ConnectionManager, Connector, Connection } from '@things-factory/integration-base'
2
- import net from 'net'
3
- import * as modbus from 'jsmodbus'
4
-
5
- export class ModbusTCPServer implements Connector {
6
- async ready(connectionConfigs) {
7
- await Promise.all(connectionConfigs.map(this.connect))
8
-
9
- ConnectionManager.logger.info('modbus-tcp-servers are ready')
10
- }
11
-
12
- async connect(config) {
13
- var [host = '0.0.0.0', port = 502] = config.endpoint.split(':')
14
-
15
- const netServer = new net.Server()
16
-
17
- const server = new modbus.server.TCP(netServer)
18
-
19
- netServer.on('error', console.error)
20
- netServer.listen(port, host)
21
-
22
- /* default client connection */
23
- const clientSocket = new net.Socket()
24
- const client = new modbus.client.TCP(clientSocket)
25
- clientSocket.on('error', console.error)
26
- clientSocket.connect({ host: 'localhost', port })
27
-
28
- client['__server__'] = server
29
-
30
- ConnectionManager.addConnectionInstance(config, client)
31
-
32
- ConnectionManager.logger.info(`modbus-tcp-server connection(${config.name}:${config.endpoint}) is connected`)
33
- }
34
-
35
- async disconnect(connection: Connection) {
36
- var client = ConnectionManager.removeConnectionInstance(connection)
37
- var server = client['__server__']
38
-
39
- client.socket.end()
40
- server && server._server.close()
41
-
42
- ConnectionManager.logger.info(`modbus-tcp-server connection(${connection.name}) is disconnected`)
43
- }
44
-
45
- get parameterSpec() {
46
- return []
47
- }
48
- }
49
-
50
- ConnectionManager.registerConnector('modbus-tcp-server', new ModbusTCPServer())
@@ -1,173 +0,0 @@
1
- import * as modbus from 'jsmodbus'
2
- import { Socket } from 'net'
3
- import PQueue from 'p-queue'
4
- import PromiseSocket from 'promise-socket'
5
-
6
- import { Connection, ConnectionManager, Connector } from '@things-factory/integration-base'
7
- import { sleep } from '@things-factory/utils'
8
-
9
- const debug = require('debug')('things-factory:modbus-tcp-connector')
10
-
11
- export class ModbusTCPConnector implements Connector {
12
- async ready(connectionConfigs) {
13
- await Promise.all(connectionConfigs.map(this.connect.bind(this)))
14
-
15
- ConnectionManager.logger.info('modbus-tcp connections are ready')
16
- }
17
-
18
- checkConnectionInstance(domain, connectionName): boolean {
19
- try {
20
- const connection = ConnectionManager.getConnectionInstanceByName(domain, connectionName)
21
-
22
- return !!(connection?.client?.connectionState !== 'online')
23
- } catch (e) {
24
- return false
25
- }
26
- }
27
-
28
- async connect(connection) {
29
- var [host, port = 502] = connection.endpoint.split(':')
30
- var {
31
- params: { keepalive = true }
32
- } = connection
33
-
34
- try {
35
- /*
36
- try to keep connecting if keepalive is true
37
- */
38
- var clientIdx = 1
39
- var connected: boolean = false
40
- var looped: boolean = true
41
- while (true) {
42
- var clientSocket = new Socket()
43
- clientSocket = new Socket()
44
- var promiseSocket = new PromiseSocket(clientSocket)
45
-
46
- var client = new modbus.client.TCP(clientSocket, clientIdx++, 10000)
47
-
48
- clientSocket.on('error', async ex => {
49
- debug(ex)
50
- ConnectionManager.logger.error(`modbus tcp connection error: ${ex}`)
51
- })
52
-
53
- clientSocket.on('close', async () => {
54
- debug(`modbus tcp connection closed`)
55
- if (keepalive && !looped) {
56
- await this.disconnect(connection)
57
- await this.connect(connection)
58
- }
59
- })
60
-
61
- debug(`connecting to ${connection.endpoint}...`)
62
-
63
- looped = true
64
- await promiseSocket
65
- .connect(port, host)
66
- .then(() => {
67
- connected = true
68
- })
69
- .catch(ex => {
70
- promiseSocket && promiseSocket.destroy()
71
- })
72
-
73
- // if the current connections have the connection with the same name, the current try should be stopped.
74
- if (!keepalive || connected) {
75
- looped = false
76
- break
77
- }
78
-
79
- await sleep(1000)
80
- }
81
-
82
- var queue = new PQueue({ concurrency: 1 })
83
- ConnectionManager.addConnectionInstance(connection, {
84
- readModBus: async function (objectType, address, quantity, { logger }) {
85
- return await queue.add(async () => {
86
- var response
87
-
88
- switch (objectType) {
89
- case 'descrete input':
90
- response = await client.readDiscreteInputs(address, quantity)
91
- break
92
- case 'input register':
93
- response = await client.readInputRegisters(address, quantity)
94
- break
95
- case 'holding register':
96
- response = await client.readHoldingRegisters(address, quantity)
97
- break
98
- default:
99
- response = await client.readCoils(address, quantity)
100
- }
101
-
102
- var data = response && response.response._body.valuesAsArray.slice(0, quantity)
103
- logger.info(`${JSON.stringify(data)}`)
104
- return {
105
- data
106
- }
107
- })
108
- },
109
- writeSingleModBus: async function (objectType, address, value, { logger }) {
110
- return await queue.add(async () => {
111
- var response
112
-
113
- switch (objectType) {
114
- case 'holding register':
115
- await client.writeSingleRegister(address, parseInt(value))
116
- response = await client.readHoldingRegisters(address, 1)
117
- break
118
- default:
119
- await client.writeSingleCoil(address, !!Number(value))
120
- response = await client.readCoils(address, 1)
121
- }
122
-
123
- var data = response && response.response._body.valuesAsArray[0]
124
- logger.info(data)
125
- return {
126
- data
127
- }
128
- })
129
- },
130
- close: function () {
131
- queue.clear()
132
- keepalive = false
133
- promiseSocket.destroy()
134
- }
135
- })
136
-
137
- ConnectionManager.logger.info(`modbus-tcp connection(${connection.name}:${connection.endpoint}) is connected`)
138
- } catch (ex) {
139
- ConnectionManager.logger.info(`modbus-tcp connection(${connection.name}:${connection.endpoint}) failed to connect`)
140
- throw ex
141
- }
142
- }
143
-
144
- async disconnect(connection: Connection) {
145
- var { close } = ConnectionManager.removeConnectionInstance(connection)
146
- close()
147
-
148
- ConnectionManager.logger.info(`modbus-tcp connection(${connection.name}) is disconnected`)
149
- }
150
-
151
- get parameterSpec() {
152
- return [
153
- {
154
- type: 'checkbox',
155
- name: 'keepalive',
156
- label: 'keepalive',
157
- property: {
158
- value: 'checked'
159
- }
160
- }
161
- ]
162
- }
163
-
164
- get taskPrefixes() {
165
- return ['modbus']
166
- }
167
-
168
- get help() {
169
- return 'integration/connector/modbus-tcp'
170
- }
171
- }
172
-
173
- ConnectionManager.registerConnector('modbus-tcp', new ModbusTCPConnector())
@@ -1,2 +0,0 @@
1
- import './connector'
2
- import './task'
@@ -1,2 +0,0 @@
1
- import './modbus-read'
2
- import './modbus-write-single'
@@ -1,58 +0,0 @@
1
- import { access } from '@things-factory/utils'
2
- import { ConnectionManager, TaskRegistry } from '@things-factory/integration-base'
3
-
4
- const debug = require('debug')('things-factory:modbus-read')
5
-
6
- async function modbusRead(step, { logger, domain, data }) {
7
- var {
8
- connection,
9
- params: { objectType = 'coil', address, quantity = 1, accessorAddress }
10
- } = step
11
-
12
- var connectionInstance = ConnectionManager.getConnectionInstanceByName(domain, connection)
13
- if (!connectionInstance) {
14
- debug(`no connection : ${connection}`)
15
- throw new Error(`no connection : ${connection}`)
16
- }
17
-
18
- address = accessorAddress ? access(accessorAddress, data) : address
19
- if (isNaN(address)) {
20
- debug(`invalid number address : ${address}`)
21
- throw new Error(`invalid number address : ${address}`)
22
- }
23
-
24
- var { readModBus } = connectionInstance
25
- var content = await readModBus(objectType, address, quantity, { logger })
26
- debug(`result : ${JSON.stringify(content)}`)
27
- return content
28
- }
29
-
30
- modbusRead.parameterSpec = [
31
- {
32
- type: 'select',
33
- name: 'objectType',
34
- label: 'object-type',
35
- property: {
36
- options: ['', 'coil', 'descrete input', 'input register', 'holding register']
37
- }
38
- },
39
- {
40
- type: 'number',
41
- name: 'address',
42
- label: 'address'
43
- },
44
- {
45
- type: 'number',
46
- name: 'quantity',
47
- label: 'quantity'
48
- },
49
- {
50
- type: 'scenario-step-input',
51
- name: 'accessorAddress',
52
- label: 'accessor-address'
53
- }
54
- ]
55
-
56
- modbusRead.help = 'integration/task/modbus-read'
57
-
58
- TaskRegistry.registerTaskHandler('modbus-read', modbusRead)
@@ -1,68 +0,0 @@
1
- import { access } from '@things-factory/utils'
2
- import { ConnectionManager, TaskRegistry } from '@things-factory/integration-base'
3
-
4
- const debug = require('debug')('things-factory:modbus-write-single')
5
-
6
- async function modbusWriteSingle(step, { logger, domain, data }) {
7
- var {
8
- connection,
9
- params: { objectType = 'coil', accessorAddress, address, accessor, value }
10
- } = step
11
-
12
- var connectionInstance = ConnectionManager.getConnectionInstanceByName(domain, connection)
13
- if (!connectionInstance) {
14
- debug(`no connection : ${connection}`)
15
- throw new Error(`no connection : ${connection}`)
16
- }
17
-
18
- address = accessorAddress ? access(accessorAddress, data) : address
19
- if (isNaN(address)) {
20
- debug(`invalid number address : ${address}`)
21
- throw new Error(`invalid number address : ${address}`)
22
- }
23
-
24
- // determine accessor or value as a input value value
25
- value = accessor ? access(accessor, data) : value
26
- if (isNaN(value)) {
27
- throw new Error(`invalid number value : ${value}`)
28
- }
29
-
30
- var { writeSingleModBus } = connectionInstance
31
- var content = await writeSingleModBus(objectType, address, value, { logger })
32
- return content
33
- }
34
-
35
- modbusWriteSingle.parameterSpec = [
36
- {
37
- type: 'select',
38
- name: 'objectType',
39
- label: 'object-type',
40
- property: {
41
- options: ['', 'coil', 'holding register']
42
- }
43
- },
44
- {
45
- type: 'number',
46
- name: 'address',
47
- label: 'address'
48
- },
49
- {
50
- type: 'number',
51
- name: 'value',
52
- label: 'value'
53
- },
54
- {
55
- type: 'scenario-step-input',
56
- name: 'accessor',
57
- label: 'accessor-value'
58
- },
59
- {
60
- type: 'scenario-step-input',
61
- name: 'accessorAddress',
62
- label: 'accessor-address'
63
- }
64
- ]
65
-
66
- modbusWriteSingle.help = 'integration/task/modbus-write-single'
67
-
68
- TaskRegistry.registerTaskHandler('modbus-write-single', modbusWriteSingle)
package/server/index.ts DELETED
@@ -1 +0,0 @@
1
- import './engine'