hi there,
is there anybody who uses matrix/synapse (element) to send messages from openhab?
i think its very similar to xmpp.
maybe someone has already had experience with it and can share it
thanks
hi there,
is there anybody who uses matrix/synapse (element) to send messages from openhab?
i think its very similar to xmpp.
maybe someone has already had experience with it and can share it
thanks
Note There’s a much easier way of doing this using Even easier, just use the HTTP binding, and JINJA transformation - see post 4.sendHttpPostRequest
- see the next post!
I’m self-hosting Matrix using the Synapse package.
I am pushing messages from openHAB to Matrix via MQTT. The flow is roughly as follows, though is not for the faint-of-heart - it’s ugly!
openhab → MQTT broker → paho-mqtt → matrix-commander → Matrix/Synapse
Bridge mqtt:broker:MosquittoMqttBroker "Mosquitto MQTT Broker" [
host="mqtt.lan",
secure=false,
port=1883,
clientID="OpenHAB3",
username="",
password=""
]
// Main Bedroom Light
Thing mqtt:topic:log "Log" (mqtt:broker:MosquittoMqttBroker) {
Channels:
Type string : strInfo "Info" [
commandTopic="openhab/log/info"
]
}
String strLogInfo "Log Info" {channel="mqtt:topic:log:strInfo"}
openhab
using app.element.io
openhab/log/info
and relay any messages received to matrix-commander
#!/usr/bin/env python3
import paho.mqtt.client as mqtt
import os
# The callback for when the client receives a CONNACK response from the server.
def on_connect(client, userdata, flags, rc):
print("Connected with result code "+str(rc))
# Subscribing in on_connect() means that if we lose the connection and
# reconnect then subscriptions will be renewed.
client.subscribe("openhab/log/info")
# The callback for when a PUBLISH message is received from the server.
def on_message(client, userdata, msg):
message = msg.payload
message = message.decode("utf-8")
print(msg.topic+" "+message)
os.system("/path/to/matrix-commander/matrix-commander.py -c \"/path/to/matrix-commander/credentials.json\" -s \"/path/to/matrix-commander/store/\" -m \""+message+"\"")
client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message
client.connect("192.168.1.151", 1883, 60)
# Blocking call that processes network traffic, dispatches callbacks and
# handles reconnecting.
# Other loop*() functions are available that give a threaded interface and a
# manual interface.
client.loop_forever()
I use Jython rules, so just send a command to the Item with the text that I want to be published to the Matrix room:
events.sendCommand("strLogInfo","DAY mode activated.")
In DSL rules this would be
strLogInfo.sendCommand("DAY mode activated")
matrix-commander
directly from openHAB, but for me:
Here’s a much easier way of sending messages to a Matrix room from a rule:
sendHttpPostRequest("https://YOURMATRIXDOMAIN/_matrix/client/r0/rooms/YOURROOMID/send/m.room.message?access_token=YOURACCESSTOKEN", "application/json", "{\"msgtype\":\"m.text\", \"body\":\"YOURMESSAGE\"}")
or a little more readable
val String URL = 'https://YOURMATRIXDOMAIN/_matrix/client/r0/rooms/YOURROOMID/send/m.room.message?access_token=YOURACCESSTOKEN'
var String DATA = '{
"msgtype": "m.text",
"body": "YOURMESSAGE"
}'
sendHttpPostRequest(URL, "application/json", DATA)
where:
YOURMATRIXDOMAIN
your (subdomain) URL, such as matrix.example.org
YOURROOMID
is the room ID in which you want the messages to appear. If you’re using Element as a client you can click on the room name, go to Advanced and you’ll find the Internal room ID which will look something like !hGbNiOPDjfsJfF:matrix.example.org
YOURACCESSTOKEN
is the access token for your user. To find out my user token for my Matrix user openhab
I executed the following command (substituting the password and URL) in a terminal on the same system that is running openHAB:curl -XPOST -d '{"type":"m.login.password", "user":"openhab", "password":"PASSWORD"}' "https://matrix.example.org/_matrix/client/r0/login"
This will spit out something like the following, from which you can grab your access token.
{
"user_id": "@openhab:matrix.example.org",
"access_token": "YOURACCESSTOKEN",
"home_server": "matrix.example.org",
"device_id": "HFNFBSUHSK",
"well_known": {
"m.homeserver": {
"base_url": "https://matrix.example.org/"
}
}
}
Notes
openhab
) on your Matrix/Synapse homeserver, and that you have created a room with the user and one other user (maybe yourself).from core.actions import HTTP
matrix_openhab_token = "MYUSERTOKEN"
matrix_homeserver_url = "MYMATRIXDOMAIN"
matrix_openhab_room = "MYROOMID"
matrix_message = "MYMESSAGE"
url = "https://{}/_matrix/client/r0/rooms/{}/send/m.room.message?access_token={}".format(matrix_homeserver_url, matrix_openhab_room,matrix_openhab_token)
HTTP.sendHttpPostRequest(str(url), 'application/json', '{"msgtype":"m.text", "body":matrix_message}')
Even easier - use the HTTP Binding and JINJA transformation - no rules required.
All the prerequisites/caveats of the previous post still hold true, but everything can be configured via the UI if you desire. Simply, a String Item is linked to a String Channel in the HTTP Thing, and that String Channel uses a JINJA transformation to put the message into JSON required by the Matrix server.
//Matrix server
Thing http:url:matrix "Matrix" [
baseURL = "https://YOURMATRIXDOMAIN/",
refresh = "300",
timeout ="3000",
ignoreSSLErrors = "true",
commandMethod = "POST"
]
{
Channels:
Type string: home "Home Room" [
mode = "WRITEONLY",
commandExtension = "_matrix/client/r0/rooms/YOURROOMID/send/m.room.message?access_token=YOURACCESSTOKEN",
commandTransformation = "JINJA:{\"msgtype\":\"m.text\", \"body\":\"{{value}}\"}"
]
}
UID: http:url:matrix
label: Matrix
thingTypeUID: http:url
configuration:
authMode: BASIC
ignoreSSLErrors: "true"
baseURL: https://YOURMATRIXDOMAIN/
delay: 0
stateMethod: GET
refresh: "300"
commandMethod: POST
timeout: "3000"
bufferSize: 2048
channels:
- id: home
channelTypeUID: http:string
label: Home Room
description: null
configuration:
mode: WRITEONLY
commandExtension: _matrix/client/r0/rooms/YOURROOMID/send/m.room.message?access_token=YOURACCESSTOKEN
commandTransformation: JINJA:{"msgtype":"m.text", "body":"{{value}}"}
String strMatrixMessageHomeRoom "Matrix message home room" {channel="http:url:matrix:home"}
When I enter something like
https://YOURMATRIXDOMAIN/_matrix/client/r0/rooms/YOURROOMID/send/m.room.message?access_token=YOURACCESSTOKEN
into my browser, it says
As YOURMATRIXDOMAIN, I entered “matrix.org”. Could it be that this is not working for matrix.org instance?
Oh, no idea! Did you enter known working values for the room ID and access token too?
Wouldn’t surprise me if matrix.org prevented robots.
All of my posts have assumed a self hosted Synapse server.
I have HTTP binding error
org.eclipse.jetty.client.HttpResponseException: HTTP protocol violation: Authentication challenge without WWW-Authenticate header
What could be the problem?
Solved
In curl -XPOST my key code %21C…
HTTP binding need !C…
Expansion of the Openhab+Matrix functionality.
Sending commands from the Matrix room to Openhab
Thing http:url:matrix "Matrix. Message" [
baseURL = "https://MY_MATRIX_DOMAIN:8448/",
refresh = "60",
timeout ="3000",
ignoreSSLErrors = "false",
commandMethod = "POST"
]
{
Channels:
Type string: openhab_matrix "Matrix. Send message" [
mode = "WRITEONLY",
commandExtension = "_matrix/client/r0/rooms/MY_ROOM_ID/send/m.room.message?access_token=ACCESS_TOKEN",
commandTransformation = "JINJA:{\"msgtype\":\"m.text\",\"format\": \"org.matrix.custom.html\",\"body\":\"{{value}}\", \"formatted_body\":\"{{value}}\"}"
]
}
Thing http:url:matrix_command "Matrix. Command" [
baseURL = "https://MY_MATRIX_DOMAIN:8448/_matrix/client/v3/rooms/MY_ROOM_ID/messages?access_token=ACCESS_TOKEN&dir=b&limit=1"
refresh = "60",
timeout ="3000",
ignoreSSLErrors = "false",
commandMethod = "GET"
]
{
Channels:
Type string: message_type "Message type" [
mode = "READONLY",
stateTransformation = "JSONPATH:$.chunk[0].content.msgtype"
]
Type string: message "Message" [
mode = "READONLY",
stateTransformation = "JSONPATH:$.chunk[0].content.body"
]
Type string: message_id "Message id" [
mode = "READONLY",
stateTransformation = "JSONPATH:$.chunk[0].event_id"
]
Type string: user_id "User id" [
mode = "READONLY",
stateTransformation = "JSONPATH:$.chunk[0].user_id"
]
}
String openhab_matrix_p "Matrix. Send message" ["Point"] { channel="http:url:matrix:openhab_matrix"}
String matrix_command_message_id_p "Matrix. Message id" ["Point"] { channel="http:url:matrix_command:message_id"}
String matrix_command_message_type_p "Matrix. Message type" ["Point"] { channel="http:url:matrix_command:message_type"}
String matrix_command_message_p "Matrix. Message" ["Point"] { channel="http:url:matrix_command:message"}
String matrix_command_user_id_p "Matrix. User id" ["Point"] { channel="http:url:matrix_command:user_id"}
rule "Matrix. Command"
when
Item matrix_command_message_id_p changed
then
if (matrix_command_message_type_p.state == "m.text" && matrix_command_user_id_p.state == "YOUR_USER_ID" ) {
var mm = matrix_command_message_p.state
if(mm == "Help"){
var cl = "\u003cp\u003eCommand list:\u003c/p\u003e"
var cl1 = "\u003cp\u003e1. Help - list command\u003c/p\u003e"
var cl2 = "\u003cp\u003e2. \u003cb\u003eSwitch off\u003c/b\u003e - Room Switch off\u003c/p\u003e"
openhab_matrix_p.sendCommand(cl + cl1 + cl2)
return
}
if(mm == "Switch off"){
openhab_matrix_p.sendCommand("\u003cp\u003e" + mm + "\u003c/p\u003e")
YOUR_SWITCH.sendCommand(OFF)
return
}
}
end
Oh incredible - just to confirm, is this so that you can control openHAB by sending messages to a specific Matrix room?
And presumably this is poll based, so every 60 seconds (or whatever), openHAB will check the Matrix room and process every (or just the last?) message and act accordingly?
Yes.
For simplicity of implementation - only the last message.
Polling time, can be changed by parameter
refresh = "60"
OK, yeah, so perhaps a little tricky in a room with multiple people unless polling every second.
I’ll see if I can build on this to process all messages since the last one - I might have to break away from Blockly for that one…!!
Thanks for sharing!
It’s possible. But it takes more time to implement.
For my tasks. One room. Two accounts, me and openhab. Enough.
If you are looking for a docker based approach with end to end encryption: I summarized my solution here at github. Not ideal but fits my needs, as especially end-to-end encryption is given in difference to the solutions so far and no changes to the Dockerfile of openhab are required.
Hi,
I am gladly using the Matrix Messaging option.
I would like to “format” my message with a “line break”.
How would i do this? From Messagin with xmpp it would have been “\n” in the quoted text-part, but that does not work for Matrix - I tried.
events.sendCommand("MatrixMessage", "TestButton - MatrixMessage: " + test);
I would like the line break after the “TestButton - MatrixMessage:” befor the value of the variable “test” shows up.
Thanks for your help in advance.
Eckart
The following works for me:
events.sendCommand("MatrixMessage", "TestButton - MatrixMessage:\n" + test);
Hi,
thank you for your help, but unfortunately that does not work for me. In tails it shows only:
[WARN ] [p.internal.http.HttpResponseListener] - Requesting ‘https://myserver/_matrix/client/r0/rooms/myroom/send/m.room.message?access_token=mytoken’ (method=‘POST’, content=‘org.eclipse.jetty.client.util.StringContentProvider@db9b5c’) failed: 400 Bad Request
I did not implement the “Matrix.command” part, but that should not make a change in my understanding for the Matrix.message part.
I think I will resign on formatting the messages.
Thanks.
Eckart