[solved] JSONPATH > String > Number

Hello!
i have a hard time with a number that’s not really a number…

{"sessionId":"123","customData":null,"siteId":"default","input":"mach die musik um zehn lauter","asrTokens":[[{"value":"mach","confidence":1.0,"rangeStart":0,"rangeEnd":4,"time":{"start":0.0,"end":0.51}},{"value":"die","confidence":1.0,"rangeStart":5,"rangeEnd":8,"time":{"start":0.51,"end":0.51}},{"value":"musik","confidence":1.0,"rangeStart":9,"rangeEnd":14,"time":{"start":0.51,"end":1.02}},{"value":"um","confidence":0.96901065,"rangeStart":15,"rangeEnd":17,"time":{"start":1.02,"end":1.2027891}},{"value":"zehn","confidence":0.9816874,"rangeStart":18,"rangeEnd":22,"time":{"start":1.2027891,"end":1.5010988}},{"value":"lauter","confidence":1.0,"rangeStart":23,"rangeEnd":29,"time":{"start":1.5010988,"end":2.52}}]],"intent":{"intentName":"test12345:volume_up","confidenceScore":0.9739778},"slots":[{"rawValue":"zehn","value":{"kind":"Number","value":10.0},"range":{"start":18,"end":22},"entity":"snips/number","slotName":"amount","confidenceScore":0.9816874}]}

with " $.slots[0].value.value " i get the result “10.0”, but that’s as far as it gets…

i tried this one, but i’m not able to make any use of it…:

val amount = transform("JSONPATH", "$.slots[0].value.value", StringItem.state.toString)
NumberItem.postUpdate( amount )
logInfo("Test: ", (NumberItem)

comes to this error

2019-03-10 23:10:12.729 [ERROR] [ntime.internal.engine.RuleEngineImpl] - Rule 'Snips Volume': An error occurred during the script execution: Could not invoke method: org.eclipse.smarthome.model.script.actions.LogAction.logInfo(java.lang.String,java.lang.String,java.lang.Object[]) on instance: null

in the end i would like to change the volume on my squeezebox:

squeezeboxVolume.sendCommand((squeezeboxVolume.state as DecimalType).intValue + "Value of my **** NumberItem")

this works for example

squeezeboxVolume.sendCommand((squeezeboxVolume.state as DecimalType).intValue + 3)

what am i doing wrong? i just lost 1.5 hours while trying everything i found on the forum. (please do not ask my WHAT i tried, bc in the end nothing worked and i didn’t write down everything :frowning: )

good night!
narf!

Your logInfo() is wrong.
Please try

val Number amount = transform("JSONPATH", "$.slots[0].value.value", StringItem.state.toString)
NumberItem.postUpdate(amount)
logInfo("testrule", "Val: {}", amount)
logInfo("testrule", "Item: {}", NumberItem.state)

instead. Please be aware that it’s very likely that both logInfo lines will produce different messages as postUpdate() is asynchronous and there is no ordered execution.

hmm. this is not working either…

val Number amount = transform […] is flagged with “Type mismatch: cannot convert from String to Number”

i tried anyway and got this error:

Rule 'Snips Volume': An error occurred during the script execution: Could not invoke method: org.eclipse.smarthome.model.script.actions.BusEvent.postUpdate(org.eclipse.smarthome.core.items.Item,java.lang.Number) on instance: null

So more logging…

val String myVal = transform("JSONPATH", "$.slots[0].value.value", StringItem.state.toString)
logInfo("testrule", "String: {}", myVal)

val Number amount = Float::parseFloat(myVal)
logInfo("testrule", "Val: {}", amount)

NumberItem.postUpdate(amount)
logInfo("testrule", "Item: {}", NumberItem.state)

that i can do =)

Eclupse SmartHome Designer flags the “NumberItem.postUpdate(amount)” row with “the method or field state is undefined for the type Class <NumberItem”

and this is my log:

2019-03-11 19:14:00.151 [INFO ] [ipse.smarthome.model.script.testrule] - String: 10.0
2019-03-11 19:14:00.160 [INFO ] [ipse.smarthome.model.script.testrule] - Val: 10.0
2019-03-11 19:14:00.171 [ERROR] [ntime.internal.engine.RuleEngineImpl] - Rule 'Snips Volume': 'state' is not a member of 'java.lang.Class'; line 163, column 33, length 16

So I guess that NumberItem is not an Item at all :slight_smile:

ok, this one is on me. missed the NumberItem :frowning: obviously that’s not real item name. now i changed it and everything goes smooth:

2019-03-11 21:53:55.889 [INFO ] [ipse.smarthome.model.script.testrule] - String: 10.0
2019-03-11 21:53:55.895 [INFO ] [ipse.smarthome.model.script.testrule] - Val: 10.0
2019-03-11 21:53:55.904 [INFO ] [ipse.smarthome.model.script.testrule] - Item: 10.0 

last thing to do: how can i “insert” the value 10 in this command?

squeezeboxVolume.sendCommand((squeezeboxVolume.state as DecimalType).intValue + 10)

this is not working:

squeezeKuchlVolume.sendCommand((squeezeKuchlVolume.state as DecimalType).intValue + (NumberItem.state as DecimalType))

oh, and another thing: i don’t really need the “NumberItem”, i created it only to be a temporary variable in this specific rule. is there any other way to do this within the rule?

Use Number instead of DecimalType:

squeezeKuchlVolume.sendCommand((squeezeKuchlVolume.state as Number) + (NumberItem.state as Number))

It works!
now there’s just (?) one last thing to do…

it can happen that jsonpath transormation will fail because the amount is missing.
how can i fill NumerItem with a fixed value (f.e. 3)?

my thought: if transform(“JSONPATH”, […] “fails”, NumberItem.postUpdate(3), else if "all the code we (you!) just created…

good night!

It’s always possible to test the val but I guess it would be better then to change it to var:

var Number amount = Float::parseFloat(myVal)
if(!(amount instanceof Number)) amount = 0

i’m sorry, but where should these lines go? this is completely new to me…
here are all my lines, maybe this way it’s more clear:

rule "Snips Volume"
when
	Item Snips_Intent received update 'volume_up' or
	Item Snips_Intent received update 'volume_down'
then

val String myVal = transform("JSONPATH", "$.slots[0].value.value", Snips_mqtt.state.toString)
val Number amount = Float::parseFloat(myVal)
logInfo("testrule", "Item: {}", Snips_Volume.state)
Snips_Volume.postUpdate(amount)

if (Snips_Intent.state.toString == 'volume_up') {
  squeezeKuchlVolume.sendCommand((squeezeKuchlVolume.state as Number) + (Snips_Volume.state as Number))
} else if (Snips_Intent.state.toString == 'volume_down') {
  squeezeKuchlVolume.sendCommand((squeezeKuchlVolume.state as Number) - (Snips_Volume.state as Number))
}
end
rule "Snips Volume" 
when
    Item Snips_Intent received update 'volume_up' or 
    Item Snips_Intent received update 'volume_down' 
then
    val String myVal = transform("JSONPATH", "$.slots[0].value.value", Snips_mqtt.state.toString) 
    var Number amount = Float::parseFloat(myVal) 
    if(!(amount instanceof Number)) 
        amount = 0
    Snips_Volume.postUpdate(amount) 
    logInfo("testrule", "Item: {}", Snips_Volume.state) 
    if (Snips_Intent.state.toString == 'volume_up') {
        squeezeKuchlVolume.sendCommand((squeezeKuchlVolume.state as Number) + (Snips_Volume.state as Number)) 
    } else if (Snips_Intent.state.toString == 'volume_down') {
        squeezeKuchlVolume.sendCommand((squeezeKuchlVolume.state as Number) - (Snips_Volume.state as Number)) 
    } 
end

Maybe consider to change the rule:

rule "Snips Volume" 
when
    Item Snips_Intent received update
then
    val String myVal = transform("JSONPATH", "$.slots[0].value.value", Snips_mqtt.state.toString) 
    var Number amount = Float::parseFloat(myVal) 
    if(!(amount instanceof Number)) 
        amount = 0
    Snips_Volume.postUpdate(amount)                        // do you need it as an Item at all? Maybe to display...
//    logInfo("testrule", "Item: {}", Snips_Volume.state) 
    var Number nAdd = 0
    switch (Snips_Intent.state.toString) {
        case "volume_up"   : nAdd =  amount
        case "volume_down" : nAdd = -amount
    }
    if (nAdd != 0)
        squeezeKuchlVolume.sendCommand((squeezeKuchlVolume.state as Number) + nAdd) 
end

Good evening!
i tried the 2nd version of the rule but it doesn’t work if

    val String myVal = transform("JSONPATH", "$.slots[0].value.value", Snips_mqtt.state.toString) 

fails. the transform command WILL fail sometimes because sometimes the user will just issue the command “lower volume” without indicating the amount. in this case the rule shoud set nAdd to “5”.

This is the error it get when transform is failing:

2019-03-12 19:53:02.075 [ERROR] [ntime.internal.engine.RuleEngineImpl] - Rule 'Snips Volume': For input string: "{"sessionId":"cdf6c6e6-fa20-4f3e-ae55-dfbcb5223f41","customData":null,"siteId":"default","input":"mach die musik leiser","asrTokens":[[{"value":"mach","confidence":1.0,"rangeStart":0,"rangeEnd":4,"time":{"start":0.0,"end":0.71999997}},{"value":"die","confidence":1.0,"rangeStart":5,"rangeEnd":8,"time":{"start":0.71999997,"end":0.81}},{"value":"musik","confidence":1.0,"rangeStart":9,"rangeEnd":14,"time":{"start":0.81,"end":1.41}},{"value":"leiser","confidence":1.0,"rangeStart":15,"rangeEnd":21,"time":{"start":1.41,"end":2.31}}]],"intent":{"intentName":"oida1753:volume_down","confidenceScore":0.99365544},"slots":[]}"

Oh, yes… try this:

rule "Snips Volume" 
when
    Item Snips_Intent received update
then
    val String myVal = transform("JSONPATH", "$.slots[0].value.value", Snips_mqtt.state.toString) 
    if(myVal !== null && myVal != "" )                     // maybe this line does help
        var Number amount = Float::parseFloat(myVal) 
    if(!(amount instanceof Number)) 
        amount = 0
    Snips_Volume.postUpdate(amount)                        // do you need it as an Item at all? Maybe to display...
//    logInfo("testrule", "Item: {}", Snips_Volume.state) 
    var Number nAdd = 0
    switch (Snips_Intent.state.toString) {
        case "volume_up"   : nAdd =  amount
        case "volume_down" : nAdd = -amount
    }
    if (nAdd != 0)
        squeezeKuchlVolume.sendCommand((squeezeKuchlVolume.state as Number) + nAdd) 
end

Hi! Today i was finally able to test your latest input but there seems to be a problem with this line:

        var Number amount = Float::parseFloat(myVal)

Error:

2019-03-18 20:05:16.848 [WARN ] [el.core.internal.ModelRepositoryImpl] - Configuration model 'snips.rules' has errors, therefore ignoring it: [224,9]: no viable alternative at input 'var'

@Udo_Hartmann i feel it: we’re almost there, aren’t we?
:hushed:

Argh, context…

rule "Snips Volume" 
when
    Item Snips_Intent received update
then
    var Number amount
    val String myVal = transform("JSONPATH", "$.slots[0].value.value", Snips_mqtt.state.toString) 
    if(myVal !== null && myVal != "" )                     // maybe this line does help
        amount = Float::parseFloat(myVal) 
    if(!(amount instanceof Number)) 
        amount = 0
    Snips_Volume.postUpdate(amount)                        // do you need it as an Item at all? Maybe to display...
//    logInfo("testrule", "Item: {}", Snips_Volume.state) 
    var Number nAdd = 0
    switch (Snips_Intent.state.toString) {
        case "volume_up"   : nAdd =  amount
        case "volume_down" : nAdd = -amount
    }
    if (nAdd != 0)
        squeezeKuchlVolume.sendCommand((squeezeKuchlVolume.state as Number) + nAdd) 
end

still no luck:

2019-03-21 18:25:50.344 [ERROR] [ntime.internal.engine.RuleEngineImpl] - Rule 'Snips Volume': For input string: "{"sessionId":"15572a95-4418-4618-bd15-d001f634f42c","customData":null,"siteId":"default","input":"mach die musik lauter","asrTokens":[[{"value":"mach","confidence":1.0,"rangeStart":0,"rangeEnd":4,"time":{"start":0.0,"end":1.02}},{"value":"die","confidence":1.0,"rangeStart":5,"rangeEnd":8,"time":{"start":1.02,"end":1.02}},{"value":"musik","confidence":1.0,"rangeStart":9,"rangeEnd":14,"time":{"start":1.02,"end":1.62}},{"value":"lauter","confidence":1.0,"rangeStart":15,"rangeEnd":21,"time":{"start":1.62,"end":2.52}}]],"intent":{"intentName":"test12345:volume_up","confidenceScore":0.98489004},"slots":[]}"

rule works fine if i specify the mount, if “transform(“JSONPATH”, “$.slots[0].value.value”, Snips_mqtt.state.toString)” fails, nothing is executed.

Jepp, there is no $.slots[0].value.value at all.

Maybe this is better:

...
rule "Snips Volume" 
when
    Item Snips_Intent received update
then
    var Number amount = 0 // default
    val String myVal = transform("JSONPATH", "$.slots[0].value.value", Snips_mqtt.state.toString) 
    if(myVal != Snips_mqtt.state.toString)       // transform worked 
        amount = Float::parseFloat(myVal)        // so parse to float
    Snips_Volume.postUpdate(amount)                        // do you need it as an Item at all? Maybe to display...
//    logInfo("testrule", "Item: {}", Snips_Volume.state) 
    var Number nAdd = 0
    switch (Snips_Intent.state.toString) {
        case "volume_up"   : nAdd =  amount
        case "volume_down" : nAdd = -amount
    }
    if (nAdd != 0)
        squeezeKuchlVolume.sendCommand((squeezeKuchlVolume.state as Number) + nAdd) 
end

If there is no $.slots[0].value.value in the string, JSONPATH will return the complete json string. So if myVal is other than the source string, there should be a number in it…

yeah that’s my problem, sometimes the command is just to raise the volume and openhab should raise for 3 (or some defined number).
with this latest code the rule gave no errors, only thing missing is something like…
“else if … amount = 3”