Rule and << 8... something I do not understand

Hello,

I have a rule:

rule “Update time on modbus devices”
when
Time cron “0 0/1 * * * ?”
then
var Calendar cal = Calendar.getInstance()
logInfo("===", “===”)
var int second = cal.get(Calendar.SECOND)
var int dayOfWeek = cal.get(Calendar.DAY_OF_WEEK) - 1
if (dayOfWeek == 0) dayOfWeek = 7
var int hourOfDay = cal.get(Calendar.HOUR_OF_DAY)
var int minute = cal.get(Calendar.MINUTE)
var int dayOfMonth = cal.get(Calendar.DAY_OF_MONTH)
var int month = cal.get(Calendar.MONTH) + 1
var int year = (Math.floor(cal.get(Calendar.YEAR) / 100) << 8) + (cal.get(Calendar.YEAR) % 100)

logInfo(“SECOND”, second.toString())
logInfo(“DAY_OF_WEEK”, dayOfWeek.toString())
logInfo(“HOUR_OF_DAY”, hourOfDay.toString())
logInfo(“MINUTE”, minute.toString())
logInfo(“DAY_OF_MONTH”, dayOfMonth.toString())
logInfo(“MONTH”, month.toString())
logInfo(“YEAR”, year.toString())

reg40036.sendCommand(year)
reg40035.sendCommand((month << 8) + dayOfMonth)
reg40034.sendCommand((hourOfDay << 8) + minute)
reg40033.sendCommand((second << 8) + dayOfWeek)

end

why I receive an error
Error during the execution of rule ‘Update time on modbus devices’: Unknown variable or command ‘<<’; line 17, column 20, length 45 (Line 17 in bold).

if I change this string with transformation, everithing is works fine, but why I can’t use it in rules???

Please use code fences when posting code…

<< is a bitwise operator
<< 8 is equivalent to * 256 have you tried that?

Rules DSL does not implement bit wise operators like shift. In Xtend << is the doubleLessThan operator which means “much less than”, not a bit shift left. It would appear that Rules DSL doesn’t support bit shift operations at all.

That is quite subjective… I have never heard of that. How does that work?

I honestly have no idea. I put it on my list to look into at some later date when I have more time. All I have so far is:

Xtend docs

e1 << e2 e1.operator_doubleLessThan(e2)

And wikipedia:

The double less-than sign ( << ) is used for an approximation of the much-less-than sign (≪)

I didn’t get any farther and couldn’t set up a test since Rules DSL doesn’t support it anyway.

Hello,

If you see my code:

reg40035.sendCommand((month << 8) + dayOfMonth)
reg40034.sendCommand((hourOfDay << 8) + minute)
reg40033.sendCommand((second << 8) + dayOfWeek)

that one works without any issues. So, my question is why is working one those lines, but if I try to use Math function it stops. but in rules only. when I use JS transformation, then my formula works perfect :slight_smile:

I know I can use *256 or biginteger. But what me confused:

(Math.floor(year/ 100) << 8) + (year % 100)) —> return error about “<<”
((month << 8) + dayOfMonth) ----> no error, works perfect.

Ed

Are you sure it works in the other statements? If it errors on the line

var int year = (Math.floor(cal.get(Calendar.YEAR) / 100) << 8) + (cal.get(Calendar.YEAR) % 100)

the rule exits immediately and the other statements are never reached.

Yes. 100% sure. because line with year I add last.

Then the problem could be that the value isn’t cast to int until after the entire expression is evaluated. The <<-operator might work on primitive ints, but not on whatever the Calendar-functions or Math.floor returns. Try splitting it up in different steps, something like:

var int century = Math.floor(cal.get(Calendar.YEAR) / 100)
var int year = cal.get(Calendar.YEAR) % 100
reg40036.sendCommand((century << 8) + year)

Or something like that.

I already use biginteger. floor return 20.0 not 20, maybe it’s a problem.

but when i use transformation, in transformation this code works. thats confused

What programming language is your transform written in? It doesn’t seem surprising that any given statement doesn’t work (or works differently) in any given language.

The same. JS

you can try to yourself in
(Math.floor(2019 / 100) << 8) + (2019 % 100)

for example in chrome console return 5139

and it’s works in transformation.js… but in rules i see a problem for <<… strange

Ed

Why do you think that is strange? Rules are not written in javascript. There’s no reason any particular operator from javascript should be available in rules.

Math.floor returns a double accordning to javadoc, while bitshift for technical reasons only works with ints (please correct me if I’m wrong). However (unless the rules DSL/Xtend performs some conversion) division with ints should return an int with the remainder discarded, so Math.floor shouldn’t be necessary. Edit: Since Calendar.get returns an int.

Not sure how rules DSL/Xtend handles this though…

yes, math.floor returns me “20.0”, it’s double instead of int.

but in java console you can try:

20 << 8
5120

20.0 << 8
5120

same result.

So save you a headache and multiple by 258…!

Did a little fiddling:

rule "test"
	when
		Item Test received command //or 
	then
		val cal = Calendar.getInstance()
		var y = cal.get(Calendar.YEAR)
		logInfo("test", "y is a " + y.class.toString + " with value " + y.toString)
		var century = y / 100
		logInfo("test", "century is a " + century.class.toString + " with value " + century.toString)
		var rounded = Math.floor(century)
		logInfo("test", "rounded is a " + rounded.class.toString + " with value " + rounded.toString)
		logInfo("test", "y << 8 returns a " + (y << 8).class.toString + " with value " + (y << 8).toString)
		logInfo("test", "century << 8 returns a " + (century << 8).class.toString + " with value " + (century << 8).toString)
		logInfo("test", "rounded << 8 returns a " + (rounded << 8).class.toString + " with value " + (rounded << 8).toString)
		
end

outputs:

2019-10-18 12:45:03.847 [INFO ] [.eclipse.smarthome.model.script.test] - y is a class java.lang.Integer with value 2019

2019-10-18 12:45:03.849 [INFO ] [.eclipse.smarthome.model.script.test] - century is a class java.lang.Integer with value 20

2019-10-18 12:45:03.850 [INFO ] [.eclipse.smarthome.model.script.test] - rounded is a class java.lang.Double with value 20.0

2019-10-18 12:45:03.852 [INFO ] [.eclipse.smarthome.model.script.test] - y << 8 returns a class java.lang.Integer with value 516864

2019-10-18 12:45:03.853 [INFO ] [.eclipse.smarthome.model.script.test] - century << 8 returns a class java.lang.Integer with value 5120

2019-10-18 12:45:03.855 [ERROR] [ntime.internal.engine.RuleEngineImpl] - Rule 'test': Unknown variable or command '<<'; line 17, column 48, length 12

Conclusion: No need for Math.floor, the returned Double (note: not primitive double, but its wrapper class) don’t support the <<-operator, but since the division is performed on Integers no rounding is needed.

2 Likes