Receiving and parsing webhook POST

Not sure where this should go but I am currently using the http binding to poll an API for changes (my beer tap tracker). It works but puts unnecessary load on the network and server.

I can get the keg tap server to post a json formatted webhook on event however I am unsure how to receive this and have it update an item once parsed. Is there a binding that will do this or do I ned to build a service that will receive it, transform and then update the item via the API?

Cheers,

Moad.

Install the REST API Docs, scroll down to “Items” and you will find the syntax and examples for how to POST to OH to send a command to an Item.

The sending server can’t format the post it is just a json post that will need to be parsed. Does that mean I need to create something that “brokers” the receipt of the json post and then sends the formatted command to the rest API?

I’ll read the docs now, thanks

So use the JSONPATH transform if you only need one value out of that JSON, or trigger a Rule on the Item that receives the full JSON string and parse out the parts you need and update or command other Items as necessary. You can use the JSONPATH transform from Rules as well.

Here is an example I just wrote today to get rid of a bunch of errors in my logs because sometimes an HTTP request I make returns an empty JSON “”.

NOTE: This is in JSR223 Jython, not Rules DSL.

from core.rules import rule
from core.triggers import when
from core.actions import Transformation

@rule("Handle empty results",
      description="Accept the full JSON and parse in this Rule.",
      tags=["nightscout"])
@when("Item NS_Reading received update")
def ns_reading(event):
    json = str(event.itemState)
    lr_time = "UNDEF"
    lr      = "UNDEF"
    trend   = "UNDEF"

    if json != "[]":
        lr_time = Transformation.transform("JSONPATH", "$[0].dateString", json)
        lr = Transformation.transform("JSONPATH", "$[0].sgv", json)
        trend = Transformation.transform("JSONPATH", "$[0].direction", json)

    events.postUpdate("NS_LastReading_Time", lr_time)
    events.postUpdate("NS_LastReading", lr)
    events.postUpdate("NS_Trend", trend)
1 Like

Awesome thanks Rich, I am looking to pull out two values from each post.

So send the full post to an item (via rest API) that is used to then parse and update the values on target items? The code posted makes sense I will have a crack at it and post back later today.

Thanks again

Not quite working as expected.

I can’t get the item to accept the post from the sending party. The only option I get for sending the webhook is the URL. So I have used http://192.168.1.21:8079/rest/items/WebHook (WebHook is the item and is simply defined as a String).

The item isn’t updated but a webhook test does receive the post.

I am very sorry if I am missing something simple and appreciate the help

Look at the REST API Docs and make sure the header and contents of the POST are what OH needs.

I think what you are saying is that you are stuck with the POST payload that the device wants to send, and of course it is not in the format that openHAB REST is looking for.

Can you change the target port? you might be able to intercept with the TCP binding

Yes that’s what I mean, sorry I didn’t articulate that well at all


I’ll see what options I have, I’m sure I’ll be able to use a different port. The other option might be to setup a service to reformat the post data and send it to openhab API.

I’ve configured a node server to receive and parse the request and then update the item.

Cheers

Sorry to resurrect but can you share the node.js code, please?

Thank you,
Zsolt.

apologies I just came back to this.

This takes the webhook from my keg tracking software and parses the beer name from the JSON payload, then sends it to the channel in OH.

var express = require(‘express’)
var bodyParser = require(‘body-parser’)
var port = 81
require(“util”).inspect.defaultOptions.depth = null;
var request = require(‘request’);
var app = express()
var headers = {
‘Content-Type’: ‘text/plain’,
‘Accept’: ‘application/json’
};

// parse application/json
app.use(express.json({extended: true}))

app.use(function (req, res, next) {
console.log(req.body) // populated!
var beer=req.body.data.drink.keg.beverage.name
console.log(beer)
var options = {
url: ‘http://192.168.1.21:8079/rest/items/Garage_Speak’,
method: ‘POST’,
headers: headers,
body: “enjoy” + beer
};
next(request(options, callback))
})

console.log(‘Web server listening on port: %s’, port);

//Start the server and make it listen for connections on port
app.listen(port);

function callback(error, response, body) {
if (!error && response.statusCode == 200) {
console.log(body);
}
}

1 Like