Timeline picker to setup heating, light and so on

Hallo,

Here is my directory structure under OPENHAB_CONF. I have another directory /js223 but I can’t copy in there. I think this is correct.

$ OPENHAB_CONF=/etc/openhab

/etc/openhab/automation/js/conf/00_RNTs-tlp3_conf.js
/etc/openhab/automation/js/RNTs-tlp3.js
/etc/openhab/automation/js223

/etc/openhab/html/tlp-jsr/css
/etc/openhab/html/tlp-jsr/fonts
/etc/openhab/html/tlp-jsr/icons
/etc/openhab/html/tlp-jsr/js
/etc/openhab/html/tlp-jsr/index.html

Do I have to set any permissions?

Is the name of the token important? I just named it timeLine.

My directory structure differs as I am using the docker image. I believe yours is ok for a default install.
I also used an arbitrary name for the token. Does not matter.

Sorry and thanks for the help.
I had in the file tlp_thing_controller.js not yet the token encoded.

hey @tose
I thought about trying this again in OH3 now and applied the branch “develop_v3.x_for_OH3.x(GraalVM)”

I edited the 3 config files and applied the base64 encoded token (you might adjust your readme). After that I adjusted my existing sitemap to the following:

sitemap zeitsteuerung label="Zeitsteuerung der Poolpumpe" {
    Frame label="Mo-So" {
        Webview icon="none" url="/static/tlp-jsr/index.html?id=MoSo&mode=1,2,3,4,5,6,7&states=0,1&lang=de&deactivation=true" height=14
    }
}

I edited the “automation/js/conf/00_RNTs-tlp3_conf.js” to the following:

var tlp_ids = {
  'MoSo': 'MBF_PAR_FILT_MANUAL_STATE'
}

But if I check the sitemap it complains about a missing id which I could create now. This is confusing because If I read the readme and check against the files I would assume everything should be set by defining the id in the url and in this config file.

What is the correct way to do it?

I also do not know what to do with this statement: “the path in automation is changed !”

EDIT: Same warning and error as mentioned before. The file exists!

2022-07-10 19:30:00.499 [WARN ] [.automation.script.file.RNTs-tlp3.js] - tlp - W001: no config file exist
2022-07-10 19:30:00.505 [WARN ] [.automation.script.file.RNTs-tlp3.js] - tlp - E002: error in inner loop {}

EDIT2: curl -X GET --header "Accept: application/json" "http://127.0.0.1:8080/rest/things/tlpicker:tlp:home" -u 'token:'
{"error":{"message":"Thing tlpicker:tlp:home does not exist!","http-code":404}}

EDIT3: Adjusting the path in RNTs-tlp3.js to tlp_ids = require('/etc/openhab/automation/js/conf/00_RNTs-tlp3_conf.js')seems to fix the loading issue of the file (there seems to be something wrong about loading files inside /automation/js subfolders? Do you use a customize script / binding / installation of openhab / openhab-js?)

But the list seems to be empty anyways:

      tlp_ids = require('/etc/openhab/automation/js/conf/00_RNTs-tlp3_conf.js')
      console.warn("IDs: ", tlp_ids)

[.automation.script.file.RNTs-tlp3.js] - IDs: {}

Ref1: [jsscripting] JS script engine no longer watches node_modules for scripts by jpg0 · Pull Request #11830 · openhab/openhab-addons · GitHub
Ref2: [jsscripting] Allow loading files relative from root folder automation/js · Issue #12016 · openhab/openhab-addons · GitHub

But there is still no thing being created. Reading tlpThing you get the error mentioned above

2022-07-10 20:50:00.817 [WARN ] [.automation.script.file.RNTs-tlp3.js] - {
  "error": {
    "message": "Thing tlpicker:tlp:home does not exist!",
    "http-code": 404
  }
}

Hi Sefer,

There are two ways to declare items for switching. The first in the sitemapfile as url parameter, the second in file 00__RNTs-tlp3_config.js. The definition in file is only for switch items. When you call the timeline for the first time, you still have to confirm the creation of the id.

The folder structure has changed.

You can use this statement (the origin line on GitLab is wrong and must updated):

tlp_ids = require('../../js/conf/00_RNTs-tlp3_conf.js')

Please post the console from your browser after an click on ‘yes - create id’.

Alright, I see. So I choose an ID of my liking and don’t have to add “linkedItems=VirtualItem” to the url anymore because it checks this one against the ID in the config file (which should match the id in the URL).

But the confirmation of the ID seems unnecessary if it is in the config (might implement a check against that). I can live with that anyways :slight_smile:

Got it. Was confused. I applied every file anyways (for me nothing changed because it was a fresh start). You might want to make that clear in the readme.

Thank you very much. Indeed, the error is gone. I only tested .../ too instead of .../.../

I am using this in HABPanel as an iframe-widget, too. Works great more or less (but not with the mobile apps, hard to navigate and a bit is cut off from the iframe). Wasn’t able to fit it yet. But this is none of your problems because even now the apps are still not optimized…

On OH3 UI it also works as an webframe-card

component: oh-webframe-card
config:
  src: /static/tlp-jsr/index.html?id=MoSo&linkedItems=VirtualPumpenmodus_TLP&mode=1,2,3,4,5,6,7&states=OFF,ON&lang=de&deactivation=true
  title: Timeline
  height: 1000px

Current console log after fixing the path:

roboto.css:1          GET http://192.168.2.20:8080/basicui/fonts/Roboto-Regular.woff2 net::ERR_ABORTED 404 (Not Found)
roboto.css:1          GET http://192.168.2.20:8080/basicui/fonts/Roboto-Medium.woff2 net::ERR_ABORTED 404 (Not Found)
vue.js:8542 Download the Vue Devtools extension for a better development experience:
https://github.com/vuejs/vue-devtools
vue.js:8553 You are running Vue in development mode.
Make sure to turn on production mode when deploying for production.
See more tips at https://vuejs.org/guide/deployment.html
roboto.css:1          GET http://192.168.2.20:8080/basicui/fonts/Roboto-Medium.woff net::ERR_ABORTED 404 (Not Found)
roboto.css:1          GET http://192.168.2.20:8080/basicui/fonts/Roboto-Regular.woff net::ERR_ABORTED 404 (Not Found)
vue.js:8542 Download the Vue Devtools extension for a better development experience:
https://github.com/vuejs/vue-devtools
vue.js:8553 You are running Vue in development mode.
Make sure to turn on production mode when deploying for production.
See more tips at https://vuejs.org/guide/deployment.html
roboto.css:1          GET http://192.168.2.20:8080/basicui/fonts/Roboto-Medium.ttf net::ERR_ABORTED 404 (Not Found)
roboto.css:1          GET http://192.168.2.20:8080/basicui/fonts/Roboto-Regular.ttf net::ERR_ABORTED 404 (Not Found)
tlp_thing_controller.js:29 TypeError: Failed to fetch
    at tlp_thing_controller.js:26:11
    at new Promise (<anonymous>)
    at tlpThing.get (tlp_thing_controller.js:12:12)
    at tlp_thing_controller.js:137:16
    at new Promise (<anonymous>)
    at tlpThing.get_id (tlp_thing_controller.js:134:12)
    at Vue._initTimelineView (switchPointSet_jsr.js:234:20)
    at Vue.created (switchPointSet_jsr.js:97:10)
    at callHook (vue.js:2921:21)
    at Vue._init (vue.js:4617:5)
tlp_thing_controller.js:29 TypeError: Failed to fetch
    at tlp_thing_controller.js:26:11
    at new Promise (<anonymous>)
    at tlpThing.get (tlp_thing_controller.js:12:12)
    at VueComponent._initAdminSetupView (tlpAdminSetup.js:105:18)
    at VueComponent.created (tlpAdminSetup.js:87:10)
    at callHook (vue.js:2921:21)
    at Vue._init (vue.js:4617:5)
    at new VueComponent (vue.js:4785:12)
    at createComponentInstanceForVnode (vue.js:4304:10)
    at init (vue.js:4125:45)
switchPointSet_jsr.js:293 TypeError: Cannot read properties of null (reading 'location')
    at Vue._getParamsFromURL (switchPointSet_jsr.js:144:50)
    at switchPointSet_jsr.js:238:20
vue.js:8542 Download the Vue Devtools extension for a better development experience:
https://github.com/vuejs/vue-devtools
vue.js:8553 You are running Vue in development mode.
Make sure to turn on production mode when deploying for production.
See more tips at https://vuejs.org/guide/deployment.html
vue.js:8542 Download the Vue Devtools extension for a better development experience:
https://github.com/vuejs/vue-devtools
vue.js:8553 You are running Vue in development mode.
Make sure to turn on production mode when deploying for production.
See more tips at https://vuejs.org/guide/deployment.html

I adjusted the widget from @fabian_b for the OH3 GraalVM version. I left out “&event” because it causes the warning to keep or remove the timeline on each refresh
oh and Dark mode doesn’t work as of commit 250ad0a2801f55550229fa6d2ad943d9bcfa2fb7

uid: widget_timelinepicker
tags: []
props:
  parameters:
    - description: Titel of your widget
      label: Title
      name: title
      required: false
      type: TEXT
    - description: Unique identifier for your timeline
      label: ID
      name: timeline_id
      required: true
      type: TEXT
    - description: Configuration Mode (Default is params, ui)
      label: Configuration
      name: conf
      required: false
      type: TEXT
    - description: Days to be managed in your timeline (1,2,3,4,5,6,7 = Each day, 15 = Mon-Fri, 17 = Full Week, 67 = Sat-Sun)
      label: Day Configuration
      name: mode
      required: true
      type: TEXT
    - description: States available for your item (Comma-separated list of maximum six states, i.e. 0,15,INCREASE,DECREASE,OFF,ON, ...)
      label: Switch States
      name: states
      required: true
      type: TEXT
    - context: item
      description: Item(s) which you want to control with the timeline
      label: Linked Item(s)
      name: linked_Items
      required: true
      multiple: true
      type: TEXT
    - description: Language for your widget (Default english)
      label: Language selection
      name: language
      required: false
      type: TEXT
      options:
        - value: "en"
          label: "English"
        - value: "fr"
          label: "French"
        - value: "de"
          label: "German"
        - value: "it"
          label: "Italian"
        - value: "nl"
          label: "Dutch"
        - value: "pt"
          label: "Portuguese"
      limitToOptions: true
    - description: Allows deactivation of timeline in the UI
      label: Deactivation button
      name: deactivation
      required: false
      type: TEXT
      options:
        - value: "true"
          label: "Button active"
        - value: "false"
          label: "Button inactive"
      limitToOptions: true
    - description: Zoom mode to enable control slider for mobiles and tablets
      label: Zoom mode
      name: zoom
      required: false
      type: TEXT
      options:
        - value: "auto"
          label: "Automatic zoom"
        - value: "force"
          label: "Force zoom control"
        - value: "no"
          label: "Disable zoom control"
      limitToOptions: true
    - description: Colorset for the timeline (Default 1, 2, 3, hex values without hash (i.e. 555E7B,B7D968,B576AD))
      label: Colorset
      name: colorset
      required: false
      type: TEXT
    - description: Darkmode for the timeline
      label: Dark mode
      name: dark
      required: false
      type: TEXT
      options:
        - value: "true"
          label: "Enable dark mode"
        - value: "false"
          label: "Disable dark mode"
      limitToOptions: true
  parameterGroups: []
timestamp: Jul 12, 2022, 7:28:50 PM
component: oh-webframe-card
config:
  src: ="/static/tlp-jsr/index.html?id=" + props.timeline_id + "&linkedItems=" + props.linked_Items + "&mode=" + props.mode + "&states=" + props.states + "&lang=" + ((props.language)?props.language:"en") + "&colorset=" + ((props.colorset)?props.colorset:"1") + ((props.deactivation === "true")?"&deactivation":"") + "&zoom=" + ((props.zoom)?props.zoom:"auto") + "&conf=" + ((props.conf)?props.conf:"params") + ((props.dark === "true")?"&dark":"")
  height: 600px
  title: = props.title

EDIT: My approach for a manual mode. I guess there is a better way to do it or code it, but I wanted it done :slight_smile:

VirtualPumpenmodus_States: Managed = OFF, Manual = ON
VirtualPumpenmodus_TLP: OFF, ON
VirtualPumpenmodus_Manuell: OFF, ON

Virtual switches:

Switch VirtualPumpenmodus_States "Pumpenmodus [MAP(virtual_pumpenmodus.map):%s]"
Switch VirtualPumpenmodus_TLP "Pumpenmodus Timeline Picker"
Switch VirtualPumpenmodus_Manuell "Wenn manuell, Pumpe ist"

The rule checks every switch. Since I didn’t test a restart of openhab yet and what happens to these virtual items, I decided to switch everything to off (which means a Managed run setup anyways) if the state is NULL

Then I go and look for the triggering item and decide what to do. If the trigger comes from VirtualPumpenmodus_States to status OFF (managed) I compare the state of VirtualPumpenmodus_TLP to the real world item and switch it accordingly. If States switches to ON (manual) I compare to selected state of VirtualPumpenmodus_Manuell with the real world item and make a switch if neccessary.

The trigger from VirtualPumpenmodus_TLP or VirtualPumpenmodus_Manuell just gets handled based on the States state to (if allowed) switch the real world item

Rule:

rule "Pumpenschaltung"
when
    Item VirtualPumpenmodus_States received command or
    Item VirtualPumpenmodus_TLP received command or
    Item VirtualPumpenmodus_Manuell received command
then
    if (VirtualPumpenmodus_States.state == NULL) {
        VirtualPumpenmodus_States.sendCommand(OFF)
        logInfo("Pumpensteuerung", "VirtualPumpenmodus_States was NULL, changed")
    } else if (VirtualPumpenmodus_TLP.state == NULL) {
        VirtualPumpenmodus_TLP.sendCommand(OFF)
        logInfo("Pumpensteuerung", "VirtualPumpenmodus_TLP was NULL, changed")
    } else if (VirtualPumpenmodus_Manuell.state == NULL) {
        VirtualPumpenmodus_Manuell.sendCommand(OFF)
        logInfo("Pumpensteuerung", "VirtualPumpenmodus_Manuell was NULL, changed")
    }

    switch(triggeringItemName) {
        case "VirtualPumpenmodus_States": {
            if (receivedCommand == OFF) {
                switch(VirtualPumpenmodus_TLP.state.toString) {
                    case "OFF": {
                        if (MBF_PAR_FILT_MANUAL_STATE.state != 0) {
                            MBF_PAR_FILT_MANUAL_STATE.sendCommand(0)
                        }
                    }
                    case "ON": {
                        if (MBF_PAR_FILT_MANUAL_STATE.state != 1) {
                            MBF_PAR_FILT_MANUAL_STATE.sendCommand(1)
                        }
                    }
                }
            }
            if (receivedCommand == ON) {
                switch(VirtualPumpenmodus_Manuell.state.toString) {
                    case "OFF": {
                        if (MBF_PAR_FILT_MANUAL_STATE.state != 0) {
                            MBF_PAR_FILT_MANUAL_STATE.sendCommand(0)
                        }
                    }
                    case "ON": {
                        if (MBF_PAR_FILT_MANUAL_STATE.state != 1) {
                            MBF_PAR_FILT_MANUAL_STATE.sendCommand(1)
                        }
                    }
                }
            }
        }

        case "VirtualPumpenmodus_TLP": {
            if (VirtualPumpenmodus_States.state == OFF) {
                if (receivedCommand == OFF) {
                    MBF_PAR_FILT_MANUAL_STATE.sendCommand(0)
                }
                if (receivedCommand == ON) {
                    MBF_PAR_FILT_MANUAL_STATE.sendCommand(1)
                }
            }
        }

        case "VirtualPumpenmodus_Manuell": {
            if (VirtualPumpenmodus_States.state == ON) {
                if (receivedCommand == OFF) {
                    MBF_PAR_FILT_MANUAL_STATE.sendCommand(0)
                }
                if (receivedCommand == ON) {
                    MBF_PAR_FILT_MANUAL_STATE.sendCommand(1)
                }
            }
        }
    }
end

Hi, timeline picker is a great tool, many thanks.
I have used it for a while on OH 2 and am now upgrading to OH 3 on a fresh install on a Pi.
It took me four frustrating hours to get timeline picker working, I was getting “error in transfer string”.
in the end the solution was simple, I didn’t have jsonpath transformation installed. Would be good if this was included as a step in the installation instructions.

I look forward to timeline picker working flawlessly in the future as it has in the past.

Again many thanks

1 Like

Hi Frederick,
it’s nice that the timeline picker is working well.
Only the requierements are written in the doc :wink:

MapDB and JSONpath transformation (JSONpath only for the DSL-rules version).

1 Like

Hi, this is exactly what i missed for my heating control. Thank you.

With small change in swtichPointSet.js is working also from openHab cloud.

if(window.location.host == ‘home.myopenhab.org’){
this.ip = ‘https://home.myopenhab.org/rest/items/’;
} else {
this.ip = ‘http://’ + openHAB_ip + ‘/rest/items/’;
}

@MilosM Thank’s for your feedback and advice. You are solveing this task. :+1:

In general i will not change anything in the ruleDSL version of timelinepicker. The javascript version is the future, my time is limited and unfortunately i can’t see how many guys is using the timelinepicker and the various versions. So it’s not so cool, to invest a lot of time for to few installations. (5?, 50?, 300?)

The new v3 is maintained! :grinning:

Here you will find new features:

  • switching depending of sunrise and sunset
  • easer installation (a pretty solution for the token for access on the REST- API is missing but the version is running pretty well)

There are two versions:

I posted this infos a few months ago. The interest is pretty limited and i was busy with other things.
Tester and feedback woud be a good idea. Than i can/would update the OP in this thread.

5 Likes

Ok, I was trying to use this updated version. So far no luck. I continue to have the following error:
[WARN ] [b.automation.script.file.RNTs-tlp3.js] - tlp - E002: error in inner loop {}

The API-token has been set to the three files named. Took some detour before reading to use encoding instead of decoding.

Next issue is with the sitemap not showing anything in the windows. Just the windows and some indication of an icon plus the title. I tried with Chrome and Safari.

Any idea how to resolve these issues?
All files have been double and triple checked for its right location. The conf file has been tried and the link in the site map as well.

The second issue is primary. First you need to see the timeline in UI. Please post the line from your sitemap-file where you call the timelinePicker.

The second you can post the output from the developer console when you refresh the site with the timeline picker.

Ok, long time spend and finally seeing some progress. In Chrome I do see the charts and can change settings. Still there is an issue. When restarting the webpage the graph every time asks for either continue with accepting a change or clear timeline.

The ‘.conf’ file is not in use/empty. Therefore I would expect to set the id in the url together with the name for the linked item. How else would the chart know which item to link to.

Webview url=“http://xx.xx.xx.xx:8080/static/tlp-jsr/index.html?id=uid_140&conf=params&mode=15,67&states=Tag,Nacht,Komfort&linkedItems=BadUG&lang=en&deactivation&event&dark&zoom=force” height=14

Please tell us what was wrong.

What happens, when you refresh the site in your browser? Are you see empty timelines?
You can post the output from the developer console in crome. First refresh the site, set some entrys in the timeline and save this value’s.

I have no clue what made in run the end. After numerous reboots, trying with the paths in the files etc. it suddenly showed the desired info on the Chrome.

Ok, lets come to the error list. For some strange reason I do have Vietnamese fonts only. The software is looking for Robot_Medium.

Next thing see in the image.
image

Have you past the token in file tlp_thing_controller?
(base64 !)

The output from your console shows the refresh moment not the moment when you save the timeline.

checked the token between the three files. Its exactly the same in all files.

after pressing save it only says ‘update succeeded’ in switchPointSet jar.js:343

before that it shows
TypeError: Cannot read properties of undefined (reading ‘event’)
at switchPointSet_jsr.js:263:70
switchPointSet_jsr.js:293 TypeError: Cannot read properties of undefined (reading ‘event’)
at switchPointSet_jsr.js:263:70
switchPointSet_jsr.js:293 TypeError: Cannot read properties of undefined (reading ‘event’)
at switchPointSet_jsr.js:263:70

and another copy from Chrome

GET http://192.168.0.5:8080/basicui/fonts/Roboto-Regular.ttf 404 (Not Found)
roboto.css:1 GET http://192.168.0.5:8080/basicui/fonts/Roboto-Medium.ttf net::ERR_ABORTED 404 (Not Found)
tlp_thing_controller.js:29 TypeError: Failed to fetch
at MaterialLayout.init (ripple.js:243:1)
at new MaterialLayout (ripple.js:243:1)
at n (ripple.js:243:1)
at i (ripple.js:243:1)
at Object.o [as upgradeAllRegistered] (ripple.js:243:1)
at ripple.js:243:1
tlp_thing_controller.js:29 TypeError: Failed to fetch
at MaterialLayout.init (ripple.js:243:1)
at new MaterialLayout (ripple.js:243:1)
at n (ripple.js:243:1)
at i (ripple.js:243:1)
at Object.o [as upgradeAllRegistered] (ripple.js:243:1)
at ripple.js:243:1
tlp_thing_controller.js:29 TypeError: Failed to fetch
at tlp_thing_controller.js:26:11
at new Promise ()
at tlpThing.get (tlp_thing_controller.js:12:12)
at tlp_thing_controller.js:137:16
at new Promise ()
at tlpThing.get_id (tlp_thing_controller.js:134:12)
at Vue._initTimelineView (switchPointSet_jsr.js:234:20)
at Vue.created (switchPointSet_jsr.js:97:10)
at callHook (vue.js:2921:21)
at Vue._init (vue.js:4617:5)
tlp_thing_controller.js:29 TypeError: Failed to fetch
at tlp_thing_controller.js:26:11
at new Promise ()
at tlpThing.get (tlp_thing_controller.js:12:12)
at tlpThing.getAll_id (tlp_thing_controller.js:177:31)
at VueComponent._initAdminSetupView (tlpAdminSetup.js:101:16)
at VueComponent.created (tlpAdminSetup.js:87:10)
at callHook (vue.js:2921:21)
at Vue._init (vue.js:4617:5)
at new VueComponent (vue.js:4785:12)
at createComponentInstanceForVnode (vue.js:4304:10)
tlp_thing_controller.js:29 TypeError: Failed to fetch
at tlp_thing_controller.js:26:11
at new Promise ()
at tlpThing.get (tlp_thing_controller.js:12:12)
at VueComponent._initAdminSetupView (tlpAdminSetup.js:105:18)
at VueComponent.created (tlpAdminSetup.js:87:10)
at callHook (vue.js:2921:21)
at Vue._init (vue.js:4617:5)
at new VueComponent (vue.js:4785:12)
at createComponentInstanceForVnode (vue.js:4304:10)
at init (vue.js:4125:45)
switchPointSet_jsr.js:293 TypeError: Cannot read properties of undefined (reading ‘event’)
at switchPointSet_jsr.js:263:70
switchPointSet_jsr.js:293 TypeError: Cannot read properties of undefined (reading ‘event’)
at switchPointSet_jsr.js:263:70
switchPointSet_jsr.js:293 TypeError: Cannot read properties of undefined (reading ‘event’)
at switchPointSet_jsr.js:263:70
vue.js:8542 Download the Vue Devtools extension for a better development experience:
GitHub - vuejs/devtools: ⚙️ Browser devtools extension for debugging Vue.js applications.
vue.js:8553 You are running Vue in development mode.
Make sure to turn on production mode when deploying for production.
See more tips at Production Deployment — Vue.js

Okay. But here is the first time we need access to OH and use the token. Have you really encoded in base64?

I can reproduce the error message. However, it is not important at the moment.

for the token… at first I followed your description going with the decode. There were quite different errors when using this token. So I have to assume when using the correct way for the encrypting of the token and the error messages disappeared that on this end I should be fine.

Used the link you provided for encoding.

Just did the encoding again. Behaviour remains the same.

When encoding there are basically two options. Destination character set is set to UTF8 and destination newline character is set to LF (Unix).