Amazon Echo Countdown

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”

Resources

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
9 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:

Great Work thank you so much
Is it posible to make a widget for the HABPanel?

Furthermore, when the timer rings, it counts down from 24:00:00 until I stop the timer, then it stops at 23:59:55, for example, which is very annoying for a widget. Is there a fix for this?

Außerdem bekomme ich in der countdown rule während kein timer läuft jede sekunde diesen fehler im log(port 9001)

Script execution of rule with UID '48f5d55b65' failed: TypeError: alarm.getZonedDateTime is not a function in <eval> at line number 3

Update:
I fixed it with:

try {
  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("EchoTobias_NachsterTimer").state; var countdown = itemRegistry.getItem("EchoTobias_Countdown"); var coutndownSekunden = itemRegistry.getItem("EchoTobias_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());
}
catch (e) {
}