Textual vs. Ui driven configuration

Here is a rule that I have that is disabled and it is called ztemplate because it is a collection of commands I have used and I can cut and paste from this. You cannot run this rule it is for reference only. Just get the bits you want.
I don’t use DSL as I read somewhere it caused memory issues. Javascript works better apparently. Whether that is still the case I don’t know.

Click here for sample code
//This contains things that I have found that work in javascript
//More information here: https://openhab-scripters.github.io/openhab-helper-libraries/Guides/But%20How%20Do%20I.html

//need below to log to openhab.log file
var logger = Java.type('org.slf4j.LoggerFactory').getLogger('org.openhab.rule.' + ctx.ruleUID);
//below is if you are going to use the ececute command
var Exec = Java.type("org.openhab.core.model.script.actions.Exec");
//below is also neede for the execute command
var Duration = Java.type("java.time.Duration");

//below is example of executeComand
Exec.executeCommandLine(Duration.ofSeconds(5), "/usr/bin/mosquitto_pub","\-h","192.168.0.164","\-t","cmnd/coffee/displaytext","\-m","[zOa2f0s1l1c1]" + device + "[s3l2c1]" +stateof + "[s1l8c1]Updated[c9]at:[c13tS]");

//This is the tricky part to get the triggering item. It uses event and event does NOT exist until the trigger
//has run and that is what creates the event. You CANNOT just press run now from the editor
//and expect it to work. It MUST be tested using an item trigger.

//below is get the triggering item Label
var device = itemRegistry.getItem(event.itemName).getLabel();
//or you can use the shorthand version
var device = ir.getItem(event.itemName).getLabel();

//below is to get the triggering item command from the item
var stateof = event.itemCommand ;

//below is an example to test the triggering event and see the old state and the new state
logger.info([itemRegistry.getItem(event.itemName).getLabel(), 'Changed From:', event.oldItemState ? event.oldItemState : 'Null', 'To:', newState].join(' '));

//below is how to get the state of an item
var rfinput = itemRegistry.getItem('RFBridgekitchen_Receiveddata').getState();

//below is example of logging
  logger.info('Back door opened' + variablename);

// below is a sleep funtion to slow down execution. I want to flash a lamp 3 times
function sleep(milliseconds) {
  date = Date.now();
  currentDate = null;
  do {
    currentDate = Date.now();
  } while (currentDate - date < milliseconds);
}
if (itemRegistry.getItem('Doorgarage_Doorgarage').getState() == 'OPEN' || itemRegistry.getItem('DoorshedLH_DoorshedLH').getState() == 'OPEN') {
  for (var count = 0; count < 3; count++) {
    events.sendCommand('Zigbeesengledbulb_Zigbeesengledbulb', 'ON');
    sleep(2000);
    events.sendCommand('Zigbeesengledbulb_Zigbeesengledbulb', 'OFF');
    logger.info('Door open somewhere');
  }
    events.sendCommand('Zigbeesengledbulb_Zigbeesengledbulb', 'ON');
}
// end of sleep example


//below is an example of how to send email assuming you have the mail binding correctly set up
//the mail:smtp:a514b96247 is found by looking at the mail thing

//below is how to sent html email with multiple attachemments (NOTE the plural of attachments)
var ArrayList = Java.type('java.util.ArrayList');
message = "<H2>Someone is at the front door at " + Date() + "</H2>";
attachmentUrlList = new ArrayList();
attachmentUrlList.add("http://192.168.0.164/zm/cgi-bin/zms?mode=single&monitor=6&scale=50");
attachmentUrlList.add("http://192.168.0.164/zm/cgi-bin/zms?mode=single&monitor=7&scale=50");
actions.get("mail", "mail:smtp:a514b96247").sendHtmlMailWithAttachments("testuser@gmail.com", "openHAB 3 front door bell", message , attachmentUrlList );


//below is how to post an update to an item
events.postUpdate('Doorcat_Doorcat', 'CLOSED');

//below is how to send a command to an item
events.sendCommand('CoffeeMachine_CoffeeMachine', 'OFF');

//below is how to test a value of an item and then do something
  if (itemRegistry.getItem('Tricklecharger_Tricklechargerpower').getState() < '5') {
  events.sendCommand('Tricklecharger_Tricklecharger', 'OFF');
//   logger.info('Script ran inner loop');
}


//I have left the code in to calculate the day etc as it was a pain to find any docs about it.
//calculate the day number
var datetoday = new Date();
var numberofweek = datetoday.getDay();

//if it is not NIGHT then change colour
if (itemRegistry.getItem("LocalSun_SunPhaseName").getState() != 'NIGHT') {

 if (numberofweek == 0){
 //It is Sunday and that week day is 0 and that doesn't work with the colour
  //set it to 7
  numberofweek = 7 ; 
  numberofweek = 5  //green
}else{
//it is NIGHT so only do red light  
  numberofweek = 1  //red
}
}

//end of calculate the day of the week


//this is how to find and replace - with _
events.postUpdate(itemRegistry.getItem(event.itemName).getName(), itemRegistry.getItem(event.itemName).getState().toString().replace(/-/g, '_'));

//Get the weeday name
var datetoday = new Date();
//var numberofweek = datetoday.getDate();
var weekday = datetoday.toLocaleString("default", { weekday: "short" })


//get list of group members
itemRegistry.getItem("gAllLights").members
itemRegistry.getItem("gAllLights").members.stream().forEach(function(i) { events.sendCommand(i.name, i.state.toString()); } );

var whatitis = "";
ir.getItem("Batteries").members
                   .stream()
                   .filter(function(batt) {return batt.state.intValue() <= 10; } )
                   .forEach(function(batt) { whatitis = whatitis + batt.label +": "+ batt.state +"%" + "\r\n"; } );
if(whatitis != ""){
    events.sendCommand('TelegramText', "Batteriewarnung für: \r\n" + whatitis);
}

//below will list all items and states in a group
var whatitis = "";
ir.getItem("Bedroom").members
                   .stream()
                   .forEach(function(batt) { whatitis = whatitis + batt.label +": "+ batt.state + "\r\n"; } );
if(whatitis != ""){
//    events.sendCommand('TelegramText', "Batteriewarnung für: \r\n" + whatitis);
  logger.info('\r\nGroup list: \r\n' + whatitis );
}

//below is json parse
var obj = itemRegistry.getItem("BOMdata").getState();
var test = JSON.parse(obj) ;


for (var count = 0; count < 7; count++) {
logger.info('Icon: ' + test.data[count].icon_descriptor);
logger.info('Short text: ' + test.data[count].short_text);
logger.info('Date: ' + test.data[count].date);
logger.info('Max: ' + test.data[count].temp_max);
logger.info('Min: ' + test.data[count].temp_min);
logger.info('Forecast ' + test.data[count].extended_text);
}

//>>>>>>>>>>>>>>>>>>>>>>>>>>
//More information here: https://openhab-scripters.github.io/openhab-helper-libraries/Guides/But%20How%20Do%20I.html
var OPENHAB_CONF = Java.type('java.lang.System').getenv('OPENHAB_CONF');

//need below to log to openhab.log file
var logger = Java.type('org.slf4j.LoggerFactory').getLogger('org.openhab.rule.' + ctx.ruleUID);
//below is if you are going to use the ececute command
var Exec = Java.type("org.openhab.core.model.script.actions.Exec");
//below is also neede for the execute command
var Duration = Java.type("java.time.Duration");

//var HttpUtil = Java.type("org.openhab.core.io.net.http.HttpUtil");
var HttpGet = Java.type("org.openhab.core.model.script.actions.HTTP");


//because icon names with dashes in them are reserved I replace the dash with underscore
function input(i) {
    return i.replace(/-/g,'_');
}

//var DATA = HttpUtil.executeUrl("GET","https://api.weather.bom.gov.au/v1/locations/r3fgmyd/forecasts/daily", 2000).replace(/icon_descriptor...\w+/g,input);
var DATA = HttpGet.sendHttpGetRequest("https://api.weather.bom.gov.au/v1/locations/r3fgmyd/forecasts/daily", 2000).replace(/icon_descriptor...\w+/g,input);

events.postUpdate("BOMdata", DATA);



                   
//>>>>>>>>>>>>>>>>>>>>>>>>>>>
//this is how to run a script file
var FrameworkUtil = Java.type("org.osgi.framework.FrameworkUtil");
var _bundle = FrameworkUtil.getBundle(scriptExtension.class);
var bundle_context = _bundle.getBundleContext()
var classname = "org.openhab.core.automation.RuleManager"
var RuleManager_Ref = bundle_context.getServiceReference(classname);
var RuleManager = bundle_context.getService(RuleManager_Ref);
RuleManager.runNow("8e1e6893d6"); //the 8e1e6893d6 is the id of the script found when you look in the script list

//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
//Stuff below keeps the results so you can run scripts and use the this.Storage result                   
//below is to create a global array
//this.Storage = (this.Storage === undefined) ? [] : this.Storage;
this.Storage = (this.Storage === undefined) ? 1 : this.Storage;
//below is to create a global number
this.Storage = this.Storage + 1;

//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>.
These 2 statements are the do the same thing:
logger.info(items["CoffeeMachine_CoffeeMachine"])
logger.info(itemRegistry.getItem("CoffeeMachine_CoffeeMachine").getState())

//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
//below splits the results comma separated
var test = itemRegistry.getItem("LightHall_Lighthallcolour").getState().toString().split(",");
logger.info("Test " +  test);
logger.info("Test " +  test[0]);
logger.info("Test " +  test[1]);
logger.info("Test " +  test[2]);

logger.info("Hue " + items["LightHall_Lighthallcolour"].getHue());
logger.info("Saturation " + items["LightHall_Lighthallcolour"].getSaturation());
logger.info("Brightness " + items["LightHall_Lighthallcolour"].getBrightness());

//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
  //below will list all items and states in a group
var whatitis = "";
ir.getItem("gBatterycheck").members
                   .stream()
                   .filter(function(batt) {return batt.state.intValue() <= 45; } )
                   .forEach(function(batt) { whatitis = whatitis + batt.label +": "+ batt.state + "\r\n"; } );
if(whatitis != ""){
//    events.sendCommand('TelegramText', "Batteriewarnung für: \r\n" + whatitis);
  logger.info('\r\nGroup list: \r\n' + whatitis );
}
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
//below gets the historical sate if an item
var PersistenceExtensions = Java.type("org.openhab.core.persistence.extensions.PersistenceExtensions");
var ZonedDateTime = Java.type("java.time.ZonedDateTime");

var myPersistentItem = ir.getItem("Zigbeesengledbulb_Zigbeesengledbulb");
logger.info("The pyload is {}", myPersistentItem);

var sinceDate = ZonedDateTime.now().minusDays(7);
//var sinceDate = ZonedDateTime.now().minusHours(5);

var maximumValueSince = PersistenceExtensions.maximumSince(myPersistentItem, sinceDate);

logger.info("Historic item is {}", maximumValueSince);
logger.info("Item name is {}", maximumValueSince.name);
logger.info("Item state is {}", maximumValueSince.state);

//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
//below is logic for a javascript timer. I have used similar in the coffee machine on off logic
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");  
var Exec = Java.type("org.openhab.core.model.script.actions.Exec");
var Duration = Java.type("java.time.Duration");

//set up the timercoffee
  var TimerMinutes = 55;
    logger.info("Coffee timer minutes: "+TimerMinutes);
  
if (this.timercoffee != undefined) {
      this.timercoffee.cancel();
      logger.info("Coffee timer undefined: ");
    }

    
    function displaywaring() {
      Exec.executeCommandLine(Duration.ofSeconds(5), "/usr/bin/mosquitto_pub","\-h","192.168.0.164","\-t","cmnd/coffee/displaytext","\-m","[zOf0s2]Coffee[c1l2]machine[c1l3]OFF in 5[c1l4]minutes.~3");
//      logger.info("CoffeeMachine_CoffeeMachine turned "+items["CoffeeMachine_CoffeeMachine"]);
      this.timercoffee = undefined;
            logger.info("Sending message to display: ");
    }

    this.timercoffee = ScriptExecution.createTimer(ZonedDateTime.now().plusMinutes(TimerMinutes), displaywaring);

}else{
results = Exec.executeCommandLine(Duration.ofSeconds(5), "/usr/bin/mosquitto_pub","\-h","192.168.0.164","\-t","cmnd/coffee/displaytext","\-m","[zOf0s2]Coffee[c1l2]machine[c1l3]is now off[c1l4]Bye.~3");
//If off then cancel the timercoffee
  if (this.timercoffee != undefined) {
      this.timercoffee.cancel();
      logger.info("Cancelled timer for coffee machine: ");
    }else{
      logger.info("Expired timer coffee machine: ");}

}  
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
  //Get a time in between two times:
  if ((LocalDateTime.now().isAfter(LocalDate.now().atTime(19, 0))) && (LocalDateTime.now().isBefore(LocalDate.now().atTime(22, 0)))) {
	sendCommand(blablabla)
}

//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
//parse json data:
  var test = JSON.parse('{"localNumber":"012345","remoteNumber":"012345","date":"2021-06-26T17:55:00+02","type":2,"duration":0}') 
logger.info("test: " + test.remoteNumber)
logger.info("date: " + test.date)
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

You will use this the most:

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

So you can see what is happening in the code in the log files.
For example:

 logger.info('Back door opened' + variablename);

image

1 Like

I posted my examples for you to look at.

I use DSL and I’ve never had memory issues. The bigger issue is that it’s specific to openHAB, so newer users with coding experience can find it confusing/frustrating to learn.

If someone already has DSL rules in OH2, there’s no significant benefit to changing them. For anyone who’s just starting, I’d recommend against learning DSL.

The tricky thing is that many of the older tutorials and examples in the community are written in DSL. The transition away from them will take some time, but posting your Javascript definitely helps. If you’re up for it, you might even want to make a new post to share the sample code you posted above, with headings/descriptions so that it’s easy for people to scroll through and find what they’re looking for. I think a lot of people would benefit.

Hello,
I am migrating to OH3.1 and I’d like to keep textual definitions. However, I am struggling to get my MQTT Setup in a text file and the Main UI definitions.

Whenever I modify something on the UI this huge json file is changed:
./userdata/jsondb/uicomponents_ui_page.json
All pages go in here. Is it possible somehow to have the main ui config in the conf folder and hierarchic (meaning a json file per page for example)?

in OH 2.x the mqtt broker could be defined here:
conf/services/mqtt.cfg

Seems not be possible either.
Now the mqtt definitions using the automatic approach go here:
./userdata/jsondb/org.openhab.core.thing.Thing.json

AFAIK no.

Err, no. That was in OH 1.x (or in compatibility mode).
MQTT for OH 2.3 and newer is different since this was implemented.

Well in theory you should be able to define any Thing via .thing file.
You “just” have to figure out the format. Haven’t tried with MQTT but there’s a section in the link I gave above.

1 Like

Hi Markus,
this didn’t work for me:

Bridge mqtt:broker:myUnsecureBroker [ host="192.168.0.42", secure=false ]
{
    Thing mqtt:topic:mything {
    Channels:
        Type switch : lamp "Kitchen Lamp" [ stateTopic="lamp/enabled", commandTopic="lamp/enabled/set" ]
        Type switch : fancylamp "Fancy Lamp" [ stateTopic="fancy/lamp/state", commandTopic="fancy/lamp/command", on="i-am-on", off="i-am-off" ]
        Type string : alarmpanel "Alarm system" [ stateTopic="alarm/panel/state", commandTopic="alarm/panel/set", allowedStates="ARMED_HOME,ARMED_AWAY,UNARMED" ]
        Type color : lampcolor "Kitchen Lamp color" [ stateTopic="lamp/color", commandTopic="lamp/color/set", rgb=true ]
        Type dimmer : blind "Blind" [ stateTopic="blind/state", commandTopic="blind/set", min=0, max=5, step=1 ]
    }
}

Should this be possible in OH3.1?

I have mqtt working but only using the “Magic”.

Dunno, as I wrote I didn’t try that myself. Possibly the syntax has changed, might be worth to cross-check with these binding docs.

You might look at Roomba980-Python/roomba.things at master · NickWaterton/Roomba980-Python · GitHub as an example for configuring MQTT. The structure looks a bit different from yours. Did work for me.

Following this

the following worked for me:

Bridge mqtt:broker:myUnsecureBroker [ host="192.168.0.42", secure=false ]

Thing mqtt:topic:mything "mything" (mqtt:broker:myUnsecureBroker) {
    Channels:
    Type switch : lamp "Kitchen Lamp" [ stateTopic="lamp/enabled", commandTopic="lamp/enabled/set" ]
    Type switch : fancylamp "Fancy Lamp" [ stateTopic="fancy/lamp/state", commandTopic="fancy/lamp/command", on="i-am-on", off="i-am-off" ]
    Type string : alarmpanel "Alarm system" [ stateTopic="alarm/panel/state", commandTopic="alarm/panel/set", allowedStates="ARMED_HOME,ARMED_AWAY,UNARMED" ]
    Type color : lampcolor "Kitchen Lamp color" [ stateTopic="lamp/color", commandTopic="lamp/color/set", rgb=true ]
    Type dimmer : blind "Blind" [ stateTopic="blind/state", commandTopic="blind/set", min=0, max=5, step=1 ]
}

PS: probably worth to update the binding docs with a (corrected) example like in the blogpost - any takers?

Hi Markus,
yes this works for me too. This eases the whole configuration quite a lot.
Thank you for the input.

I’ve put this into the docs.

The experimental file config simulation of things and items defined in UI is hanging up in the air since April. We all should force @mstormi and openhab band to pay some attention to this, as this is a necessary feature.

@11194, I’d appreciate if you could reconsider your choice of words. No one can “force” any of our volunteers to do anything, and the mere suggestion shows a lack of respect for Markus and all of the developers and maintainers who put their own time and effort into this project.

If you don’t like what’s going on with openHAB, no one will “force” you to use it. If you think you’re owed something because you downloaded free software, then you’re wrong. The only thing we owe each other here is mutual respect.

I hope I’ve misread your intention, in which case I apologize for over-reacting. However, in my 2.5 years in this community, I don’t recall anyone ever suggesting that users should try to force developers to do something.

I also hope that others will give you a chance to respond before this gets out of hand. Instead of letting a moment of frustration define us, let’s all take the high road. There’s enough negativity in the world, and I personally come to the openHAB community to get away from it.

5 Likes

What do you mean here? I am not aware of any simulation for configs.

Who decides what a necessary feature is ?

@rpwong Don’t worry Russ, I didn’t meant we should rope volunteer maintainers and actually force them to apply some feature with a help of soldering iron =) But as a new user I actively search community forum for solutions and I often see other users asking questions and having issues with items or things, added with textual or UI config. Old users have issues when migrating from Oh2.5, new users see Oh2 recipes, apply them, then cannot find out how to edit their newly created items to add them to semantic model.
I personally got an issue with the very start to Oh while using RGroll’s example widget for OpenWheatherMap - there are two options how to create 667 needed items, by .items or by 667 clicks in UI, I’ve chosen file config and had to redo everything later to UI items to apply semantic model, tags and so on.
I think that those two approaches, UI and textual-based, have their own advantages and disadvantages, the first is better for fast changes of single item or fine tuning, the second is better for sharing solutions and initial setup, so we all have to use both of them, so we really need interaction between them.

No, you could have clicked „select all“ at the end of the channel list and have all items created at once and added to the model.

2 Likes

This!

Just FTR, I am openHABian maintainer but no core developer i.e. just a user like everybody else.
So even if I agreed to what @11194 wrote (which I do by no means even if I disregarded his wording),
I could not do anything about it other than to enhance the docs.
Which is what I did while @11194 was busy texting his lack of respect.

FYI, and as mentioned in an earlier post on this thread, you don’t need the UI to generate the semantic model.

2 Likes

This way my browser window just hanged up and never recovered. And in the end I decided to have just a 7-day forecast, as 14-days is too far from truth for my location and has no sense. And remember - I was totally new to Openhab, and this widget was a first try for me, as it was for many other users.

Here it is, a compromise between the two approaches.

I am not shure if that proposal will allow editing GUI created things/items/etc. via VS-Code, as you cannot edit the JSON-DB where those are stored while openHAB is running. This might need some core changes for the way those entities are stored internally which will introduce breaking changes….