Strange behavior rule when trying to get 2 decimals in String

Hello,

I have a problem with a rule that changes a dimmer state into a 2 digit value that is needed in a Sting. this value has to be between 00 and 99.

Items:

Dimmer dimmer_item
String calculated_value

Rules:

rule "change to 2 digits"
when
  Item dimmer_item changed
then
 var int calculated = 0
 if(dimmer_item.state == 100){
  calculated = (dimmer_item.state as DecimalType) - 1
 }
else{
 calculated = (dimmer_item.state as DecimalType).format("%02d")
 }
 calculated_value.postUpdate(calculated)
end

when the value Item “dimmer_item” is 100 the rule result is fine and the string value changes to 99. but when value of the “dimmer_item” is less then 100 the String value don’t change (it gets no update from the rule).
when I change the last line in the rule to:

calculated_value.postUpdate("" + calculated)

The rule works fine but I don’t think this is the right way to do this.
What do I wrong? I think that I’m mixing to mush decimal, integer and string in a wrong way?

Does this work?

 calculated = (dimmer_item.state as DecimalType).format("%02d")

to:

 calculated = dimmer_item.state.toString

nope that also doesn’t work.

What does the event.log and openhab.log say?

Hm, I think I would rewrite it like this :

rule "change to 2 digits"
when
  Item dimmer_item changed
then
 if(dimmer_item.state > 99) {
  calculated_value.postUpdate((dimmer_item.state as DecimalType) - 1)
 } else {
  calculated_value.postUpdate(dimmer_item.state.toString)
 }
end

You cannot format a Number. You can format a number into a String with leading zeros.

rule "change to 2 digits"
when
  Item dimmer_item changed
then
  var calculated = 0
  if(dimmer_item.state as Number == 100){
    calculated = (dimmer_item.state as Number) - 1
  }
  else{
    calculated = dimmer_item.state as Number
  }
  calculated_value.postUpdate(calculated.toString(%02d")
end

though the rule can be massively simplified to two lines:

rule "change to 2 digits"
when
  Item dimmer_item changed
then
    var calculated = if(dimmer_item.state as Number > 99) 99 else dimmer_item.state as Number
    calculated_value.postUpdate(calculated.toString.format("%02d"))
end

Thanks for simplifying the rule!
But changing the format to 2 digits don’t work.
zero is not “00” but just “0”. any idea?

Doh! Stupid typo on my part.

calculated_value.postUpdate(String::format("%02d", calculated))

It only works when the dimmer value changes to 100.
Then I get a result (in the String) of 99.
When I change the dimmer value to 0, nothing happens.
The string value stays at 99.
Do I need to import some special java util?

Do you see errors in the log?

I see this ERROR:

[ERROR] [.script.engine.ScriptExecutionThread] - Rule "change to 2 digits" : d != org.eclipse.smarthome.core.library.types.PercentType

I have no Idea what this means…

What type of Item is calculated_value? I’ve been assuming that it is a String Item.

Yes it is a String item.

When I change the dimmer_item to 100 the Sring changes to 99.
But when I change the dimmer item to a value less than 100 then I get this error.

when I change:

calculated_value.postUpdate(String::format("%02d", calculated))

to:

calculated_value.postUpdate(calculated)

It works but I don’t get 00 or 05 but 0 and 5 as a result when the dimmer value is 0 or 5.

Taking a step back, why does calculated_value need to have the leading zero. Is it just for display or is the Item linked to something that needs the leading zero? If it is linked to something, does that binding support transformations?

Try:

var calculated = if(dimmer_item.state as Number > 99) 99 else (dimmer_item.state as Number).intValue
1 Like

YESS that is working, thank you SOOOOOO much!!!

Can you tell me what was going wrong?

I need values from 00 to 99 to send (with a String) to a serial port or to an MQTT.
The device where i want to send it to need to get 2 digits or it won’t accept the command!
so 0 has to be 00.

The Rules DSL is not very good at dealing with Numbers and primitives. Most of the time it manages to figure out how to transform everything for you but sometimes, particularly when it needs to convert to a primitive number it fails. This is one of those cases. By adding the .intValue I gave the Rules DSL the hint it needed to convert the state of dimmer_item to an int.

Thank you for all the above information.

After a little playing around, I managed to format a batch of alarm time components into a set of strings for displaying in my UI.

The background is that the Alarm time values in the Velbus Binding are divided into Minutes and Hours, which is easy to display as two sliders / knobs in HabPanel for editing, but on a summary page, 6:0 isn’t an ideal way of displaying a time.

My aim was to create a rule that took the hours and minutes of each alarm and convert them into 24hr time strings.

So

Hour “6”
Minute “5”

Would display as “06 : 05”

The following rule works perfectly :smile:

var Number Alarm1WH = 6
var Number Alarm1WM = 15
var Number Alarm1BH = 23
var Number Alarm1BM = 0
 
var Number Alarm2WH = 8
var Number Alarm2WM = 0
var Number Alarm2BH = 23
var Number Alarm2BM = 30
 
 
 
rule "Alarm times combine"
when
      Item LoungeGPO_ClockAlarm_ClockAlarm2BedtimeHour changed or
  Item LoungeGPO_ClockAlarm_ClockAlarm2BedtimeMinute changed or
      Item LoungeGPO_ClockAlarm_ClockAlarm2WakeupHour changed or
  Item LoungeGPO_ClockAlarm_ClockAlarm2WakeupMinute changed or
      Item LoungeGPO_ClockAlarm_ClockAlarm1BedtimeHour changed or
  Item LoungeGPO_ClockAlarm_ClockAlarm1BedtimeMinute changed or
      Item LoungeGPO_ClockAlarm_ClockAlarm1WakeupHour changed or
  Item LoungeGPO_ClockAlarm_ClockAlarm1WakupMinute changed
then
      var Alarm1WH = (LoungeGPO_ClockAlarm_ClockAlarm1WakeupHour.state as Number).intValue
      var Alarm1WM = (LoungeGPO_ClockAlarm_ClockAlarm1WakupMinute.state as Number).intValue
      var Alarm1BH = (LoungeGPO_ClockAlarm_ClockAlarm1BedtimeHour.state as Number).intValue
      var Alarm1BM = (LoungeGPO_ClockAlarm_ClockAlarm1BedtimeMinute.state as Number).intValue
      var Alarm2BH = (LoungeGPO_ClockAlarm_ClockAlarm2BedtimeHour.state as Number).intValue
      var Alarm2BM = (LoungeGPO_ClockAlarm_ClockAlarm2BedtimeMinute.state as Number).intValue
      var Alarm2WH = (LoungeGPO_ClockAlarm_ClockAlarm2WakeupHour.state as Number).intValue
      var Alarm2WM = (LoungeGPO_ClockAlarm_ClockAlarm2WakeupMinute.state as Number).intValue
 
   

Alarm1_Wake_Time.sendCommand(String::format("%02d",Alarm1WH)+" : "+String::format("%02d",Alarm1WM)
  
  
Alarm1_Bed_Time.sendCommand(String::format("%02d",Alarm1BH)+" : "+String::format("%02d",Alarm1BM))


  
Alarm2_Wake_Time.sendCommand(String::format("%02d",Alarm2WH)+" : "+String::format("%02d",Alarm2WM)


  
Alarm2_Bed_Time.sendCommand(String::format("%02d",Alarm2BH)+" : "+String::format("%02d",Alarm2BM))
 
  end

Well - not an answer to this question maybe, but after 4 hours trial and error, I came up with this to suit my needs:

switch (true)
    {
        case (now.getHourOfDay() >= vTCD_HOUR_01_Number.state as Number && now.getMinuteOfHour() >= vTCD_MINUTE_01_Number.state as Number):
        {
           msg.append("Timing              = slot_01 " + java.lang.String.format("%02d", (vTCD_HOUR_01_Number.state as Number).intValue) + ":" + java.lang.String.format("%02d", (vTCD_HOUR_01_Number.state as Number).intValue) + "\n")
        }
        case (now.getHourOfDay() >= vTCD_HOUR_02_Number.state as Number && now.getMinuteOfHour() >= vTCD_MINUTE_02_Number.state as Number):
        {
            msg.append("Timing              = slot_01 " + java.lang.String.format("%02d", (vTCD_HOUR_02_Number.state as Number).intValue) + ":" + java.lang.String.format("%02d", (vTCD_HOUR_02_Number.state as Number).intValue) + "\n")
        }
    ....

Just wanted to share in case anyone else considers giving up trying :grinning:

java.lang.String.format("%02d", (vTCD_HOUR_02_Number.state as Number).intValue)
1 Like