/traffic-light-server-elixir

Configure traffic lights on Heroku, powered by Elixir and Phoenix

Primary LanguageElixir

Traffic Light Server

This is a small Elixir server with the purpose to configure and serve a light configuration to a real traffic light, like this one:

It is meant to be used with a corresponding client to read the light and do something awesome with it. An example is a client running on a Raspberry PI that fetches the light configuration of this app and displays it on a real traffic light.

The server features the following capabilities:

  • LiveView-powered web UI to view a virtual traffic light.
  • JSON API to connect a real traffic light client.
  • Webhook API to receive status updates from CI services like CodeShip.
  • Interactive “public” mode where you can control the traffic light with the web UI.

Light Modes

When in public mode, the light configuration can be changed by clicking on the corresponding lights on the UI.

In ci mode the web UI is read-only and only shows the current status.

Just change the heroku env variable like this heroku config:set LIGHT_MODE=public, heroku will automatically restart your app and the new light mode is applied.

JSON API

GET http://localhost:4000/lights
{
  "green": true,
  "mode": "public",
  "red": false,
  "yellow": false
}

Webhook API

Example for a webhook for GitHub checks

For GitHub you can setup webhooks within your repository:

<Repository> -> Settings -> Webhooks

Make sure to only choose the following webhook events:

The traffic light will turn yellow when a check run is started and will turn either red or green when a check suite was finished.

The reason why both events are needed is because repository-based webhooks only receive a call for check suites when they are finished, but not when they are started.

Additionally there is currently no way to retrieve the combined pull request status. This project should not get access to the GitHub data of a repo on its own. So right now we stay with webhooks even though they might jump between results when multiple actions are called.

Another option would be to leave out webhooks altogether and call the endpoints via curl in your GH actions directly, but this solution has not been evaluated yet.

More information can be found here:

POST http://localhost:4000/webhooks/github?token=MY-SECRET-CI-TOKEN
Content-Type: application/json

{
  "action": "created",
  "check_run": {
    "status": "queued",
    "conclusion": null,
  }
}

Example for a webhook for CodeShip

POST http://localhost:4000/webhooks/codeship?token=MY-SECRET-CI-TOKEN
Content-Type: application/json

{
  "build": {
    "build_url":"https://www.codeship.com/projects/10213/builds/973711",
    "commit_url":"https://github.com/codeship/docs/ commit/96943dc5269634c211b6fbb18896ecdcbd40a047",
    "project_id":10213,
    "build_id":973711,
    "status":"success",
    "project_full_name":"codeship/docs",
    "project_name":"codeship/docs",
    "commit_id":"96943dc5269634c211b6fbb18896ecdcbd40a047",
    "short_commit_id":"96943",
    "message":"Merge pull request #34 from codeship/feature/shallow-clone",
    "committer":"beanieboi",
    "branch":"master"
  }
}

Development

Start server with

iex -S mix phx.server

Deploy on Heroku

Install the Heroku Redis addon. This will also provide you with the REDIS_URL environment variable.

Make sure all other required environment variables have been set by you using heroku config.

heroku config:set CI_SECRET=YOURSECRET
heroku config:set LIGHT_MODE=public
heroku config:set DASHBOARD_AUTH_USERNAME=ADMIN
heroku config:set DASHBOARD_AUTH_PASSWORD=PASSWORD

Open a new iex console on Heroku.

heroku run iex -S mix

Setup some initial data for each mode:

ls = TrafficLight.LightSetting.build(mode: "ci")
TrafficLight.LightSetting.save(ls, "ci")
ls = TrafficLight.LightSetting.build(mode: "public")
TrafficLight.LightSetting.save(ls, "public")

A little bit of Traffic Light history

This traffic light project exists since 2010. I use this side project as a form of recreational programming and joyful overengineering.

The software/hardware project has seen many stages:

  • Connected to a Synology NAS with a self-soldered Velleman K8055 USB experimentation board.
  • Connected to a Raspberry PI, running a Ruby script locally, node.js on the server side.
  • Wiring mostly replaced by a custom etched circuit board - a Raspberry shield built only for the purpose of changing the traffic light (and debugging it at home without disassembling the whole traffic light).
  • Replacement of the Raspbian/Ruby client with Elixir and Nerves.
  • Replacement of the node.js server with Elixir and Phoenix.

The physical traffic light has been set up at two companies and four offices, motivating me and many others to keep your CI green and clean.

It also had its own dedicated blog, showing the appearances of the traffic light in different articles and videos as it was a welcome guest in German media.

🚥 ❤ 🚥