Skip to content

Commit 3b43a96

Browse files
committed
Documentation updates
Modbus adapter configuration check File Adapter template support OPCUA target monitor output fix
1 parent 1d2c8ba commit 3b43a96

File tree

77 files changed

+538
-291
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

77 files changed

+538
-291
lines changed

Diff for: README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ At first, we have to download and extract the SFC bundles. These are precompiled
9191

9292
```shell
9393
# Define sfc version and directory
94-
export VERSION=$(git describe --tags --abbrev=0)
94+
export VERSION=$(curl -s "https://api.github.com/repos/aws-samples/shopfloor-connectivity/tags" | jq -r '.[0].name')
9595
export SFC_DEPLOYMENT_DIR="./sfc"
9696
```
9797

Diff for: RELEASE NOTES.md

+9
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,13 @@
11
# Release Notes:
2+
## Version 1.8.5, 4 march February 2025
3+
4+
- Documentation updates
5+
- OPCUA Target monitor output fix
6+
- Support for [templates](./docs/core/target-configuration.md#template) in File Target adapter
7+
- Modbus TCP configuration validation update
8+
- OPCUA Target handling of unsigned datatypes
9+
- Fix in quickstart documentation
10+
211
## Version 1.8.4, 26 February 2025
312

413
- New [OPCUA Writer](./docs/targets/opcua-writer.md) Target

Diff for: adapters/modbus/src/main/kotlin/com/amazonaws/sfc/modbus/adapter/ModbusDevice.kt

-10
Original file line numberDiff line numberDiff line change
@@ -63,15 +63,8 @@ class ModbusDevice(
6363

6464
val reader = launch("Reader") {
6565

66-
val logTrace = logger.get()?.getCtxTraceLog(ModbusDevice::class.java.simpleName, "reader")
67-
6866
try {
6967

70-
// get exclusive access to the device
71-
logTrace?.invoke("Acquiring lock on device \"${configuration.sourceAdapterDevice}\" on adapter \"${configuration.protocolAdapterID}\" to read data for source \"$sourceID\"")
72-
modbus.modbusDevice.lock()
73-
logTrace?.invoke("Acquired lock on device \"${configuration.sourceAdapterDevice}\" on adapter \"${configuration.protocolAdapterID}\" for source \"${configuration.name}\"")
74-
7568
// number of requests that can be sent to a without a response received for it, guarded by this semaphore
7669
val requestSlots = Semaphore(permits = adapter.get()?.requestDepth(configuration)?.toInt() ?: 1)
7770

@@ -127,9 +120,6 @@ class ModbusDevice(
127120
} catch (e: Exception) {
128121
readResult = SourceReadError(e.toString())
129122

130-
} finally {
131-
modbus.modbusDevice.unlock()
132-
logTrace?.invoke("Released lock on device\"${configuration.sourceAdapterDevice}\" on adapter \"${configuration.protocolAdapterID}\"")
133123
}
134124
}
135125

Diff for: core/sfc-core/src/main/kotlin/com/amazonaws/sfc/awsiot/AwsIotCredentialProviderClientConfiguration.kt

-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import com.amazonaws.sfc.config.BaseConfiguration.Companion.CONFIG_PRIVATE_KEY
1212
import com.amazonaws.sfc.data.JsonHelper
1313
import com.amazonaws.sfc.log.Logger.Companion.HIDDEN_VALUE
1414
import com.google.gson.annotations.SerializedName
15-
import kotlin.Throws
1615

1716
@ConfigurationClass
1817
class AwsIotCredentialProviderClientConfiguration : ClientConfiguration(), Validate {

Diff for: core/sfc-core/src/main/kotlin/com/amazonaws/sfc/config/BaseSourceConfiguration.kt

-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ package com.amazonaws.sfc.config
99
import com.amazonaws.sfc.config.BaseConfiguration.Companion.CONFIG_DESCRIPTION
1010
import com.amazonaws.sfc.config.BaseConfiguration.Companion.CONFIG_NAME
1111
import com.google.gson.annotations.SerializedName
12-
import kotlin.Throws
1312

1413
/**
1514
* Base class with minimum set of attributes for an SFC input sourceService

Diff for: core/sfc-core/src/main/kotlin/com/amazonaws/sfc/config/ChannelConfiguration.kt

-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import com.amazonaws.sfc.config.BaseConfiguration.Companion.CONFIG_NAME
1212
import com.amazonaws.sfc.config.BaseConfiguration.Companion.CONFIG_SPREAD_CHANNEL_VALUE
1313
import com.amazonaws.sfc.config.BaseConfiguration.Companion.CONFIG_VALUE_FILTER
1414
import com.google.gson.annotations.SerializedName
15-
import kotlin.Throws
1615

1716
/**
1817
* Base class with minimum set of attributes for a channel of a source.

Diff for: core/sfc-core/src/main/kotlin/com/amazonaws/sfc/config/ClientConfiguration.kt

-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import com.amazonaws.sfc.config.BaseConfiguration.Companion.CONFIG_CERTIFICATE
1111
import com.amazonaws.sfc.config.BaseConfiguration.Companion.CONFIG_PRIVATE_KEY
1212
import com.google.gson.annotations.SerializedName
1313
import java.io.File
14-
import kotlin.Throws
1514

1615
@ConfigurationClass
1716
open class ClientConfiguration : Validate {

Diff for: core/sfc-core/src/main/kotlin/com/amazonaws/sfc/config/ConfigurationException.kt

-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ package com.amazonaws.sfc.config
77

88
import com.amazonaws.sfc.data.JsonHelper
99
import com.amazonaws.sfc.data.JsonHelper.Companion.gsonExtended
10-
import kotlin.Throws
1110

1211
interface Validate {
1312
@Throws(ConfigurationException::class)

Diff for: core/sfc-core/src/main/kotlin/com/amazonaws/sfc/config/HealthProbeConfiguration.kt

-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ package com.amazonaws.sfc.config
77

88
import com.amazonaws.sfc.config.BaseConfiguration.Companion.CONFIG_ACTIVE
99
import com.google.gson.annotations.SerializedName
10-
import kotlin.Throws
1110
import kotlin.time.Duration
1211
import kotlin.time.DurationUnit
1312
import kotlin.time.toDuration

Diff for: core/sfc-core/src/main/kotlin/com/amazonaws/sfc/config/ScheduleConfiguration.kt

-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ import com.amazonaws.sfc.config.BaseConfiguration.Companion.CONFIG_META_DATA
1313
import com.amazonaws.sfc.config.BaseConfiguration.Companion.CONFIG_NAME
1414
import com.amazonaws.sfc.config.BaseConfiguration.Companion.CONFIG_TARGETS
1515
import com.google.gson.annotations.SerializedName
16-
import kotlin.Throws
1716
import kotlin.time.Duration
1817
import kotlin.time.DurationUnit
1918
import kotlin.time.toDuration

Diff for: core/sfc-core/src/main/kotlin/com/amazonaws/sfc/config/ServerConfiguration.kt

-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import com.amazonaws.sfc.crypto.CertificateConfiguration.Companion.CONFIG_CERT_E
1010
import com.amazonaws.sfc.service.ServerConnectionType
1111
import com.google.gson.annotations.SerializedName
1212
import java.io.File
13-
import kotlin.Throws
1413
import kotlin.time.Duration
1514
import kotlin.time.DurationUnit
1615
import kotlin.time.toDuration

Diff for: core/sfc-core/src/main/kotlin/com/amazonaws/sfc/config/ServiceConfiguration.kt

-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import com.amazonaws.sfc.config.ServerConfiguration.Companion.CONFIG_SERVER_ADDR
1010
import com.amazonaws.sfc.log.LogLevel
1111
import com.amazonaws.sfc.metrics.MetricsConfiguration
1212
import com.google.gson.annotations.SerializedName
13-
import kotlin.Throws
1413
import kotlin.time.Duration
1514
import kotlin.time.DurationUnit
1615
import kotlin.time.toDuration

Diff for: core/sfc-core/src/main/kotlin/com/amazonaws/sfc/config/SourceConfiguration.kt

-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import com.amazonaws.sfc.config.BaseConfiguration.Companion.CONFIG_META_DATA
1212
import com.amazonaws.sfc.config.BaseConfiguration.Companion.CONFIG_NAME
1313
import com.amazonaws.sfc.config.BaseConfiguration.Companion.CONFIG_SPREAD_CHANNEL_VALUE
1414
import com.google.gson.annotations.SerializedName
15-
import kotlin.Throws
1615

1716
/**
1817
* Source configuration with attributes for a source as used by the SFC core controller

Diff for: core/sfc-core/src/main/kotlin/com/amazonaws/sfc/crypto/KeyHelpers.kt

-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ import java.security.interfaces.ECPrivateKey
1919
import java.security.interfaces.RSAPrivateCrtKey
2020
import java.security.spec.*
2121
import java.util.*
22-
import kotlin.Throws
2322

2423
// -----BEGIN RSA PRIVATE KEY-----
2524
@Suppress("MemberVisibilityCanBePrivate") object KeyHelpers {

Diff for: core/sfc-core/src/main/kotlin/com/amazonaws/sfc/data/OutputTransformation.kt

+1-5
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,7 @@ import org.apache.velocity.app.Velocity
1414
import org.apache.velocity.app.VelocityEngine
1515
import org.apache.velocity.runtime.resource.loader.StringResourceLoader
1616
import org.apache.velocity.runtime.resource.util.StringResourceRepository
17-
import org.apache.velocity.tools.generic.CollectionTool
18-
import org.apache.velocity.tools.generic.ContextTool
19-
import org.apache.velocity.tools.generic.DateTool
20-
import org.apache.velocity.tools.generic.MathTool
21-
import org.apache.velocity.tools.generic.NumberTool
17+
import org.apache.velocity.tools.generic.*
2218
import java.io.File
2319
import java.io.StringWriter
2420
import java.nio.file.Files

Diff for: core/sfc-core/src/main/kotlin/com/amazonaws/sfc/data/SourceDataMultiValuesStore.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
package com.amazonaws.sfc.data
66

7-
import io.ktor.util.collections.ConcurrentSet
7+
import io.ktor.util.collections.*
88
import kotlinx.coroutines.runBlocking
99
import kotlinx.coroutines.sync.Mutex
1010
import kotlinx.coroutines.sync.withLock

Diff for: core/sfc-core/src/main/kotlin/com/amazonaws/sfc/data/SourcesValuesAsFlow.kt

+1
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ class SourcesValuesAsFlow(
134134
if (!initialRead && duration > interval) {
135135
log.warning("Read cycle took ${duration.inWholeMilliseconds.toDuration(DurationUnit.MILLISECONDS)}, " +
136136
"which is more than read interval of $interval ${if (schedule != null)" for schedule \"$schedule\"" else ""}")
137+
137138
} else {
138139
log.trace("Read cycle took $duration")
139140
runBlocking {

Diff for: core/sfc-core/src/main/kotlin/com/amazonaws/sfc/util/UrlReaderCache.kt

-2
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,9 @@ import kotlinx.coroutines.runBlocking
1515
import java.io.File
1616
import java.io.File.separator
1717
import java.nio.charset.Charset
18-
import java.nio.file.FileSystem
1918
import java.security.MessageDigest
2019
import java.time.Clock
2120
import java.time.Instant
22-
import kotlin.collections.toString
2321
import kotlin.time.Duration
2422

2523

Diff for: core/sfc-ipc/src/main/kotlin/com/amazonaws/sfc/ipc/IpcAdapterService.kt

+10-5
Original file line numberDiff line numberDiff line change
@@ -84,10 +84,15 @@ class IpcAdapterService(
8484

8585
val log = logger.getCtxLoggers(className, "start")
8686

87-
grpcServer.start()
88-
val addressAndPort = grpcServer.listenSockets.first() as InetSocketAddress
89-
val addressAndPortStr = "${addressAndPort.address.hostAddress}:${addressAndPort.port}"
90-
log.info("IPC protocol service started, listening on $addressAndPortStr, connection type is ${serverConfig.serverConnectionType}")
87+
try {
88+
grpcServer.start()
89+
val addressAndPort = grpcServer.listenSockets.first() as InetSocketAddress
90+
val addressAndPortStr = "${addressAndPort.address.hostAddress}:${addressAndPort.port}"
91+
log.info("IPC protocol service started, listening on $addressAndPortStr, connection type is ${serverConfig.serverConnectionType}")
92+
}catch (e: Exception) {
93+
log.error("Failed to start server, $e")
94+
exitProcess(1)
95+
}
9196

9297
Runtime.getRuntime().addShutdownHook(
9398
Thread {
@@ -321,7 +326,7 @@ class IpcAdapterService(
321326
service.restartIfInactive()
322327
}
323328
service
324-
} catch (e: Exception) {
329+
} catch ( _ : Exception) {
325330
null
326331
}
327332
healthProbeService?.start()

Diff for: core/sfc-ipc/src/main/kotlin/com/amazonaws/sfc/ipc/IpcSourceReader.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,7 @@ class IpcSourceReader(
298298
private fun adaptersToServerMap(configRaw: Map<*, *>) = allAdaptersForType(configRaw).map {
299299
val adapter = it.value as Map<*, *>
300300
val adapterID = it.key as String
301-
val serverID = adapter[CONFIG_PROTOCOL_ADAPTER_SERVER] as String
301+
val serverID = adapter[CONFIG_PROTOCOL_ADAPTER_SERVER] as String?
302302
adapterID to serverID
303303
}.toMap()
304304

Diff for: core/sfc-main/src/main/kotlin/com/amazonaws/sfc/MainControllerService.kt

+11-4
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ class MainControllerService(
118118
stopScheduleControllers(),
119119
).joinAll()
120120
}
121-
} catch (e: Exception) {
121+
} catch (_: Exception) {
122122
logger.getCtxWarningLog(className, "stop")("Timeout stopping service")
123123
}
124124

@@ -348,15 +348,22 @@ class MainControllerService(
348348
}
349349

350350
private fun buildSourceValuesReader(schedule: ScheduleConfiguration, sourceID: String, adapterID: String): SourceValuesReader? {
351-
351+
val log = logger.getCtxLoggers(className, "buildSourceValuesReader")
352352
val protocolConfiguration = configuration.protocolAdapters[adapterID]
353-
val protocolServerConfiguration = configuration.protocolAdapterServers[protocolConfiguration?.protocolAdapterServer]
353+
val protocolAdapterServer = protocolConfiguration?.protocolAdapterServer
354+
val protocolServerConfiguration = if (protocolAdapterServer!= null) {
355+
if (!configuration.protocolAdapterServers.keys.contains(protocolAdapterServer)){
356+
log.error("Protocol adapter server \"$protocolAdapterServer\" for protocol \"$adapterID\" does not exist, valid servers are ${configuration.protocolAdapterServers.keys}")
357+
null
358+
}else{
359+
configuration.protocolAdapterServers[protocolAdapterServer]
360+
}
361+
} else null
354362

355363
return if (protocolServerConfiguration != null) {
356364
createIpcReader(configReader, configuration, adapterID, schedule, logger) as SourceValuesReader
357365
} else {
358366
if (protocolConfiguration?.protocolAdapterType !in configuration.protocolAdapterTypes) {
359-
val log = logger.getCtxLoggers(className, "buildSourceValuesReader")
360367
log.error(
361368
"Protocol type ${protocolConfiguration?.protocolAdapterType} for protocol \"$adapterID\" used in source \"Source \"$sourceID\" does not exist, " +
362369
"valid types are ${configuration.protocolAdapterTypes.keys}"

Diff for: deployment/greengrass-sfc-components/local-build-as-components-py/buildSfcComponentRecipes.py

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
import os, stat, argparse, shutil, json
1+
import argparse
2+
import json
3+
import os
4+
import shutil
5+
import stat
26

37
# cli arg definitions...
48
parser = argparse.ArgumentParser()

Diff for: docs/README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
The documentation provides a comprehensive overview of SFC's architecture, capabilities, and deployment options for industrial data collection and ingestion to AWS.
66

7-
## **Summary **
7+
## **Summary**
88

99
Shop Floor Connectivity (SFC) is a data ingestion technology for collecting industrial data and delivering it to AWS services.
1010

Diff for: docs/adapters/ads.md

+18
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,31 @@ Key configuration points:
1313

1414
The adapter supports reading from various Beckhoff PLC data types and handles the protocol-specific details of ADS communication, making it straightforward to integrate Beckhoff data into your existing SFC data collection infrastructure.
1515

16+
In order to use this adapter as in [in-process](../sfc-running-adapters.md#running-protocol-adapters-in-process) type adapter the type must be added to the [AdapterTypes](../core/sfc-configuration.md#AdapterTypes) section in the [SFC configuration file](../core/sfc-configuration.md).
17+
18+
```json
19+
"AdapterTypes" :{
20+
"ADS" : {
21+
"JarFiles" : ["<location of deployment>/ads/lib"]
22+
},
23+
"FactoryClassName" : "com.amazonaws.sfc.ads.AdsAdapter"
24+
}
25+
```
26+
1627

1728

29+
**Configuration:**
30+
1831
- [AdsSourceConfiguration](#adssourceconfiguration)
32+
1933
- [AdsChannelConfiguration](#adschannelconfiguration)
34+
2035
- [AdsAdapterConfiguration](#adsadapterconfiguration)
36+
2137
- [AdsDeviceConfiguration](#adsdeviceconfiguration)
2238

39+
40+
2341
---
2442

2543
## AdsSourceConfiguration

Diff for: docs/adapters/j1939.md

+12-3
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,25 @@ An open source J1939 DBC file is available at [j1939](../../examples/j1939dbc/RE
99

1010
> **Note: This adapter requires SocketCAN and can only be used on POSIX-compliant operating systems like Linux.**
1111
12+
In order to use this adapter as in [in-process](../sfc-running-adapters.md#running-protocol-adapters-in-process) type adapter the type must be added to the [AdapterTypes](../core/sfc-configuration.md#AdapterTypes) section in the [SFC configuration file](../core/sfc-configuration.md).
13+
14+
```json
15+
"AdapterTypes" :{
16+
"J1939" : {
17+
"JarFiles" : ["<location of deployment>/ads/lib"]
18+
},
19+
"FactoryClassName" : "com.amazonaws.sfc.j1939.J1939Adapter"
20+
}
21+
```
22+
23+
**Configuration:**
1224

13-
---
1425
- [J1939SourceConfiguration](#J1939sourceconfiguration)
1526

1627
- [J1939ChannelConfiguration](#J1939channelconfiguration)
1728

1829
- [J1939AdapterConfiguration](#J1939adapterconfiguration)
1930

20-
21-
2231
---
2332

2433
## J1939SourceConfiguration

Diff for: docs/adapters/modbus.md

+15-2
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,27 @@
22

33
The Modbus TCP protocol adapter enables communication with devices supporting the Modbus TCP protocol over TCP/IP networks. It supports standard Modbus functions for reading and writing coils, discrete inputs, holding registers, and input registers. Configure device connections using IP address and port, specify unit IDs, and define register addresses and data types for your channels. The adapter handles all protocol-specific details, making it easy to integrate Modbus device data into your SFC infrastructure.
44

5+
In order to use this adapter as an [in-process](file:///Applications/Typora.app/Contents/Resources/sfc-running-adapters.md#running-protocol-adapters-in-process) type adapter, the type must be added to the [AdapterTypes](file:///Applications/Typora.app/Contents/Resources/core/sfc-configuration.md#AdapterTypes) section in the [SFC configuration file](file:///Applications/Typora.app/Contents/Resources/core/sfc-configuration.md).
6+
7+
```json
8+
"AdapterTypes" :{
9+
"MODBUS-TCP" : {
10+
"JarFiles" : ["<location of deployment>/modbus-tcp/lib"]
11+
},
12+
"FactoryClassName" : "com.amazonaws.sfc.modbus.tcp.ModbusTcpAdapter"
13+
}
14+
```
15+
16+
17+
18+
**Configuration**:
19+
520
- [ModbusSourceConfiguration](#modbussourceconfiguration)
621
- [ModbusOptimization](#modbusoptimization)
722
- [ModbusChannelConfiguration](#modbuschannelconfiguration)
823
- [ModbusTcpAdapterConfiguration](#modbustcpadapterconfiguration)
924
- [ModbusTcpDeviceConfiguration](#modbustcpdeviceconfiguration)
1025

11-
---
12-
1326
## ModbusSourceConfiguration
1427

1528
[SFC Configuration](../core/sfc-configuration.md) > [Sources](../core/sfc-configuration.md#sources) > [Source](../core/source-configuration.md)

Diff for: docs/adapters/mqtt.md

+11-2
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,19 @@ The MQTT source protocol adapter enables SFC to collect data from MQTT brokers b
66

77
This adapter is particularly useful in IoT scenarios where devices and sensors publish their data to MQTT topics, allowing SFC to integrate seamlessly with existing MQTT-based infrastructure. It supports features like QoS levels, SSL/TLS security, and client authentication to ensure reliable and secure data collection from MQTT sources.
88

9-
MQTT Protocol adapter configuration.
9+
In order to use this adapter as in [in-process](../sfc-running-adapters.md#running-protocol-adapters-in-process) type adapter the type must be added to the [AdapterTypes](../core/sfc-configuration.md#AdapterTypes) section in the [SFC configuration file](../core/sfc-configuration.md).
1010

11+
```json
12+
"AdapterTypes" :{
13+
"MQTT" : {
14+
"JarFiles" : ["<location of deployment>/mqtt/lib"]
15+
},
16+
"FactoryClassName" : "com.amazonaws.sfc.mqtt.MqttAdapter"
17+
}
18+
```
19+
20+
**Configuration:**
1121

12-
---
1322
- [MqttSourceConfiguration](#mqttsourceconfiguration)
1423
- [MqttChannelConfiguration](#mqttchannelconfiguration)
1524
- [TopicNameMapping](#topicnamemapping)

0 commit comments

Comments
 (0)