Plex Webhooks and Home Assistant

Continuing the discussion from PlexDevices - Custom Media Player Component:

There isn’t an off-topic forum, so I will start a thread and continue my discussion about Webhooks.

What URL do I put in it for Webhooks? Do I put in something like http:\localhost:1250 (I used “” instead of “//” so Discourse does not convert the localhost address into links; otherwise, I’ll get a “Popular Link” badge…)? I actually found the Webhooks area in my account section, but I’m not sure what to put in Webhooks so that I can integrate it into Home Assistant.

More info about Webhooks can be found here:

I played with it a bit (PLEX all the things!) and ran into an issue where the HASS API didn’t like the response from Plex since a portion of it includes a picture, apparently.

error is:

17-02-17 14:16:31 ERROR (MainThread) [aiohttp.server] Error handling request
Traceback (most recent call last):
  File "/usr/local/lib/python3.5/site-packages/aiohttp/web_server.py", line 62, in handle_request
    resp = yield from self._handler(request)
  File "/usr/local/lib/python3.5/site-packages/aiohttp/web.py", line 270, in _handle
    resp = yield from handler(request)
  File "/usr/local/lib/python3.5/asyncio/coroutines.py", line 213, in coro
    res = yield from res
  File "/usr/local/lib/python3.5/asyncio/coroutines.py", line 213, in coro
    res = yield from res
  File "/usr/src/app/homeassistant/components/http/__init__.py", line 427, in handle
    result = yield from result
  File "/usr/src/app/homeassistant/components/api.py", line 311, in post
    body = yield from request.text()
  File "/usr/local/lib/python3.5/site-packages/aiohttp/web_reqrep.py", line 394, in text
    return bytes_body.decode(encoding)
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 6270: invalid start byte

But you missed my question:

Do I put in something like http:\\192.168.0.2:8123 or something similar (again, I used "" instead of “/” to now show as a link)?

1 Like

Based on the little I know, I believe the API may be looking for a byte stream and Plex is sending it as a utf-8 encoded string… or something like that. I’m thinking an issue may need to be opened to have a developer look at the API.

So you don’t know what URL to put in for Webhooks?

1 Like

Hey,

IIRC the way I did it way back was I called a script in which I then parsed the JSON I got as seen here: https://home-assistant.io/developers/rest_api/#post-apiservicesltdomainltservice

~Cheers

https://192.168.0.2:8123/api/services/script/plextest?api_password=PasswordGoesHere

You can see I am calling a script called plextest.

That script looks like:

  plextest:
    alias: 'Webhook test'            
    sequence:
      - service: notify.notifyall
        data_template: 
          message: >
            '{{ Player.title }}'  

Which when using the dev-service and using the example response from Plex (https://support.plex.tv/hc/en-us/articles/115002267687), this works fine.

1 Like

Something like this?

yes, the port should be your HASS port. I think you will need your HASS instance publicly accessible as I believe the request comes from plex.tv and not your local plex server.

Hmm… Well that’s too bad, as I couldn’t figure out how to configure the my mom’s router to expose port 80 so I can get a Let’s Encrypt certificate. My mom has a DSL service with Fairpoint and I don’t want to mess with the Comtrend DSL’s firewall.

Please try to get your wording correct. It is hard to follow you if you don’t use the correct words for things. There should be no such thing as a “DSL Firewall” and you need to forward port 443 for Let’s Encrypt. What you did enter in your plex should not work anyway as you did not call a script rather a light service. This probably won’t do anything.

@kylerw could you verify this please? If the calls are coming from plex.tv it would make that feature worthless imho.

~Cheers

Here is an example of how Webhooks work:

And a project:

As for an example, I have a home server and NVIDIA Shield.

I look at this line: [quote]Add the webhook to Plex (example http://192.168.1.208:12000)[/quote]

And I saw that I can put an IP address there with a port number.

I have two devices as an example:

  • ISY Devices ISY994: 192.168.0.22
  • NVIDIA Shield running Plex Media Server: 192.168.0.17

If I set the webhook as http://192.168.0.22:10000, will that work? I’m not sure how webhooks work, though.

OH!!! I got it!

Here’s the code for node.js:

var express = require('express')
  , request = require('request')
  , multer  = require('multer');;

var app = express();
var upload = multer({ dest: '/tmp/' });

app.post('/', upload.single('thumb'), function (req, res, next) {
  var payload = JSON.parse(req.body.payload);
  console.log('Got webhook for', payload.event);
});

app.listen(10000);

When I run it, here’s what I get:

grayson@home-server:~$ nodejs test.js 
Got webhook for media.play
Got webhook for media.pause

It works! Now to implement turning on/off the lights depending whether the movie is playing or paused.

So it turns out that I put in http:\192.168.0.2:10000 (change from “\” to “//” BTW) for Account->Webhooks page and it works! Node.JS can listen to whatever port I put in the JavaScript code.

(Update after a minute…)

So! If Home Assistant supports webhooks from Plex, all I have to do is change from 10000 to 32400 (Home Assistant’s port) and I can execute actions based on the events from Plex!

A Webhook is just a call on the HTTP protocol. So you can tell plex to call this thing once everytime something happens.

You still need a script WRITTEN BY YOU in HA which is entered in that webhook and you need to decide inside this script what happens in HA depending on the data it got in JSON format.

~Cheers

Looking at the screens here, they define the URL as localhost.

Doesn’t that indicate that it is more local than from plex.tv?

1 Like

I believe so. In fact, here’s the code for testing. Replace anything that you need:

var express = require('express')
  , request = require('request')
  , multer  = require('multer');;

var app = express();
var upload = multer({ dest: '/tmp/' });

app.post('/', upload.single('thumb'), function (req, res, next) {
  var payload = JSON.parse(req.body.payload);
  var cURL = "http://localhost:8123/api/";
  var json = { "entity_id": "light.living_room_floor_lamps" };
  var cType = "application/json";
  var ha_passwd = "(Home Assistant API Password Goes Here)";

  console.log('Got webhook for', payload.event);

  if(payload.event === 'media.play' || payload.event === 'media.resume')
  {
    console.log("Media is playing.");
    request({
      url: cURL + "services/light/turn_off",
      method: "POST", json: true, body: json,
      headers: { "x-ha-access" : ha_passwd, "Content-Type": cType }
    }, function(error, response, body) { console.log(response); });
  }
  else if(payload.event === 'media.pause' || payload.event === 'media.stop')
  {
    console.log("Media is stopped.");
    request({
      url: cURL + "services/light/turn_on",
      method: "POST", json: true, body: json,
      headers: { "x-ha-access" : ha_passwd, "Content-Type": cType }
    }, function(error, response, body) { console.log(response); });
  }
  res.sendStatus(200);
});

app.listen(10000);

If you then call nodejs yourscripthere.js, you should be able to watch the output in the console as you play/pause the video. The response for turning on/off my floor lamps when I pause/play the video is not bad.

However, you might want to limit the listening to only a single client if you are planning to set up a nice cinematic experience. If you have a tablet and you are in another room, the lights can go on and off as you pause/resume playback which you probably do not want. I’ll do some research and see what I can find.

Update: As I play a TV show in Plex Web, it is instantaneous. However, it does take a second for the Home Assistant API to be executed when media is playing or pausing.

Update 1:

Okay! The list of payloads can be found in “Example Payload” in Plex Webhooks page.

Here’s an example of mine:

console.log('Got webhook for ', payload.event + ", UUID " + payload.Player.uuid );

//  if(payload.Player.uuid == "(insert your UUID here.)")
//  {
    if(payload.event === 'media.play' || payload.event === 'media.resume')
    {
      console.log("Media is playing.");
      request({
        url: cURL + "services/light/turn_off",
        method: "POST", json: true, body: json,
        headers: { "x-ha-access" : ha_passwd, "Content-Type": cType }
      }, function(error, response, body) { console.log(body); });
    }
    else if(payload.event === 'media.pause' || payload.event === 'media.stop')
    {
      console.log("Media is stopped.");
      request({
        url: cURL + "services/light/turn_on",
        method: "POST", json: true, body: json,
        headers: { "x-ha-access" : ha_passwd, "Content-Type": cType }
      }, function(error, response, body) { console.log(body); });
//    }
}

Run the script with nodejs and and watch for the UUID. Once you’ve found the UUID that is outputted by the script, go ahead and uncomment the ones that have “//” for the if() { } statement and paste the UUID that’s in between quotes with “(insert your UUID here.)”

You do know that you don’t need NodeJS tho right? You could just use a script in HA to do this.

~Cheers

I’ve never written a custom component myself. How is Home Assistant going to be able to receive JSON code?

No need for a custom component. You just need a script (https://home-assistant.io/components/script/)!

Lets say you created a script called “plex_play”:

script:
  plex_play:
    sequence:
      - condition: template
        value_template: '{{ Player.uuid == "SOMETHING" }}'
      - delay:
          seconds: 10
      - service: scene.turn_on
        data:
          entity_id: scene.livingroom_normal

You would then enter "http://[YOUR_HA_IP]:[YOUR_HA_PORT]/api/services/script/plex_play as your webhook URL.

As you can see above with

{{ Player.uuid == "SOMETHING" }}

I test in a condition wether the uuid in the Play is “SOMETHING” you can just access the provided JSON like that.

If you have more questions or need further explanation let me know :slight_smile:

~Cheers

2 Likes