Keep Talking and Nobody Explodes (Ktane) is a great game about defusing bombs, communication and accuracy in a stressful environment. I recently received a set of hue lamps from my friends, with the subtle hint that some kind of integration with Ktane was expected next time we play it. Challenge accepted?

It turns out that the hue lights have an easy to use interface; they (or more precisely, the bridge) accept http get and post requests which you can use to receive status info or update settings, respectively. Applying “rule 43”, I decided to google for ktane hue, and found this reddit post, describing the efforts of another Ktane player to control hue lights based on the game. The effect he created looks quite nice, but unfortunately, the source code is not available, so I attempted to spin my own version. My current prototype is available on github.

The log file in <your_ktane_folder>/logs/ktane.log contains quite a lot of debug data, which can be used to derive the current game state. Here’s a few useful snippets:

1
2
3
4
5
6
7
8
9
10
11
12
 INFO 2015-12-20 18:14:59,965 [State] Enter GameplayState
(...)
DEBUG 2015-12-20 18:15:06,970 [Assets.Scripts.Props.AlarmClock] TurnOn
DEBUG 2015-12-20 18:15:08,467 [Assets.Scripts.Props.AlarmClock] TurnOff
(...)
DEBUG 2015-12-20 18:16:32,384 [Bomb] Strike! 1 / 3 strikes
(...)
DEBUG 2015-12-20 18:18:36,541 [Assets.Scripts.Pacing.PaceMaker] Executing
random action of type OneMinuteLeft
(...)
INFO 2015-12-20 18:19:25,346 [Bomb] Boom
INFO 2015-12-20 18:19:25,351 [State] OnRoundEnd()

The first line indicates the start of the countdown timer, the others are self explanatory I think.

I selected the Python phue library to control my lights. It seemed like a nice enough API, and is written in Python 3, which just happened to be the Python version I installed on my windows Ktane machine:

1
2
3
4
5
6
7
8
9
10
BRIDGE = '192.168.0.42' # The ip of the bridge
(...)
self.b = Bridge(BRIDGE)
self.b.connect()

(...)
for lamp in self.b.lights:
# Switch on all the lights, and set their brightness to max
lamp.on = True
lamp.brightness = 251

My log-file parser is not very majestic: it reads the entire log file approximately every 0.1 seconds, and parses the thing based on some string /regex matching. If the timestamp of a log message is sufficiently new (less than 0.3 seconds old), then it is interpreted by the class that keeps track of the game state. This works, assuming the game and the python script use the same clock, which they typically do if they run on the same machine. I had to correct for the local timezone I am in (the game writes UTC stamps), but besides that, it worked as expected. The relatively high sample rate (10 ticks / second) makes the delay between quick events, like the bomb exploding and the associated light effect, unnoticeable.

I later found there are github projects dedicated to parsing Ktane logs, so I could have used one of those. However, for this project, the quick and dirty method is sufficient.

Using the log, I keep track of these events:

  • Being in the menu / bomb selection screen results in neutral lighting
  • When the bomb defusal part of the game starts, the lights alternate between two shades of orange
  • On a strike, the pulse rate increases
  • When the bomb explodes, the lights go bright red, yellow, and then red with a very low brightness.

Here’s a little demo video showing these phases:

There is room for improvement: I want to use the OneMinuteLeft entry to change the pulse colors to shades of red, and improve robustness of the state tracker, such that it can pick up on a game that is already running. Also, backing up the settings of the lights and restoring them when the script exits might be useful. A small (persistent) settings file that keeps track of the lamps to control and the bridge’s ip could reduce the hardcoding, and make it easier to use. Overall, code quality could be better (I’ve “only” invested about 2.5 hours of development time so far). I’ll update the git repo as I make changes.