Timeline picker to setup heating, light and so on

When I used

openhab-cli

(console) and used command

things list

I see

tlpicker:tlp:home (Type=Thing, Status=UNINITIALIZED (HANDLER_MISSING_ERROR): Handler factory not found, Label=TimelinePicker, Bridge=null)

And with status

UNINITIALIZED or CONFIGURATION_PENDING

Openhab never reaches above 70…

You can disable it via rest API

curl -X 'PUT' \ 'https://demo.openhab.org/rest/things/A/enable' \ -H 'accept: */*' \ -H 'Content-Type: text/plain' \ -H 'X-OPENHAB-TOKEN: eyJraWQiOm51bGwsImFsZyI6IlJTMjU2In0.eyJpc3MiOiJvcGVuaGFiIiwiYXVkIjoib3BlbmhhYiIsImV4cCI6MTcxNTUyNzQ0NywianRpIjoiZkFzUFplR0FUaHdNQXFZWFp0cUpMUSIsImlhdCI6MTcxNTUyMzg0NywibmJmIjoxNzE1NTIzNzI3LCJzdWIiOiJkZW1vIiwiY2xpZW50X2lkIjoiaHR0cHM6Ly9kZW1vLm9wZW5oYWIub3JnIiwic2NvcGUiOiJhZG1pbiIsInJvbGUiOlsiYWRtaW5pc3RyYXRvciJdfQ.2ZPgvauITPXBbkmGacthjesa76BlLIWBzHY8okE6Jpe3PLi_kh0qhlZWAhcJHzcLMaF58cQ5viA3DgKmtKHNRawChdWy9t1fygtQ6jh5A-KEDxQMzEnb59TQ9DC5CgmdLk-XuIRfLO8d7n0EjSpnSmJ8fvHhhH1IkqPDglR8Qa_lSrU28_zqcnaAO-8sT-jB-2diqehOb4kSHIAtqomRHtFlfH1xUBtZbbWwgjpa9dLOmH9fNhDNH2yFhbrWYwXNaDFcdiRj9jcF3QtDMV9A15mzlZBYmgdEwcET5unOK7vvGdEiCvsZZqbbZQKfqDK_nEv10IMrgbmFr9Wom1PrBQ' \ -d 'string'

‘string’ : true or false

You can also modify the script that the thing will be initialized with enable = false

Btw: I am on OH4.2M2

Do I misinterpret this?

openhab> system:start-level 
Level 100
openhab> things list|grep tlp
tlpicker:tlp:home (Type=Thing, Status=UNINITIALIZED (HANDLER_MISSING_ERROR): Handler factory not found, Label=TimelinePicker, Bridge=null)

I am not an expert…
My knowledge is from

and

I checked it via an rule…let me see later when I am at home

You can enable system runlevel logging by changing the openhab.event.StartlevelEvent logger to INFO and you’ll see the runlevel events logged to the events.log.

I don’t want to read 850+ posts: What is the thing for and which binding creates it? Why is it unitialized?

ok.
Anyway, beautiful work!

As far as I understand the thing is used to store data and there is no binding creating it. Some information by the OP can be found in this post

@milo
as discussed in a private chat I’ll add my test results here.

I tested it today by rebooting the whole server (did anyway system updates which require a reboot).
After starting OpenHAB, events.log shows this:

*2024-05-13 14:15:25.153 [INFO ] [openhab.event.StartlevelEvent       ] - Startlevel '30' reached.*
*2024-05-13 14:15:25.153 [INFO ] [openhab.event.StartlevelEvent       ] - Startlevel '40' reached.*
*2024-05-13 14:16:15.162 [INFO ] [openhab.event.StartlevelEvent       ] - Startlevel '50' reached.*
*2024-05-13 14:16:15.162 [INFO ] [openhab.event.StartlevelEvent       ] - Startlevel '70' reached.*

But in the CLI, I see this before any message is written to events.log (start-level is here already @100 before any thing is initialized/started):

openhab> system:start-level                                                                                                                                                    
Level 80
openhab> system:start-level                                                                                                                                                    
Level 100

So it looks like CLI query and events.log output do not match regarding start-level value.

And @milo is correct, after DISABLE the tlp thing, the start-level goes immediately to 100

[root@homeserver openhab]# cat events.log | grep StartlevelEvent
2024-05-13 14:15:25.153 [INFO ] [openhab.event.StartlevelEvent       ] - Startlevel '30' reached.
2024-05-13 14:15:25.153 [INFO ] [openhab.event.StartlevelEvent       ] - Startlevel '40' reached.
2024-05-13 14:16:15.162 [INFO ] [openhab.event.StartlevelEvent       ] - Startlevel '50' reached.
2024-05-13 14:16:15.162 [INFO ] [openhab.event.StartlevelEvent       ] - Startlevel '70' reached.
2024-05-13 14:31:35.256 [INFO ] [openhab.event.StartlevelEvent       ] - Startlevel '80' reached.
2024-05-13 14:31:35.256 [INFO ] [openhab.event.StartlevelEvent       ] - Startlevel '100' reached.

The start-level issue is a different thing, I’ll try to have a look at that. Storing data in things is not a correct usage. Since you use jsscripting, you should be able to get the StorageService by using getService. You can then request a Storage with getStorage and use that. You can store anything you like (e.g. a HashMap) in that storage.

Thank you J-N-K,
For your reply…

I opened an issue, for the start level thing…

For the other issue…
I am not a programmer I don’t know how to do it…

After @J-N-K points out that using things as a configuration store is not the correct way, what to do?

  • I am not familiar with the use of StorageStore.
  • A complete redesign of the timeline picker is very time consuming. I do not have that time.
  • But as far i can see, is the timeline picker the only really userfriendly solution to schedul in OH - including sun events - and it’s working. (Cron is not userfriendly :melting_face:)

So, is someone willing to contribute code?
First question: Is data stored in the StorageStore persissted and present after a reboot?

If someone may be @rlkoshak can give an easy example or point us to an implementation here in the forum. I can help try to rewrite it, but programming skills are very basic.

I agree to you @tose that I really love your time schedule.

As I understood the linked page correctly it will persists, other idea is to store it in a json file in.the openhab directory? It’s dirty but it will do…

No, this is not possible. One need read and write access from the UI. Years ago, in the first version from the timeline picker (TLP) the data was stored in an item, but this is really odd and not transparent i will not do this again.

I have an other project where i store data in files but for this i have an npm express server and an own API created. This is an huge effort for someone who want install the TLP.

On the other side: When the TLP would be a real binding, i would store all the data in the thing, just like now. Perhaps it exist a way to set the state of the thing as ‘INITALIZED’?

Second question: Why exist an the OH API an endpoint to create a thing? This is what i do in the TLP.

I’ve never worked with the StorageService from a rule but based on the links from @J-N-K it’s pretty basic. Using JS Scripting

// Get the StorageService
var ss = osgi.getService('org.openhab.core.storage.StorageService');
// Get your custom Storage
var storage = ss.getStorage('TestStorage');

// Put something into the storage
storage.put('foo', 'bar');
// Delete something from the storage
storage.remove('foo');

It supports all the usual Map operations.

Values are saved to $OH_USERDATA/jsondb/<storage name>.json.

See above. It’s just a couple lines of code.

I agree it’s very user friendly but disagree that cron is the only other alternative. There are many other ways to configure timed events in OH.

Yes, see above for how to find the file.

When I first saw @milo’s issue I too felt that this was a misuse of Things.

2 Likes

It’s quite easy, you just have to replace the way you store data:

storing:

var storageService = osgi.getService('org.openhab.core.storage.StorageService')
var myStorage = storageService.getStorage('timelinepicker')

var conf1 = {
  foo: 'x',
  bar: 'y'
}

var conf2 = {
  foo: 'a',
  bar: 'b'  
}

myStorage.put('key_for_conf1', JSON.stringify(conf1))
myStorage.put('key_for_conf2', JSON.stringify(conf2))

Then a file <userdata>/jsondb/timelinepicker.json with the content

{
  "key_for_conf1": {
    "class": "java.lang.String",
    "value": "{\"foo\":\"x\",\"bar\":\"y\"}"
  },
  "key_for_conf2": {
    "class": "java.lang.String",
    "value": "{\"foo\":\"a\",\"bar\":\"b\"}"
  }
}

which of course persists over restarts. It’s the same storage that is used for UI configured items/things/…

Retrieval is the similar (and you can of course re-use the storage above, it’s just doubled here because I created two rules to test it:

var storageService = osgi.getService('org.openhab.core.storage.StorageService')
var myStorage = storageService.getStorage('timelinepicker')

var conf = JSON.parse(myStorage.get('key_for_conf1'))
console.log('foo='+conf.foo+', bar='+conf.bar)

and the log reads:

19:54:20.558 [INFO ] [enhab.automation.script.ui.bbf7444e1a] - foo=x, bar=y

Regarding the REST API: The endpoint is used to create new thing e.g. from UIs. It’s perfectly fine to create things that way. But things are linked to bindings which provide a thing handler for them. You just want to store data which is much easier without using the REST API (see above).

Edit: In principle you can store whatevery data-type you like, but Java must be able to serialize and deserialize it. That will not work out-of-the-box for JS maps, because Java does not know how to deserialize them. It’s easier to use strings.

Edit2: If you create an own storage for each configuration, you can do it lile @rlkoshak said. But you have to make sure the naming is unique.

4 Likes

Another option (probably the best) would be to use item-metadata for storage. You can easily set that via the REST API and the configuration is stored together with the item that is controlled by the picker.

Creating and using the storage in rules is clear and easy. Thanks @J-N-K , @rlkoshak.

For now the REST API is also used to show and modify the TLP data in the UI. The UI- element is an iframe with some JS in the OH html-folder.

Can i get the data stored in the storage from outside a rule to use it in the TLP HTML and JS?
The same question for modifing of the TLP im UI?

I can auto create items with the REST API and use these for transfering data. But i dont like this.

Yip, this is the way. Thanks :grinning:

In summary:
The current TLP is working as well and i will not change it. The usage from the Thing is not intendet but it is been working for a long time.

I will work at a new version :new:, since a long time on my roadmap is the possibility to define and auto create Holidays. I think this is good point to change the storage and i will use item-metadata and remove the thing.

For german holidays there is an npm package ‘Feiertage.js’, that is resolving this days. Exist this for other contrys too?

2 Likes

Take a look at the Ephemeris package.

Functions like Ephemeris.isWeekend oder Ephemeris.isBankHoliday will allow you to detect whether it’s a wekend or bank holiday day in whatever local location the user of the system has set for their system.

i.e.:

rule "Ephemeris Regel"
when    System started or
        Time cron "0 0 * * * ?" 
then
   if (Ephemeris.isWeekend == true) {
       postUpdate(Weekend,"Wochenende")
   }
   if (Ephemeris.isWeekend == false) {
       postUpdate(Weekend,"")
   }
   if (Ephemeris.isBankHoliday == true) {
       postUpdate(Holiday,"Feiertag")
       postUpdate(HolidayName,Ephemeris.getHolidayDescription(Ephemeris.getBankHolidayName))
   }
   if (Ephemeris.isBankHoliday == false) {
       postUpdate(Holiday,"")
       postUpdate(HolidayName,"")
   }
   
    var String nextHoliday  = Ephemeris.getHolidayDescription(Ephemeris.getNextBankHoliday)
    var String untilHoliday    = Ephemeris.getDaysUntil(Ephemeris.getNextBankHoliday).toString

    if (untilHoliday == "0") {
       nextHoliday  = Ephemeris.getHolidayDescription(Ephemeris.getNextBankHoliday(1)) 
       untilHoliday = Ephemeris.getDaysUntil(Ephemeris.getNextBankHoliday(1)).toString
    }


    postUpdate(NextHoliday,nextHoliday + ", in " + untilHoliday + " Tage(n)")
 end

Thanks. Do you know of an easy way to set custom holidays? I’ve seen the possibility xml file, but I can’t do that in a simple UI widget.

1 Like