Skip to content

Commit b35b613

Browse files
committed
Camel IEC60870 Producer improvements
1 parent 8392785 commit b35b613

File tree

9 files changed

+808
-13
lines changed

9 files changed

+808
-13
lines changed

catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/iec60870-client.json

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,18 @@
3333
"CamelIec60870Value": { "index": 0, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "Object", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The value", "constantName": "org.apache.camel.component.iec60870.Constants#IEC60870_VALUE" },
3434
"CamelIec60870Timestamp": { "index": 1, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "long", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The timestamp of the value", "constantName": "org.apache.camel.component.iec60870.Constants#IEC60870_TIMESTAMP" },
3535
"CamelIec60870Quality": { "index": 2, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "org.eclipse.neoscada.protocol.iec60870.asdu.types.QualityInformation", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The quality information of the value", "constantName": "org.apache.camel.component.iec60870.Constants#IEC60870_QUALITY" },
36-
"CamelIec60870Overflow": { "index": 3, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "boolean", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Is overflow", "constantName": "org.apache.camel.component.iec60870.Constants#IEC60870_OVERFLOW" }
36+
"CamelIec60870Overflow": { "index": 3, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "boolean", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Is overflow", "constantName": "org.apache.camel.component.iec60870.Constants#IEC60870_OVERFLOW" },
37+
"CamelIec60870ConnectionState": { "index": 4, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "org.eclipse.neoscada.protocol.iec60870.client.AutoConnectClient.State", "enum": [ "SLEEPING", "DISCONNECTED", "LOOKUP", "CONNECTING", "CONNECTED" ], "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The connection state (CONNECTED, DISCONNECTED, etc.)", "constantName": "org.apache.camel.component.iec60870.Constants#IEC60870_CONNECTION_STATE" },
38+
"CamelIec60870ConnectionError": { "index": 5, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "Throwable", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The connection state error if any", "constantName": "org.apache.camel.component.iec60870.Constants#IEC60870_CONNECTION_ERROR" },
39+
"CamelIec60870ConnectionUptime": { "index": 6, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "long", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Connection uptime in milliseconds since last connected", "constantName": "org.apache.camel.component.iec60870.Constants#IEC60870_CONNECTION_UPTIME" },
40+
"CamelIec60870CommandType": { "index": 7, "kind": "header", "displayName": "", "group": "producer", "label": "producer", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The command type: 'value' (default), 'interrogation', 'read', or 'status'", "constantName": "org.apache.camel.component.iec60870.Constants#IEC60870_COMMAND_TYPE" },
41+
"CamelIec60870AsduAddress": { "index": 8, "kind": "header", "displayName": "", "group": "producer", "label": "producer", "required": false, "javaType": "org.eclipse.neoscada.protocol.iec60870.asdu.types.ASDUAddress", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The ASDU address for interrogation (optional, defaults to broadcast)", "constantName": "org.apache.camel.component.iec60870.Constants#IEC60870_ASDU_ADDRESS" },
42+
"CamelIec60870Qoi": { "index": 9, "kind": "header", "displayName": "", "group": "producer", "label": "producer", "required": false, "javaType": "short", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The qualifier of interrogation: 20 (global) or 21-36 (groups 1-16)", "constantName": "org.apache.camel.component.iec60870.Constants#IEC60870_QOI" },
43+
"CamelIec60870QualityBlocked": { "index": 10, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "boolean", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Quality flag: Blocked (BL)", "constantName": "org.apache.camel.component.iec60870.Constants#IEC60870_QUALITY_BLOCKED" },
44+
"CamelIec60870QualitySubstituted": { "index": 11, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "boolean", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Quality flag: Substituted (SB)", "constantName": "org.apache.camel.component.iec60870.Constants#IEC60870_QUALITY_SUBSTITUTED" },
45+
"CamelIec60870QualityNotTopical": { "index": 12, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "boolean", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Quality flag: Not topical (NT)", "constantName": "org.apache.camel.component.iec60870.Constants#IEC60870_QUALITY_NOT_TOPICAL" },
46+
"CamelIec60870QualityValid": { "index": 13, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "boolean", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Quality flag: Invalid (IV)", "constantName": "org.apache.camel.component.iec60870.Constants#IEC60870_QUALITY_VALID" },
47+
"CamelIec60870CauseOfTransmission": { "index": 14, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "org.eclipse.neoscada.protocol.iec60870.asdu.types.CauseOfTransmission", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The cause of transmission", "constantName": "org.apache.camel.component.iec60870.Constants#IEC60870_CAUSE_OF_TRANSMISSION" }
3748
},
3849
"properties": {
3950
"uriPath": { "index": 0, "kind": "path", "displayName": "Uri Path", "group": "common", "label": "", "required": true, "type": "object", "javaType": "org.apache.camel.component.iec60870.ObjectAddress", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The object information address" },

components/camel-iec60870/src/generated/resources/META-INF/org/apache/camel/component/iec60870/client/iec60870-client.json

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,18 @@
3333
"CamelIec60870Value": { "index": 0, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "Object", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The value", "constantName": "org.apache.camel.component.iec60870.Constants#IEC60870_VALUE" },
3434
"CamelIec60870Timestamp": { "index": 1, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "long", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The timestamp of the value", "constantName": "org.apache.camel.component.iec60870.Constants#IEC60870_TIMESTAMP" },
3535
"CamelIec60870Quality": { "index": 2, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "org.eclipse.neoscada.protocol.iec60870.asdu.types.QualityInformation", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The quality information of the value", "constantName": "org.apache.camel.component.iec60870.Constants#IEC60870_QUALITY" },
36-
"CamelIec60870Overflow": { "index": 3, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "boolean", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Is overflow", "constantName": "org.apache.camel.component.iec60870.Constants#IEC60870_OVERFLOW" }
36+
"CamelIec60870Overflow": { "index": 3, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "boolean", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Is overflow", "constantName": "org.apache.camel.component.iec60870.Constants#IEC60870_OVERFLOW" },
37+
"CamelIec60870ConnectionState": { "index": 4, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "org.eclipse.neoscada.protocol.iec60870.client.AutoConnectClient.State", "enum": [ "SLEEPING", "DISCONNECTED", "LOOKUP", "CONNECTING", "CONNECTED" ], "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The connection state (CONNECTED, DISCONNECTED, etc.)", "constantName": "org.apache.camel.component.iec60870.Constants#IEC60870_CONNECTION_STATE" },
38+
"CamelIec60870ConnectionError": { "index": 5, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "Throwable", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The connection state error if any", "constantName": "org.apache.camel.component.iec60870.Constants#IEC60870_CONNECTION_ERROR" },
39+
"CamelIec60870ConnectionUptime": { "index": 6, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "long", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Connection uptime in milliseconds since last connected", "constantName": "org.apache.camel.component.iec60870.Constants#IEC60870_CONNECTION_UPTIME" },
40+
"CamelIec60870CommandType": { "index": 7, "kind": "header", "displayName": "", "group": "producer", "label": "producer", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The command type: 'value' (default), 'interrogation', 'read', or 'status'", "constantName": "org.apache.camel.component.iec60870.Constants#IEC60870_COMMAND_TYPE" },
41+
"CamelIec60870AsduAddress": { "index": 8, "kind": "header", "displayName": "", "group": "producer", "label": "producer", "required": false, "javaType": "org.eclipse.neoscada.protocol.iec60870.asdu.types.ASDUAddress", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The ASDU address for interrogation (optional, defaults to broadcast)", "constantName": "org.apache.camel.component.iec60870.Constants#IEC60870_ASDU_ADDRESS" },
42+
"CamelIec60870Qoi": { "index": 9, "kind": "header", "displayName": "", "group": "producer", "label": "producer", "required": false, "javaType": "short", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The qualifier of interrogation: 20 (global) or 21-36 (groups 1-16)", "constantName": "org.apache.camel.component.iec60870.Constants#IEC60870_QOI" },
43+
"CamelIec60870QualityBlocked": { "index": 10, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "boolean", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Quality flag: Blocked (BL)", "constantName": "org.apache.camel.component.iec60870.Constants#IEC60870_QUALITY_BLOCKED" },
44+
"CamelIec60870QualitySubstituted": { "index": 11, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "boolean", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Quality flag: Substituted (SB)", "constantName": "org.apache.camel.component.iec60870.Constants#IEC60870_QUALITY_SUBSTITUTED" },
45+
"CamelIec60870QualityNotTopical": { "index": 12, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "boolean", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Quality flag: Not topical (NT)", "constantName": "org.apache.camel.component.iec60870.Constants#IEC60870_QUALITY_NOT_TOPICAL" },
46+
"CamelIec60870QualityValid": { "index": 13, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "boolean", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Quality flag: Invalid (IV)", "constantName": "org.apache.camel.component.iec60870.Constants#IEC60870_QUALITY_VALID" },
47+
"CamelIec60870CauseOfTransmission": { "index": 14, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "org.eclipse.neoscada.protocol.iec60870.asdu.types.CauseOfTransmission", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The cause of transmission", "constantName": "org.apache.camel.component.iec60870.Constants#IEC60870_CAUSE_OF_TRANSMISSION" }
3748
},
3849
"properties": {
3950
"uriPath": { "index": 0, "kind": "path", "displayName": "Uri Path", "group": "common", "label": "", "required": true, "type": "object", "javaType": "org.apache.camel.component.iec60870.ObjectAddress", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The object information address" },

components/camel-iec60870/src/main/docs/iec60870-client-component.adoc

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,4 +64,97 @@ include::partial$component-endpoint-options.adoc[]
6464
include::partial$component-endpoint-headers.adoc[]
6565
// component options: END
6666

67+
== Producer Command Types
68+
69+
The producer supports different command types via the `CamelIec60870CommandType` header:
70+
71+
[cols="1,3"]
72+
|===
73+
|Command Type |Description
74+
75+
|`value`
76+
|Send value command (default). Body type determines command: Boolean→Single, Integer→Scaled, Float→Float setpoint.
77+
78+
|`interrogation`
79+
|Trigger interrogation (C_IC_NA_1). Use `CamelIec60870Qoi` header for group interrogation (21-36).
80+
81+
|`read`
82+
|Read single data point (C_RD_NA_1).
83+
84+
|`status`
85+
|Get connection state only. No protocol command sent.
86+
|===
87+
88+
=== Getting Connection Status (Producer)
89+
90+
[source,java]
91+
----
92+
from("direct:status")
93+
.setHeader("CamelIec60870CommandType", constant("status"))
94+
.to("iec60870-client:localhost:2404/00-01-00-00-01");
95+
96+
// Usage
97+
Exchange result = producerTemplate.send("direct:status", e -> {});
98+
State state = result.getMessage().getHeader("CamelIec60870ConnectionState", State.class);
99+
Long uptime = result.getMessage().getHeader("CamelIec60870ConnectionUptime", Long.class);
100+
----
101+
102+
=== Triggering Interrogation
103+
104+
[source,java]
105+
----
106+
from("direct:interrogate")
107+
.setHeader("CamelIec60870CommandType", constant("interrogation"))
108+
.to("iec60870-client:localhost:2404/00-01-00-00-01");
109+
110+
from("direct:interrogateGroup")
111+
.setHeader("CamelIec60870CommandType", constant("interrogation"))
112+
.setHeader("CamelIec60870Qoi", constant((short) 21))
113+
.to("iec60870-client:localhost:2404/00-01-00-00-01");
114+
----
115+
116+
=== Sending Value Commands
117+
118+
[source,java]
119+
----
120+
from("direct:bool").setBody(constant(true))
121+
.to("iec60870-client:localhost:2404/00-01-00-00-01");
122+
123+
from("direct:float").setBody(constant(42.5f))
124+
.to("iec60870-client:localhost:2404/00-01-00-00-01");
125+
----
126+
127+
== Consumer Examples
128+
129+
Each message received by the consumer includes connection state and quality headers.
130+
131+
=== Getting Connection Status (Consumer)
132+
133+
[source,java]
134+
----
135+
from("iec60870-client:localhost:2404/00-01-00-00-01")
136+
.process(exchange -> {
137+
// Connection state is included in every message
138+
State state = exchange.getIn().getHeader("CamelIec60870ConnectionState", State.class);
139+
Long uptime = exchange.getIn().getHeader("CamelIec60870ConnectionUptime", Long.class);
140+
141+
// Get the value and quality
142+
Object value = exchange.getIn().getHeader("CamelIec60870Value");
143+
Boolean valid = exchange.getIn().getHeader("CamelIec60870QualityValid", Boolean.class);
144+
145+
log.info("State: {}, Uptime: {} ms, Value: {}, Valid: {}", state, uptime, value, valid);
146+
})
147+
.to("log:values");
148+
----
149+
150+
=== Filtering by Quality
151+
152+
[source,java]
153+
----
154+
from("iec60870-client:localhost:2404/00-01-00-00-01")
155+
.filter(header("CamelIec60870QualityValid").isEqualTo(true))
156+
.log("Good value: ${header.CamelIec60870Value}")
157+
.to("seda:process");
158+
----
159+
67160
include::spring-boot:partial$starter.adoc[]

components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/Constants.java

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,4 +54,54 @@ public interface Constants {
5454
String TYPE = "type";
5555
@Metadata(label = "consumer", description = "Is execute", javaType = "boolean", applicableFor = SCHEME_SERVER)
5656
String EXECUTE = "execute";
57+
58+
// Connection state headers
59+
@Metadata(label = "consumer", description = "The connection state (CONNECTED, DISCONNECTED, etc.)",
60+
javaType = "org.eclipse.neoscada.protocol.iec60870.client.AutoConnectClient.State", applicableFor = SCHEME_CLIENT)
61+
String IEC60870_CONNECTION_STATE = "CamelIec60870ConnectionState";
62+
@Metadata(label = "consumer", description = "The connection state error if any",
63+
javaType = "Throwable", applicableFor = SCHEME_CLIENT)
64+
String IEC60870_CONNECTION_ERROR = "CamelIec60870ConnectionError";
65+
@Metadata(label = "consumer", description = "Connection uptime in milliseconds since last connected",
66+
javaType = "long", applicableFor = SCHEME_CLIENT)
67+
String IEC60870_CONNECTION_UPTIME = "CamelIec60870ConnectionUptime";
68+
69+
// Producer command types
70+
@Metadata(label = "producer",
71+
description = "The command type: 'value' (default), 'interrogation', 'read', or 'status'",
72+
javaType = "String", applicableFor = SCHEME_CLIENT)
73+
String IEC60870_COMMAND_TYPE = "CamelIec60870CommandType";
74+
75+
// Command type values
76+
String COMMAND_TYPE_VALUE = "value";
77+
String COMMAND_TYPE_INTERROGATION = "interrogation";
78+
String COMMAND_TYPE_READ = "read";
79+
String COMMAND_TYPE_STATUS = "status";
80+
81+
// Interrogation headers
82+
@Metadata(label = "producer", description = "The ASDU address for interrogation (optional, defaults to broadcast)",
83+
javaType = "org.eclipse.neoscada.protocol.iec60870.asdu.types.ASDUAddress", applicableFor = SCHEME_CLIENT)
84+
String IEC60870_ASDU_ADDRESS = "CamelIec60870AsduAddress";
85+
@Metadata(label = "producer", description = "The qualifier of interrogation: 20 (global) or 21-36 (groups 1-16)",
86+
javaType = "short", applicableFor = SCHEME_CLIENT)
87+
String IEC60870_QOI = "CamelIec60870Qoi";
88+
89+
// Individual quality flag headers
90+
@Metadata(label = "consumer", description = "Quality flag: Blocked (BL)", javaType = "boolean",
91+
applicableFor = SCHEME_CLIENT)
92+
String IEC60870_QUALITY_BLOCKED = "CamelIec60870QualityBlocked";
93+
@Metadata(label = "consumer", description = "Quality flag: Substituted (SB)", javaType = "boolean",
94+
applicableFor = SCHEME_CLIENT)
95+
String IEC60870_QUALITY_SUBSTITUTED = "CamelIec60870QualitySubstituted";
96+
@Metadata(label = "consumer", description = "Quality flag: Not topical (NT)", javaType = "boolean",
97+
applicableFor = SCHEME_CLIENT)
98+
String IEC60870_QUALITY_NOT_TOPICAL = "CamelIec60870QualityNotTopical";
99+
@Metadata(label = "consumer", description = "Quality flag: Invalid (IV)", javaType = "boolean",
100+
applicableFor = SCHEME_CLIENT)
101+
String IEC60870_QUALITY_VALID = "CamelIec60870QualityValid";
102+
103+
// Cause of transmission header
104+
@Metadata(label = "consumer", description = "The cause of transmission",
105+
javaType = "org.eclipse.neoscada.protocol.iec60870.asdu.types.CauseOfTransmission", applicableFor = SCHEME_CLIENT)
106+
String IEC60870_CAUSE_OF_TRANSMISSION = "CamelIec60870CauseOfTransmission";
57107
}

0 commit comments

Comments
 (0)