Self-hosted notifications with Nextcloud Talk

Many users turn to openHAB because they want home automation solutions that do not rely on any external cloud infrastructure. Unfortunately, often the notification options that connect with OH rely on 3rd party companies and their cloud services. These have their strengths and weaknesses which are discussed in numerous threads here on the forum and this isn’t the place to rehash those topics. Options for self-hosting an OH notification system do exist: for example, xmpp or an individual instance of openHAB Cloud.

This tutorial will show you how to use the Nextcloud Talk chat API as a notification system for openHAB. I am not going to claim that this notification system is better than any of the others. For me, the advantage of this was simply that I already had a Nextcloud instance and used, in a limited capacity, the Talk app. This system does allow for bidirectional communication, which, at present openHAB Cloud notification system does not. It does not, however, present an option for simple prompts in the notification as some other 3rd-party cloud services do (e.g., Telegram).

Nextcloud Talk

Nextcloud talk (Talk) is a WebRTC messaging and video chat app for Nextcloud (NC). This isn’t the place to cover all the details of NC installation and setup, but you must have administrative access to a NC instance to install this app and perform the setup of this tutorial. If you do not, there is plenty of good information available on the NC site and beyond about how to start your own NC instance.

Disclaimer: If you want to use this setup to have remote notifications, your NC instance must be available remotely by some means. NC has some very good documentation about their product and network security, but, as with all self-hosted services, the final responsibility is on you, the user, to understand the different security options available and implement the most rigorous option that fits your use case.

For the NC portion of this setup you will need:

  • Talk app added to your NC instance
    • This should be straightforward, Talk is one of the featured apps and easy to locate on the app marketplace.
  • At least 2 NC users created to be able to initiate a chat between them
    • For my instance and this demonstration, I use a chat channel between my own NC account and an account created specifically for OH notifications named Behrend House.
    • OH will use the login credentials for one of the NC users, this is the reason I have created a completely separate NC account for OH to send the notifications.
  • Talk mobile app installed on a mobile device
    • This is required for mobile push notifications, but any browser logged in to NC will also display the chat notifications, so this is not required for initial testing.

Create Talk Conversation

Before using the API to add chats to a conversation, a conversation must exist. The easiest way to do this is the Talk pane in the NC browser window.

  1. Open up the Talk pane
  2. Click on the + button next to the chat search box:
    image
  3. You will be asked to name the conversation and select some options for it. I leave both the options off, as I do not want others to be able to post messages to this chat.
    image
  4. Click on the Add Participants button on the bottom of the dialog and search for the user you created for your OH instance. When you have at least one user selected to add to the conversation, you can click to Create Conversation button.

This will create the conversation, take you to the conversation’s chat window and, most importantly, assign the conversation an ID. The conversation ID is the 8 character alpha-numeric code at the end of the url displayed in your browser while the conversation is open. For example, with the url:

https://your.nextcloud.server/call/o6b6fik9

the ID for this conversation is o6b6fik9. You will need this ID for use with the API.

If you want more than one notification stream, you can repeat this process as many times as necessary to collect the IDs of each conversation. This would allow you to have, for example, one notification stream that is just for you and a separate broadcast notification stream for all your users of OH (as long as they also have an account on your NC instance). You can even establish a notification stream for non-OH users, for instance for home security notifications (again, as long as the intended recipients have an NC account).

Talk API

You can find the docs for the Talk chat API here: Chat management - Nextcloud Talk API documentation. Via the chat API, we will be able to have OH post chat messages to the conversation we created in the previous section. Depending on the options each user has set for that conversation that user will get notifications of those messages. If you have the Talk mobile app installed on a mobile device you will get push notifications to that device. We will then extend this to OH being able to read recent messages from the chat in order to receive feedback from questions or direct basic commands.

openHAB

In OH, I have chosen to use the Http binding to access the NC Talk API.

Http binding

First we will create a single http thing for connecting to the chat API. The base endpoint for the chat api is /ocs/v2.php/apps/spreed/api/v1 and we will use this make our thing as general a connection as possible giving us the option to create multiple different channels for sending and receiving chat messages for different chats as well as some possible advanced features in the future.

  1. Create an http thing. Give it a label and, if you wish, a custom UID. Also, check the Show advanced box to expand the available options.
  2. In Base URL put the address of your nextcloud server with the addition of the chat API base endpoint /ocs/v2.php/apps/spreed/api/v1.
  3. I have left connection timing and buffer size options at their defaults, but raising or lowering the Refresh Time interval will impact the responsiveness of OH to messages sent to it because the http thing polls the chat for new messages at that interval.
  4. The API requires authentication and you will want to use the Preemptive Basic Authentication option. For user name and password you need the credentials of the account that will be sending chats in the name of your OH system.
  5. The State Method is Get and the Command Method is Post.
  6. The Content Type should be set to applicatoin/json and you will need two lines in the Headers box: OCS-APIRequest=true and Accept=application/json
Sample thing configuration yaml
UID: http:url:chatdemo
label: NC Chat Demo
thingTypeUID: http:url
configuration:
  headers:
    - OCS-APIRequest=true
    - Accept=application/json
  ignoreSSLErrors: false
  stateMethod: GET
  refresh: 30
  commandMethod: POST
  timeout: 3000
  authMode: BASIC_PREEMPTIVE
  password: your_secure_password_here
  baseURL: https://your.nextcloud.server/ocs/v2.php/apps/spreed/api/v1
  delay: 0
  contentType: application/json
  username: your_oh_user_on_nc_here
  bufferSize: 2048

Send Message Channel

To have NC create notifications in the browser or mobile app, we need to create new messages in the chat we have established. Now that we have created the http thing for our basic API access, the mechanism for sending a chat message will be to set up a channel that uses the command structure to post the new chat message to the API.

  1. On the Channels tab of the http thing click the Add Channel button.
  2. Set the Label and identifier for the channel and select a String Channel as the type. I use Send Chat Message as my label and Send_Message as the identifier.
  3. Check the Show advanced box to display the additional channel properties and set this channel’s Read/Write Mode to Write Only.
  4. Then we need to use the Command URL Extension to create the full address of the API endpoint to be called. In this case the endpoint for creating new messages is /chat/{conversation ID} where the conversation ID is the code you extracted from the chat window URL in the previous section. For this example case, I need to put /chat/o6b6fik9.

At this point your channel will work. You could link the channel to a string item and any properly formatted commands sent to that string item would be passed to the chat API to create a new message. The API, however, is expecting the posted payload in a JSON form. The entire JSON can include quite a bit of information (see Receive Message Channel below), but at a minimum the message text must be the value of the message key:

{
  message: Message text goes here.
}

Most of the time, the commands sent to items linked to this channel will be set in a rule of some other mechanism through which it will be easier to format the payload correctly. On the other hand, That’s not as elegant as just being able to send the message text as the command to the item. So here is an optional additional configuration for the Send Chat Message channel:

  1. Make sure the the Regex transformation is installed.
  2. Set the Command Transformation for the channel to:
REGEX:s/(.*)/\{"message": "$1"\}/

This regex expression will take the basic text of the string Item’s command and place it into the properly formatted json string. With this addition the only command that has to be sent to the item is the actual text of the notification.

Here’s an example where I have linked a string Item named NexcloudChat_SendChatMessage to this channel. Then I can use a rule to send a command to that item. For example, a blockly rule:
image

If I look in the NC chat window I see that the new chat message has been added to the conversation.
image

And on a mobile device with the Talk app installed, I get a notification of this chat message:

Of course, the notification even shows up on my smart watch:
image

…and I’m given an (autogenerated) list of possible quick replies. But, for OH to be able to make use of those replies we need to set up a channel for receiving messages.

Receive Message Channel

Once the message sending channel is up and working the receiving channel is easy to configure, with just a few small changes. I use Incoming Message as my label and Incoming_Message as the identifier for this channel.

The API endpoint is the same: /chat/{conversation ID} (for our example: /chat/o6b6fik9). However there are some options we want to set using parameters in the API URL:

  1. lookIntoFuture: setting this to 0 will request the return of the most recent messages in the chat.
  2. limit: this caps the number of messages that are returned. For the simplest of cases we want no more than 1 or 2 (Messages the OH account sends will also be returned with this call so if there’s a lot of communication back and forth you may need the last 2 messages to ensure you get the one sent to the OH account)
  3. setReadMarker: this is mostly just an optional house-keeping issue, as it’s name implies setting this to 1 allows the API to register messages retrieved by this call as read.

Put all that together and this is an example of the State URL Extension that you want to set for this channel:

/chat/o6b6fik9?lookIntoFuture=0&limit=1&setReadMarker=1

You’ll want to also set this channel to Read Only, and then it should be ready.

However, as with the send payload, the returned value for this call is a JSON string, although, in this case, it contains a lot more than just the message text.

Returned JSON

Here’s an example of the message “Hello OH” sent from my account to the OH account:

{
  "ocs":{
    "meta": {
      "status":"ok",
      "statuscode":200,
      "message":"OK"
    },
    "data":
      [
        {
          "id":829,
          "token":"o6b6fik9",
          "actorType":"users",
          "actorId":"justing",
          "actorDisplayName":"Justin G",
          "timestamp":1675481481,
          "message":"Hello OH.",
          "messageParameters":[],
          "systemMessage":"",
          "messageType":"comment",
          "isReplyable":true,
          "referenceId":"94972c80475e371ad32326492edcbf4f41004cec5e1ae63f271795d8812973ec",
          "reactions":{},
          "expirationTimestamp":0
        }
      ]
    }
  }
}

I don’t transform this returned value at the level of the channel. Instead I do so with a JSONPATH profile for the linked items. This gives me the ability to have individual items for different parts of the message. For example, here’s a String Item linked to this channel that extracts just the message text:

Final Thoughts

At this point You should now have a String Item that sends a NC chat which becomes a notification and a second String Item that contains the text of any message. From this starting point you can expand to anywhere OH can take you. Here are a few of the things that I’ve done with my system:

  • Actions based on answers to direct questions such as “Do you want the water closet light turned off?”.
  • With Habot installed, you can use Habot’s natural language processing in the interpretation action to respond to messages with basic commands such as “Turn off the kitchen light” with the appropriate action. Habot’s written response can also easily be sent back out as a notification.
  • If you use one of the TTS services you can send a message to OH and have it spoken through one of the audio sinks.

There are some things this system should be capable of that I haven’t tried yet.

  • It should be possible to send images with the NC chat API so that frames from camera feeds for example could be included in messages.
  • Messages can include an expiration time at which point the message is removed from the chat thread which could be useful 1) for notifications that are time sensitive and 2) simply to avoid having a chat thread that is 3000 messages about low batteries…

Talk appears to be one of the apps that the next cloud team is really putting a lot of focus on, and it’s improving tremendously with every update. I’m sure that there are more features to come that will provide even more interesting options for interacting with OH.

10 Likes

Awesome! Is this like telepathy?? :smiley:
I litteraly just added this to the oh 4.0 wishlist 30 minutes ago (native support) and now you show up with a workaround. Thank you, nice one!
I’d love to see this supported natively, with install instructions as simple as

  • install openhab-android app.

done! Works! Would be awesome but i guess that needs some internal work.
Have a great evening and thx for the nice workaround/tutorial. :slight_smile:

Great tutorial, Justin. Wasn’t it just last week that you said this was far down on your priority list? :wink:

Is the Nextcloud Talk app smart enough to dismiss notifications that have been read on another device? I send OH notifications to my phone and tablet (so that I’ll see them on whichever device I’m using at the time) and use Tasker to dismiss them after a period of time.

Yep, and I had a bit of time to get it started last night when I discovered that some past me had actually laid out most of it many many weeks ago…I have no recollection of doing that.

Either that or I have markdown gnomes around here and need to leave cookies out more often.

I only have the mobile app installed on one device so I can’t say. Browser notifications certainly don’t get dismissed when you dismiss the mobile ones so I doubt it.

Seems unlikely since I wasn’t even reading my own mind (see above)…

The API is fairly robust, so I assume that someone with binding development experience (of which I have precisely none) could whip up a binding for this with relative ease. Maybe I’ll try the cookie approach for that too… :cookie:

1 Like

Great Tutorial THX!

I have one small problem.
I used the credentials of a new Nextcloud user called openhabTalk.
However even if I use those credential when I send a message it comes always from the main account an therefore I don’t get a notification since it looks like I sent myself a message.
I hope you understand what I’m trying to explain…

Do you habe an Idea how to fix this issue?

Without seeing all the configurations you have created, I can only guess. The only method NC has for determining which user is sending a message is the authentication that is being sent.

You can try and make sure the your openhabTalk user is configured correctly for access to the chat by using curl in the from any terminal. The command would look like this:

curl -d '{"message": "Test message"}' -H "Content-Type: application/json" -H "Accept: application/json" -H "OCS-APIRequest: true" -u "openhabTalk:[your openhabTalk password here]" https://[your nc server here]/ocs/v2.php/apps/spreed/api/v1/chat/[your chatID here]

I’ve tried exactly the same thing with curl and with curl it does work as intended.
Does openHAB have a cache where it does store old login credentials. Since in
the beginning I tried a different user name.
However deleting the thing I created and recreate it with the new credentials didn’t helped…

So it must be an openHAB problem…

Are you sure you selected Preemptive Basic Authentication?

I’ve never looked into the details, but I assume that the http binding does cache various authentications for expedience. It would seem safe to assume, however, that those cached values are overwritten if the thing authentication parameters change.

If there is some http cache then it is almost certainly tied to the thing’s UID. If you create a thing with a completely different UID do you still see the same problem?

Ok I removed now the thing ansnthe http binding. Installed the binding again and added the thing. And now it works as desired. phu thx again for the tutorial!

1 Like

@JustinG were you able to send Images via the API? I managed to share a file hosted on the nextcloud like an image to the chat however it does not generate a preview of the image.

I’ve not tried to get this to work yet, so I don’t have any specific advice for you, unfortunately.

My guess would be you have to use the “rich object sharing” and not just the file sharing but I don’t know.

Thanks for the detailed tutorial but I still ran into a problem.
Do I have to do something on the nextcloud server side to open or enable the API?
I followed the given instructions to the letter and while I can chat via browser and mobile app API access from openhab fails with errors alternating between 404 and timeout elapsed.

2023-03-26 22:43:08.994 [WARN ] [p.internal.http.HttpResponseListener] - Requesting 'https://my.server.tld/ocs/v2.php/apps/spreed/api/v1' (method='GET', content='null') failed: 404 Not Found
2023-03-26 22:43:39.493 [WARN ] [p.internal.http.HttpResponseListener] - Requesting 'https://my.server.tld/ocs/v2.php/apps/spreed/api/v1' (method='GET', content='null') failed: 404 Not Found
2023-03-26 22:44:10.469 [WARN ] [p.internal.http.HttpResponseListener] - Requesting 'https://my.server.tld/ocs/v2.php/apps/spreed/api/v1' (method='GET', content='null') failed: java.util.concurrent.TimeoutException: Total timeout 3000 ms elapsed
2023-03-26 22:44:40.469 [WARN ] [p.internal.http.HttpResponseListener] - Requesting 'https://my.server.tld/ocs/v2.php/apps/spreed/api/v1' (method='GET', content='null') failed: java.util.concurrent.TimeoutException: Total timeout 3000 ms elapsed

When I open the base url in a browser I get a

<ocs>
<meta>
<status>failure</status>
<statuscode>404</statuscode>
<message>
Invalid query, please check the syntax. API specifications are here: http://www.freedesktop.org/wiki/Specifications/open-collaboration-services.
</message>
</meta>
<data/>
</ocs>

but the examples listed at that place look very different and it was not helpful for me.

Something about your configuration didn’t go right, because this is not the full url that you should be using. It is missing /chat/[the id of your chat conversation] at the end. See point #4 in the Send Message Channel step, you have to make sure that extra portion gets appended by the channel that will send the message.