Run scripts in home assistant based on incoming normal or whatsapp call

My problem was that people can’t reach my other half on phone. She keeps it silent quite often and just does not notice it ringing.

I ended up solving this with Tasker app running on Android. No idea if there are something similar for iOS. The Tasker can read almost everything on the Android, events, sensors you name it. I’m reading states for phone ringing, idle, on call and same for real calls and whatsapp calls.

Real calls where a bit easier to handle. There are events built in tasker for that. Whatsapp was a bit more tricky. Had to use a plugin to intercept notifications that the phone is creating and run actions based on that. After understanding the idea around it wasn’t so hard either.

Tasker is sending POST command to Home Assistant to run scripts. I was first thinking of sending MQTT message so I could have some more freedom and act on other devices more easily on incoming calls if necessary. Then one option was to create input_boolean, switch or some other and change the state for those. I was able to change switch state and send MQTT messages from the phone with tasker, but I desiced that I want to call the script directly without any automations and switches. Thanks to Discord and tips received there I was able to call the scripts directly using POST message from the phone.

Tasker

So, lets start with the Tasker.
There is a bit different terminology compared to Home Assistant. In Tasker “profiles” match both trigger and condition. “Tasks” matches action.

Configuring Tasks

Tasker recommends first to configure tasks (actions). Lets take an example for incoming calls. The others are similiar and can be cloned when the first one is done. Then just change few parameters.

  1. Start by pressing the + sign at the bottom.
  2. Name the tasks how you like. I used “POST incoming call”.
  3. You will now enter to “Task Edit” window. Hit again the + sign at the bottom.
  4. The post action is in the path: Net -> HTTP Post.
  5. Fill in the following fields
    • Server Port -> http://ip:port
    • Path -> /api/services/script/turn_on?api_password=yourpassword
    • Data / File -> {“entity_id”:“script.script_name_in_HA”}
    • Content Type -> application/json
  6. Press the left arrow on top left corner to finish.
  7. Test that it works by pressing play button on bottom left corner. Of course you need to have the script first up and running in home assistant. (scripts pasted to the end)

Then I created tasks with the names “POST Active Call On” and “POST Active Call Ends”. Optionally you can set variable to specific value when the call is active and use that to determine in other tasks/profiles if the call is active. Add “Variable Set” in the task. I named my variable %INCALL. Capital letters make it global. When the call is active i set it to 1 and when call ends to 0. Then I cant check in other tasks if %INCALL > 0, then it means I have active call. See this for clarification.

These three tasks can be reused for each program you want to monitor incoming calls.

Configuring Profile

I want Home Assistant to react to incoming call if the screen is off. If it would be on I assume that the phone is in hand and the user does not need extra notifications. I also require the phone to be in the same network with the HA instance. Othervice the POST command does not go through.

Incoming normal call

  1. Start by pressing the + sign at the bottom.
  2. Name the task how you like. I used “Incoming Call”. If it doesnt ask for the name you can rename it afterwards with long press.
  3. Select State -> display -> display state. Set it to off. Finish with the back arrow.
  4. Pop up asks for the task. Select the one created previously.
  5. Long press the “Display State” condition and select add.
  6. Select State -> net -> wifi connected. Press the magnifying class to set parameters. Better use the MAC address to make sure you are connected to correct network. Press the back arrow to finish.
  7. Add one more condition. this time select Event -> phone -> Phone ringing. Press the magnifying class to set parameters.
  8. Finish by pressing the back arrow.

And now it is set. It might take some time for the profile to kick in. The conditions evaluaiting to true should turn to green when it is working. Test it out by calling on the phone with another phone.

For active call use “Phone Offhook” and for call end or reject use “phone idle”.

Incoming Whatsapp call

Now this is a bit more tricky. This might be easier with the Tasker itself but I found it to be a lot easier with a plugin called Autonotification. There seemed to be similiar plugins available. This was the first I found and never tested the others.

The principle how this works is that Autonotification read the notifications from the notification center. Then those can be used as triggers and conditions. Awesome and easy!
Lets start with active whatsapp call. We want the notification to be active in the notification center before proceeding.

  1. From tasker select new profile -> event -> plugin -> Autonotification -> intercept
  2. a blank screen opens. Press top right corner, the pen.
  3. Easiest way to fill in data is the “Fill from current” button. Make sure the notification is active. You can also fill in the data without active notification but then you really need to know what to fill in.
  4. Select the notification to take the data from and click all points you want to have. At least good choises are:
    • Action type
    • Notification title
    • Notification text
  5. When done press the “correct” tick from the top bar.
  6. Click “Action type”. Set it for incoming call and to active call to “created”. For active call end and call rejected put this to “cancelled”. Add also cancel reason “Original app cancelled”.
  7. When coming down in the menu you can click all buttons to see if there are text behind it. For example if you enabled to intercept notification ID the app will see some notification ID. No idea if it is going to be same everytime so better clear out any ID’s from this.
  8. For “Notification app” select whatsapp, or what ever you are going to use.
  9. “Notification text” is based on your language. I have it Finnish and have no idea what are the specific words. Something like Incoming call, ongoing call… You can view it from the notification center.
  10. Thats it, save it, set the task when prompt, add other conditions as screen state, wifi connected…

Home Assistant

Finally to the scripts I run in Home Assistant.

I chose to put a time condition at Home Assistant because it is easier to modify. And it has to be done only once. So multiple phones can call these same scripts but I think it would be rather easy to modify the code to see who triggered the scripts. I also use one input boolean as condition if I want to run any notifcations or not.

There is still room for improvement. For example some timeout is needed for my light flasher in case the phone fails to send signal or some other reason so that the light just keep flashing. Also not directly related to this but the spotify component does not work if some other account is used to start the spotify player (with spotify on connect). The spotify doesnt either seem to support media_stop. Meaning that it will always change to “play” after a call.

But anyway, the project is getting quite long so I figured to post it already. My scripts below:

#####################################################################
## Phone notifications from Tasker
#####################################################################
flash_on_phone_ring:
  alias: Flash when phone rings
  sequence:
  - condition: and
    conditions:
    - condition: time
      after: '08:00:00'
      before: '21:50:00'
    - condition: state
      entity_id: input_boolean.call_notifier
      state: 'on'
  - alias: FLash TV
    service: light.turn_on
    data:
      entity_id: light.tv
      flash: short
  - alias: FLash bedroom
    service: light.turn_on
    data:
      entity_id: light.desk
      flash: short
  - alias: Flash kitchen
    service: light.turn_on
    data:
      entity_id: group.kitchen_lights
      flash: short
  - alias: Keep flashing lights
    service: script.turn_on
    data:
      entity_id: script.light_flasher

light_flasher:
  alias: Flash loop when phone rings
  sequence:
  - condition: and
    conditions:
    - condition: time
      after: '08:00:00'
      before: '21:50:00'
    - condition: state
      entity_id: input_boolean.call_notifier
      state: 'on'
  - alias: FLash TV
    service: light.turn_on
    data:
      entity_id: light.tv
      flash: short
  - alias: Flash kitchen
    service: light.turn_on
    data:
      entity_id: group.kitchen_lights
      flash: short
  - alias: Keep flashing lights
    service: script.turn_on
    data:
      entity_id: script.light_flasher_looper

light_flasher_looper:
  alias: Flash looper when phone rings
  sequence:
  - condition: and
    conditions:
    - condition: time
      after: '08:00:00'
      before: '21:50:00'
    - condition: state
      entity_id: input_boolean.call_notifier
      state: 'on'
  - delay:
      seconds: 2
  - alias: Keep flashing lights
    service: script.turn_on
    data:
      entity_id: script.light_flasher

phone_call_active:
  alias: Pause media when in call
  sequence:
  - service: script.turn_off
    data:
      entity_id: script.light_flasher_looper
  - service: script.turn_off
    data:
      entity_id: script.light_flasher
  - condition: or
    conditions:
    - condition: state
      entity_id: media_player.olohuone
      state: 'playing'
    - condition: state
      entity_id: media_player.spotify
      state: 'playing'
  - alias: Pause spotify
    service: media_player.media_pause
    data:
      entity_id: media_player.spotify
  - alias: Pause chromecast
    service: media_player.media_pause
    data:
      entity_id: media_player.olohuone

phone_call_end:
  alias: Continue media after call
  sequence:
  # Cancel light flasher if the call was rejected
  - service: script.turn_off
    data:
      entity_id: script.light_flasher_looper
  - service: script.turn_off
    data:
      entity_id: script.light_flasher
  # Check if some of the media players are paused
  - condition: or
    conditions:
    - condition: state
      entity_id: media_player.olohuone
      state: 'paused'
    - condition: state
      entity_id: media_player.spotify
      state: 'paused'
  # Hit play for paused media player
  - alias: Resume spotify
    service: media_player.media_play
    data:
      entity_id: media_player.spotify
  - alias: Resume chromecast
    service: media_player.media_play
    data:
      entity_id: media_player.olohuone

#####################################################################

End result

Not the best but fits for my purpose. All comments, improvements and ideas are warmly welcomed.

There didn’t seem to be an easy data export/import in tasker. Other vice I would have shared the source code. I found it easier to write the rules from scratch than modifying my IP’s, MAC’s, passwords etc. Just use the clone feature when the first task/profile is done. And do the tasks first.

My “Tasks” structure on title basis:

  • POST incoming call
  • POST Active call on
  • POST active call ends

My “Profile” structure on title basis:

  • Incoming call -> POST incoming call
  • Active call -> POST Active call on
  • Active call ends -> POST active call ends
  • Whatsapp incoming call -> POST incoming call
  • Whatsapp Active call -> POST Active call on
  • Whatsapp call ends -> POST active call ends
  • Whatsapp reject call -> POST active call ends

Best regards,
Taikapanu

2 Likes

I made few improvements and cleanup of the code.
Changes

  • Added timeout for the flashing in case stop message not received from tasker.
  • Cleaned up the syntax of the scripts.
  • Spotify does not obey media_stop command. It is always in paused state. I made a workaround to check if it has been playing in last definable time period then continue playing after the call.
  • Changed the HUE lights in one lightgroup (inside the HUE bridge) to reduce api calls.

There is also at least one problem I haven’t yet solved. In case there are multiple people calling at the same time this doesn’t work. Need to find a way so that first person to call activates this and last person to stop deactivates the feature. Preferably so that lights are flashing for all new people that are receiving phone calls.

If someone has tips/ideas for this I would gladly take them!

Modified codes below:
Scripts

#####################################################################
## Phone notifications from Tasker
#####################################################################
flash_on_phone_ring:
  alias: Flash when phone rings
  sequence:
  - condition: and
    conditions:
    - condition: time
      after: '08:00:00'
      before: '21:50:00'
    - condition: state
      entity_id: input_boolean.call_notifier
      state: 'on'
  - alias: Flash selected lights once
    service: light.turn_on
    data:
      entity_id: 
      - light.notify_hue_lights
      - light.desk
      flash: short
  - alias: Keep flashing lights
    service: script.turn_on
    data:
      entity_id: 
      - script.light_flasher
      - script.light_flasher_timeout

light_flasher:
  alias: Flash loop when phone rings
  sequence:
  - condition: and
    conditions:
    - condition: time
      after: '08:00:00'
      before: '21:50:00'
    - condition: state
      entity_id: input_boolean.call_notifier
      state: 'on'
  - alias: Flash selected lights
    service: light.turn_on
    data:
      entity_id: light.notify_hue_lights
      flash: short
  - alias: Keep flashing lights
    service: script.turn_on
    data:
      entity_id: script.light_flasher_looper

light_flasher_looper:
  alias: Flash looper when phone rings
  sequence:
  - condition: and
    conditions:
    - condition: time
      after: '08:00:00'
      before: '21:50:00'
    - condition: state
      entity_id: input_boolean.call_notifier
      state: 'on'
  - delay:
      seconds: 2
  - alias: Keep flashing lights
    service: script.turn_on
    data:
      entity_id: script.light_flasher

light_flasher_timeout:
  alias: Flash looper timeout
  sequence:
  - delay:
      seconds: 25
  - service: script.turn_off
    data:
      entity_id: script.light_flasher_looper
  - service: script.turn_off
    data:
      entity_id: script.light_flasher


phone_call_active:
  alias: Pause media when in call
  sequence:
  - service: script.turn_off
    data:
      entity_id: script.light_flasher_looper
  - service: script.turn_off
    data:
      entity_id: script.light_flasher
  - service: script.turn_off
    data:
      entity_id: script.light_flasher_timeout
  - condition: or
    conditions:
    - condition: state
      entity_id: media_player.olohuone
      state: 'playing'
    - condition: state
      entity_id: media_player.spotify
      state: 'playing'
  - alias: Pause spotify and chromecast
    service: media_player.media_pause
    data:
      entity_id: 
      - media_player.spotify
      - media_player.olohuone

phone_call_end:
  alias: Continue media after call
  sequence:
  # Cancel light flasher if the call was rejected
  - service: script.turn_off
    entity_id: 
    - script.light_flasher_looper
    - script.light_flasher
    - script.light_flasher_timeout
  # Hit play for paused media player
  # Do this via separate scripts to check
  # if that particular media was playing
  - alias: Resume spotify and chromecast
    service: script.turn_on
    data:
      entity_id: 
      - script.play_spotify_if_was_playing
      - script.play_chromecast_if_was_playing

play_spotify_if_was_playing:
  alias: Resume spotify
  sequence:
  - condition: and
    conditions:
    - condition: state
      entity_id: media_player.spotify
      state: 'paused'
    - condition: state
      entity_id: input_boolean.was_spotify_playing
      state: 'on'
  - service: media_player.media_play
    data:
      entity_id: media_player.spotify

# No condition check as chromecast does not turn on
# if it has been turned off. Spotify cannot be 
# turned off in a same way.
play_chromecast_if_was_playing:
  alias: Resume chromecast
  sequence:
  - condition: state
    entity_id: media_player.olohuone
    state: 'paused'
  - service: media_player.media_play
    data:
      entity_id: media_player.olohuone
#####################################################################

Automation for spotify condition:

#--------------------------------------------------------------
#
# Determine if spotify has been playing in the last
# defined timeperiod. Use this to continue media after
# a phone call.
#  
#--------------------------------------------------------------

- alias: Was spotify playing (turn off)
  hide_entity: true
  trigger:
  - platform: state
    entity_id: media_player.spotify
    to: 'paused'
    for:
      minutes: 15
  action:
  - service: input_boolean.turn_off
    data:
      entity_id: input_boolean.was_spotify_playing

- alias: Was spotify playing (turn on)
  hide_entity: true
  trigger:
  - platform: state
    entity_id: media_player.spotify
    to: 'playing'
    for:
      seconds: 5
  action:
  - service: input_boolean.turn_on
    data:
      entity_id: input_boolean.was_spotify_playing
1 Like