PhaultLines

Using the Plex webhook API to control Hue lights

A Plex Media Server update released earlier this year introduced a new webhook API that exposes media playback events, making it possible to track when Plex starts and stops playing content. I used the API to make my living room lights dim automatically when I’m watching a movie or television show.

To use the API, you create a simple web application that receives HTTP POST requests at a given URL endpoint. If you add the URL to Plex’s webhook configuration panel, it sends a POST request every time an event occurs. At the present time, the events that it sends are: play, pause, resume, stop, scrobble, and rate.

I built my webhook receiver in JavaScript with Node.js. I didn’t need to use a framework or routing library because the application only has one URL endpoint. In the request handler, I check the event type and perform the corresponding Hue API request:

const http = require("http");
const {IncomingForm} = require("formidable");

const hueGroup = 1;
const hueAddress = "...";
const hueToken = "...";
const plexPlayer = "...";

const server = http.createServer((req, res) => {
  if (req.url !== "/plex" || req.method !== "POST") {
    res.writeHead(404, {"Content-Type": "text/plain"});
    return res.end("404");
  }

  res.end();

  let form = new IncomingForm();
  form.parse(req, (err, {payload}) => {
    let {event, Player} = JSON.parse(payload);
    if (Player.title !== plexPlayer) return;

    let bri = ["media.stop", "media.pause"].includes(event) ? 200 :
              ["media.play", "media.resume"].includes(event) ? 5 : null;

    if (!bri) return;

    let request = http.request({
      method: "put", hostname: hueAddress, port: 80,
      path: `/api/${hueToken}/groups/${hueGroup}/action`
    });

    request.on("error", err => console.log(err));
    request.write(JSON.stringify({bri}));
    request.end();
  });
});

server.listen(8000, () => console.log("Running Webhook Server"));

If you use the code above, be sure to fill in the four hard-coded constants:

  • hueAddress is the local network IP address of the Hue base station
  • hueToken is the authentication token that you include in the URL for Hue requests
  • hueGroup is the light group that you want to change in response to Plex events
  • plexPlayer is the name of the individual Plex client device that you want to monitor

Filtering for the specific Plex client is important, because I only want playback on my living room television to affect the living room lights. The only dependency in this example is formidable, which I use for parsing the request body.

I’ve had this integration running for about a week. There appear to be some edge cases where Plex doesn’t emit an event when playback stops. Aside from that issue, it’s working very well.