wifi-telegraph

picture of two devices, each one of them is rounded, with a big circle in the middle, and connected with a coiled cable to a plastic cup. they are sitting in a flat surface.
picture of one device mounted in a wall, it is rounded, with a big circle in the middle, and connected with a coiled cable to a plastic cup

fact sheet

date: ca. 2018

geography: new york city

culture: (?)

medium: wifi-enabled microcontroller, led, buzzer, hummus plastic container, plastic cup, rubber band, paper clip, washer, wires, 5V ac to dc adapter

dimensions: 30cm x 15cm x 10cm

classification: telecommunications

description

wifi-telegraph is an instrument for basic communication using a complex wireless technology.

when a button is pressed in any of them, a light is lit and a sound is emmitted in both.

letting go of the use of words.

falling back without feeling bad.

scavenging.

images

photo of two microcontrollers in small protoboards
testing in protoboard
photo of two soldered boards, one with a connected microcontroller
after soldering the circuit
photo of two microcontrollers connected each to a soldered board
testing the soldered circuit
photo of containers of hummus with some remanents of food in them
scavenging hummus containers
photo of one plastic hummus container with a rubber band around it and a paper clip in it. below the paper clip there's a washer.
prototyping the button
photo of coiled wires and other wires in a surface
soldering the cables
photo of the plastic container with two cables coming out of it: one with a washer attached and the other with a paper clip
cabling the button
photo of a plastic container connected with a coiled wire to a plastic cup
cabling the plastic cup handset
photo of the two devices in a table with other wires
testing the assembled devices
photo of a person with glasses and short hair holding the device in one hand and the plastic cup in the other, close to their ear
rare picture of one of the possible inventors

source code

download the source code and/or read it below.
/*
*******************
wifi-telegraph
sep 2018
******************
a wireless telegraph:
communication of a change of state between two arduinos mkr1000 via udp

based on the WiFiUdpSendReceiveString example from the Wifi101 library

---
hardware:
---
* arduino mkr1000
* pin 6: output, LED (on: HIGH)
* pin 7: input, button (pressed: HIGH)
* pin 8: pwm output, buzzer

---
software:
---
requires the following libraries:
* Adafruit_ASFcore
* Adafruit_SleepyDog.h
* SPI.h
* WiFi101.h
* WiFiUdp.h

---
configuration:
---
* add a file arduino_secrets.h. it should contain the following info, changing the values accordingly:

#define SECRET_SSID "nameofnetwork"
#define SECRET_PASS "password"
#define IP_0 192,168,1,2
#define IP_1 192,168,1,3

(IP_0 is the ip address assigned to the board 0, and IP_1 the address assigned to the board 1;
this can be checked with a serial monitor using this sketch or another WiFi101 example)
note that the four numbers of the ip address are separated by commas, not dots

* the only thing that has to be changed when programming one board or the other, is the 
#define BOARD 0
statement, either to 0 or 1. below in the code there are other directives that change the hardcoded destination address according to that parameter.

---
description:
---
the boards, once connected to the network, continuously send each other a one-character UDP message with their current state.

when any of them change their state (i.e. because their button was either pushed or released), they send the update in "real time" so that the other can adjust accordingly.

the led and the buzzer of one board will be on when either the local or the remote state is "on" (i.e. when either the local or the remote button is pushed).

if a board doesn't receive an update for a given amount of time, it will auto-reset to reconnect to the network. it uses a watchdog timer for this.
(if both of them are on at the same time, but lose connection, they will auto-reset more or less at the same time)

the connection process can be seen as the LED being lit (no buzzer) for at least 5 seconds (or as long as it needs to connect (?)).

 */


// number of board to program, either 0 or 1
#define BOARD 0

// watchdog library to reset arduino when connection is lost
#include <Adafruit_SleepyDog.h>
#include <SPI.h>
#include <WiFi101.h>
#include <WiFiUdp.h>

// characters that are sent to indicate a state
#define CHAR_ON 'a'
#define CHAR_OFF 'b'

// how many millis before sending an update
#define TIME_UPDATE 200

// how much time to wait before resetting connection
#define TIME_CHECK_CONNECTION 1000*60*5

// hardware
#define LED 6
#define BUTTON 7
#define BUZZER 5
#define DEBOUNCE_DELAY 20
#define BUZZER_DC_ON 42

int currentButton, lastButton, stateButton;
int stateLED, stateRemote;
unsigned long lastMillisButton;
unsigned long lastMillis;

int status = WL_IDLE_STATUS;
#include "arduino_secrets.h" 
///////please enter your sensitive data in the Secret tab/arduino_secrets.h
char ssid[] = SECRET_SSID;        // your network SSID (name)
char pass[] = SECRET_PASS;    // your network password (use for WPA, or use as key for WEP)
int keyIndex = 0;            // your network key Index number (needed only for WEP)

unsigned int localPort = 2333;      // local port to listen on

char packetBuffer[255]; //buffer to hold incoming packet

WiFiUDP Udp;

// the two involved addresses
IPAddress ip0(IP_0);
IPAddress ip1(IP_1);

void setup() {
  // enable watchdog to reset arduino if connection hasn't happened in 
  // TIME_CHECK_CONNECTION ms
  Watchdog.enable(TIME_CHECK_CONNECTION);
  // initialize pins
  pinMode(LED,OUTPUT);
  pinMode(BUTTON,INPUT);
  pinMode(BUZZER,OUTPUT);

  lastButton = LOW;

  // turn on LED before attempting connection
  digitalWrite(LED,HIGH);

  //Initialize serial
  Serial.begin(9600);

  // check for the presence of the shield:
  if (WiFi.status() == WL_NO_SHIELD) {
    Serial.println("WiFi shield not present");
    // don't continue:
    while (true);
  }

  // attempt to connect to wifi, report results via serial
  connectToWiFi();

  // start "counter" for continuous updates
  lastMillis = millis();

  // turn off LED
  digitalWrite(LED,LOW);

  // restart watchdog timer
  Watchdog.reset();
}

void loop() {
  // check for changes in the state of the button, debouncing it
  checkButton();
  // check to see if there are new udp messages
  checkUDP();
  // given the previous results, update the state of the hardware
  updateLEDandBuzzer();
}

void updateLEDandBuzzer(){
  // LED will be on when either the local or the remote button is on
  stateLED =  stateButton || stateRemote ;

  // update the LED
  digitalWrite(LED, stateLED);

  // mirror the LED with the buzzer
  if(stateLED == HIGH){
    analogWrite(BUZZER, BUZZER_DC_ON);
  }
  else{
    analogWrite(BUZZER, 0);
  }
}

void checkUDP(){
  // if there's data available, read a packet
  int packetSize = Udp.parsePacket();
  if (packetSize)
  {
    Serial.print("Received packet of size ");
    Serial.println(packetSize);
    Serial.print("From ");
    IPAddress remoteIp = Udp.remoteIP();
    Serial.print(remoteIp);
    Serial.print(", port ");
    Serial.println(Udp.remotePort());

    // read the packet into packetBufffer
    int len = Udp.read(packetBuffer, 255);
    if (len > 0) packetBuffer[len] = 0;
    Serial.println("Contents:");
    Serial.println(packetBuffer);

    // we only care about the first character
    // update the remote state accordingly
    if(packetBuffer[0] == CHAR_ON){
      stateRemote = HIGH;	
    }
    else if(packetBuffer[0] == CHAR_OFF){
      stateRemote = LOW;
    }

    // because a message was received, reset the watchdog
    // so that this can keep working
    Watchdog.reset();
  }

  // if it's time for a local update
  if( (millis() - lastMillis) > TIME_UPDATE){
    // send the update
    sendMessage();
    // start counting again
    lastMillis = millis();
  }
}

void sendMessage(){
      // send message to remote board
    // use directives to decide at compile time the remote address
#if BOARD == 0
    Udp.beginPacket(ip1,localPort); 
#endif
#if BOARD == 1
    Udp.beginPacket(ip0,localPort); 
#endif

    // add the current state as a message
    if(stateButton == HIGH){
      Udp.write(CHAR_ON);
    }
    else{
      Udp.write(CHAR_OFF);
    }
    // send the packet
    Udp.endPacket();
}

void checkButton(){
  // read button state
  currentButton = digitalRead(BUTTON);
  // if there was a change of state in the button, start counting
  if(currentButton != lastButton){
    lastMillisButton = millis();
  }

  // if there has been enough time without a change of state...
  if( (millis() - lastMillisButton) > DEBOUNCE_DELAY ){
    // ...and the new state is different than the previous one
    if(currentButton != stateButton){
      // update the local state
      stateButton = currentButton; 
      // and send an update
      sendMessage();
    }
  }
  // store the immediately previous reading
  lastButton = currentButton;
}


void connectToWiFi(){
  // attempt to connect to WiFi network:
  do{
    Serial.print("Attempting to connect to SSID: ");
    Serial.println(ssid);
    // Connect to WPA/WPA2 network. Change this line if using open or WEP network:
    status = WiFi.begin(ssid, pass);

    // wait 5 seconds for connection:
    delay(5000);
  }
  while ( status != WL_CONNECTED);

  Serial.println("Connected to wifi");

  printWiFiStatus();

  Serial.println("\nStarting udp connection...");
  // if you get a connection, report back via serial:
  Udp.begin(localPort);
}

void printWiFiStatus() {
  // print the SSID of the network you're attached to:
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());

  // print your WiFi shield's IP address:
  IPAddress ip = WiFi.localIP();
  Serial.print("IP Address: ");
  Serial.println(ip);

  // print the received signal strength:
  long rssi = WiFi.RSSI();
  Serial.print("signal strength (RSSI):");
  Serial.print(rssi);
  Serial.println(" dBm");
}
			

extra

imagemagick command for the image filter:
			 convert -verbose image.jpg \
			 	-resize 640x480 \
				-blur 3x0.5 -edge 4 \
				-negate -normalize \
				-colorspace Gray -blur 3x.5 \
				-contrast-stretch 0x50% \
				-colors 2 filtered_image.jpg 
			

preservation

seed with dat / beaker browser: dat://ab7b18b7a4ea06fc42b85c8f2147cb06d2236590be3dc17b087aa939940e7354

or simply download, print and re-share.