Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge of Version 2.3 additions to the agent #413

Merged
merged 25 commits into from
Feb 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
dd336f9
Merge pull request #289 from mtconnect/add-dynamic-device-creation-fo…
wsobel Jul 19, 2023
0cffec0
added condition_id to the CONDITION SHDR format and example
dwickelhaus Aug 29, 2023
8da96a2
Merge pull request #315 from mtconnect/main-dev-readme-codition-update
wsobel Sep 4, 2023
31891a3
Merge branch 'main' into main-dev
wsobel Sep 4, 2023
9545360
Merge branch 'main' into main-dev
wsobel Sep 6, 2023
ff7f878
Merge branch 'main' into main-dev
wsobel Oct 3, 2023
c0db9e7
Added support for conditionId in version 2.3 and native code field in…
wsobel Oct 3, 2023
2d4e473
default condition code to condition id when creating condition observ…
wsobel Oct 4, 2023
769a93a
Merge pull request #332 from mtconnect/version-2.3-adding-condition-i…
wsobel Oct 5, 2023
1a65154
initial device type rest argument
wsobel Oct 5, 2023
cac6065
Updated condition shdr format for the addition of condition_id to the…
dwickelhaus Oct 16, 2023
bf04910
Corrected SHDR pattern conditions and the condtion_id parameter
dwickelhaus Oct 17, 2023
9a8e22a
Removed * from the comments under the adapter condition shdr examples.
dwickelhaus Oct 17, 2023
112b841
Merge pull request #344 from mtconnect/condition_id_shdr_readme_update
wsobel Oct 19, 2023
0d966f5
Merge branch 'main' into version-2.3-device-type-rest-interface
wsobel Oct 22, 2023
eb15f9f
added deviceType and tests
wsobel Oct 22, 2023
2742c25
Version 2.3.0.0 RC 1
wsobel Oct 22, 2023
02adeeb
Merge branch 'main-dev' into version-2.3-device-type-rest-interface
wsobel Oct 27, 2023
d8a818c
Merge pull request #356 from mtconnect/version-2.3-device-type-rest-i…
wsobel Nov 3, 2023
8bd58e4
On branch main-dev_readme_update
dwickelhaus Jan 23, 2024
4a206c1
Merge pull request #402 from mtconnect/main-dev_readme_update
wsobel Jan 24, 2024
615bb8c
On branch main-dev_readme_update
dwickelhaus Jan 26, 2024
a328743
Merge pull request #406 from mtconnect/main-dev_readme_update2
wsobel Jan 26, 2024
875a96d
Merge branch 'main' into main-dev
wsobel Feb 17, 2024
0bf7711
fixed merge of json mapper test
wsobel Feb 17, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# The version number.
set(AGENT_VERSION_MAJOR 2)
set(AGENT_VERSION_MINOR 2)
set(AGENT_VERSION_MINOR 3)
set(AGENT_VERSION_PATCH 0)
set(AGENT_VERSION_BUILD 17)
set(AGENT_VERSION_BUILD 1)
set(AGENT_VERSION_RC "")

# This minimum version is to support Visual Studio 2019 and C++ feature checking and FetchContent
Expand Down
188 changes: 182 additions & 6 deletions README.md
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

MTConnect C++ Agent Version 2.2
MTConnect C++ Agent Version 2.3
--------
[![Build MTConnect C++ Agent](https://github.com/mtconnect/cppagent/actions/workflows/build.yml/badge.svg)](https://github.com/mtconnect/cppagent/actions/workflows/build.yml)

Expand Down Expand Up @@ -958,6 +958,171 @@ Sinks {
* `SuppressIPAddress` - Suppress the Adapter IP Address and port when creating the Agent Device ids and names.

*Default*: false

* `AdapterIdentity` - Adapter Identity name used to prefix dataitems within the Agent device ids and names.

*Default*:
* If `SuppressIPAddress` == false:\
`AdapterIdentity` = ```_ {IP}_{PORT}```\
example:`_localhost_7878`

* If `SuppressIPAddress` == true:\
`AdapterIdentity` = ```_ sha1digest({IP}_{PORT})```\
example: `__71020ed1ed`

#### MQTT Adapter/Source

* `MqttHost` - IP Address or name of the MQTT Broker

*Default*: 127.0.0.1

* `MqttPort` - Port number of MQTT Broker

*Default*: 1883

* `topics` - list of topics to subscribe to. Note : Only raw SHDR strings supported at this time

*Required*

* `MqttClientId` - Port number of MQTT Broker

*Default*: Auto-generated

> **⚠️Note:** Mqtt Sinks and Mqtt Adapters create separate connections to their respective brokers, but currently use the same client ID by default. Because of this, when using a single broker for source and sink, best practice is to explicitly specify their respective `MqttClientId`
>

Example mqtt adapter block:
```json
mydevice {
Protocol = mqtt
MqttHost = localhost
MqttPort = 1883
MqttClientId = myUniqueID
Topics = /ingest
}
```

### MQTT JSON Ingress Protocol Version 2.0

In general the data format will be {"timestamp": "YYYY-MM-DDThh:mm:ssZ","dataItemId":"value", "dataItemId":{"key1":"value1", ..., "keyn":"valuen}}

**NOTE**: See the standard for the complete description of the fields for the data item representations below.

A simple set of events and samples will look something like this:

```json
{
"timestamp": "2023-11-06T12:12:44Z", //Time Stamp
"tempId": 22.6, //Temperature
"positionId": 1002.345, //X axis position
"executionId": "ACTIVE" //Execution state
}
```

A `CONDITION` requires the key to be the dataItemId and requires the 6 fields as shown in the example below

```json
{
"timestamp": "2023-11-06T12:12:44Z",
"dataItemId": {
"level": "fault",
"conditionId":"ac324",
"nativeSeverity": "1000",
"qualifier": "HIGH",
"nativeCode": "ABC",
"message": "something went wrong"
}
}
```
A `MESSAGE` requires the key to be the dataItemId and requires the nativeCode field as shown in the example below

```json
{
"timestamp": "2023-11-06T12:12:44Z",
"messsageId": {
"nativeCode": "ABC",
"message": "something went wrong"
}
}
```

The `TimeSeries` `REPRESENTATION` requires the key to be the dataItemId and requires 2 fields "count" and "values" and 1 to n comma delimited values.
**NOTE**: The "frequency" field is optional.

```json
{
"timestamp": "2023-11-06T12:12:44Z",
"timeSeries1": {
"count": 10,
"frequency": 100,
"values": [1,2,3,4,5,6,7,8,9,10]
}
}
```
The `DataSet` `REPRESENTATION` requires the the dataItemId as the key and the "values" field. It may also have the optional "resetTriggered" field.

```json
{
{
"timestamp": "2023-11-09T11:20:00Z",
"dataSetId": {
"key1": 123,
"key2": 456,
"key3": 789
}
}
```

Example with the optional "resetTriggered" filed:

```json
{
"timestamp": "2023-11-09T11:20:00Z",
"cncregisterset1": {
"resetTriggered": "NEW",
"value": {"r1":"v1", "r2":"v2", "r3":"v3" }
}
}
```

The `Table` `REPRESENTATION` requires the the dataItemId as the key and the "values" field. It may also have the optional "resetTriggered" field.

```json

{
"timestamp":"2023-11-06T12:12:44Z",
"tableId":{
"row1":{
"cell1":"Some Text",
"cell2":3243
},
"row2": {
"cell1":"Some Other Text",
"cell2":243
}
}
}
```

Example with the optional resetTriggered field:

```json
{
"timestamp": "2023-11-09T11:20:00Z",
"a1": {
"resetTriggered": "NEW",
"value": {
"r1": {
"k1": 123.45,
"k3": 6789
},
"r2": null
}
}
}
```



* `AdapterIdentity` - Adapter Identity name used to prefix dataitems within the Agent device ids and names.

Expand Down Expand Up @@ -1080,9 +1245,20 @@ Conditions require six (6) fields as follows:

<timestamp>|<data_item_name>|<level>|<native_code>|<native_severity>|<qualifier>|<message>

Condition id and native code are set to the same value given as <native_code>

<timestamp>|<data_item_name>|<level>|<native_code>:<condition_id>|<native_severity>|<qualifier>|<message>

Condition id is set to condition_id and native code is set to native_code

<timestamp>|<data_item_name>|<level>|<condition_id>|<native_severity>|<qualifier>|<message>

Condition id is set to condition_id and native code is not set


For a complete description of these fields, see the standard. An example line will look like this:

2014-09-29T23:59:33.460470Z|htemp|WARNING|HTEMP|1|HIGH|Oil Temperature High
2014-09-29T23:59:33.460470Z|htemp|WARNING|HTEMP-1-HIGH|HTEMP|1|HIGH|Oil Temperature High

The next special format is the Message. There is one additional field, native_code, which needs to be included:

Expand Down Expand Up @@ -1551,7 +1727,7 @@ to instruct conan to not parallelize the builds. Some of the modules that includ

### Build the agent

conan create cppagent -pr cppagent/conan/profile/gcc --build=missing
conan create cppagent -pr cppagent/conan/profiles/gcc --build=missing

## Building on Mac OS

Expand All @@ -1572,11 +1748,11 @@ Install brew and xcode command line tools

### Build the agent

conan create cppagent -pr cppagent/conan/profile/macos --build=missing
conan create cppagent -pr cppagent/conan/profiles/macos --build=missing

### Generate an xcode project for debugging

conan build . -pr conan/profile/xcode -s build_type=Debug --build=missing -o development=True
conan build . -pr conan/profiles/xcode -s build_type=Debug --build=missing -o development=True

## Building on Fedora Alpine

Expand All @@ -1596,7 +1772,7 @@ Install brew and xcode command line tools

### Build the agent

conan create cppagent -pr cppagent/conan/profile/gcc --build=missing
conan create cppagent -pr cppagent/conan/profiles/gcc --build=missing

## For some examples, see the CI/CD workflows in `.github/workflows/build.yml`

Expand Down
16 changes: 11 additions & 5 deletions src/mtconnect/agent.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1301,17 +1301,20 @@ namespace mtconnect {
// Validation methods
// -----------------------------------------------

string Agent::devicesAndPath(const std::optional<string> &path, const DevicePtr device) const
string Agent::devicesAndPath(const std::optional<string> &path, const DevicePtr device, const std::optional<std::string> &deviceType) const
{
string dataPath;

if (device)
if (device || deviceType)
{
string prefix;
if (device->getName() == "Agent")
if ((device && device->getName() == "Agent") ||
(deviceType && *deviceType == "Agent"))
prefix = "//Devices/Agent";
else
else if (device)
prefix = "//Devices/Device[@uuid=\"" + *device->getUuid() + "\"]";
else if (deviceType)
prefix = "//Devices/Device";

if (path)
{
Expand All @@ -1331,7 +1334,10 @@ namespace mtconnect {
}
else
{
dataPath = path ? *path : "//Devices/Device|//Devices/Agent";
if (path)
dataPath = *path;
else
dataPath = "//Devices/Device|//Devices/Agent";
}

return dataPath;
Expand Down
14 changes: 11 additions & 3 deletions src/mtconnect/agent.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,10 @@ namespace mtconnect {
/// @return The MTConnect schema version as a string
const auto &getSchemaVersion() const { return m_schemaVersion; }

/// @brief Get the integer schema version based on configuration.
/// @returns the schema version as an integer [major * 100 + minor] as a 32bit integer.
const auto getIntSchemaVersion() const { return m_intSchemaVersion; }

/// @brief Find a device by name
/// @param[in] name The name of the device to find
/// @return A shared pointer to the device
Expand Down Expand Up @@ -421,9 +425,11 @@ namespace mtconnect {
///
/// @param[in] path Optional path to prefix
/// @param[in] device Optional device if one device is specified
/// @param[in] deviceType optional Agent or Device selector
/// @return The rewritten path properly prefixed
std::string devicesAndPath(const std::optional<std::string> &path,
const DevicePtr device) const;
const DevicePtr device,
const std::optional<std::string> &deviceType = std::nullopt) const;

/// @brief Creates unique ids for the device model and maps to the originals
///
Expand Down Expand Up @@ -575,6 +581,7 @@ namespace mtconnect {
fun(ldi);
}
}
int32_t getSchemaVersion() const override { return m_agent->getIntSchemaVersion(); }
void deliverObservation(observation::ObservationPtr obs) override
{
m_agent->receiveObservation(obs);
Expand Down Expand Up @@ -636,9 +643,10 @@ namespace mtconnect {
const PrinterMap &getPrinters() const override { return m_agent->getPrinters(); }

void getDataItemsForPath(const DevicePtr device, const std::optional<std::string> &path,
FilterSet &filter) const override
FilterSet &filter,
const std::optional<std::string> &deviceType) const override
{
std::string dataPath = m_agent->devicesAndPath(path, device);
std::string dataPath = m_agent->devicesAndPath(path, device, deviceType);
const auto &parser = m_agent->getXmlParser();
parser->getDataItems(filter, dataPath);
}
Expand Down
12 changes: 10 additions & 2 deletions src/mtconnect/observation/observation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -333,14 +333,22 @@ namespace mtconnect {
auto cond = make_shared<Condition>(name, props);
if (cond)
{
auto code = cond->m_properties.find("nativeCode");
if (code != cond->m_properties.end())
if (auto code = cond->m_properties.find("conditionId");
code != cond->m_properties.end())
{
cond->m_code = std::get<string>(code->second);
}
else if (auto code = cond->m_properties.find("nativeCode");
code != cond->m_properties.end())
{
cond->m_code = std::get<string>(code->second);
}
}
return cond;
});
factory->addRequirements(Requirements {{"type", ValueType::USTRING, true},
{"nativeCode", false},
{"conditionId", false},
{"nativeSeverity", false},
{"qualifier", ValueType::USTRING, false},
{"statistic", ValueType::USTRING, false},
Expand Down
1 change: 1 addition & 0 deletions src/mtconnect/observation/observation.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,7 @@ namespace mtconnect::observation {
m_level = NORMAL;
m_code.clear();
m_properties.erase("nativeCode");
m_properties.erase("conditionId");
m_properties.erase("nativeSeverity");
m_properties.erase("qualifier");
m_properties.erase("statistic");
Expand Down
3 changes: 3 additions & 0 deletions src/mtconnect/pipeline/pipeline_contract.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,9 @@ namespace mtconnect {
/// @param[in] name name or id of the data item
/// @return shared pointer to the data item if found
virtual DataItemPtr findDataItem(const std::string &device, const std::string &name) = 0;
/// @brief get the current schema version as an integer
/// @returns the schema version as an integer [major * 100 + minor] as a 32bit integer.
virtual int32_t getSchemaVersion() const = 0;
/// @brief iterate through all the data items calling `fun` for each
/// @param[in] fun The function or lambda to call
virtual void eachDataItem(EachDataItem fun) = 0;
Expand Down
Loading
Loading