Light Conversation is an iOS app to translate morse code from flashing lights and broadcast morse code using your flash. This app was built as part of Inanimata, a project to translate lights around the city that have been hacked to tell stories with morse code.
How to hack your own lights:
The morse code broadcaster runs on an Arduino micro-controller. You will need one with an operating voltage of 5v as opposed to 3.3v to drive the solid state relays referenced below. The code for this can be found below (simply replace the text at the top with your own). In some cases you could use the same power source used for the lights as the Arduino, but I typically use a separate 9v battery or USB power supply to keep things simple.
Please note that you do any of this wiring at your own risk. Although I have used this with many kinds of lights they have all so far all been powered by one of the following options (each uses the same code but requires a slightly different circuit):
-
240v mains (regular Australian power point, other countries may use 120v). For this I use an AC solid state relay like this one. Simply connect the Arduino ground and output pin to the input and use the output to interrupt the power or neutral going to the lamp. It does not matter which way around the output is wired. An easy way to do this is by cutting just one of the cables in an extension cord running to the light. Be careful and make sure not to have anything plugged in when making connections as this is enough voltage to kill you :)
-
12v car or motorcycle type battery. For this I use a DC solid state relay like this one. Simply connect the Arduino ground and output pin to the input and use the output to interrupt the power or ground to the lamp. It does matter which way around the output is wired. I interrupted the ground wire coming from a car headlight. In this case the positive output is connected to the the wire going to the lamp whilst the negative output is connected to the wire going to the battery. If I had interrupted the power going to the lamp then the positive would have been wired to the battery and the negative to the light. I have also used 12v batteries for LED lights.
-
5v output from Arduino. In this case you may be working with standard LEDs, which can be connected as per this Arduino tutorial.
/*
This work by René Christen is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License:
http://creativecommons.org/licenses/by-nc-sa/4.0/
Permissions beyond the scope of this license may be available at http://renechristen.net
*/
String msg = "Replace this with your text.";
int outputPin = 12;
int unit = 300;//milliseconds
/*
UNIT LENGTHS
dot = 1
dash = 3
char gap space = 1
letter gap = 3
word gap = 7
*/
int offset = 33;//lowest ascii val
String db[63];//96 - offset (highest ascii val is 95)
//---------------------------------------------------------------
void setup() {
Serial.begin(9600);
initDB();
pinMode(outputPin, OUTPUT);
digitalWrite(outputPin, LOW);
}
//---------------------------------------------------------------
void loop() {
for (int i=0; i<msg.length(); i++)
{
Serial.println(msg[i]);//print letter to serial
if (msg[i] == ' ') {//if space in message
low();
delay((7-3) * unit);//word delay - letter delay already made after each letter
} //end if space in message
else
{
String morse = getMorseString(msg[i]);
Serial.println(getMorseString(msg[i]));//print letter to serial
for (int j=0; j<morse.length(); j++)
{
char c = morse[j];
if (c == '.')
{
high();
delay(1 * unit);
}
else if (c == '-')
{
high();
delay(3 * unit);
}
//in between letter gap:
low();
delay(1 * unit);
}//end for j / morse string
//letter gap:
low();
delay(3 * unit);
}//end else not space
}//end i / entire message
//word gap at message end:
low();
delay((7-3) * unit);//word delay - letter delay made after last letter
}
//---------------------------------------------------------------
void high() {
digitalWrite(outputPin, HIGH);
}
void low() {
digitalWrite(outputPin, LOW);
}
//---------------------------------------------------------------
String getMorseString(char _index) {
int index = (int) _index;
if (index <= 90 || index == 95) {
return db[index - offset];
} else { //change lower to upper case
return db[index - offset - 32];
}
}
//---------------------------------------------------------------
void initDB() {
//other chars start at 33
db[33 -offset]="-.-.--"; // !
db[34 -offset]=".-..-."; // "
db[36 -offset]="...-..-"; // $
db[38 -offset]=".-..."; // &
db[39 -offset]=".----."; // '
db[40 -offset]="-.--."; // (
db[41 -offset]="-.--.-"; // )
db[43 -offset]=".-.-."; // +
db[44 -offset]="--..--"; // ,
db[45 -offset]="-....-"; // -
db[46 -offset]=".-.-.-"; // .
db[47 -offset]="-..-."; // /
db[58 -offset]="---..."; // :
db[59 -offset]="-.-.-."; // ;
db[61 -offset]="-...-"; // =
db[63 -offset]="..--.."; // ?
db[64 -offset]=".--.-."; // @
db[95 -offset]="..--.-"; // _
//numeric chars start at ascii 48
db[(int) '0' -offset]="-----"; // 0
db[(int) '1' -offset]=".----"; // 1
db[(int) '2' -offset]="..---"; // 2
db[(int) '3' -offset]="...--"; // 3
db[(int) '4' -offset]="....-"; // 4
db[(int) '5' -offset]="....."; // 5
db[(int) '6' -offset]="-...."; // 6
db[(int) '7' -offset]="--..."; // 7
db[(int) '8' -offset]="---.."; // 8
db[(int) '9' -offset]="----."; // 9
//alphabetic chars start at ascii 65 for upper - end at 90, 97 for lower case - end at 122
db[(int) 'A' -offset]=".-"; // a
db[(int) 'B' -offset]="-..."; // b
db[(int) 'C' -offset]="-.-."; // c
db[(int) 'D' -offset]="-.."; // d
db[(int) 'E' -offset]="."; // e
db[(int) 'F' -offset]="..-."; // f
db[(int) 'G' -offset]="--."; // g
db[(int) 'H' -offset]="...."; // h
db[(int) 'I' -offset]=".."; // i
db[(int) 'J' -offset]="-..."; // j
db[(int) 'K' -offset]="-.-"; // k
db[(int) 'L' -offset]=".-.."; // l
db[(int) 'M' -offset]="--"; // m
db[(int) 'N' -offset]="-."; // n
db[(int) 'O' -offset]="---"; // o
db[(int) 'P' -offset]=".--."; // p
db[(int) 'Q' -offset]="--.-"; // q
db[(int) 'R' -offset]=".-."; // r
db[(int) 'S' -offset]="..."; // s
db[(int) 'T' -offset]="-"; // t
db[(int) 'U' -offset]="..-"; // u
db[(int) 'V' -offset]="...-"; // v
db[(int) 'W' -offset]=".--"; // w
db[(int) 'X' -offset]="-..-"; // x
db[(int) 'Y' -offset]="-.--"; // y
db[(int) 'Z' -offset]="--.."; // z
}