Skip to content

Commit

Permalink
[Features] Adding tag format to Industrial Simulator (#55)
Browse files Browse the repository at this point in the history
## Purpose

We have a customer scenario where the payloads come like this:

```json
{
    "timestamp": "2023-12-18T07:08:51.9706158Z",
    "messageType": "ua-deltaframe",
    "payload": {
        "ns=2;s=MyTag.Automatic": {
            "SourceTimestamp": "2023-12-18T07:08:51.5575029Z",
            "Value": true
        },
        "ns=2;s=MyTag.Counter": {
            "SourceTimestamp": "2023-12-18T07:08:52.0515453Z",
            "Value": 223
        }
    },
    "dataSetWriterName": "SomeName",
    "sequenceNumber": 9149
}
```

As you can notice the tag uses a very different format of the default
one. It also uses only the site number (ex. ns=2) and tag name (not the
id). The Industrial Simulator is perfect for what we need, but this is a
small gap.

This PR introduces a way to format the tag, while preserving the default
format if such property is not added.

You can configure the tag with the idTemplate (optional) property, ex.

```yaml
   sites:
        - name: 2
          mqttVersion: v5
          assetCount: 1
          tags:
            - id: GoodCounter
              idTemplate: "ns=%s;s=AreaName.MachineName.Counter.%s"
              configuration: x
              count: 1
```

It also fixes a couple of small issues:

* Fixes a typo in the way to build the app, where is missing a folder.
* Uses a parameter for the image owner, this way I could test it in a
fork.

## Does this introduce a breaking change?
<!-- Mark one with an "x". -->
```
[ ] Yes
[x] No
```

## Pull Request Type
What kind of change does this Pull Request introduce?

<!-- Please check the one that applies to this PR using "x". -->
```
[ ] Bugfix
[x] Feature
[ ] Code style update (formatting, local variables)
[ ] Refactoring (no functional changes, no api changes)
[ ] Documentation content changes
[ ] Other... Please describe:
```

## How to Test

```
go build -o ./bin/industrial-data-simulator ./cmd
./bin/industrial-data-simulator < config.yml
```
  • Loading branch information
mahomedalid authored Feb 28, 2024
1 parent 68a8e08 commit 4344e61
Show file tree
Hide file tree
Showing 4 changed files with 33 additions and 14 deletions.
5 changes: 3 additions & 2 deletions .github/workflows/ghcr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,6 @@ jobs:

- name: "Build Inventory Image"
run: |
docker build ${{ inputs.context }} -f ${{ inputs.file }} --tag ghcr.io/azure-samples/explore-iot-operations/${{ inputs.name }}:latest
docker push ghcr.io/azure-samples/explore-iot-operations/${{ inputs.name }}:latest
owner=$(echo "${{ github.repository_owner }}" | tr '[:upper:]' '[:lower:]')
docker build ${{ inputs.context }} -f ${{ inputs.file }} --tag ghcr.io/$owner/explore-iot-operations/${{ inputs.name }}:latest
docker push ghcr.io/$owner/explore-iot-operations/${{ inputs.name }}:latest
2 changes: 1 addition & 1 deletion samples/industrial-data-simulator/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ go run . < config.yml
```sh
# With Golang installed, build a binary of the simulator.
go build -o ./bin/industrial-data-simulator ./cmd
./industrial-data-simulator < config.yml
./bin/industrial-data-simulator < config.yml

# Or by reading in a file instead of stdin:
# ./industrial-data-simulator --stdin=false --config=config.yml
Expand Down
15 changes: 8 additions & 7 deletions samples/industrial-data-simulator/lib/external/configuration.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ type (
Configuration string `json:"configuration" yaml:"configuration"`
Count int `json:"count" yaml:"count"`
MissingChance int `json:"missingChance" yaml:"missingChance"`
IDTemplate string `json:"idTemplate" yaml:"idTemplate"`
}

// Rate describes the flow of message publishes from the simulator,
Expand Down Expand Up @@ -84,13 +85,13 @@ type (
)

const (
BrokerID = "0"
ClientIDFormat = "%s__asset_%d"
TopicIDFormat = "%s__%s__%s"
TagIDFormat = "%s__%s__%d"
TagParentIDFormat = "%s__parent"
TagChildIDFormat = "%s__child"
ProviderIDFormat = "industrial_data_simulator_%s_asset_publish_counter"
BrokerID = "0"
ClientIDFormat = "%s__asset_%d"
TopicIDFormat = "%s__%s__%s"
TagIDDefaultFormat = "%s__%s__%d"
TagParentIDFormat = "%s__parent"
TagChildIDFormat = "%s__child"
ProviderIDFormat = "industrial_data_simulator_%s_asset_publish_counter"

TagTimestampIDFormat = "%s__timestamp"
OPCUATimeExpression = "now()"
Expand Down
25 changes: 21 additions & 4 deletions samples/industrial-data-simulator/lib/external/external.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"errors"
"fmt"
"io"
"strings"

"github.com/explore-iot-ops/samples/industrial-data-simulator/components/broker"
"github.com/explore-iot-ops/samples/industrial-data-simulator/components/client"
Expand Down Expand Up @@ -338,12 +339,28 @@ func (builder *DeviceSimulatorBuilder) ParseJSONTagPerMessage(
return tagNames, nil
}

func (builder *DeviceSimulatorBuilder) GenerateTagID(siteName string, tag Tag, count int) string {
var tagIDFormat string
if tag.IDTemplate != "" {
tagIDFormat = tag.IDTemplate
} else {
tagIDFormat = TagIDDefaultFormat
}

// Counting how many format specifiers came (tag can be %s_%s to ignore the id %d)
n := strings.Count(tagIDFormat, "%")

args := []interface{}{siteName, tag.ID, count}

return fmt.Sprintf(tagIDFormat, args[:n]...)
}

func (builder *DeviceSimulatorBuilder) ParseJSONTag(
siteName string,
tag Tag,
count int,
) (string, error) {
tagID := fmt.Sprintf(TagIDFormat, siteName, tag.ID, count)
tagID := builder.GenerateTagID(siteName, tag, count)
childID := fmt.Sprintf(TagChildIDFormat, tagID)

err := builder.ParseRootNode(siteName, tagID, node.COLLECTION)
Expand Down Expand Up @@ -450,7 +467,7 @@ func (builder *DeviceSimulatorBuilder) ParseOPCUATag(
tag Tag,
count int,
) error {
tagID := fmt.Sprintf(TagIDFormat, configuration.Name, tag.ID, count)
tagID := builder.GenerateTagID(configuration.Name, tag, count)

err := builder.ParseCollectionNode(rootId, tagID, tagID, tagID)
if err != nil {
Expand Down Expand Up @@ -533,7 +550,7 @@ func (builder *DeviceSimulatorBuilder) ParseComplex(

for _, tag := range configuration.Tags {
for count := 0; count < tag.Count; count++ {
tagID := fmt.Sprintf(TagIDFormat, configuration.Name, tag.ID, count)
tagID := builder.GenerateTagID(configuration.Name, tag, count)

err := builder.ParseExpressionNode(
configuration.Name,
Expand Down Expand Up @@ -601,7 +618,7 @@ func (builder *DeviceSimulatorBuilder) ParseFlat(
field := 0
for _, tag := range configuration.Tags {
for count := 0; count < tag.Count; count++ {
tagID := fmt.Sprintf(TagIDFormat, configuration.Name, tag.ID, count)
tagID := builder.GenerateTagID(configuration.Name, tag, count)

err := builder.ParseExpressionNode(
configuration.Name,
Expand Down

0 comments on commit 4344e61

Please sign in to comment.