How to get actionable notifications using Slack

Holy hell i used to have slack but my api expired on the team i was using.
I got the iOS actionable notifications up and thought they were amazing.
I have rocketchat and love if could be done via selfhosted rocketchat cause these Callbacks are super neat.
Great work.

@SteveDinn excellent research, I tried following but lost track somewhere in the middle and was not sure if it my lack of patience or few things got upgraded as there is lot of middleware involved in this thread.

I stumbled upon Twilio SMS APIs which are priced at 3/4th of a penny and works great with AppDaemon python scripts. One factor in favor of Twilio’s paid service is that notifications are meant for rare occasions so transaction costs becomes irrelevant. Also found Simple Push ($4.99 one time) app as another alternative to notification and it takes literally one line of code for integration.

Please check these out and feel free to share your thoughts and suggest how novices like us can use notification services in HA.

Great stuff, this really helped me!

However, I am trying to accomplish this in node-red and I have hit one snag: When clicking an action in Slack I route this to a webhook-node in node-red but the message I receive is really strange encoded, this is the payload being received:

"payload=%7B%22type%22%3A%22interactive_message%22%2C%22actions%22%3A%5B%7B%22name%22%3A%22button_remind%22%2C%22type%22%3A%22button%22%2C%22value%22%3A%22remind%22%7D%5D%2C%22callback_id%22%3A%22buttons%22%2C%22team%22%3A%7B%22id%22%3A%22T0TND8YKB%22%2C%22domain%22%3A%22loslandinos%22%7D%2C%22channel%22%3A%7B%22id%22%3A%22D01FWUU9C5C%22%2C%22name%22%3A%22directmessage%22%7D%2C%22user%22%3A%7B%22id%22%3A%22U0TLSHKR9%22%2C%22name%22%3A%22larre%22%7D%2C%22action_ts%22%3A%221612445417.836968%22%2C%22message_ts%22%3A%221612445343.000600%22%2C%22attachment_id%22%3A%221%22%2C%22token%22%3A%22xVnrVbOQtnxKlWvnCUdM2733%22%2C%22is_app_unfurl%22%3Afalse%2C%22enterprise%22%3Anull%2C%22is_enterprise_install%22%3Afalse%2C%22original_message%22%3A%7B%22type%22%3A%22message%22%2C%22subtype%22%3A%22bot_message%22%2C%22text%22%3A%22%22%2C%22ts%22%3A%221612445343.000600%22%2C%22username%22%3A%22Home+Assistant%22%2C%22bot_id%22%3A%22B01FNUJF3MM%22%2C%22attachments%22%3A%5B%7B%22callback_id%22%3A%22buttons%..."

I realize it is JSON encoded some way but also it contains the “payload=” in the beginning.

Any ideas? Is there a setting in Slack that I can look at, is maybe my original Slack message badly formed or should I just accept it and convert it as is?

slack is a bit strange here.

just strip payload= from the start of the string
and then use a html decode function to convert the html encoded characters back to regular characters to reveal the json string. %7B -> { etc

That worked like a charm, thanks a lot!!!

Is anyone else having issues with the callback after the latest release (2021.4.3)? In particular, it seems like this change may have broken the callback from above: 2021.4: For our advanced users ❤️ - Home Assistant

Previous to April 4th I was seeing the callback message in slack, but now the message is edited in slack to be empty and this error is showing in HA logs for all my callbacks I had setup and working:

Template variable warning: 'message' is undefined when rendering '{ "replace_original": {{ replace_original if (replace_original is defined) else 'true' }}, "text": "{{ message }}", "attachments": {{ attachments if (attachments is defined) else '[]' }} }'

I changed {{ message }} to {{ message | default(’’)}} in chat.postMessage and the slack response, which got rid of the warning about empty message, however, now I’m seeing this:

Error. Url: https://hooks.slack.com/actions/[channel_id]/[remaining_slack_url]. Status code 404. Payload: b'{\n "replace_original": True,\n "text": "",\n "attachments": [{\'pretext\': \'The Garage lights were left on for 10 minutes.\', \'title\': "Handled with \'turn_off\' by <@[slack_bot_id]>", \'color\': \'#03a9f4\'}]\n}

I also get this 404 error.
According to slack this means “channel_not_found”.
See: Improving error conditions for Incoming Webhooks | Slack

I wonder if it has something to do with the return URL being /actions/ . The channel ID in my URL is the correct one. Also as a side note, I tried switching my automation to use blocks with the Slack integration, but I could only get the basic text area to display. The post seemed to fail if I tried adding in action elements such as buttons. I didn’t have time to do more verbose logging to see what the problem was. I had copied the configuration directly from Slack’s block builder and transformed it to yaml using a json to yaml converter. As soon as I removed the action elements, the text section would display in Slack again.

Set up a callback to perform actions
On https://api.slack.com , when looking at your app, click on “Interactive components” and turn on “Interactivity” . In the “Request URL” box, you’re going to enter the address of a webhook that you’ll create in Home Assistant (something like https://[your domain]/api/webhook/[webhook_id]). When you click one of those buttons in your notifications, Slack will POST a bunch of JSON to that URL (see the bottom of this post for an example of what Slack sends to this webhook). We can set up an automation to deal with that.

I don’t see a Interactive components tab. This is the closes I can find. Is there where I need to create the webhook url?

The url string would be like? The my_custom_id is the id of my choosing which I create in the automation?

https://ha_domain.com/api/webhook/my_custom_id

Correct. Mine is:

https://{ha-domain}/api/webhook/slack for simplicity just called it slack

Ok. That is how I set it up, but it is not working. I am up to this part where I can view the buttons. However, when I press close it, nothing happens and I do not see any errors in log.

This is the webhook in HA I have setup.

- alias: slack_webhook
  trigger:
    - platform: webhook
      webhook_id: 'not-working-webhook'
  condition:
    - condition: template
      value_template: >
        {% set payload = trigger.data.payload | from_json %}
        {{ (payload.token == <Verification Token
>) and (payload.type == 'interactive_message') }}
  action:
    - service_template: >
        {%- set payload = trigger.data.payload | from_json -%}
        script.{{ payload.callback_id }}
      data_template:
        payload: '{{ trigger.data.payload }}'

Do I need to setup anything else for the webhook in HA? I’ve added in config file this line, but I don’t think it is needed?

webhook:

Now, I am starting to get some error after I added quotes between 'Verification Token'

Errors:

Error while executing automation automation.slack_webhook: Error rendering service name template: UndefinedError: 'trigger' is undefined
7:29:00 PM – Automation (ERROR) - message first occurred at 3:05:48 PM and shows up 3 times

slack_webhook: Error executing script. Error for call_service at pos 1: Error rendering service name template: UndefinedError: 'trigger' is undefined
7:29:00 PM – Automation (ERROR) - message first occurred at 3:05:48 PM and shows up 3 times

cover_left_open_callback: Error executing script. Error for call_service at pos 1: Error rendering data template: JSONDecodeError: Expecting value: line 1 column 1 (char 0)
7:29:00 PM – Script (ERROR) - message first occurred at 3:03:44 PM and shows up 5 times

Error. Url: https://hooks.slack.com/actions/T01U5CCJJDHAA/19720984849124/zwQrAMAd9KDNCD3UG3JKVBVEV. Status code 404. Payload: b'{\n "replace_original": True,\n "text": "",\n "attachments": [{\'pretext\': \'The temperature outside is above 32c\', \'title\': "Handled with \'Close it\' by <@U01UQQG357B>", \'color\': \'#03a9f4\'}]\n}'
7:29:00 PM – RESTful Command (WARNING) - message first occurred at 7:16:05 PM and shows up 2 times

Yeah me and mat @mat1583 have the same issue, see above your initial post. Something changed recently, as in this month, not sure what yet and how to fix.

@duceduc I would remove the webhook: from configuration. It’s not needed. I think you have a couple issues going on - one of which is the webhook automation. See my comments below. The other issue is the same one @tinuva and I are having, which is the response_url problem after the button is clicked. When I click one of the buttons, HA is correctly handling the click and turning off/closing the entity, but when it tries to respond back to Slack to update the message, I get that 404 that you’re seeing. This was not the case before around 4/4. I would correctly see it change the message.

Here’s my current setup for the webhook automation. Note that I used the input_text idea from another commenter so I could throw my verification token into secrets:

  alias: Slack Webhook for handling Slack interactions
  description: 'Webhook for Slack -> Home Assistant. DO NOT DELETE OR EDIT

    '
  trigger:
  - platform: webhook
    webhook_id: <my_slack_webhook_id>
  condition:
  - condition: template
    value_template: >
      {% set payload = trigger.data.payload | from_json %}   
      {{ (payload.token == states('input_text.slack_app_verification_token')) and (payload.type == 'interactive_message') }}
  action:
  - service_template: >
      {%- set payload = trigger.data.payload | from_json -%} 
      script.{{ payload.callback_id }}
    data_template:
      payload: '{{ trigger.data.payload }}'
  mode: parallel

@duceduc @tinuv

I figured it out! What I did to troubleshoot was post the message from postman to the URL provided with the exact payload. The 404 respond was actually “invalid_payload”. The invalid part is this:
“replace_original”: True

capitalized, it won’t work. It should be all lowercase. I’m not sure what caused the sudden change from true to True, but for now I changed the slack response to just be replace_original: ‘true’ instead of the check for defined. I’ll look into it further when I have the time.

1 Like

I am still getting same errors after changing the webhook automation and the `replace_original: True.

- alias: slack_webhook
  description: 'Webhook for Slack -> Home Assistant. DO NOT DELETE OR EDIT'
  trigger:
    - platform: webhook
      webhook_id: webhook-not-working
  condition:
    - condition: template
      value_template: >
        {% set payload = trigger.data.payload | from_json %}
        {{ (payload.token == states('input_text.slack_app_verification_token')) and (payload.type == 'interactive_message') }}
  action:
    - service_template: >
        {%- set payload = trigger.data.payload | from_json -%}
        script.{{ payload.callback_id }}
      data_template:
        payload: '{{ trigger.data.payload }}'
  mode: parallel
  slack_response:
    url: '{{ response_url }}'
    content_type: 'application/json; charset-utf-8'
    verify_ssl: true
    method: 'post'
    timeout: 20
    payload: >
      {
        "replace_original": True,
        "text": "{{ message }}",
        "attachments": {{ attachments if (attachments is defined) else '[]' }}
      }

Error

Crap! Just noticed you said capitol does not work.

Surround the replace_original value in single quotes like this:

{{ replace_original if (replace_original is defined) else ‘true’ }}

I think what was happening is that it was being translated to a python boolean which is either True or False.

Edit: I spoke too soon about putting single quotes around the replace original. I don’t think I had re-loaded everything before testing. It still returns True in the payload, so for now I’ve just hardcoded the response to set replace_original to true.

1 Like

ok. For now, I just changed it to lower case true and I can see the reply.

"replace_original": true,

However, the undefineError: trigger is still there. The automation isn’t triggering.

error:

Error while executing automation automation.slack_webhook: Error rendering service name template: UndefinedError: 'trigger' is undefined
7:29:00 PM – Automation (ERROR) - message first occurred at 3:05:48 PM and shows up 3 times

slack_webhook: Error executing script. Error for call_service at pos 1: Error rendering service name template: UndefinedError: 'trigger' is undefined
7:29:00 PM – Automation (ERROR) - message first occurred at 3:05:48 PM and shows up 3 times

cover_left_open_callback: Error executing script. Error for call_service at pos 1: Error rendering data template: JSONDecodeError: Expecting value: line 1 column 1 (char 0)
7:29:00 PM – Script (ERROR) - message first occurred at 3:03:44 PM and shows up 5 times

More troubleshooting:
I think I have found the cause, but am not sure where to look to fix it. It is in this script, entity_id. If I just add the actual entity id, which is cover.living_room_curtains, the curtain closes when I click on the Close it button in slack.

  cover_left_open_callback:
    sequence:
      - service: script.callback_handled
        data_template:
          replace_original: true
          payload: '{{ payload }}'
      - condition: template
        value_template: >
          {%- set action = (payload | from_json).actions[0] -%}
          {{ (action.value == "Close it") and not (action.name == "")}}
      - service: cover.close_cover
        data_template:
          entity_id: >
            {%- set entity_id = (payload | from_json).actions[0].name -%}
            cover.{{ entity_id if (not entity_id.startswith("cover.")) else entity[6:] }}

The only place that has this entity id is this automation, which I have stated the entity id.

- alias: Temperature above 32
  trigger:
    platform: state
    entity_id: input_boolean.guest_mode
    to: 'on'
  action:
    - service: script.notify_slack
      data_template:
        channel: !secret slack_channel_id
        message: "The temperature outside is above 32c"
        attachments:
          - title: Turn on the Living Room AC?
            callback_id: cover_left_open_callback
            color: '#03a9f4'
            attachment_type: default
            actions:
              - text: Close it
                value: Close it
                name: 'cover.living_room_curtains'
                type: button
              - text: Leave it
                value: Leave it
                name: 'anything_just_not_blank'
                type: button

Update: Found the cause. see this post.

1 Like

Thank you!!!

Fixed for me now as well.

@duceduc
You can see my working configs on github if that helps.
The slack_interactive part that is re-usable: home-assistant-config/packages/slack_interactive.yaml at 599748f1a5babafec294f8a3d16e0b719ba53ff8 ¡ tinuva/home-assistant-config ¡ GitHub

Then my garage doors are from here: home-assistant-config/packages/cover_garage_doors.yaml at 599748f1a5babafec294f8a3d16e0b719ba53ff8 ¡ tinuva/home-assistant-config ¡ GitHub
Look towards the bottom to see the part that invokes the original slack message.

Oh one more thing, since I like to use Notify instead of just an automation (i should change it to be simpler) I have this script: home-assistant-config/ha_to_api_notify_cover.sh at 599748f1a5babafec294f8a3d16e0b719ba53ff8 ¡ tinuva/home-assistant-config ¡ GitHub

But technically, you dont need notify anymore like I did there.

2 Likes

Thank you for sharing your code. I found the cause. The issue was in this code.

  cover_left_open_callback:
    sequence:
      - service: script.callback_handled
        data_template:
          replace_original: true
          payload: '{{ payload }}'
      - condition: template
        value_template: >
          {%- set action = (payload | from_json).actions[0] -%}
          {{ (action.value == "Close it") and not (action.name == "")}}
      - service: cover.close_cover
        data_template:
          entity_id: >
            {%- set entity_id = (payload | from_json).actions[0].name -%}
            cover.{{ entity_id if (not entity_id.startswith("cover.")) else entity_id[6:] }}

In the original code provide by the OP, the _id was missing from the last line bit of code.

cover.{{ entity_id if (not entity_id.startswith("cover.")) else entity[6:]

It should be

cover.{{ entity_id if (not entity_id.startswith("cover.")) else entity_id[6:]
1 Like