Garden runners

my gift for all those who in this sad period, to keep a little fit, are forced to run around their garden. The system will allow you to listen to information from your phone on the number of laps completed, the time taken, and also some extra comments on your performance ; -) …
Required … for the software part: Home Assistant and the Lannouncer application. For hardware, a smartphone and a Pir sensor, preferably mobile ones that work with Sonoff rf bridge.

Here are the codes …
configuration.yaml:

timer:
  stopwatch:
    name: ''
    duration:
      seconds: 540
	  
	  
input_number:
  averageminutes:
    name: minutes
    initial: 0
    max: 9
    min: 0
    step: 1  
  averageseconds:
    name: seconds
    initial: 0
    max: 59
    min: 0
    step: 1 
  delay:
    name: delay
    initial: 5
    max: 59
    min: 5
    step: 1   

input_text:
  averagelap:
    name: averagelap
    initial: '0' 
  timelap:
    name: timelap
    initial: '00:00' 	
	
counter:
  revcounter:
    name: ''
    initial: 0
    step: 1
    maximum: 500
    restore: true
    icon: mdi:walk 
	
input_boolean:
  revcounter:
    name: revcounter
    initial: off
  motivator:
    name: motivator
    initial: off
  averagelap:
    name: averagelap
    initial: off
	
notify:
  - platform: lannouncer #(you need to download the app to your smartphone)
    name: lannouncertts
    host: 192.168.0.xxx  #(you have to set the static ip for your smartphone)
    port: 1035	

# This works with a Sonoff Pir sensor and a SONOFF 433 RF Bridge)	
binary_sensor:	
  - platform: mqtt
    state_topic: "tele/sonoff-bridge/RESULT"
    name: 'sensor pir'
    value_template: '{{value_json.RfReceived.Data}}'
    payload_on: 'xxxxxx'    # (SONOFF RF BRIDGE codes)
    payload_off: 'xxxxxx'    
    off_delay: 10
    device_class: motion
    qos: 0	

AUTOMATION

- id: 'revcounteron' 
  alias: revcounteron
  trigger:
  - entity_id: input_boolean.revcounter
    platform: state
    from: 'off'
    to: 'on'
  action:
  - data:
      entity_id: timer.stopwatch
    service: timer.cancel
  - service: counter.reset
    entity_id: counter.revcounter
  - data:
      entity_id: timer.stopwatch
    service: timer.start    
  - data:
      entity_id: 
      - automation.stopwatch
    service: automation.turn_on
  initial_state: 'on' 
  
- id: 'revcounteroff' 
  alias: revcounteroff
  trigger:
  - entity_id: input_boolean.revcounter
    platform: state
    from: 'on'
    to: 'off'
  action:
  - data:
      entity_id: 
      - automation.stopwatch
    service: automation.turn_off
  - data:
      entity_id: timer.stopwatch
    service: timer.cancel    
  - service: counter.reset
    entity_id: counter.revcounter   
  - service: input_text.set_value
    data:
      entity_id: input_text.averagelap
      value: '0'  
  - service: input_text.set_value      
    data:
      entity_id: input_text.timelap
      value: '00:00'        
  initial_state: 'on'   
  
- id: 'stopwatch'
  alias: stopwatch
  trigger:
  - entity_id: binary_sensor.sensor_pir
    from: 'off'
    platform: state
    to: 'on'
  action:
  - data:
      entity_id: timer.stopwatch
    service: timer.pause
  - service: counter.increment
    entity_id: counter.revcounter
  - service: input_text.set_value
    data_template:
      entity_id: input_text.averagelap
      value: >
        {% if is_state('counter.revcounter', '2') and is_state('input_boolean.averagelap', 'on') %}
        {% set min = state_attr('timer.stopwatch', 'remaining')|replace('0:0', '') %}
        {% set sec = 59 - min[2:]|int %}
        {% set min2 = min|truncate(1,false,'',0) %}
        {% set min3 = 8 |float - min2| round(0) %}
        {% set min4 = min3| round(0) %}
        {% set minsec = min4 * 60 %}
        {% set sectot = minsec + sec %}
        {{ sectot }}
        {% else %}
        {{ states(input.text.averagelap) }}
        {% endif %}
  - service: input_text.set_value
    data_template:
      entity_id: input_text.timelap
      value: >
        {% set min = state_attr('timer.stopwatch', 'remaining')|replace('0:0', '') %}
        {% set sec = 59 - min[2:]|int %}
        {% if sec < 10 %}
        {% set sec ="0" + sec|string %}
        {% endif %}          
        {% set min2 = min|truncate(1,false,'',0) %}
        {% set min3 = 8 |float - min2| round(0) %}
        {% set min4 = min3| round(0) %}
        {% set min5 ="0" +  min4|string + ":" + sec|string %}
        {{min5}}
  - service: notify.lannouncertts
    data_template:
      message: >
        {% set media = states('input_number.averageminutes') | float * 60 | float + states('input_number.averageseconds') | int  %}
        {% set marg = states('input_number.delay')| int %}
        {% set min = state_attr('timer.stopwatch', 'remaining')|replace('0:0', '') %}
        {% set sec = 59 - min[2:]|int %}
        {% set min2 = min|truncate(1,false,'',0) %}
        {% set min3 = 8 |float - min2| round(0) %}
        {% set min4 = min3| round(0) %}
        {% set minsec = min4 * 60 %}
        {% set sectot = minsec + sec %}
        {% if min4 == 0 %}
        {% set min4 = '' + sec|string + " seconds"%}
        {% elif min4 == 1 %}
        {% set min4 = min4|string + ' minute and ' + sec|string + " seconds" %}
        {% else %}
        {% set min4 = min4|string + ' minutes and ' + sec|string + " seconds" %}
        {% endif %}
        {% if states('counter.revcounter') | float > 2 %}
        lap {{ states('counter.revcounter') }}... Time {{min4}} . 
        {% endif %}        
        {% if is_state('input_boolean.motivator', 'on') %}
        {% if is_state('counter.revcounter', '1') and is_state('input_boolean.averagelap', 'on') %}
        now go at a regular pace that I take your time
        {% endif %}
        {% if is_state('counter.revcounter', '2') and is_state('input_boolean.averagelap', 'on') %}
        your reference time {{min4}}
        {% endif %} 
        {% if states('counter.revcounter') | float > 2 %}
        {% if is_state('input_text.averagelap', '0') %}
        {% else %}
        {% set media = states('input_text.averagelap')| int %}
        {% endif %}   
        {% if sectot < media| float -marg %}
        {{["great, you are doing well", "today nobody beats you", "great time" ] | random}}
        {% elif sectot > media| float +marg %}
        {{["Can you do any better", "you look like a snail", "you are slowing down a bit" ] | random}}
        {% else %}
        {{["regular pace", "you are average" ] | random}}
        {% endif %}
        {% endif %}
        {% endif %}          
  - data:
      entity_id: timer.stopwatch
    service: timer.cancel
  - data:
      entity_id: timer.stopwatch
    service: timer.start  
  initial_state: 'off' 

LOVELACE CARDs

PICTURE ELEMENTS:

elements:
  - entity: input_boolean.revcounter
    image: /local/images/runner.gif
    state_image:
      'off': /local/images/revcounteroff.png
    style:
      left: 50%
      top: 40%
      width: 30%
    tap_action:
      action: toggle
    type: image
  - entity: input_boolean.revcounter
    image: /local/images/null.png
    state_image:
      'on': /local/images/stopwatch.gif
    style:
      left: 15%
      top: 25%
      width: 15%
    tap_action:
      action: none
    type: image
  - entity: counter.revcounter
    style:
      font-size: 22px
      left: 80%
      top: 25%
    tap_action:
      action: null
    type: state-badge
  - entity: input_text.timelap
    style:
      font-size: 16px
      left: 80%
      top: 35%
    type: state-label
  - entity: input_boolean.averagelap
    image: /local/images/averagelapon.png
    state_image:
      'off': /local/images/averagelapoff.png
    style:
      left: 16%
      top: 70%
      width: 20%
    tap_action:
      action: toggle
    type: image
  - entity: input_boolean.motivator
    image: /local/images/ttson.png
    state_image:
      'off': /local/images/ttsoff.png
    style:
      left: 80%
      top: 70%
      width: 20%
    tap_action:
      action: toggle
    type: image
image: /local/images/race.jpg
type: picture-elements

CONDITIONAL CARD

card:
  entities:
    - entity: input_number.delay
  type: entities
conditions:
  - entity: input_boolean.motivator
    state: 'on'
type: conditional

card:
  entities:
    - entity: input_number.averageminutes
    - entity: input_number.averageseconds
  type: entities
conditions:
  - entity: input_boolean.averagelap
    state: 'off'
  - entity: input_boolean.motivator
    state: 'on'
type: conditional


averagelapoff averagelapon null revcounteroff runner stopwatch ttsoff ttson

1 Like