Open fpellicciotti opened 5 years ago
getTimestamp is my own OpenHab lambda for returning a DateTime or string timestamp. You can replace it with anything that returns a date/time (eg new DateTimeType() or now()).
My actual lambda is this
val Functions$Function2<GenericItem, String, String> getTimestamp = [ //function (lambda) to get a timestamp. Returns formatted string and optionally updates an item
item,
date_format |
var date_time_format = date_format
if(date_format == "" || date_format === null) date_time_format = "%1$ta %1$tT" //default format Day Hour:Minute:Seconds
var String Timestamp = String::format( date_time_format, new Date() )
if(item != NULL && item !== null) {
var t = new DateTimeType()
if(item instanceof DateTimeItem) {
item.postUpdate(t) ////postUpdate(item, t)
logInfo("Last Update", item.name + " DateTimeItem updated at: " + Timestamp )
}
else if(item instanceof StringItem) {
item.postUpdate(Timestamp) //postUpdate(item, Timestamp)
logInfo("Last Update", item.name + " StringItem updated at: " + Timestamp )
}
else
logWarn("Last Update", item.name + " is not DateTime or String - not updating")
}
Timestamp
]
I saw that, however, where would I put this function?
Sent from my iPhone. On Jan 11, 2019, 1:01 PM -0500, Nick Waterton notifications@github.com, wrote:
getTimestamp is my own OpenHab lambda for returning a DateTime or string timestamp. You can replace it with anything that returns a date/time (eg new DateTimeType() or now()). My actual lambda is this val Functions$Function2<GenericItem, String, String> getTimestamp = [ //function (lambda) to get a timestamp. Returns formatted string and optionally updates an item item, date_format |
var date_time_format = date_format if(date_format == "" || date_format === null) date_time_format = "%1$ta %1$tT" //default format Day Hour:Minute:Seconds var String Timestamp = String::format( date_time_format, new Date() ) if(item != NULL && item !== null) { var t = new DateTimeType() if(item instanceof DateTimeItem) { item.postUpdate(t) ////postUpdate(item, t) logInfo("Last Update", item.name + " DateTimeItem updated at: " + Timestamp ) } else if(item instanceof StringItem) { item.postUpdate(Timestamp) //postUpdate(item, Timestamp) logInfo("Last Update", item.name + " StringItem updated at: " + Timestamp ) } else logWarn("Last Update", item.name + " is not DateTime or String - not updating") } Timestamp ] — You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub, or mute the thread.
It's an Openhab Rule, it goes in the same .rules file as the other rules goes. With the latest versions of OH, you have to include this at the top of the rules files for lambdas to work
import org.eclipse.xtext.xbase.lib.Functions //apparently needed for OH2 lambda's
import org.eclipse.xtext.xbase.lib.Procedures //apparently needed for OH2 lambda's
I've copied the two lines on top of Roomba.rules and I copied the lambda in rooma.rules as well, now I get this in the logs:
Configuration model 'roomnba.rules' has errors, therefore ignoring it: [155,1]: missing EOF at 'val'
Can you post your complete Roomba.rules file? you have some errors in it somewhere. What version of OpenHab are you running?
I am using OH 2.4.0
Here is my complete Roomba.rules:
/ Roomba Rules / import org.eclipse.xtext.xbase.lib.Functions //apparently needed for OH2 lambda's import org.eclipse.xtext.xbase.lib.Procedures //apparently needed for OH2 lambda's
rule "Roomba start and stop" when Item roomba_control received command then logInfo("Roomba", "Roomba ON/OFF received command: " + receivedCommand) if (receivedCommand == ON) sendCommand(roomba_command, "start") if (receivedCommand == OFF) { sendCommand(roomba_command, "stop") Thread::sleep(1000) sendCommand(roomba_command, "dock") } end
rule "Roomba Auto Boost Control" when Item roomba_carpetBoost changed then logInfo("Roomba", "Roomba Boost changed to: Auto " + roomba_carpetBoost.state + " Manual: " + roomba_vacHigh.state) if (roomba_carpetBoost.state == ON && roomba_vacHigh.state == ON) sendCommand(roomba_vacHigh, OFF) end
rule "Roomba Manual Boost Control" when Item roomba_vacHigh changed then logInfo("Roomba", "Roomba Boost changed to: Auto " + roomba_carpetBoost.state + " Manual: " + roomba_vacHigh.state) if (roomba_carpetBoost.state == ON && roomba_vacHigh.state == ON) sendCommand(roomba_carpetBoost, OFF) end
rule "Roomba Auto Passes Control" when Item roomba_noAutoPasses changed or Item roomba_twoPass changed then logInfo("Roomba", "Roomba Passes changed to: Auto " + roomba_noAutoPasses.state + " Manual: " + roomba_twoPass.state) if (roomba_noAutoPasses.state == ON && roomba_twoPass.state == ON) sendCommand(roomba_twoPass, OFF) end
rule "Roomba Last Update Timestamp" when Item roomba_rssi received update then getTimestamp.apply(roomba_lastheardfrom, "%1$ta %1$tR") end
rule "Roomba Bin Full" when Item roomba_full changed from OFF to ON then val Timestamp = getTimestamp.apply(roomba_lastheardfrom, "%1$ta %1$tR") pushNotification("Roomba", "BIN FULL reported by Roomba at: " + Timestamp) end
rule "Roomba Error" when Item roomba_error changed from OFF to ON then val Timestamp = getTimestamp.apply(roomba_lastheardfrom, "%1$ta %1$tR") pushNotification("Roomba", "ERROR reported by Roomba at: " + Timestamp) sendMail(mailTo, "Roomba", "ERROR reported by Roomba at: " + Timestamp + "See attachment for details", "http://your_OH_ip:port/static/map.png") end
rule "Roomba percent completed" when Item roomba_sqft received update then var sqft_completed = roomba_sqft.state as Number
var max_sqft = 470 //insert max square footage here
var min_sqft = 0
var Number completed_percent = 0
if (sqft_completed < min_sqft) {completed_percent = 0)
else if (sqft_completed > max_sqft) {completed_percent = 100}
else {
completed_percent = (((sqft_completed - min_sqft) * 100) / (max_sqft-min_sqft)).intValue
}
logInfo("Roomba", "Roomba percent complete "+roomba_sqft.state+" of "+max_sqft.toString+" calculated as " + completed_percent.toString + "%")
postUpdate(roomba_percent_complete,completed_percent)
end
rule "Roomba update command" when Item roomba_phase received update then logInfo("Roomba", "Roomba phase received update: " + roomba_phase.state} switch(roomba_phase.state) { case "run" : postUpdate(roomba_command,"start") case "hmUsrDock" : postUpdate(roomba_command,"pause") case "hmMidMsn" : postUpdate(roomba_command,"pause") case "hmPostMsn" : { postUpdate(roomba_command,"dock") getTimestamp.apply(roomba_lastmissioncompleted, "%1$ta %1$tR") } case "charge" : postUpdate(roomba_command,"dock") case "stop" : postUpdate(roomba_command,"stop") case "pause" : postUpdate(roomba_command,"pause") case "stuck" : postUpdate(roomba_command,"stop") } end
rule "Roomba Notifications" when Item roomba_status changed then logInfo("Roomba", "Roomba status is: " + roomba_status.state} val Timestamp = getTimestamp.apply(roomba_lastheardfrom, "%1$ta %1$tR") switch(roomba_status.state) { case "Running" : pushNotification("Roomba", "Roomba is RUNNING at: " + Timestamp) case "Docking - End Mission" : { createTimer(now.plusSeconds(2)) [| pushNotification("Roomba", "Roomba has FINISHED cleaning at: " + Timestamp) sendMail(mailTo, "Roomba", "Roomba has FINISHED cleaning at: " + Timestamp + "See attachment for details", "http://your_OH_ip:port/static/map.png") ] } case "Stuck" : { pushNotification("Roomba", "HELP! Roomba is STUCK at: " + Timestamp) sendMail(mailTo, "Roomba", "HELP! Roomba is STUCK at: " + Timestamp + "See attachment for location", "http://your_OH_ip:port/static/map.png") } } end
rule "Roomba Schedule Display"
when
Item roomba_cycle changed or
Item roomba_cleanSchedule_h changed or
Item roomba_cleanSchedule_m changed
then
logInfo("Roomba", "Roomba Schedule: Day " + roomba_cycle.state + " Hour: " + roomba_cleanSchedule_h.state + " Minute: " + roomba_cleanSchedule_m.state)
var String schedule = ""
var String days = (roomba_cycle.state as StringType).toString
var String hours = (roomba_cleanSchedule_h.state as StringType).toString
var String minutes = (roomba_cleanSchedule_m.state as StringType).toString
val ArrayList daysOfWeek = newArrayList("Sun","Mon","Tues","Wed","Thur","Fri","Sat")
val ArrayList
val Functions$Function2<GenericItem, String, String> getTimestamp = [ //function (lambda) to get a timestamp. Returns formatted string and optionally updates an item item, date_format |
var date_time_format = date_format
if(date_format == "" || date_format === null) date_time_format = "%1$ta %1$tT" //default format Day Hour:Minute:Seconds
var String Timestamp = String::format( date_time_format, new Date() )
if(item != NULL && item !== null) {
var t = new DateTimeType()
if(item instanceof DateTimeItem) {
item.postUpdate(t) ////postUpdate(item, t)
logInfo("Last Update", item.name + " DateTimeItem updated at: " + Timestamp )
}
else if(item instanceof StringItem) {
item.postUpdate(Timestamp) //postUpdate(item, Timestamp)
logInfo("Last Update", item.name + " StringItem updated at: " + Timestamp )
}
else
logWarn("Last Update", item.name + " is not DateTime or String - not updating")
}
Timestamp
]
I've simply used your Roomba.rules file and added the function at the end of the file and added the 2 import lines on top.
I think lambdas are meant to go at the beginning of the rules file, just after the import statement. They are like global variables.
I did that too, now I get even more errors:
2019-01-11 15:49:07.259 [WARN ] [el.core.internal.ModelRepositoryImpl] - Configuration model 'roomba2.rules' has errors, therefore ignoring it: [147,15]: missing ')' at 'Stuck' [148,84]: no viable alternative at input 'is' [148,95]: mismatched input ':' expecting ']' [149,67]: no viable alternative at input '", "' [149,84]: no viable alternative at input 'is' [149,95]: mismatched input ':' expecting 'end' [158,1]: no viable alternative at input 'end' [160,1]: mismatched input 'rule' expecting 'then'
You haven't filled in any of the variables. For instance mailTo on line 146 is a global variable containing an e-mail addresss.. like this:
val String mailTo = "your-e-mail@gmail.com"
or just replace mailTo with an actual e-mail address (in quotes as shown)
You do realize that things like "http://your_OH_ip:port/static/map.png"
is not an actual web address right? you have to replace your_OH_ip:port
with your actual ip address and port of your OH server. These things are just placeholders for you to fill in with your actual values. I don't know what your e-mail address and ip address are.
I might have figured it out. I removed the Roomba.rule file, and copied a new file line by line.
There were some lines that had { instead of (… I corrected them and now I got furhtur… I just get the following error now:
2019-01-11 16:56:50.139 [ERROR] [ntime.internal.engine.RuleEngineImpl] - Rule 'Roomba Last Update Timestamp': null 2019-01-11 16:56:52.945 [WARN ] [ui.internal.items.ItemUIRegistryImpl] - Exception while formatting value 'OFF' of item roomba_error with format '%': Conversion = '%'
Can you repost you actual rule file? and use code flags (<> above) it's easier to read. A single error (lie a %) will kill OH's rule engine.
I've attached the rules file (renamed to txt file)
Please note that this is a straight copy and paste from your code on the main page....
I need to see your actual rules file, the one you sent won't work as you haven't filled in any of the placeholders, like mailTo
or your_OH_ip:port
with actual values, so it won't work as is (or delete the rules I mention below).
It also assumes that you have e-mail and pushNotification set up, if you don't the sendMail and pushNotification won't work either. You would have to delete these rules (or just comment out the pushNotification and sendMail until you have them set up):
rule "Roomba Error"
when
Item roomba_error changed from OFF to ON
then
val Timestamp = getTimestamp.apply(roomba_lastheardfrom, "%1$ta %1$tR")
pushNotification("Roomba", "ERROR reported by Roomba at: " + Timestamp)
sendMail(mailTo, "Roomba", "ERROR reported by Roomba at: " + Timestamp + "See attachment for details", "http://your_OH_ip:port/static/map.png")
end
rule "Roomba Notifications"
when
Item roomba_status changed
then
logInfo("Roomba", "Roomba status is: " + roomba_status.state}
val Timestamp = getTimestamp.apply(roomba_lastheardfrom, "%1$ta %1$tR")
switch(roomba_status.state) {
case "Running" : pushNotification("Roomba", "Roomba is RUNNING at: " + Timestamp)
case "Docking - End Mission" : {
createTimer(now.plusSeconds(2)) [|
pushNotification("Roomba", "Roomba has FINISHED cleaning at: " + Timestamp)
sendMail(mailTo, "Roomba", "Roomba has FINISHED cleaning at: " + Timestamp + "See attachment for details", "http://your_OH_ip:port/static/map.png")
]
}
case "Stuck" : {
pushNotification("Roomba", "HELP! Roomba is STUCK at: " + Timestamp)
sendMail(mailTo, "Roomba", "HELP! Roomba is STUCK at: " + Timestamp + "See attachment for location", "http://your_OH_ip:port/static/map.png")
}
}
end
as they would not work without email and pushNotification set up.
Also I don't know where
import time
import datetime
import date
comes from, but that can't work.
Attached with info mailTo or your_OH_ip:port filled in. However, I am more concerned about the error:
2019-01-11 16:56:50.139 [ERROR] [ntime.internal.engine.RuleEngineImpl] - Rule 'Roomba Last Update Timestamp': null 2019-01-11 16:56:52.945 [WARN ] [ui.internal.items.ItemUIRegistryImpl] - Exception while formatting value 'OFF' of item roomba_error with format '%': Conversion = '%'
Where the timestamp is null. It does not seem to get the timestamp and the format error of the value OFF.
I gave up on the lambda function. Instead I went with: roomba_lastheardfrom.postUpdate( new DateTimeType() )
Which works :).
However in the logs, I still get the formatting error
Line 144 is still incorrect, but that shouldn't cause your error. Are all your items defined correctly?
This rule is incorrect syntax:
rule "Roomba Last Update Timestamp"
when
Item roomba_rssi received update
then
Timestamp = getTimestamp.apply(roomba_lastheardfrom, "%1$ta %1$tR")
end
It should be:
rule "Roomba Last Update Timestamp"
when
Item roomba_rssi received update
then
getTimestamp.apply(roomba_lastheardfrom, "%1$ta %1$tR")
end
This is probably the cause of the errors.
What about all the other occurrences of getTimestamp, what did you replace those with? some rules use the returned Timestamp String as part of the notification message.
All I can say is that these rules work perfectly in my OH 2.4 set up. (actually I think I'm on 2.5 now, but I have been using the rules for nearly 2 years).
You have some basic syntax errors in these rules, you need to go through them carefully to check what you have done, or use the Visual Studio OH plugin to check for you.
Nick, i have mine mostly working but I'm also having an issue with the Date(). I'm getting error message in VSCode:
"Date cannot be resolved.(org.eclipse.xtext.diagnostics.Diagnostic.Linking) [10,66]"
My OH log shows the the following error:
2019-02-09 14:01:14.710 [ERROR] [ntime.internal.engine.RuleEngineImpl] - Rule 'Roomba Last Update Timestamp': null
All the associated items that use the "Timestamp" function are null as well.
I have the lambda at the top of my rules file with the recommended imports.
Here is my rules file:
import org.eclipse.xtext.xbase.lib.Functions //apparently needed for OH2 lambda's
import org.eclipse.xtext.xbase.lib.Procedures //apparently needed for OH2 lambda's
val Functions$Function2<GenericItem, String, String> getTimestamp = [ //function (lambda) to get a timestamp. Returns formatted string and optionally updates an item
item,
date_format |
var date_time_format = date_format
if(date_format == "" || date_format === null) date_time_format = "%1$ta %1$tT" //default format Day Hour:Minute:Seconds
var String Timestamp = String::format( date_time_format, new Date() )
if(item != NULL && item !== null) {
var t = new DateTimeType()
if(item instanceof DateTimeItem) {
item.postUpdate(t) ////postUpdate(item, t)
logInfo("Last Update", item.name + " DateTimeItem updated at: " + Timestamp )
}
else if(item instanceof StringItem) {
item.postUpdate(Timestamp) //postUpdate(item, Timestamp)
logInfo("Last Update", item.name + " StringItem updated at: " + Timestamp )
}
else
logWarn("Last Update", item.name + " is not DateTime or String - not updating")
}
Timestamp
]
/* Roomba Rules */
rule "Roomba start and stop"
when
Item roomba_control received command
then
logInfo("Roomba", "Roomba ON/OFF received command: " + receivedCommand)
if (receivedCommand == ON)
sendCommand(roomba_command, "start")
if (receivedCommand == OFF) {
sendCommand(roomba_command, "stop")
Thread::sleep(1000)
sendCommand(roomba_command, "dock")
}
end
rule "Roomba Auto Boost Control"
when
Item roomba_carpetBoost changed
then
logInfo("Roomba", "Roomba Boost changed to: Auto " + roomba_carpetBoost.state + " Manual: " + roomba_vacHigh.state)
if (roomba_carpetBoost.state == ON && roomba_vacHigh.state == ON)
sendCommand(roomba_vacHigh, OFF)
end
rule "Roomba Manual Boost Control"
when
Item roomba_vacHigh changed
then
logInfo("Roomba", "Roomba Boost changed to: Auto " + roomba_carpetBoost.state + " Manual: " + roomba_vacHigh.state)
if (roomba_carpetBoost.state == ON && roomba_vacHigh.state == ON)
sendCommand(roomba_carpetBoost, OFF)
end
rule "Roomba Auto Passes Control"
when
Item roomba_noAutoPasses changed or
Item roomba_twoPass changed
then
logInfo("Roomba", "Roomba Passes changed to: Auto " + roomba_noAutoPasses.state + " Manual: " + roomba_twoPass.state)
if (roomba_noAutoPasses.state == ON && roomba_twoPass.state == ON)
sendCommand(roomba_twoPass, OFF)
end
rule "Roomba Last Update Timestamp"
when
Item roomba_rssi received update
then
getTimestamp.apply(roomba_lastheardfrom, "%1$ta %1$tR")
end
rule "Roomba Bin Full"
when
Item roomba_full changed from OFF to ON
then
val Timestamp = getTimestamp.apply(roomba_lastheardfrom, "%1$ta %1$tR")
sendPushoverMessage(pushoverBuilder("BIN FULL reported by Roomba at: " + Timestamp))
end
rule "Roomba Error"
when
Item roomba_error changed from OFF to ON
then
val Timestamp = getTimestamp.apply(roomba_lastheardfrom, "%1$ta %1$tR")
sendPushoverMessage(pushoverBuilder("ERROR reported by Roomba at: " + Timestamp))
sendMail("myemailaddress", "Roomba", "ERROR reported by Roomba at: " + Timestamp + "See attachment for details", "http:XXX.XXX.X.XX:8080/static/map.png")
end
rule "Roomba percent completed"
when
Item roomba_sqft received update
then
var sqft_completed = roomba_sqft.state as Number
var max_sqft = 470 //insert max square footage here
var min_sqft = 0
var Number completed_percent = 0
if (sqft_completed < min_sqft) {completed_percent = 0}
else if (sqft_completed > max_sqft) {completed_percent = 100}
else {
completed_percent = (((sqft_completed - min_sqft) * 100) / (max_sqft-min_sqft)).intValue
}
logInfo("Roomba", "Roomba percent complete "+roomba_sqft.state+" of "+max_sqft.toString+" calculated as " + completed_percent.toString + "%")
postUpdate(roomba_percent_complete,completed_percent)
end
rule "Roomba update command"
when
Item roomba_phase received update
then
logInfo("Roomba", "Roomba phase received update: " + roomba_phase.state)
switch(roomba_phase.state) {
case "run" : postUpdate(roomba_command,"start")
case "hmUsrDock" : postUpdate(roomba_command,"pause")
case "hmMidMsn" : postUpdate(roomba_command,"pause")
case "hmPostMsn" : {
postUpdate(roomba_command,"dock")
getTimestamp.apply(roomba_lastmissioncompleted, "%1$ta %1$tR")
}
case "charge" : postUpdate(roomba_command,"dock")
case "stop" : postUpdate(roomba_command,"stop")
case "pause" : postUpdate(roomba_command,"pause")
case "stuck" : postUpdate(roomba_command,"stop")
}
end
rule "Roomba Notifications"
when
Item roomba_status changed
then
logInfo("Roomba", "Roomba status is: " + roomba_status.state)
val Timestamp = getTimestamp.apply(roomba_lastheardfrom, "%1$ta %1$tR")
switch(roomba_status.state) {
case "Running" : sendPushoverMessage(pushoverBuilder("Roomba is RUNNING at: " + Timestamp))
case "Docking - End Mission" : {
createTimer(now.plusSeconds(2)) [|
sendPushoverMessage(pushoverBuilder("Roomba has FINISHED cleaning at: " + Timestamp))
sendMail("myemailaddress", "Roomba", "Roomba has FINISHED cleaning at: " + Timestamp + "See attachment for details", "http://XXX.XXX.X.XX:8080/static/map.png")
]
}
case "Stuck" : {
sendPushoverMessage(pushoverBuilder("HELP! Roomba is STUCK at: " + Timestamp))
sendMail("myemailaddress", "Roomba", "HELP! Roomba is STUCK at: " + Timestamp + "See attachment for location", "http://XXX.XXX.X.XX:8080/static/map.png")
}
}
end
rule "Roomba Schedule Display"
when
Item roomba_cycle changed or
Item roomba_cleanSchedule_h changed or
Item roomba_cleanSchedule_m changed
then
logInfo("Roomba", "Roomba Schedule: Day " + roomba_cycle.state + " Hour: " + roomba_cleanSchedule_h.state + " Minute: " + roomba_cleanSchedule_m.state)
var String schedule = ""
var String days = (roomba_cycle.state as StringType).toString
var String hours = (roomba_cleanSchedule_h.state as StringType).toString
var String minutes = (roomba_cleanSchedule_m.state as StringType).toString
val ArrayList daysOfWeek = newArrayList("Sun","Mon","Tues","Wed","Thur","Fri","Sat")
val ArrayList<String> daysList = new ArrayList(days.replace("[","").replace("]","").replace("'","").split(","))
val ArrayList<String> hoursList = new ArrayList(hours.replace("[","").replace("]","").split(","))
val ArrayList<String> minutesList = new ArrayList(minutes.replace("[","").replace("]","").split(","))
daysList.forEach[ item, i |
if(item.trim() == "start") {
schedule += daysOfWeek.get(i) + ": " + hoursList.get(i) + ":" + minutesList.get(i) + ", "
}
]
postUpdate(roomba_cleanSchedule, schedule.trim())
end
Everything else seems to be funtioning normal with exception of another VSCode error regarding "ArrayList cannot be resolved" which I don't think is related.
Any ideas?
RESOLVED: I figured it out. Although everything you read about OH 2 is you don't need any imports, however the Date() issue and the other "ArrayList cannot be resolved" issue are both resolved by adding the following imports:
import java.util.ArrayList
import java.util.Date
Hi,
I am not sure if this is an issue. But I re-installed everything and everything seems to work. except, during the logs and sitemap, I get: Rule 'Roomba Last Update Timestamp': The name 'getTimestamp' cannot be resolved to an item or type; line 48, column 5, length 12