Closed lolodomo closed 1 month ago
For the following action
@RuleAction(label = "test", description = "Test action")
public @ActionOutput(name = "result", label = "Test result", type = "java.lang.Integer") int testAction(
@ActionInput(name = "booleanParam1", label = "@text/rule.testAction.param.booleanParam1.label", required = true, description = "@text/rule.testAction.param.booleanParam1.description") boolean booleanParam1,
@ActionInput(name = "booleanParam2", label = "Boolean parameter 2", required = false, description = "Descr Boolean parameter 1") @Nullable Boolean booleanParam2,
@ActionInput(name = "booleanParam3", label = "Boolean parameter 3", required = true, description = "Descr Boolean parameter 2") Boolean booleanParam3,
@ActionInput(name = "intParam", label = "int parameter", required = true, description = "Descr int parameter") int intParam,
@ActionInput(name = "integerParam", label = "Integer parameter", description = "Descr Integer parameter") @Nullable Integer integerParam,
@ActionInput(name = "longParam1", label = "long parameter", required = true, description = "Descr long parameter") long longParam1,
@ActionInput(name = "longParam2", label = "Long parameter", description = "Descr Long parameter") @Nullable Long longParam2,
@ActionInput(name = "doubleParam1", label = "double parameter", required = true, description = "Descr double parameter") double doubleParam1,
@ActionInput(name = "doubleParam2", label = "Double parameter", description = "Descr Double parameter") @Nullable Double doubleParam2,
@ActionInput(name = "numberParam", label = "Number parameter", description = "Descr Number parameter") @Nullable Number numberParam,
@ActionInput(name = "stringParam", label = "String parameter", description = "Descr String parameter") @Nullable String stringParam,
@ActionInput(name = "decimalTypeParam", label = "DecimalType parameter", description = "Descr DecimalType parameter") @Nullable DecimalType decimalTypeParam,
@ActionInput(name = "localDateParam", label = "LocalDate parameter", description = "Descr LocalDate parameter") @Nullable LocalDate localDateParam,
@ActionInput(name = "localTimeParam", label = "LocalTime parameter", description = "Descr LocalTime parameter") @Nullable LocalTime localTimeParam,
@ActionInput(name = "localDateTimeParam", label = "LocalDateTime parameter", description = "Descr LocalDateTime parameter") @Nullable LocalDateTime localDateTimeParam,
@ActionInput(name = "zonedDateTimeParam", label = "ZonedDateTime parameter", description = "Descr ZonedDateTime parameter") @Nullable ZonedDateTime zonedDateTimeParam,
@ActionInput(name = "dateParam", label = "Date parameter", description = "Descr Date parameter") @Nullable Date dateParam,
@ActionInput(name = "instantParam", label = "Instant parameter", description = "Descr Instant parameter") @Nullable Instant instantParam,
@ActionInput(name = "durationParam", label = "Duration parameter", description = "Descr Duration parameter") @Nullable Duration durationParam,
@ActionInput(name = "quantityTemperatureParam", label = "QuantityType<Temperature> parameter", description = "Descr QuantityType<Temperature> parameter", type = "QuantityType<Temperature>") @Nullable QuantityType<Temperature> quantityTemperatureParam,
@ActionInput(name = "quantityPowerParam", label = "QuantityType<Power> parameter", description = "Descr QuantityType<Power> parameter", type = "org.openhab.core.library.types.QuantityType<javax.measure.quantity.Power>") @Nullable QuantityType<Power> quantityPowerParam) {
logger.info(
"testAction booleanParam1 = {}, booleanParam2 = {}, booleanParam3 = {}, intParam = {}, integerParam = {}, longParam1 = {}, longParam2 = {}, doubleParam1 = {}, doubleParam2 = {}, numberParam = {}, stringParam = {}, decimalTypeParam = {}, localDateParam = {}, localTimeParam = {}, localDateTimeParam = {}, zonedDateTimeParam = {}, dateParam = {}, instantParam = {}, durationParam = {}, quantityTemperatureParam = {}, quantityPowerParam = {}",
booleanParam1, booleanParam2, booleanParam3, intParam, integerParam, longParam1, longParam2,
doubleParam1, doubleParam2, numberParam, stringParam, decimalTypeParam, localDateParam, localTimeParam,
localDateTimeParam, zonedDateTimeParam, dateParam, instantParam, durationParam,
quantityTemperatureParam, quantityPowerParam);
return 256;
}
The GET API now returns:
[
{
"actionUid": "astro.testAction",
"label": "test",
"description": "Test action",
"inputs": [
{
"name": "booleanParam1",
"type": "boolean",
"label": "Paramêtre boolean",
"description": "Un paramêtre booléen",
"required": true,
"tags": [],
"reference": "",
"defaultValue": ""
},
{
"name": "booleanParam2",
"type": "java.lang.Boolean",
"label": "Boolean parameter 2",
"description": "Descr Boolean parameter 1",
"required": false,
"tags": [],
"reference": "",
"defaultValue": ""
},
{
"name": "booleanParam3",
"type": "java.lang.Boolean",
"label": "Boolean parameter 3",
"description": "Descr Boolean parameter 2",
"required": true,
"tags": [],
"reference": "",
"defaultValue": ""
},
{
"name": "intParam",
"type": "int",
"label": "int parameter",
"description": "Descr int parameter",
"required": true,
"tags": [],
"reference": "",
"defaultValue": ""
},
{
"name": "integerParam",
"type": "java.lang.Integer",
"label": "Integer parameter",
"description": "Descr Integer parameter",
"required": false,
"tags": [],
"reference": "",
"defaultValue": ""
},
{
"name": "longParam1",
"type": "long",
"label": "long parameter",
"description": "Descr long parameter",
"required": true,
"tags": [],
"reference": "",
"defaultValue": ""
},
{
"name": "longParam2",
"type": "java.lang.Long",
"label": "Long parameter",
"description": "Descr Long parameter",
"required": false,
"tags": [],
"reference": "",
"defaultValue": ""
},
{
"name": "doubleParam1",
"type": "double",
"label": "double parameter",
"description": "Descr double parameter",
"required": true,
"tags": [],
"reference": "",
"defaultValue": ""
},
{
"name": "doubleParam2",
"type": "java.lang.Double",
"label": "Double parameter",
"description": "Descr Double parameter",
"required": false,
"tags": [],
"reference": "",
"defaultValue": ""
},
{
"name": "numberParam",
"type": "java.lang.Number",
"label": "Number parameter",
"description": "Descr Number parameter",
"required": false,
"tags": [],
"reference": "",
"defaultValue": ""
},
{
"name": "stringParam",
"type": "java.lang.String",
"label": "String parameter",
"description": "Descr String parameter",
"required": false,
"tags": [],
"reference": "",
"defaultValue": ""
},
{
"name": "decimalTypeParam",
"type": "org.openhab.core.library.types.DecimalType",
"label": "DecimalType parameter",
"description": "Descr DecimalType parameter",
"required": false,
"tags": [],
"reference": "",
"defaultValue": ""
},
{
"name": "localDateParam",
"type": "java.time.LocalDate",
"label": "LocalDate parameter",
"description": "Descr LocalDate parameter",
"required": false,
"tags": [],
"reference": "",
"defaultValue": ""
},
{
"name": "localTimeParam",
"type": "java.time.LocalTime",
"label": "LocalTime parameter",
"description": "Descr LocalTime parameter",
"required": false,
"tags": [],
"reference": "",
"defaultValue": ""
},
{
"name": "localDateTimeParam",
"type": "java.time.LocalDateTime",
"label": "LocalDateTime parameter",
"description": "Descr LocalDateTime parameter",
"required": false,
"tags": [],
"reference": "",
"defaultValue": ""
},
{
"name": "zonedDateTimeParam",
"type": "java.time.ZonedDateTime",
"label": "ZonedDateTime parameter",
"description": "Descr ZonedDateTime parameter",
"required": false,
"tags": [],
"reference": "",
"defaultValue": ""
},
{
"name": "dateParam",
"type": "java.util.Date",
"label": "Date parameter",
"description": "Descr Date parameter",
"required": false,
"tags": [],
"reference": "",
"defaultValue": ""
},
{
"name": "instantParam",
"type": "java.time.Instant",
"label": "Instant parameter",
"description": "Descr Instant parameter",
"required": false,
"tags": [],
"reference": "",
"defaultValue": ""
},
{
"name": "durationParam",
"type": "java.time.Duration",
"label": "Duration parameter",
"description": "Descr Duration parameter",
"required": false,
"tags": [],
"reference": "",
"defaultValue": ""
},
{
"name": "quantityTemperatureParam",
"type": "QuantityType<Temperature>",
"label": "QuantityType<Temperature> parameter",
"description": "Descr QuantityType<Temperature> parameter",
"required": false,
"tags": [],
"reference": "",
"defaultValue": ""
},
{
"name": "quantityPowerParam",
"type": "org.openhab.core.library.types.QuantityType<javax.measure.quantity.Power>",
"label": "QuantityType<Power> parameter",
"description": "Descr QuantityType<Power> parameter",
"required": false,
"tags": [],
"reference": "",
"defaultValue": ""
}
],
"inputConfigDescriptions": [
{
"default": "false",
"description": "Un paramêtre booléen",
"label": "Paramêtre boolean",
"name": "booleanParam1",
"required": true,
"type": "BOOLEAN",
"readOnly": false,
"multiple": false,
"advanced": false,
"verify": false,
"limitToOptions": true,
"options": [],
"filterCriteria": []
},
{
"description": "Descr Boolean parameter 1",
"label": "Boolean parameter 2",
"name": "booleanParam2",
"required": false,
"type": "BOOLEAN",
"readOnly": false,
"multiple": false,
"advanced": false,
"verify": false,
"limitToOptions": true,
"options": [],
"filterCriteria": []
},
{
"description": "Descr Boolean parameter 2",
"label": "Boolean parameter 3",
"name": "booleanParam3",
"required": true,
"type": "BOOLEAN",
"readOnly": false,
"multiple": false,
"advanced": false,
"verify": false,
"limitToOptions": true,
"options": [],
"filterCriteria": []
},
{
"default": "0",
"description": "Descr int parameter",
"label": "int parameter",
"name": "intParam",
"required": true,
"type": "INTEGER",
"readOnly": false,
"multiple": false,
"advanced": false,
"verify": false,
"limitToOptions": true,
"options": [],
"filterCriteria": []
},
{
"description": "Descr Integer parameter",
"label": "Integer parameter",
"name": "integerParam",
"required": false,
"type": "INTEGER",
"readOnly": false,
"multiple": false,
"advanced": false,
"verify": false,
"limitToOptions": true,
"options": [],
"filterCriteria": []
},
{
"default": "0",
"description": "Descr long parameter",
"label": "long parameter",
"name": "longParam1",
"required": true,
"type": "INTEGER",
"readOnly": false,
"multiple": false,
"advanced": false,
"verify": false,
"limitToOptions": true,
"options": [],
"filterCriteria": []
},
{
"description": "Descr Long parameter",
"label": "Long parameter",
"name": "longParam2",
"required": false,
"type": "INTEGER",
"readOnly": false,
"multiple": false,
"advanced": false,
"verify": false,
"limitToOptions": true,
"options": [],
"filterCriteria": []
},
{
"default": "0",
"description": "Descr double parameter",
"label": "double parameter",
"name": "doubleParam1",
"required": true,
"type": "DECIMAL",
"readOnly": false,
"multiple": false,
"advanced": false,
"verify": false,
"limitToOptions": true,
"options": [],
"filterCriteria": []
},
{
"description": "Descr Double parameter",
"label": "Double parameter",
"name": "doubleParam2",
"required": false,
"type": "DECIMAL",
"readOnly": false,
"multiple": false,
"advanced": false,
"verify": false,
"limitToOptions": true,
"options": [],
"filterCriteria": []
},
{
"description": "Descr Number parameter",
"label": "Number parameter",
"name": "numberParam",
"required": false,
"type": "DECIMAL",
"readOnly": false,
"multiple": false,
"advanced": false,
"verify": false,
"limitToOptions": true,
"options": [],
"filterCriteria": []
},
{
"description": "Descr String parameter",
"label": "String parameter",
"name": "stringParam",
"required": false,
"type": "TEXT",
"readOnly": false,
"multiple": false,
"advanced": false,
"verify": false,
"limitToOptions": true,
"options": [],
"filterCriteria": []
},
{
"description": "Descr DecimalType parameter",
"label": "DecimalType parameter",
"name": "decimalTypeParam",
"required": false,
"type": "DECIMAL",
"readOnly": false,
"multiple": false,
"advanced": false,
"verify": false,
"limitToOptions": true,
"options": [],
"filterCriteria": []
},
{
"context": "date",
"description": "Descr LocalDate parameter",
"label": "LocalDate parameter",
"name": "localDateParam",
"required": false,
"type": "TEXT",
"readOnly": false,
"multiple": false,
"advanced": false,
"verify": false,
"limitToOptions": true,
"options": [],
"filterCriteria": []
},
{
"context": "time",
"description": "Descr LocalTime parameter",
"label": "LocalTime parameter",
"name": "localTimeParam",
"required": false,
"type": "TEXT",
"readOnly": false,
"multiple": false,
"advanced": false,
"verify": false,
"limitToOptions": true,
"options": [],
"filterCriteria": []
},
{
"context": "datetime",
"description": "Descr LocalDateTime parameter",
"label": "LocalDateTime parameter",
"name": "localDateTimeParam",
"required": false,
"type": "TEXT",
"readOnly": false,
"multiple": false,
"advanced": false,
"verify": false,
"limitToOptions": true,
"options": [],
"filterCriteria": []
},
{
"description": "Descr ZonedDateTime parameter",
"label": "ZonedDateTime parameter",
"name": "zonedDateTimeParam",
"required": false,
"type": "TEXT",
"readOnly": false,
"multiple": false,
"advanced": false,
"verify": false,
"limitToOptions": true,
"options": [],
"filterCriteria": []
},
{
"context": "datetime",
"description": "Descr Date parameter",
"label": "Date parameter",
"name": "dateParam",
"required": false,
"type": "TEXT",
"readOnly": false,
"multiple": false,
"advanced": false,
"verify": false,
"limitToOptions": true,
"options": [],
"filterCriteria": []
},
{
"description": "Descr Instant parameter",
"label": "Instant parameter",
"name": "instantParam",
"required": false,
"type": "TEXT",
"readOnly": false,
"multiple": false,
"advanced": false,
"verify": false,
"limitToOptions": true,
"options": [],
"filterCriteria": []
},
{
"description": "Descr Duration parameter",
"label": "Duration parameter",
"name": "durationParam",
"required": false,
"type": "TEXT",
"readOnly": false,
"multiple": false,
"advanced": false,
"verify": false,
"limitToOptions": true,
"options": [],
"filterCriteria": []
},
{
"description": "Descr QuantityType<Temperature> parameter",
"label": "QuantityType<Temperature> parameter",
"name": "quantityTemperatureParam",
"required": false,
"type": "DECIMAL",
"readOnly": false,
"multiple": false,
"advanced": false,
"verify": false,
"limitToOptions": true,
"unit": "℃",
"options": [],
"filterCriteria": []
},
{
"description": "Descr QuantityType<Power> parameter",
"label": "QuantityType<Power> parameter",
"name": "quantityPowerParam",
"required": false,
"type": "DECIMAL",
"readOnly": false,
"multiple": false,
"advanced": false,
"verify": false,
"limitToOptions": true,
"unit": "W",
"options": [],
"filterCriteria": []
}
],
"outputs": []
}
]
An example with the POST API using these input values in API explorer:
{
"booleanParam1": true, "booleanParam2": false, "booleanParam3": true,
"intParam": 128, "integerParam": 256,
"longParam1": 1000, "longParam2": 123456,
"doubleParam1": 123.456, "doubleParam2": 456.789, "numberParam": 789.012,
"stringParam": "Test Value",
"decimalTypeParam": 10.25, "localDateParam": "2024-08-31", "localTimeParam": "08:30:55",
"localDateTimeParam": "2024-07-01 20:30:45", "zonedDateTimeParam": "2007-12-03T10:15:30+01:00[Europe/Paris]",
"dateParam": "2024-11-05 09:45:12", "instantParam": "2017-12-09T20:15:30.00Z",
"durationParam": "P2DT17H25M30.5S",
"quantityTemperatureParam": 19.7, "quantityPowerParam": 50.5
}
The logs:
19:25:20.244 [DEBUG] [dule.handler.AnnotationActionHandler] - Calling action method testAction with the following arguments:
19:25:20.245 [DEBUG] [dule.handler.AnnotationActionHandler] - - Argument 1: type java.lang.Boolean value true
19:25:20.245 [DEBUG] [dule.handler.AnnotationActionHandler] - - Argument 2: type java.lang.Boolean value false
19:25:20.245 [DEBUG] [dule.handler.AnnotationActionHandler] - - Argument 3: type java.lang.Boolean value true
19:25:20.245 [DEBUG] [dule.handler.AnnotationActionHandler] - - Argument 4: type java.lang.Integer value 128
19:25:20.245 [DEBUG] [dule.handler.AnnotationActionHandler] - - Argument 5: type java.lang.Integer value 256
19:25:20.246 [DEBUG] [dule.handler.AnnotationActionHandler] - - Argument 6: type java.lang.Long value 1000
19:25:20.246 [DEBUG] [dule.handler.AnnotationActionHandler] - - Argument 7: type java.lang.Long value 123456
19:25:20.246 [DEBUG] [dule.handler.AnnotationActionHandler] - - Argument 8: type java.lang.Double value 123.456
19:25:20.246 [DEBUG] [dule.handler.AnnotationActionHandler] - - Argument 9: type java.lang.Double value 456.789
19:25:20.246 [DEBUG] [dule.handler.AnnotationActionHandler] - - Argument 10: type java.lang.Double value 789.012
19:25:20.246 [DEBUG] [dule.handler.AnnotationActionHandler] - - Argument 11: type java.lang.String value Test Value
19:25:20.246 [DEBUG] [dule.handler.AnnotationActionHandler] - - Argument 12: type org.openhab.core.library.types.DecimalType value 10.25
19:25:20.247 [DEBUG] [dule.handler.AnnotationActionHandler] - - Argument 13: type java.time.LocalDate value 2024-08-31
19:25:20.247 [DEBUG] [dule.handler.AnnotationActionHandler] - - Argument 14: type java.time.LocalTime value 08:30:55
19:25:20.247 [DEBUG] [dule.handler.AnnotationActionHandler] - - Argument 15: type java.time.LocalDateTime value 2024-07-01T20:30:45
19:25:20.247 [DEBUG] [dule.handler.AnnotationActionHandler] - - Argument 16: type java.time.ZonedDateTime value 2007-12-03T10:15:30+01:00[Europe/Paris]
19:25:20.247 [DEBUG] [dule.handler.AnnotationActionHandler] - - Argument 17: type java.util.Date value Tue Nov 05 09:45:12 CET 2024
19:25:20.247 [DEBUG] [dule.handler.AnnotationActionHandler] - - Argument 18: type java.time.Instant value 2017-12-09T20:15:30Z
19:25:20.248 [DEBUG] [dule.handler.AnnotationActionHandler] - - Argument 19: type java.time.Duration value PT65H25M30.5S
19:25:20.250 [DEBUG] [dule.handler.AnnotationActionHandler] - - Argument 20: type org.openhab.core.library.types.QuantityType value 19.7 °C
19:25:20.250 [DEBUG] [dule.handler.AnnotationActionHandler] - - Argument 21: type org.openhab.core.library.types.QuantityType value 50.5 W
19:25:20.251 [INFO ] [g.astro.internal.action.AstroActions] - testAction booleanParam1 = true, booleanParam2 = false, booleanParam3 = true, intParam = 128, integerParam = 256, longParam1 = 1000, longParam2 = 123456, doubleParam1 = 123.456, doubleParam2 = 456.789, numberParam = 789.012, stringParam = Test Value, decimalTypeParam = 10.25, localDateParam = 2024-08-31, localTimeParam = 08:30:55, localDateTimeParam = 2024-07-01T20:30:45, zonedDateTimeParam = 2007-12-03T10:15:30+01:00[Europe/Paris], dateParam = Tue Nov 05 09:45:12 CET 2024, instantParam = 2017-12-09T20:15:30Z, durationParam = PT65H25M30.5S, quantityTemperatureParam = 19.7 °C, quantityPowerParam = 50.5 W
And the returned response body:
{
"result": 256
}
@lolodomo The /rest/module-types
endpoint also needs to provide these config descriptions for Thing action modules, so Thing actions can be invoked from rules.
I don't understand, Thing actions can already be invoked from rules. ???
After reading #1745 completely, yes they could in theory - the problem is however the same we attempt to fix with this PR: The Thing action module types only contain the inputs like the /actions
endpoint, which makes it impossible for the UI to allow the user to provide the required inputs.
@lolodomo Please do not force push from now on - I will start working on your PR as well and create a PR to your PR branch afterwards.
@lolodomo I have created https://github.com/lolodomo/openhab-core/pull/3, which adds support for invoking Thing actions through UI-based rules. Please merge it with rebase merge to keep commit history. If you want me to do so I can also take over the remaining work on this topic.
Thanks for integrating my changes ... now we have to update the PR description:
Fixes #1745.
Return config description parameters for the ActionInputs of ThingActions for the REST GET /action/{thingUID}
and REST GET /module-types
endpoints.
The config description parameters are only provided if all input parameters have a type that can be mapped to a config description parameter.
Enhance the REST POST /actions/{thingUID}/{actionUid}
endpoint (allows invoking Thing actions via REST) and the AnnotationActionHandler
(allows invoking Thing actions from UI-rules) in order to be more flexible regarding the type of each provided argument value and to map the value to the expected data type.
This will be used by the UI's Thing page and rule editor to allow invoking Thing actions through the UI or adding them to UI-bases rules.
When PR is ready for review, I will squash everything, provide a proper description and mention you as co-author.
@florian-h05 : I believe it is almost ready now. Can you please have a look to my last commits before I squash everything and update the 2 first messages ?
I am tempted to change the expected format for "datetime" context. Documentation mentions "YYYY-MM-DD hh:mm". I would prefer "YYYY-MM-DD hh:mm:ss". https://www.openhab.org/docs/developer/addons/config-xml.html#supported-context As the "datetime"context is not yet used, this would not be a problem. WDYT ?
Can you please have a look to my last commits before I squash everything and update the 2 first messages ?
I will do.
I am tempted to change the expected format for "datetime" context.
Agreed, having seconds is better than not having seconds - and as it is not yet used, there should be no problems.
Agreed, having seconds is better than not having seconds - and as it is not yet used, there should be no problems.
Done.
I also updated my second message with a full example when using GET and POST API.
Now ready for an "official" review.
@openhab/core-maintainers : a review would be really appreciated. I assume @florian-h05 is waiting for this merge before starting working on the UI part.
@J-N-K : all your comments are now considered. I am happy with the helper classes being now OSGi components.
Thanks again for your work on this. This is a great step forward.
Especially the ActionsInputHelper looks quite complex and easy to break. Could you add some tests for that?
Yes, that is doable.
@J-N-K : I added unit tests but I will continue later to cover more cases.
@J-N-K : unit tests are now fully defined for class ActionInputHelper
.
@florian-h05 : I hope you are in the starting blocks ;)
Fixes #1745
Return config description parameters for the ActionInputs of ThingActions for the REST GET
/action/{thingUID}
and REST GET/module-types endpoints
. The config description parameters are only provided if all input parameters have a type that can be mapped to a config description parameter (String, boolean, Boolean, byte, Byte, short, Short, int, Integer, long, Long, float, Float, double, Double, Number, DecimalType,QuantityType<?>
, LocalDateTime, LocalDate, LocalTime, ZonedDateTime, Date, Instant and Duration).Enhance the REST POST
/actions/{thingUID}/{actionUid}
endpoint (allows invoking Thing actions via REST) and theAnnotationActionHandler
(allows invoking Thing actions from UI-rules) in order to be more flexible regarding the type of each provided argument value and to map the value to the expected data type. Number and string values will be accepted as inputs and the expected data type will be created from this value.This will be used by the UI's Thing page and rule editor to allow invoking Thing actions through the UI or adding them to UI-bases rules.
Signed-off-by: Laurent Garnier lg.hc@free.fr Signed-off-by: Florian Hotze florianh_dev@icloud.com