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

Fixed inconsistencies between listen and emit #943

Closed
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
e1d565a
fix: restrict extra properties
matthias-pichler Jul 18, 2024
ec69fd1
fix: move output to correct level
matthias-pichler Jul 18, 2024
cd7a0b9
fix: examples in dsl-reference
matthias-pichler Jul 18, 2024
93dcd34
fix: add even more property checks
matthias-pichler Jul 18, 2024
21eac79
Merge branch 'main' into schema-extra-props
cdavernas Jul 29, 2024
5bf4ad7
Fixed inconsistencies between listen and emit tasks
JBBianchi Aug 2, 2024
e605f67
Adding missing titles for better pojo generation
fjtirado Aug 2, 2024
0579a94
Charles comments
fjtirado Aug 2, 2024
302fe64
Merge branch 'main' into Adding_title_for_auth_schema
fjtirado Aug 2, 2024
333c83c
Merge pull request #944 from fjtirado/Adding_title_for_auth_schema
ricardozanini Aug 2, 2024
2ac77b4
Merge branch 'main' into schema-extra-props
cdavernas Aug 3, 2024
555a0f7
Fix Badges
cdavernas Aug 3, 2024
fcd10fd
Create SECURITY.md
cdavernas Aug 3, 2024
04cd3be
Merge pull request #928 from matthias-pichler-warrify/schema-extra-props
cdavernas Aug 4, 2024
ebd2e10
docs: specify runtime argument
matthias-pichler Aug 4, 2024
821b56f
docs: specify task and workflow arguments
matthias-pichler Aug 4, 2024
233accb
docs: document string substitution feature
matthias-pichler Aug 4, 2024
876bf2c
feat: allow query parameters in call http
matthias-pichler Aug 4, 2024
839492e
fix: remove duplicate uri scheme from error types
matthias-pichler Aug 4, 2024
92562e0
docs: document uri template support
matthias-pichler Aug 5, 2024
caec8ab
fix: broken links
matthias-pichler Aug 5, 2024
97d59e7
Fixed inconsistencies between listen and emit tasks
JBBianchi Aug 2, 2024
7c749d3
Merge branch 'fix-917-semantic-inconsistencies-listen-vs-emit' of htt…
JBBianchi Aug 5, 2024
fceb957
Merge branch 'main' into fix-readme-badges
ricardozanini Aug 6, 2024
34c678b
Merge branch 'main' into feat-security
cdavernas Aug 6, 2024
1ecec3f
Merge pull request #947 from serverlessworkflow/feat-security
cdavernas Aug 6, 2024
0aaead4
Updated Badge styles and text
cdavernas Aug 6, 2024
98d73ee
Merge branch 'main' into fix-readme-badges
cdavernas Aug 6, 2024
f1c32af
Merge pull request #946 from serverlessworkflow/fix-readme-badges
cdavernas Aug 6, 2024
43c3d15
Merge branch 'main' into string-substitution
matthias-pichler Aug 6, 2024
c49c263
Merge branch 'main' into query-params
matthias-pichler Aug 6, 2024
5961814
Merge branch 'main' into runtime-arg
matthias-pichler Aug 6, 2024
52ad683
Merge branch 'main' into fix-error-types
ricardozanini Aug 6, 2024
ca94f62
Merge pull request #957 from matthias-pichler-warrify/fix-error-types
ricardozanini Aug 6, 2024
624d402
Merge branch 'main' into workflow-task-arg
ricardozanini Aug 6, 2024
7fcc3ca
Merge pull request #953 from matthias-pichler-warrify/workflow-task-arg
ricardozanini Aug 6, 2024
808d72b
Merge branch 'main' into string-substitution
ricardozanini Aug 6, 2024
434e0eb
Merge pull request #955 from matthias-pichler-warrify/string-substitu…
ricardozanini Aug 6, 2024
85c43c8
Merge branch 'main' into query-params
ricardozanini Aug 6, 2024
538a0a6
Merge pull request #956 from matthias-pichler-warrify/query-params
ricardozanini Aug 6, 2024
0ea6dcb
Merge branch 'main' into runtime-arg
matthias-pichler Aug 6, 2024
151392d
Merge pull request #952 from matthias-pichler-warrify/runtime-arg
cdavernas Aug 6, 2024
b7236c8
Fixed inconsistencies between listen and emit tasks
JBBianchi Aug 2, 2024
87758fc
Merge branch 'fix-917-semantic-inconsistencies-listen-vs-emit' of htt…
JBBianchi Aug 7, 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
2 changes: 1 addition & 1 deletion ctk/features/set.feature
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ Feature: Set Task
I want to ensure that set tasks can be executed within the workflow
So that my implementation conforms to the expected behavior

# Tests emit tasks
# Tests set tasks
Scenario: Set Task
Given a workflow with definition:
"""yaml
Expand Down
81 changes: 58 additions & 23 deletions dsl-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@
+ [Shell](#shell-process)
+ [Script](#script-process)
+ [Workflow](#workflow-process)
- [Switch](#switch)
- [Set](#set)
- [Switch](#switch)
- [Try](#try)
- [Wait](#wait)
+ [Flow Directive](#flow-directive)
Expand All @@ -42,6 +42,7 @@
- [Standard Error Types](#standard-error-types)
+ [Event Consumption Strategy](#event-consumption-strategy)
+ [Event Filter](#event-filter)
+ [Event Properties](#event-properties)
+ [Retry](#retry)
+ [Input](#input)
+ [Output](#output)
Expand Down Expand Up @@ -229,9 +230,9 @@ The Serverless Workflow DSL defines a list of [tasks](#task) that **must be** su
- [Call](#call), used to call services and/or functions.
- [Do](#do), used to define one or more subtasks to perform in sequence.
- [Fork](#fork), used to define one or more subtasks to perform concurrently.
- [Emit](#emit), used to emit [events](#event).
- [Emit](#emit), used to emit [events](#event-properties).
- [For](#for), used to iterate over a collection of items, and conditionally perform a task for each of them.
- [Listen](#listen), used to listen for an [event](#event) or more.
- [Listen](#listen), used to listen for an [event](#event-properties) or more.
- [Raise](#raise), used to raise an [error](#error) and potentially fault the [workflow](#workflow).
- [Run](#run), used to run a [container](#container-process), a [script](#script-process) , a [shell](#shell-process) command or even another [workflow](#workflow-process).
- [Switch](#switch), used to dynamically select and execute one of multiple alternative paths based on specified conditions
Expand Down Expand Up @@ -368,7 +369,7 @@ The [HTTP Call](#http-call) enables workflows to interact with external services
| Name | Type | Required | Description|
|:--|:---:|:---:|:---|
| method | `string` | `yes` | The HTTP request method. |
| endpoint | [`endpoint`](#endpoint) | `yes` | An URI or an object that describes the HTTP endpoint to call. |
| endpoint | `string`\|[`endpoint`](#endpoint) | `yes` | An URI or an object that describes the HTTP endpoint to call. |
cdavernas marked this conversation as resolved.
Show resolved Hide resolved
| headers | `map` | `no` | A name/value mapping of the HTTP headers to use, if any. |
| body | `any` | `no` | The HTTP request body, if any. |
| output | `string` | `no` | The http call's output format.<br>*Supported values are:*<br>*- `raw`, which output's the base-64 encoded [http response](#http-response) content, if any.*<br>*- `content`, which outputs the content of [http response](#http-response), possibly deserialized.*<br>*- `response`, which outputs the [http response](#http-response).*<br>*Defaults to `content`.* |
Expand Down Expand Up @@ -494,7 +495,7 @@ Allows workflows to publish events to event brokers or messaging systems, facili

| Name | Type | Required | Description |
|:--|:---:|:---:|:---|
| emit.event | [`event`](#event) | `yes` | Defines the event to emit. |
| emit.event | [`eventProperties`](#event-properties) | `yes` | Defines the event to emit. |

##### Examples

Expand All @@ -508,15 +509,16 @@ do:
- emitEvent:
emit:
event:
source: https://petstore.com
type: com.petstore.order.placed.v1
data:
client:
firstName: Cruella
lastName: de Vil
items:
- breed: dalmatian
quantity: 101
with:
source: https://petstore.com
type: com.petstore.order.placed.v1
data:
client:
firstName: Cruella
lastName: de Vil
items:
- breed: dalmatian
quantity: 101
```

#### For
Expand All @@ -528,9 +530,9 @@ Allows workflows to iterate over a collection of items, executing a defined set
| Name | Type | Required | Description|
|:--|:---:|:---:|:---|
| for.each | `string` | `no` | The name of the variable used to store the current item being enumerated.<br>Defaults to `item`. |
| for.in | `string` | `yes` | A [runtime expression](#runtime-expressions) used to get the collection to enumerate. |
| for.in | `string` | `yes` | A [runtime expression](dsl.md#runtime-expressions) used to get the collection to enumerate. |
| for.at | `string` | `no` | The name of the variable used to store the index of the current item being enumerated.<br>Defaults to `index`. |
| while | `string` | `no` | A [runtime expression](#runtime-expressions) that represents the condition, if any, that must be met for the iteration to continue. |
| while | `string` | `no` | A [runtime expression](dsl.md#runtime-expressions) that represents the condition, if any, that must be met for the iteration to continue. |
| do | [`task`](#task) | `yes` | The task to perform for each item in the collection. |

##### Examples
Expand All @@ -555,8 +557,8 @@ do:
one:
with:
type: com.fake.petclinic.pets.checkup.completed.v2
output:
as: '.pets + [{ "id": $pet.id }]'
output:
as: '.pets + [{ "id": $pet.id }]'
```

#### Fork
Expand Down Expand Up @@ -964,7 +966,7 @@ do:

##### Switch Case

Defines a switch case, encompassing of a condition for matching and an associated action to execute upon a match.
Defines a switch case, encompassing a condition for matching and an associated action to execute upon a match.

| Name | Type | Required | Description |
|:--|:---:|:---:|:---|
Expand Down Expand Up @@ -1113,7 +1115,7 @@ document:
use:
secrets:
- usernamePasswordSecret
authentication:
authentications:
sampleBasicFromSecret:
basic:
use: usernamePasswordSecret
Expand Down Expand Up @@ -1389,6 +1391,28 @@ Represents the configuration of an event consumption strategy.
| any | [`eventFilter[]`](#event-filter) | `no` | Configures the workflow to wait for any of the defined events before resuming execution.<br>*Required if `all` and `one` have not been set.* |
| one | [`eventFilter`](#event-filter) | `no` | Configures the workflow to wait for the defined event before resuming execution.<br>*Required if `all` and `any` have not been set.* |

### Event Properties
cdavernas marked this conversation as resolved.
Show resolved Hide resolved

An event object typically includes details such as the event type, source, timestamp, and unique identifier along with any relevant data payload. The [Cloud Events specification](https://cloudevents.io/), favored by Serverless Workflow, standardizes this structure to ensure interoperability across different systems and services.

#### Properties

| Property | Type | Required | Description |
|----------|:----:|:--------:|-------------|
| id | `string` | `no` | Identifies the event. `source` + `id` is unique for each distinct event.<br>*Required when emitting an event using `emit.event.with`.* |
| source | `string` | `no` | An URI formatted string, or [runtime expression](dsl.md#runtime-expressions), that identifies the context in which an event happened. `source` + `id` is unique for each distinct event.<br>*Required when emitting an event using `emit.event.with`.* |
| type | `string` | `no` | Describes the type of event related to the originating occurrence.<br>*Required when emitting an event using `emit.event.with`.* |
| time | `string` | `no` | A string, or [runtime expression](dsl.md#runtime-expressions), representing the timestamp of when the occurrence happened. |
| subject | `string` | `no` | Describes the subject of the event in the context of the event producer. |
| datacontenttype | `string` | `no` | Content type of `data` value. If omitted, it implies the `data` is a JSON value conforming to the "application/json" media type. |
| dataschema | `string` | `no` | An URI formatted string, or [runtime expression](dsl.md#runtime-expressions), that identifies the schema that `data` adheres to. |
| data | `object` | `no` | The event payload. |

*Additional properties can be supplied, see the Cloud Events specification [documentation](https://github.com/cloudevents/spec/blob/main/cloudevents/spec.md#extension-context-attributes) for more info.*

*When used in an [`eventFilter`](#event-filter), at least one property must be supplied.*


### Event Filter

An event filter is a mechanism used to selectively process or handle events based on predefined criteria, such as event type, source, or specific attributes.
Expand All @@ -1397,7 +1421,7 @@ An event filter is a mechanism used to selectively process or handle events base

| Property | Type | Required | Description |
|----------|:----:|:--------:|-------------|
| with | `object` | `yes` | A name/value mapping of the attributes filtered events must define. Supports both regular expressions and runtime expressions. |
| with | [`eventProperties`](#event-properties) | `yes` | A name/value mapping of the attributes filtered events must define. Supports both regular expressions and runtime expressions. |
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought I was getting crazy since I couldn't see my previous comments from the other PR. Now I see you reopened it.

Regarding this property, since we are now defining that it can be regexp, runtime expressions, or eventProperties, this should reflect in the schema.

So this with should be an OneOf there amongst these types.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for the mix-up. When I rebased the branch, GitHub closed my previous PR. I opened a new one and realized afterward that I could have simply reopened the previous one after I readded my commits.

I might be mistaken, but I was under the impression that the statement "Supports both regular expressions and runtime expressions" applies to the properties of with, not the object itself. That said, there might be room for discussion about how and where we can use a runtime expression to construct an entire object, but that might be a broader topic than what is addressed in this PR.

@cdavernas @fjtirado @matthias-pichler-warrify, what are your thoughts on this?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would understand this to mean that the individual properties under with (such as id, source, ...) should each support literals, regex and runtime expressions. These are all strings so we would just produce a union of type string | string | string which doesn't seem necessary.
I would keep the with object an object.

regarding regular expressions: How would an implementor determine if a given string is a literal or a regular expression though?

For example if the filter was specified as

with:
  type: com.example  

if the string was interpreted as a literal only com.example would match. As a regex comaexample and com.example.foo would also match! Are we planning on adding a regex syntax (JSON schema support the ECMA 262 syntax with format: regex) or object? Like

with:
  type:
    re: ^com\.example

# or

with:
  type: /com\.example/

Maybe we should just stick to runtime expressions and use the test function: https://jqlang.github.io/jq/manual/#regular-expressions ?

with:
  source: ${ test(., "^com\\.example$") }

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a good point. It's a very specific pain point considering regular expressions are only supported in listen tasks event filters.

My understanding was that the value was either a string or a runtime expression. If it's a string, then it's regarded as a regular expression (regexp). But it's not very clear, can introduce undesired matches when not properly escaped, and probably have an bad impact on performance (I would assume string equality to be more performant than regexp, in turn more performant than jq/js expressions.)

For the performance reason I just mentioned (without any proof though, it's only a feeling ^^'), I would rule out relying only on jq/js for processing regexp. Therefore, we need to either consider any string as a regexp or find a way to discriminate the regexp. I must admit I'm not convinced by neither adding a property nor using a specific format but I don't have a better option to suggest. Therefore, I would rather go for the specific format rather than the extra property.

Copy link
Collaborator

@matthias-pichler matthias-pichler Aug 5, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(I would assume string equality to be more performant than regexp, in turn more performant than jq/js expressions.)

My intuition is that the performance difference between string equality and regex matching is negligible compared to jq expressions which are much slower. I however would not have a problem with taking the performance hit and only using runtime expressions

Therefore, I would rather go for the specific format rather than the extra property.

If we support regex I would also say that we should use a format such as /<regex>/. We would however not be able to rely on the format: regex from json schema since this does not have any delimiters

| correlate | [`map[string, correlation]`](#correlation) | `no` | A name/definition mapping of the correlations to attempt when filtering events. |

### Correlation
Expand Down Expand Up @@ -1473,7 +1497,7 @@ When set, runtimes must validate input data against the defined schema, unless d
| Property | Type | Required | Description |
|----------|:----:|:--------:|-------------|
| schema | [`schema`](#schema) | `no` | The [`schema`](#schema) used to describe and validate input data.<br>*Even though the schema is not required, it is strongly encouraged to document it, whenever feasible.* |
| from | `string`<br>`object` | `no` | A [runtime expression](#runtime-expressions), if any, used to filter and/or mutate the workflow/task input. |
| from | `string`<br>`object` | `no` | A [runtime expression](dsl.md#runtime-expressions), if any, used to filter and/or mutate the workflow/task input. |

#### Examples

Expand Down Expand Up @@ -1502,7 +1526,7 @@ When set, runtimes must validate output data against the defined schema, unless
| Property | Type | Required | Description |
|----------|:----:|:--------:|-------------|
| schema | [`schema`](#schema) | `no` | The [`schema`](#schema) used to describe and validate output data.<br>*Even though the schema is not required, it is strongly encouraged to document it, whenever feasible.* |
| as | `string`<br>`object` | `no` | A [runtime expression](#runtime-expressions), if any, used to filter and/or mutate the workflow/task output. |
| as | `string`<br>`object` | `no` | A [runtime expression](dsl.md#runtime-expressions), if any, used to filter and/or mutate the workflow/task output. |

#### Examples

Expand Down Expand Up @@ -1636,6 +1660,17 @@ minutes: 15
seconds: 30
```

### Endpoint

Describes an enpoint.

#### Properties

| Property | Type | Required | Description |
|----------|:----:|:--------:|-------------|
| uri | `string` | `yes` | The endpoint's URI. |
| authentication | `[authentication](#authentication)` | `no` | The authentication policy to use. |

### HTTP Response

Describes an HTTP response.
Expand Down
16 changes: 8 additions & 8 deletions dsl.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ Workflows in the Serverless Workflow DSL can exist in several phases, each indic

Additionally, the flow of execution within a workflow can be controlled using [directives*](dsl-reference.md#flow-directive), which provide instructions to the workflow engine on how to manage and handle specific aspects of workflow execution.

**To learn more about flow directives and how they can be utilized to control the execution and behavior of workflows, please refer to [Flow Directives](dsl-reference.md#flow-directive).*
\**To learn more about flow directives and how they can be utilized to control the execution and behavior of workflows, please refer to [Flow Directives](dsl-reference.md#flow-directive).*
cdavernas marked this conversation as resolved.
Show resolved Hide resolved

#### Components

Expand All @@ -102,14 +102,14 @@ The Serverless Workflow DSL defines several default [task](dsl-reference.md#task

- [Call](dsl-reference.md#call), used to call services and/or functions.
- [Do](dsl-reference.md#do), used to define one or more subtasks to perform in sequence.
- [Fork](dsl-reference.md#fork), used to define one or more two subtasks to perform in parallel.
- [Emit](dsl-reference.md#emit), used to emit [events](dsl-reference.md#event).
- [For](dsl-reference.md#for), used to iterate over a collection of items, and conditionally perform a task for each of them.
- [Fork](dsl-reference.md#fork), used to define one or more two subtasks to perform in parallel.
- [Listen](dsl-reference.md#listen), used to listen for an [event](dsl-reference.md#event) or more.
- [Raise](dsl-reference.md#raise), used to raise an [error](dsl-reference.md#error) and potentially fault the [workflow](dsl-reference.md#workflow).
- [Run](dsl-reference.md#run), used to run a [container](dsl-reference.md#container-process), a [script](dsl-reference.md#script-process), a [shell](dsl-reference.md#shell-process) command or even another [workflow](dsl-reference.md#workflow-process).
- [Switch](dsl-reference.md#switch), used to dynamically select and execute one of multiple alternative paths based on specified conditions
- [Set](dsl-reference.md#set), used to dynamically set or update the [workflow](dsl-reference.md#workflow)'s data during the its execution.
- [Switch](dsl-reference.md#switch), used to dynamically select and execute one of multiple alternative paths based on specified conditions
- [Try](dsl-reference.md#try), used to attempt executing a specified [task](dsl-reference.md#task), and to handle any resulting [errors](dsl-reference.md#error) gracefully, allowing the [workflow](dsl-reference.md#workflow) to continue without interruption.
- [Wait](dsl-reference.md#wait), used to pause or wait for a specified duration before proceeding to the next task.

Expand Down Expand Up @@ -138,7 +138,7 @@ A workflow begins with the first task defined.

Once the task has been executed, different things can happen:

- `continue`: the task ran to completion, and the next task, if any, should be executed. The task to run next is implictly the next in declaration order, or explicitly defined by the `then` property of the executed task. If the executed task is the last task, then the workflow's execution gracefully ends.
- `continue`: the task ran to completion, and the next task, if any, should be executed. The task to run next is implicitly the next in declaration order, or explicitly defined by the `then` property of the executed task. If the executed task is the last task, then the workflow's execution gracefully ends.
- `fault`: the task raised an uncaught error, which abruptly halts the workflow's execution and makes it transition to `faulted` [status phase](#status-phases).
- `end`: the task explicitly and gracefully ends the workflow's execution.

Expand Down Expand Up @@ -196,7 +196,7 @@ Runtimes **may** optionally support other runtime expression languages, which au

CloudFlows defines [several arguments](#runtime-expression-arguments) that runtimes **must** provide during the evaluation of runtime expressions.

When the evaluation of an expression fails, runtimes **must** raise an error with type `https://https://serverlessworkflow.io/spec/1.0.0/errors/expression` and status `400`.
When the evaluation of an expression fails, runtimes **must** raise an error with type `https://serverlessworkflow.io/spec/1.0.0/errors/expression` and status `400`.

#### Runtime expression arguments

Expand All @@ -220,7 +220,7 @@ Errors in Serverless Workflow are described using the [Problem Details RFC](http

*Example error:*
```yaml
type: https://https://serverlessworkflow.io/spec/1.0.0/errors/communication
type: https://serverlessworkflow.io/spec/1.0.0/errors/communication
title: Service Unavailable
status: 503
detail: The service is currently unavailable. Please try again later.
Expand Down Expand Up @@ -263,7 +263,7 @@ Workflows and tasks alike can be configured to timeout after a defined amount of

When a timeout occur, runtimes **must** abruptly interrupt the execution of the workflow/task, and **must** raise an error that, if uncaught, force the workflow/task to transition to the [`faulted` status phase](#status-phases).

A timeout error **must** have its `type` set to `https://https://serverlessworkflow.io/spec/1.0.0/errors/timeout` and **should** have its `status` set to `408`.
A timeout error **must** have its `type` set to `https://serverlessworkflow.io/spec/1.0.0/errors/timeout` and **should** have its `status` set to `408`.

### Interoperability

Expand All @@ -275,7 +275,7 @@ Serverless Workflow DSL is designed to seamlessly interact with a variety of ser
- [**AsyncAPI**](dsl-reference.md#asyncapi-call): Facilitates interaction with asynchronous messaging protocols. AsyncAPI is designed for event-driven architectures, allowing workflows to publish and subscribe to events.
- [**OpenAPI**](dsl-reference.md#openapi-call): Enables communication with services that provide OpenAPI specifications, which is useful for defining and consuming RESTful APIs.

Runtimes **must** raise an error with type `https://https://serverlessworkflow.io/spec/1.0.0/errors/communication` if and when a problem occurs during a call.
Runtimes **must** raise an error with type `https://serverlessworkflow.io/spec/1.0.0/errors/communication` if and when a problem occurs during a call.

#### Custom and Non-Standard Interactions

Expand Down
6 changes: 2 additions & 4 deletions examples/accumulate-room-readings.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,14 @@ do:
correlate:
roomId:
from: .roomid
output:
as: .data.reading
- with:
source: https://my.home.com/sensor
type: my.home.sensors.humidity
correlate:
roomId:
from: .roomid
output:
as: .data.reading
output:
as: .data.reading
- logReading:
for:
each: reading
Expand Down
Loading
Loading