Plex Webhooks and Home Assistant

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

Okay, this is the first one that came up:

17-02-19 12:43:02 ERROR (MainThread) [homeassistant.helpers.condition] Error during template condition: UndefinedError: ‘Player’ is undefined

Update: Okay, I’m getting something that looks like this:

17-02-19 13:21:02 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 1993: invalid start byte
17-02-19 13:21:15 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 312, in post
    data = json.loads(body) if body else None
  File "/usr/local/lib/python3.5/json/__init__.py", line 319, in loads
    return _default_decoder.decode(s)
  File "/usr/local/lib/python3.5/json/decoder.py", line 339, in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
  File "/usr/local/lib/python3.5/json/decoder.py", line 357, in raw_decode
    raise JSONDecodeError("Expecting value", s, err.value) from None
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)
17-02-19 13:21:15 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 312, in post
    data = json.loads(body) if body else None
  File "/usr/local/lib/python3.5/json/__init__.py", line 319, in loads
    return _default_decoder.decode(s)
  File "/usr/local/lib/python3.5/json/decoder.py", line 339, in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
  File "/usr/local/lib/python3.5/json/decoder.py", line 357, in raw_decode
    raise JSONDecodeError("Expecting value", s, err.value) from None
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)
hass@home-server:~/.homeassistant$

It seems to me as though Home Assistant does not accept UTF-8.

Update 2:

And I almost forgot. This is what I have so far:

  plex_webhook:
    alias: "Plex Webhooks"
    sequence:
      - condition: template
        value_template: '{{ Player.uuid == "..." }}'
      - service: script.turn_on
        data:
          entity_id: script.plex_webhook_play
      - service: script.turn_on
        data:
          entity_id: script.plex_webhook_stop
  plex_webhook_play:
    alias: "Plex Webhook - Play"
    sequence:
      - condition: or
        conditions:
        - condition: template
          value_template: '{{ event == "media.play" }}'
        - condition: template
          value_template: '{{ event == "media.resume" }}'
      - service: light.turn_off
        data:
          entity_id: light.living_room_floor_lamps
  plex_webhook_stop:
    alias: "Plex Webhook - Stop"
    sequence:
      - condition: or
        conditions:
        - condition: template
          value_template: '{{ event == "media.pause" }}'
        - condition: template
          value_template: '{{ event == "media.stop" }}'
      - service: light.turn_on
        data:
          entity_id: light.living_room_floor_lamps
          brightness: 128

There’s an issue surrounding the decoding of JSON:

So I’ll have to go with node.js for now.

FYI this is still an issue. The problem is HA does not handle multipart paylods which is what plex uses unfortunately.

1 Like

So still no way to get direct connection between webhooks and HA ? it’s bad as we can now get an efficient control if you are using PMP players so feedback like that to go with would be really nice !

For a long time I have been wanting the ability to script different hue light scenes to come on based on what TV show was playing on my plex server (like all red lights when I am watching the strain). Is this something this would be able to do? Most of this tech jargon is written in klingon to me.

@Blinkwise you can already control your light based on play/paused status of your plex player (only drawback is that it takes around 3s between change of state in player and update to HA, that’s why people are looking for a more efficient way to interact with Plex Media Server :wink:

@vincen yeah I got the play/paused thing down for dimming the lights, but I am looking to specifically chance to a hue scene based on whats plays (ie red and yellow lights when I start watching the flash).

Yes this would be doable with this. You could parse the json which has a lot of metadata. I already do stuff like that with emby. But the webhook there does work with HA.

~Cheers

@Blinkwise hum I think you can already do it as HA got hese at least name of media playing so I guess it’s just a question to find the correct filter in your script to change color of light depending of media played or media genre ? red for horror, pink for love movie, green for kids stuffs… :wink:

In case you don’t want to add an additional node.js server, I wrote a small Python daemon which does the necessary translation between Plex and Home Assistant: https://github.com/lorenzschmid/pyTransferMultipart

2 Likes

Awesome work! Thanks for that!

~Cheers

Hi - can you explain how things would work differently with the new Webhook Trigger in HA 0.80?

1 Like

Any update re triggering an automation from Plex using the new Webhook Trigger?

Did anyone get the plex webhooks to work? With the update of webhooks I was under the impression it would be possible to use this just with standard automations and scripts. I was looking forward to this but can’t find any documentation on this.

What URL should be used on the plex side? e.g. https://myurl.duckdns.org:8123/api/webhook/plex_user
Do you need anything in Home Assistant configuration? (don’t think so?)
How can you read the diferent payloads? (to use as conditions) (E.g. only if media.player = tv and action is media pause)

Thank you all for the help.

Don’t know for sure as I don’t have plex but my guess would be that it still is not compatible as plex sends multipart forms.

This seems to be a suitable workaround, it worked for me.

1 Like

Using webhooks from plex and the Nabucasa Cloud I got it all working.

Automation to read the webhook to MQTT

- alias: Plex - Webhook - to MQTT
  trigger:
    platform: webhook
    webhook_id: !secret webhook_plex
  action:
   - service: mqtt.publish
     data_template:
       topic: 'plex/update'
       payload_template: >
         {{ (trigger.data | string)[154:][:-55] | replace ("\\\\", "\\") | replace ("\\\'", "'") | replace ("\\x","?") }}

After that I have a input_boolean that sees if something is playing. (add correct names, uuid, …)

- alias: Plex - Webhook - Toggle Living Room Boolean
  trigger:
    platform: mqtt
    topic: 'plex/update'
  condition:
    condition: and
    conditions:
    - condition: template
      value_template: "{{trigger.payload_json.Account['title'] == 'user name' }}"
    - condition: template
      value_template: "{{trigger.payload_json.Player.title == 'player name'}}"
    - condition: template
      value_template: "{{trigger.payload_json.Player.uuid == 'player id'}}"
    - condition: template
      value_template: "{{trigger.payload_json.event != 'media.scrobble'}}"
    - condition: template
      value_template: "{{trigger.payload_json.event != 'media.rate'}}"
  action:
    service_template: >
        {% if ((trigger.payload_json.event == 'media.play') or (trigger.payload_json.event == 'media.resume')) %}
          input_boolean.turn_on
        {% elif ((trigger.payload_json.event == 'media.pause') or (trigger.payload_json.event == 'media.stop')) %}
          input_boolean.turn_off
        {% endif %}
    entity_id: input_boolean.plex_livingroom

Adn then the state of the inpu_boolean will start the scripts.

- alias: Plex - Licht - Beneden
  trigger:
  - platform: state
    entity_id: input_boolean.plex_livingroom
  condition:
  action:
  - service: script.turn_on
    data_template:
      entity_id: >
        {%- if states('input_boolean.plex_livingroom') in ['on'] -%}
          script.plex_on
        {%- elif states('input_boolean.plex_livingroom') in ['off'] -%}
          script.plex_off
        {% endif %}

I know it is not very condensed but I like to seperate my automations in steps for debugging.

The only problem I seem to have is that most of the times it won’t fire on first play. This means I have to pause and the play agin to fire the scripts. No idea why.
Anyone any thoughts please?

After some research I understand that this is because plex sends a picture on the first play to the MQTT. Does anyone found a solution for this? Or how to read the play MQTT ? (The lights don’t turn down on play, only on resume)