Android actionable notifications

I have created a simple android app (Home Assistant Notify) and custom component that allows for actionable notifications to android. It works very similar to the html5 notifications (which I didn’t find very reliable). Try it out and let me know what you think.

https://github.com/Crewski/HANotify

***** UPDATE 9-10-18 *****
I added the HANotify functionality into a forked build of HomeAssist. If you have HomeAssist already installed you’ll need to uninstall it before you can install this version.

The repository can be found here:
https://github.com/Crewski/homeassist/

***** UPDATE 8-30-18 *****
I added the ability to send an image and custom icon. Both are sent via a URL. Custom icon requires SDK >= 26.

***** UPDATE *****
I added tag, dismiss, message_type, and an option to use your own FCM project

Home Assistant Notify

Android actionable notifications for Home Assistant.

Setup

  1. Copy the fcm-android.py file into your /custom_components/notify/ folder (create it if you don’t already have it)
  2. In your configuration.yaml file, add the following to initialize the components:
notify:    
  - name: android
    platform: fcm-android
    server_key (OPTIONAL: only if using your own FCM Project): MYSERVERKEY123456
  1. Reboot Home Assistant.
  2. Install the HANotify.apk file onto your android device (or compile it in Android Studio).
  3. Enter your Home Assistant URL and API PASSWORD into the app, then click Register *NOTE - This components requires an API PASSWORD to be set.
  4. Send some notifications!

Usage

Sending the notification

The android actionable notifications are set up the same as the html5 notifications. The following parameters can be sent:

title
target
message
data:
  actions
  color
  message_type
  tag
  dismiss
  image
  icon

Parameter Required Description
message Required Body of the notification
title Optional Title for the notification, default value: Home Assistant
target Optional Target the notification to one specific device
data Optional Extra parameters for the notification

Parameters for the data section of the notification. Everything here is optional.

Parameter Description
color A hex color such as #FF0000, default value is a blue
message_type ‘notification’ or ‘data’, defaults to ‘data’. This is the type of FCM that is sent. Notification has higher priority, but can’t include actions or be dismissed by Home Assistant.
tag Must be an integer. Tag is the ‘id’ of the notifications. Sending a new notification to the same tag will overwrite the current notifcation instead of creating a separate one.
dismiss true or false, requires a tag parameter. If true, the notification will be dismissed.
actions Array of ojects (up to 3) with an ‘action’ and ‘title’. The title will be the button text on the notification, the action is what is sent back in the callback
image A URL of an image to send. The image overwrites the BigTextStyle so longer texts will be truncated. The image will also be smaller if actions are included
icon A URL of an icon to use for the notification. Only on >= SDK 26. Careful to choose icon with tranparent background to follow Android guidelines.

In order to send a “regular” notification without actions, all you have to do is not include them in the call to the service, such as below.

- service: notify.android
  data:
    message: Anne has arrived home

This will send a simple push notification without any action buttons.

If you want to include some actions, something like this will work:

- service: notify.android
  data:
    message: Anne has arrived home
    data:
      actions:
        - action: open
          title: Open Home Assistant
        - action: open_door
          title: Open door 


This will have two buttons, one that says “Open Door” and one that says “Open Home Assistant”. The action for each button (“open” or “open_door” in this example) will be returned in the callback.

Handling the callback

The callback is pushed to the event bus. It can be accessed via fcm_android_notications.clicked. The “action” of the button that was pressed is included in the event_data. So an automation would looks something like:

- alias: TEST RESPONSE
  trigger:
  - event_data:
      action: open_door
    event_type: fcm_android_notifications.clicked
    platform: event
  condition: []
  action:
  - data:
      entity_id: light.front_door
    service: light.turn_on

How it works

When you clicked register on the app, it sends a firebase token back to Home Assistant. That token is saved into the fcm-android-registrations.conf file. This token is what is used to identify what devices to send the notification to. If the notifications involve actions, the token for the device is included in the callback. Before the callback is processed, the token is checked against the fcm-android-registrations.conf file for validity.

Using your own FCM project

If you want to use your own new or existing FCM project, follow these steps. Basically you just use the server_key in the configuration.yaml and a different google-services.json in the app.

  1. Log in to https://console.firebase.google.com
  2. Create a new project or use an existing one
  3. Click on the settings icon next to Project Overview and select Project settings
  4. Click on the Cloud Messaging tab and find the Legacy Server Key
  5. In your configuration.yaml file, use the Legacy Server Key for the server_key variable:
  6. Back in the Firebase settings page, click on the General tab
  7. Under “your apps” click on the Add app button
  8. Select Add Firebase to your Android App
  9. enter “com.crewski.hanotify” for the Android Package Name and click Register App
    a. If you are planning on changing the package name for the Android app, you would enter that new name here
  10. Download the google-services.json
  11. Replace the google-services.json found in the android app with the one you just downloaded
  12. Compile and install your new app
43 Likes

I’ll try it and give you some feedback!

1 Like

Thanks for this!
It works great! :+1:

How do I define the targets?
By simply replacing the “unnamed device” in the registration file fcm_android_registrations.conf and then use the name in the automations?

EDIT:
Just tried the renaming approach and it worked fine.
Then I added a 2nd device and the names in the file fcm_android_registrations.conf were renamed to “unnamed device” and “unnamed device_2”.

1 Like

That naming scheme was pulled from the html5.py file. I’ll take a look and see if I can figure it out. I’m glad the rest is working for you!

Is it possible to translate the component?

2 Likes

I’ve played around with it a little now and it works great :+1:

Thanks again, for developing it.

And I agree with @j.assuncao - it would make a fantastic standard component!

2 Likes

Actionable notifications are great. I have two questions. Whenever I reboot my Raspberry Pi I have te re-register in the APK. Is there a way to prevent that?

I have another question regarding event data handling on automations. Lets say I have an automation like this with 2 actions:

...
  - service: notify.android
    data:
      message: "Go to sleep?"
      data:
        actions:
          - action: sleep_room1
            title: Room1
          - action: sleep_room2
            title: Room2

How can I use a template in another automation based on which event data was submitted/which action was clicked? I’ve tried this so far and it doesnt work:

- alias: push sleep             
  trigger:
  - event_data:
      action: sleep_room1
    event_type: fcm_android_notifications.clicked
    platform: event
  - event_data:
      action: sleep_room2
    event_type: fcm_android_notifications.clicked
    platform: event
  action:
  - service: script.turn_on
    data_template:
      entity_id: >
        { % if trigger.event.data["action"] == "sleep_room1" % } script.room1_readytosleep
        { % if trigger.event.data["action"] == "sleep_room2" % } script.room2_readytosleep
        { % endif % }

Just to confirm, you have to have your HA instance exposed for this to work, right?

Hey jones, thanks for trying it out. I’ll have to look into your issues when I get a chance. Do you know if the fcm_android_notifications.conf file persists after a reboot?

I never tried to do the templating with the automations. I’ll mess around with it and report back. If you figure it out before then, please let us know. Thanks.

1 Like

It depends on where/what you want to use. For actionable notifications outside of your home network, you would need to open up. The notifications will still work, just the callback won’t. Everything should work fine if you are on the same network as your HA. If you don’t have it opened up and you want notifications when you are out and about, you’ll need to register the app while on your home network.

1 Like

Pardon @Crewski . There is nothing wrong with your work. My Oneplus3 put the app into battery optimization mode. it works fine. file is also persistent. automation is still not clear to me…

Thanks for the update. I notice some delayed notifications on my Pixel 2 from time to time. I think it’s related to the priority level of the notification. I’m going to add an option to set the priority level to high. Hopefully that’ll fix it.

Just tried it out and it works really well. Great job

1 Like

@jones, It looks like the only thing you need to do is change your second if statement to be elif. Side note, you can also use trigger.event.data.action instead of trigger.event.data[“action”]…but they both appear to work. Try this and see if it works:

- alias: push sleep             
  trigger:
  - event_data:
      action: sleep_room1
    event_type: fcm_android_notifications.clicked
    platform: event
  - event_data:
      action: sleep_room2
    event_type: fcm_android_notifications.clicked
    platform: event
  action:
  - service: script.turn_on
    data_template:
      entity_id: >
        { % if trigger.event.data["action"] == "sleep_room1" % } script.room1_readytosleep
        { % elif trigger.event.data["action"] == "sleep_room2" % } script.room2_readytosleep
        { % endif % }

This was my test to emulate how you had written things.

  alias: TEST RESPONSE
  trigger:
  - event_type: fcm_android_notifications.clicked
    platform: event
    event_data:
      action: front
  - event_type: fcm_android_notifications.clicked
    platform: event
    event_data:
      action: back
  condition: []
  action:
  - data_template:
      entity_id: >
        {% if trigger.event.data["action"] == 'front' %} light.front_door
        {% elif trigger.event.data["action"] == 'back' %} light.pergola
        {% endif %}
    service: light.toggle

@j.assuncao, are you talking translate as in language? If so I am sure it can but I have no idea how to do that. Any chance you can point me in the right direction and I’ll see what I can do? Thanks.

Thanks for your effort.I’ve tried both solutions… but somehow it’s not working for me:

ERROR (MainThread) [homeassistant.core] Invalid service data for script.turn_on ...

I wonder what hass is complainng about because all I do is pass an entity_id :thinking:

UPDATE:
Got it working. Reason was bad formatting :see_no_evil: Thanks again for your work @Crewski. Actionable notifications was alsways something i really missed from Android and you made them possible. As @danielperna84 I’d also love to know some insights regarding privacy issues and technical background. Keep up the good work!

1 Like

Great work. Going to try it out as well.

Some questions though:

  1. As this seems to use Firebase messaging (fcm), I suppose there is a (hardcoded?) target-server which you are running and all messages are passing through. Is there anything worth noting about the privacy of the data?
  2. Would it be possible for users to compile their own APK and use it with a private server? If so, could you write a small guide on how to do that?
  3. Did I get this wrong and 1. and 2. are irrelevant because actually the component is the fcm server? There’s an API key in the component, which made me think it’s reaching out to your server. But maybe it’s not.

So generally I’m asking for a few more details of the whole architecture and how to customize it if users want to. I would like the Idea of your app to serve as a template to compile for use with a private server.

2 Likes

It is an FCM server not his own. In the GitHub repo it has the Android studio code if you want to self compile or if you are curious to see what all is being done.

That’s what I was curious about. The reason I am asking is because the last time I looked at Firebase was that you had to create an App in the Google dev console (like for the Google Assistant integration in HASS) if I recall correctly. Since this does not seem to be needed with this component I have assumed, that this step has already been taken, hence also the accompanying server that handles the messaging.

The question about compilation was about adapting it to the own server infrastructure if needed. As said before, there’s an API key in the code. Where does this key com from? And what if I change it? The point is that I would like this to work independently of a maybe existing Google-app from somebody else.

Edit:
To clarify why I’m so suspicious of there being a cloud-server: I made the Automate notification platform, which uses FCM as well. In that specific case there is a server that’s operated by the app creator. Therefore I thought it might be like that with the component as well.

Hey guys, security is definitely a valid concern. As @Nicholi_Knight mentioned, I’m using a FCM server which matches up to the google-services.json found in android app. If someone wanted to use their own, they would need to change the API_KEY variable in the fcm-android.py to match their legacy cloud messaging key. Then just download a google-services.json (use com.crewski.hanotify as the id) and replace the one in the android app. Compile and go…that should do it.

The app/component combo uses both FCM and Rest API. The FCM is only involved in the notification from HA to the app. Everything else is over the Rest API. A quick breakdown is:

  1. The app sends the Firebase token (unique to each device) to HA via a POST request to register it. This is the token you find in the fcm-android-registrations.conf file.
  2. When sending a notification, HA send it to the app via FCM. I use the “registration_ids” part of the FCM so that it only gets sent to devices that you have registered. The notification is sent as a “data” type and not a “notification” type so that I can include the actions.
  3. If you click on an action, that action is send back to HA via a POST request. In this POST request, the token from the device is included. HA first checks this token to make sure it is in the fcm-android-registrations.conf, then it processes the rest. If there isn’t a match, it throws an error.

The only data that I see is how many devices the app is installed in and I think a count of FCM’s send. I don’t see where it gets sent to. I haven’t received any random notifications from you guys, so it’s working. :+1: On the off chance that let’s say I did receive a notification from you, if I tried to respond via an action it would get sent to my HA since the response is over the Rest API.

Hopefully this covers it well enough to put some concerns at ease. With all that said, I’m working with @Alexxander0 to figure out a way to use the app with your own Firebase project…without needing to recompile the app. It will involve having things configured at runtime. Hopefully we can get that going.

Let me know if I need to expand on it further. I’m glad you guys are getting some use out of it!

@danielperna84, I’ll work on doing a guide for you to use your own Firebase project. I can make it so that you can enter the api_key as part of the configuration.yaml file. If not used, it can just default to mine. I’ll let you know when I get this change out and written.

3 Likes