How do I use String:format in Javascript rules

Dear all,
in OH2 I’ve used String::format in DSL-Rules:

  var Number temp = ((HausAussentemperatur_ActualTemperature.state as Number).floatValue)
  var lage = (Localweatherandforecast_Wetterlage.state.toString)
  var String Ausgabe = String::format("%s bei %.1f°C", lage, temp)

In OH3 Javascript rules I try to use these code:

 var String Ausgabe = String.format("%s bei %.1f°C", lage, temp)

as I found here
But it’s not working.
Can anybody kindly give me a little help in this case?

1 Like

There is an infinity of things that could fit into “But it’s not working”. Do you see errors in the log? Does it not run at all? Does it run but create the wrong String?

Hi Rich,
Many thanks for your quick response!
The log shows:

2021-06-23 17:25:41.585 [ERROR] [internal.handler.ScriptActionHandler] - Script execution of rule with UID 'TestZahlenformat' failed: <eval>:6:11 Expected ; but found Ausgabe

var String Ausgabe = String.format("%s bei %.1f°C", lage, temp)

           ^ in <eval> at line number 6 at column number 11 

The script stops at the name of the variable “Ausgabe” and give no output.
This is the whole script:

var logger = Java.type('org.slf4j.LoggerFactory').getLogger('org.openhab.rule.' + ctx.ruleUID);

var lage = itemRegistry.getItem('OpenWeatherMapOneCallAPIweatherandforecast_ForecastTomorrow_Condition').getState().toString() ;
var temp = itemRegistry.getItem('OpenWeatherMapOneCallAPIweatherandforecast_ForecastTomorrow_Maxtemperature').getState().intValue() ;

var String Ausgabe = String.format("%s bei %.1f°C", lage, temp)

logger.info(Ausgabe);

Do you have any idea why the script stops?

If you plan on moving from JavaScript to Rules DSL you should probably spend some time going through an online course or a tutorial to learn some of the basics of the language. JavaScript is a loosely typed language. You never specify the type of a variable. The syntax doesn’t even support it.

var Ausgabe = ...

I do not know if the Java class String is available by default in the JavaScript context. You might need to use its full name java.lang.String or import it using Java.type like you did to access the logger.

2 Likes

It seems the Java class String is not available. I think you meen I need at first a row like this:

var logger = Java.type('org.slf4j.LoggerFactory').getLogger('org.openhab.rule.' + ctx.ruleUID);
var ScriptExecution = Java.type("org.openhab.core.model.script.actions.ScriptExecution");
var ZonedDateTime = Java.type("java.time.ZonedDateTime");

For example:

var Stringformat = Java.type("....

But who knows the full name of the class? :thinking:
I will search and try something…

I already told you…

OK, I misunderstood…
Now I’ve tried this:

var StringFormat = Java.type("java.lang.String");  

var lage = itemRegistry.getItem('OpenWeatherMapOneCallAPIweatherandforecast_ForecastTomorrow_Condition').getState().toString() ;
var temp = itemRegistry.getItem('OpenWeatherMapOneCallAPIweatherandforecast_ForecastTomorrow_Maxtemperature').getState().intValue() ;
var Ausgabe = StringFormat.format("%s bei %.1f°C", lage, temp);

logger.info(Ausgabe);

But it doesn’t work:

2021-06-23 19:57:10.458 [WARN ] [e.automation.internal.RuleEngineImpl] - Fail to execute action: 1

java.util.IllegalFormatConversionException: f != java.lang.Integer
....

Do you know what it mean: “f != java.lang.Integer”?

I found it: I have to create a floatValue and it works!

Now I’ve finished the OH3 JavaScript rule and maybe it helps everyone, when I share the code:
The trigger is, when one of the items “OpenWeatherMapOneCallAPIweatherandforecast_ForecastTomorrow…” changed.
Then execute the scrip:

var logger = Java.type('org.slf4j.LoggerFactory').getLogger('org.openhab.rule.' + ctx.ruleUID);
var StringFormat = Java.type("java.lang.String");  

var str1 = itemRegistry.getItem('OpenWeatherMapOneCallAPIweatherandforecast_ForecastTomorrow_Condition').getState().toString() ;
var str2 = itemRegistry.getItem('OpenWeatherMapOneCallAPIweatherandforecast_ForecastTomorrow_Mintemperature').getState().floatValue() ;
var str3 = itemRegistry.getItem('OpenWeatherMapOneCallAPIweatherandforecast_ForecastTomorrow_Maxtemperature').getState().floatValue() ;

var Ausgabe = StringFormat.format("%s bei %.0f bis %.0f°C", str1, str2, str3);

logger.info('Wettervorhersage: ' + Ausgabe)
events.sendCommand('Wettervorhersage_Sum_String', Ausgabe)

The result in a sitemap is the weather forecast with condition, min and max temperature as one string:
Bildschirmfoto vom 2021-06-24 17-11-30
Don’t hesitate to contact me in case of any questions!

Special thanks to Rich Koshak for the support and the displayed patience :wink:!

1 Like

To share the whole rule click on the “Code” tab in the upper right corner. That will show everything, triggers, conditions, and all the actions.

Personally, I prefer to use the items dict to get Item’s states rather than using the itemRegistry. It makes for shorter and easier to understand lines of code.

var str1 = items['OpenWeatherMapOneCallAPIweatherandforecast_ForecastTomorrow_Condition'].toString();

I believe that OWM uses Units of Measurement for most of its Channels. This means the value carries units and you can compare and do math with compatible units. For example, compare one value in °C and another in °F.

if(items['MyTemp'] > new QuantityType("70 °F")){

The above will work whether MyTemp is storing a value in °C or °F. That is largely why you had to call floatValue on the states of those Items because 22.509 °C isn’t a number that String.format understands how to format. But note that the value stored in that Item is not guaranteed to be °C. You are assuming that it will be and it’s not a terrible assumption, but it’s not guaranteed.

1 Like

Hi Rich,
many thanks for your explanations! Great, again what learned!
Here the full code of the rule:

triggers:
  - id: "2"
    configuration:
      itemName: OpenWeatherMapOneCallAPIweatherandforecast_ForecastTomorrow_Condition
    type: core.ItemStateChangeTrigger
  - id: "3"
    configuration:
      itemName: OpenWeatherMapOneCallAPIweatherandforecast_ForecastTomorrow_Maxtemperature
    type: core.ItemStateChangeTrigger
  - id: "4"
    configuration:
      itemName: OpenWeatherMapOneCallAPIweatherandforecast_ForecastTomorrow_Mintemperature
    type: core.ItemCommandTrigger
conditions: []
actions:
  - inputs: {}
    id: "1"
    configuration:
      type: application/javascript
      script: >
        var logger =
        Java.type('org.slf4j.LoggerFactory').getLogger('org.openhab.rule.' +
        ctx.ruleUID);

        var StringFormat = Java.type("java.lang.String");  


        var str1 = items['OpenWeatherMapOneCallAPIweatherandforecast_ForecastTomorrow_Condition'].toString();

        var str2 = items['OpenWeatherMapOneCallAPIweatherandforecast_ForecastTomorrow_Mintemperature'].floatValue() ;

        var str3 = items['OpenWeatherMapOneCallAPIweatherandforecast_ForecastTomorrow_Maxtemperature'].floatValue() ;


        var Ausgabe = StringFormat.format("%s bei %.0f bis %.0f°C", str1, str2, str3);

        logger.info('Wettervorhersage: ' + Ausgabe)

        events.sendCommand('Wettervorhersage_Sum_String', Ausgabe)
    type: script.ScriptAction

The OWM binding brings the right Units of Measurement for me (°C) - that’s no problem. But I will pay attention in this point!
I prefer to use floatValue, so I can shorting the numbers after the decimal point and I can use the European decimal comma, if necessary:

Leichter Regen bei 13,3 bis 18,7°C
2 Likes

You can do that with Quantities as well; see the last section of

1 Like

Hi rossko57,
I’ve tried it:

Temperature is 23,2°C

Many thanks, that’s also a nice solution!