Adrian Pijoan
Published

Spiritist Telegraph

A room controller for ghosts

BeginnerFull instructions provided108
Spiritist Telegraph

Things used in this project

Hardware components

Argon
Particle Argon
×1
Grove - Barometer Sensor (BMP280)
Seeed Studio Grove - Barometer Sensor (BMP280)
×1
Rotary Encoder with Push-Button
Rotary Encoder with Push-Button
×1
Adafruit Monochrome 1.3" 128x64 OLED graphic display
×1
Flora RGB Neopixel LEDs- Pack of 4
Adafruit Flora RGB Neopixel LEDs- Pack of 4
×1
Philips hue
Philips hue
×1

Hand tools and fabrication machines

Laser cutter (generic)
Laser cutter (generic)
3D Printer (generic)
3D Printer (generic)

Story

Read more

Schematics

spiritist_telegraph_room_controller_bb_dpTZtF6ciR.jpg

spiritist_telegraph_room_controller_schem_tpC56HfHHF.jpg

Code

Spiritist_Telegraph.ino

C/C++
/*
 * Project Spiritist_Telegraph
 * Description: Room controller that allows for spirit communication and allows for spirits to control lights 
 * and outlets in the room.
 * Author: Adrian Pijoan
 * Date: 06-MAR-2023
 */

#include "wire.h"
#include "IoTClassroom_CNM.h"
#include "IoTTimer.h"
#include "encoder.h"
#include "neopixel.h"
#include "Adafruit_BMP280.h"
#include "Adafruit_SSD1306.h"
#include "ouija.h"
#include "bitmaps.h"

const int PIXELCOUNT = 2;
const int PIXELPIN = D2;
const int ENCLEDR = D4;
const int ENCLEDG = D5;
const int ENCSWITCH = D6;
const int SWITCHPIN = D7; 
const int ENCPINA = A3;
const int ENCPINB = A4;
const int EMFPIN = A1;
const int BMPADDRESS = 0x76;
const int OLEDADDRESS = 0x3C;
const int OLED_RESET = D3;

int currentTemp;
int previousTemp;

IoTTimer ouijaTimer;
IoTTimer tempTimer;
IoTTimer candleFlickerTimer;
IoTTimer emfTimer;
IoTTimer emfFlashTimer;
Encoder spiritEncoder(ENCPINB, ENCPINA);
Adafruit_NeoPixel candlePixel(PIXELCOUNT, PIXELPIN, WS2812B);
Adafruit_BMP280 spiritBmp;
Adafruit_SSD1306 spiritDisplay(OLED_RESET);

void candleFlicker();
void ouija();
void ouijaIot(int _ouijaChar);
void tempDrop();
void emf();
void emfFlash();

SYSTEM_MODE(MANUAL);

void setup() {
  Serial.begin(9600);
  WiFi.on();
  WiFi.setCredentials("IoTNetwork");
  WiFi.connect();

  spiritDisplay.begin(SSD1306_SWITCHCAPVCC, OLEDADDRESS);
  spiritDisplay.setRotation(0);
  spiritDisplay.clearDisplay();
  spiritDisplay.drawBitmap(32,0,ghost_bmp,64,64,WHITE);
  spiritDisplay.display();

  spiritBmp.begin(BMPADDRESS);

  candlePixel.begin();
  candlePixel.show();

  pinMode(ENCSWITCH, INPUT_PULLUP);
  pinMode(ENCLEDG, OUTPUT);
  pinMode(ENCLEDR, OUTPUT);
  pinMode(SWITCHPIN, INPUT_PULLUP);
  pinMode(EMFPIN, INPUT);

}

void loop() {

  digitalWrite(ENCLEDG, 255);

  if(digitalRead(SWITCHPIN)){
    digitalWrite(ENCLEDR, 126);

    tempDrop();
    ouija();
    emf();
  }

  else{
    digitalWrite(ENCLEDR, 0);

    currentTemp = (1.8 * spiritBmp.readTemperature())+32;
    spiritDisplay.setTextSize(1);
    spiritDisplay.setTextColor(WHITE);
    spiritDisplay.setCursor(5,54);
    spiritDisplay.printf("T: (%i%c)", currentTemp, 0xF8);
    spiritDisplay.display();
    spiritDisplay.fillRect(0,54,40,10,BLACK);
    
    ouija();
    candleFlicker();
  }

}


//this function flickers a neopixel inside of a 3D printed candle
void candleFlicker(){

  static int candleFlickerState = 0;

  candlePixel.setPixelColor(0, 0xFFA500);
  candlePixel.setPixelColor(1, 0xFFA500);

  if(candleFlickerState == 0){
    candleFlickerTimer.startTimer(100);
    candlePixel.setBrightness(32);
    candlePixel.show();
    candleFlickerState = 1;
  }

  if(candleFlickerState == 1 && candleFlickerTimer.isTimerReady()){
    candleFlickerTimer.startTimer(50);
    candlePixel.setBrightness(150);
    candlePixel.show();
    candleFlickerState = 2;
  }

  if(candleFlickerState == 2 && candleFlickerTimer.isTimerReady()){
    candleFlickerTimer.startTimer(150);
    candlePixel.setBrightness(75);
    candlePixel.show();
    candleFlickerState = 3;
  }

  if(candleFlickerState == 3 && candleFlickerTimer.isTimerReady()){
    candleFlickerTimer.startTimer(100);
    candlePixel.setBrightness(160);
    candlePixel.show();
    candleFlickerState = 4;
  }

  if(candleFlickerState == 4 && candleFlickerTimer.isTimerReady()){
    candleFlickerState = 0;
  }
}

//this function converts the encoder position into a character from the Ouija Array
void ouija(){

  int encPosition;
  int ouijaChar;
  static int previousOuijaChar;
  static bool ouijaToggle;

  encPosition = spiritEncoder.read();

  if(encPosition < 0){ 
    spiritEncoder.write(96);
    encPosition = 96;
  }

  if(encPosition > 96){
    spiritEncoder.write(0);
    encPosition = 0;
  }

  ouijaChar = map(encPosition,0,96,0,39); //map encoder position to ouijaBoard array

  if(ouijaChar != previousOuijaChar){ //check to see if planchette has moved to a new position
    ouijaTimer.startTimer(500); //wait 0.5 seconds
    ouijaToggle = true;
  }

  previousOuijaChar = ouijaChar;

  if(ouijaToggle && ouijaTimer.isTimerReady()){  //if it sees a new position and it has held that position for more than 0.5 seconds, do something
    Serial.printf("%s\n", ouijaBoard[ouijaChar]);
    spiritDisplay.clearDisplay();
    spiritDisplay.setTextSize(2);
    spiritDisplay.setTextColor(WHITE);
    spiritDisplay.setCursor(32,20);
    spiritDisplay.printf("%s", ouijaBoard[ouijaChar]);
    spiritDisplay.display();

    ouijaIot(ouijaChar);//do something with the ouija character...in this case interact with the IoT classroom, but change this out next time you use this code

    ouijaToggle = false;
  }
}

//this function uses the Ouija Board reading to alter the states of hue lights and wemo outlets in the IoT Classroom
void ouijaIot(int _ouijaChar){

  int i;

  if(_ouijaChar == 0){ //HELLO
    for(i=1; i<7; i++){
      setHue(i, true, HueOrange, 250, 250);
    }
  }

  if(_ouijaChar == 11){ //YES for Outlets ON
    for(i=0; i<5; i++){
      switchON(i);
    }
  }

  if(_ouijaChar == 13){ //B for BLUE
    for(i=1; i<7; i++){
      setHue(i, true, HueBlue, 250, 250);
    }
  }

  if(_ouijaChar == 18){ //G for GREEN
    for(i=1; i<7; i++){
      setHue(i, true, HueGreen, 250, 250);
    }
  }

  if(_ouijaChar == 29){ //R for RED
    for(i=1; i<7; i++){
      setHue(i, true, HueRed, 250, 250);
    }
  }

  if(_ouijaChar == 31){ //NO for Outlets OFF
    for(i=0; i<5; i++){
      switchOFF(i);
    }
  }

  if(_ouijaChar == 34){ //V for VIOLET
    for(i=1; i<7; i++){
      setHue(i, true, HueViolet, 250, 250);
    }
  }

  if (_ouijaChar == 39){ //GOOD BYE
    for(i=1; i<7; i++){
      setHue(i, false, 0, 0, 0);
    }
  }

}

//This function looks for a temperature drop
void tempDrop(){

  int i;
  static bool tempToggle;
  //if the temp drops by at least 5 degrees F within a matter of 10 seconds, do something
  currentTemp = (1.8 * spiritBmp.readTemperature())+32;//Read the BMP
  spiritDisplay.setTextSize(1);
  spiritDisplay.setTextColor(WHITE);
  spiritDisplay.setCursor(5,54);
  spiritDisplay.printf("T: (%i%c)", currentTemp, 0xF8); //print temp regardless of whether or not the temp drops
  spiritDisplay.display();
  spiritDisplay.fillRect(0,54,40,10,BLACK);

  if(currentTemp != previousTemp && tempToggle == false){
    tempTimer.startTimer(10000);
    previousTemp = currentTemp;
    tempToggle = true;
  }

  if(currentTemp <= (previousTemp - 5) && tempToggle && tempTimer.isTimerReady()){
    //once cold spot is detected, turn lights blue and gradually dim them
    Serial.printf("TEMP DROP DETECTED\n");
    spiritDisplay.clearDisplay();
    spiritDisplay.drawBitmap(32,0,ghost_bmp,64,64,WHITE);
    spiritDisplay.display();
    for(i=1; i<7;i++){
      setHue(i, true, HueBlue, 50, 250);
    }
    tempToggle = false;
  }

  if(tempToggle && tempTimer.isTimerReady()){
    tempToggle = false;
  }

}

//This function reads the EMF meter
void emf(){

  int i;
  static bool emfToggle;
  //if EMF reading exceeds a certain threshold, turn on neopixel candles and flash the lights on and off
  int emfLevel = analogRead(EMFPIN);
  Serial.printf("%i\n", emfLevel);

  if(emfLevel > 2000 && emfToggle == false){
    candlePixel.clear();
    candlePixel.setBrightness(150);
    candlePixel.show();
    emfTimer.startTimer(4000);
    spiritDisplay.clearDisplay();
    spiritDisplay.drawBitmap(32,0,ghost_bmp,64,64,WHITE);
    spiritDisplay.display();
    emfToggle = true;
  }

  if(emfToggle){
    emfFlash();
  }

  if(emfToggle && emfTimer.isTimerReady()){
    candlePixel.clear();
    candlePixel.setBrightness(0);
    candlePixel.show();
    for(i=0;i<6;i++){
      switchOFF(i);
      setHue(i+1, false, 0, 0, 0);
      emfToggle = false;
    }
  }

}

//This function changes states of Hue Lights and Wemo Outlets in the IoT Classroom based on readings from the EMF meter
void emfFlash(){ //flash Hue lights and Wemos on and off once every half second

  int i;
  static bool emfFlashToggle = true;

  if(emfFlashToggle){
    emfFlashTimer.startTimer(500);
    emfFlashToggle = false;
  }

  if(emfFlashTimer.isTimerReady()){

    for(i=0; i<6; i++){
      switchOFF(i);
      setHue(i+1, false, 0, 0, 0);
    }
    emfFlashToggle = true;
  }

  else{
    for(i=0; i<6; i++){
      switchON(i);
      setHue(i+1, true, HueOrange, 250, 250);
    }
  }

}

Github

Credits

Adrian Pijoan
3 projects • 8 followers

Comments