OH3 Echo Countdown widget

Tags: #<Tag:0x00007fc8fbda1300> #<Tag:0x00007fc8fbda1238>

Hi,

I created an Countdown widget for my Amazon Echo dot and want to share it with you.
It is not finished but i think it’s ready to share.

echoCountdown

This is my configuration:

Thing/Channel:

  • I used the “nextTimer” channel of my echo Thing

Items:

  • EchoKuche_Countdown (DateTime) -> Dummy item to store the remaining time
    – added the following stateDescription: %1$tH:%1$tM:%1$tS
  • EchoKuche_NachsterTimerSekunden (Number) -> Dummy item to store the remaining seconds
  • EchoKuche_NachsterTimerMaxSekunden(Number) -> Dummy item to store the duration of the timer in seconds
  • EchoKuche_NachsterTimer (DateTime) -> linked to the nextTimer channel

Rules:
I have created 3 rules to count down

  • Start rule
    This rule will be triggered if the item EchoKuche_NachsterTimer change from UNDEF
    Will execute an ECMAScript which will do the following
    – get the target time of EchoKuche_NachsterTimer item
    – get the diff between now and the target time
    – create a new DateTime which starts at 00:00:00 on the Same day + the diff calculated before
    – store the new DateTime into EchoKuche_Countdown item
    – store the diff in seconds into EchoKuche_NachsterTimerSekunden
    – store the diff in seconds into EchoKuche_NachsterTimerMaxSekunden
    And will enable the “Count down” rule

  • End rule
    This rule will be triggered if the item EchoKuche_NachsterTimer change to UNDEF
    Will execute an ECMAScript which will do the following
    – create a new DateTime which starts at 00:00:00
    – store the new DateTime into EchoKuche_Countdown item
    – store 0 seconds into EchoKuche_NachsterTimerSekunden
    And will disable the “Count down” rule

  • Count down rule
    This rule will be triggered by a cron every second
    Will execute an ECMAScript which will do the following
    – get the target time of EchoKuche_NachsterTimer item
    – get the diff between now and the target time (the diff is decreasing each time for 1 second)
    – create a new DateTime which starts at 00:00:00 on the Same day + the diff calculated before
    – store the new DateTime into EchoKuche_Countdown item
    – store the diff in seconds into EchoKuche_NachsterTimerSekunden

Widget:
I have created a Widget which sould look like my echo dot from above with a timer in the middle
The buttons are not working at the moment, but i think will add some functions to it later on.
You have to configure 3 props:

  • EchoKuche_Countdown in “item”
  • EchoKuche_NachsterTimerSekunden in “seconds”
  • EchoKuche_NachsterTimerMaxSekunden in “maxSeconds”

Here is the code for the rules and the widget:

Start rule
triggers:
  - id: "1"
    configuration:
      itemName: EchoKuche_NachsterTimer
      previousState: UNDEF
    type: core.ItemStateChangeTrigger
conditions: []
actions:
  - inputs: {}
    id: "2"
    configuration:
      type: application/javascript
      script: >-
        var zdt = Java.type('java.time.ZonedDateTime');
        var duration = Java.type('java.time.Duration');
        var localTime = Java.type('java.time.LocalTime');
        var chronunit = Java.type('java.time.temporal.ChronoUnit');

        var alarm = itemRegistry.getItem("EchoKuche_NachsterTimer").state;
        var countdown = itemRegistry.getItem("EchoKuche_Countdown");
        var coutndownMaxSekunden = itemRegistry.getItem("EchoKuche_NachsterTimerMaxSekunden");
        var coutndownSekunden = itemRegistry.getItem("EchoKuche_NachsterTimerSekunden");
        var jetzt = zdt.now().toLocalTime();
        var alarmTime = alarm.getZonedDateTime().toLocalTime();
        var diff = duration.between(jetzt, alarmTime);
        var startime = localTime.of(0, 0, 0).plus(diff).truncatedTo(chronunit.SECONDS);


        events.postUpdate(countdown, startime.toString());
        events.postUpdate(coutndownMaxSekunden, diff.getSeconds());
        events.postUpdate(coutndownSekunden, diff.getSeconds());
    type: script.ScriptAction
  - inputs: {}
    id: "3"
    configuration:
      enable: true
      ruleUIDs:
        - 81f01c329e
    type: core.RuleEnablementAction
End Rule
triggers:
  - id: "1"
    configuration:
      itemName: EchoKuche_NachsterTimer
      state: UNDEF
    type: core.ItemStateChangeTrigger
conditions: []
actions:
  - inputs: {}
    id: "2"
    configuration:
      enable: false
      ruleUIDs:
        - 81f01c329e
    type: core.RuleEnablementAction
  - inputs: {}
    id: "3"
    configuration:
      type: application/javascript
      script: >-
        var localTime = Java.type('java.time.LocalTime');

        var countdown = itemRegistry.getItem("EchoKuche_Countdown");
        var coutndownSekunden = itemRegistry.getItem("EchoKuche_NachsterTimerSekunden");
        var startime = localTime.of(0, 0, 0);

        events.postUpdate(countdown, startime.toString());
        events.postUpdate(coutndownSekunden, 0);
    type: script.ScriptAction
Count down
triggers:
  - id: "1"
    configuration:
      cronExpression: "* * * * * ? *"
    type: timer.GenericCronTrigger
conditions: []
actions:
  - inputs: {}
    id: "2"
    configuration:
      type: application/javascript
      script: >-
        var zdt = Java.type('java.time.ZonedDateTime');
        var duration = Java.type('java.time.Duration');
        var localTime = Java.type('java.time.LocalTime');
        var chronunit = Java.type('java.time.temporal.ChronoUnit');

        var alarm = itemRegistry.getItem("EchoKuche_NachsterTimer").state;
        var countdown = itemRegistry.getItem("EchoKuche_Countdown");
        var coutndownSekunden = itemRegistry.getItem("EchoKuche_NachsterTimerSekunden");

        var jetzt = zdt.now().toLocalTime();
        var alarmTime = alarm.getZonedDateTime().toLocalTime();
        var diff = duration.between(jetzt, alarmTime);
        var startime = localTime.of(0, 0, 0).plus(diff).truncatedTo(chronunit.SECONDS);

        events.postUpdate(countdown, startime.toString());
        events.postUpdate(coutndownSekunden, diff.getSeconds());
    type: script.ScriptAction
Widget
uid: echoTimer
tags: []
props:
  parameters:
    - context: item
      description: The time to show in the middle
      label: Item
      name: item
      required: true
      type: TEXT
    - context: item
      description: maxvalue for the gauge
      label: maxSeconds
      name: maxSeconds
      required: true
      type: TEXT
    - context: item
      description: current value for the gauge
      label: seconds
      name: seconds
      required: true
      type: TEXT
  parameterGroups: []
timestamp: Feb 5, 2021, 10:39:30 AM
component: f7-card
slots:
  default:
    - component: oh-chart
      slots:
        series:
          - component: oh-data-series
            config:
              radius: 100%
              type: gauge
              min: =0
              max: =(items[props.maxSeconds].state)
              data:
                - value: =(items[props.seconds].state)
              progress:
                show: true
              startAngle: 90
              endAngle: -270
              axisLine:
                lineStyle:
                  width: 10
                  color:
                    - - 1
                      - lightgrey
              detail:
                show: false
              axisTick:
                show: true
                length: 10
                lineStyle:
                  width: 3
                  color: darkgrey
              splitLine:
                show: false
              axisLabel:
                show: false
              pointer:
                show: false
              title:
                show: false
              anchor:
                show: false
    - component: f7-block
      config:
        style:
          position: absolute
          width: 55px
          height: 55px
          left: 55px
          right: 0
          top: 62px
          margin-left: auto
          margin-right: auto
          margin-top: auto
          transform: translate(-50%, -50%)
          border-radius: 50%
          border-style: solid
          border-color: darkgrey
          border-width: 1px
    - component: f7-icon
      config:
        size: 35
        style:
          position: absolute
          left: 37px
          right: 0
          top: 62px
          margin-left: auto
          margin-right: auto
          margin-top: auto
          transform: translate(-50%, -50%)
          color: grey
        f7: plus
    - component: f7-block
      config:
        style:
          position: absolute
          width: 55px
          height: 55px
          left: 55px
          right: 0
          top: 238px
          margin-left: auto
          margin-right: auto
          margin-top: auto
          transform: translate(-50%, -50%)
          border-radius: 50%
          border-style: solid
          border-color: darkgrey
          border-width: 1px
    - component: f7-icon
      config:
        size: 35
        style:
          position: absolute
          left: 37px
          right: 0
          top: 238px
          margin-left: auto
          margin-right: auto
          margin-top: auto
          transform: translate(-50%, -50%)
          color: grey
        f7: minus
    - component: f7-block
      config:
        style:
          position: absolute
          width: 55px
          height: 55px
          left: -120px
          right: 0
          top: 150px
          margin-left: auto
          margin-right: auto
          margin-top: auto
          transform: translate(-50%, -50%)
          border-radius: 50%
          border-style: solid
          border-color: darkgrey
          border-width: 1px
    - component: f7-icon
      config:
        size: 32
        style:
          position: absolute
          left: -144px
          right: 0
          top: 150px
          margin-left: auto
          margin-right: auto
          margin-top: auto
          transform: translate(-50%, -50%)scaleX(-1)
          color: grey
        f7: mic_slash_fill
    - component: f7-block
      config:
        style:
          position: absolute
          width: 55px
          height: 55px
          left: 230px
          right: 0
          top: 150px
          margin-left: auto
          margin-right: auto
          margin-top: auto
          transform: translate(-50%, -50%)
          border-radius: 50%
          border-style: solid
          border-color: darkgrey
          border-width: 1px
    - component: f7-icon
      config:
        size: 20
        style:
          position: absolute
          left: 195px
          right: 0
          top: 151px
          margin-left: auto
          margin-right: auto
          margin-top: auto
          transform: translate(-50%, -50%)
          color: grey
        f7: circle_fill
    - component: Label
      config:
        text: =(items[props.item].displayState)
        style:
          position: absolute
          top: 50%
          left: 50%
          transform: translate(-50%, -50%)
          font-size: 30px
8 Likes

Hi @Vradatta

very good stuff and great work!
If the gauge functionality had come earlier, I would have saved myself a lot of time. :smiley:

Due to the missing functionality I had to write everything in css myself to implement a heating widget.
( [OH3] Heating widget based on CSS )
But it was still good for learning success. :wink:

best,

Nico

Hi Nico,

I’m using your heating widget in my setup and i also tried to use it for my countdown widget (but i failed :roll_eyes:)
That’s the reason i used the gauge here.

But your widget helped me to understand CSS and Widgets a lot more, and so i knew what to do (or for what i have to google) :grinning: