Home






#include "WiFi.h"
#include "ArduinoJson.h"

#include "WebSocketsClient.h"
#include "SocketIOclient.h"

SocketIOclient SocketIO;

#include "Wire.h"
#include "Adafruit_GFX.h"
#include "Adafruit_SSD1306.h"


#include "Adafruit_Sensor.h"
#include "Adafruit_BME280.h"

#include "Adafruit_VL53L0X.h"

#include "DHT.h"

#include "EZButton.h"

#include "string"
#include "algorithm"

#include "bitmap.h"
#include "pitches.h"

int melody[] = {
  REST, NOTE_C4, NOTE_G3, NOTE_G3, NOTE_A3, NOTE_G3, REST, NOTE_B3, NOTE_C4, REST
};

float noteDurations[] = {
  16, 4, 8, 8, 4, 4, 4, 4, 4, 0.2
};

void toUpperCase(std::string& str) {
  std::transform(str.begin(), str.end(), str.begin(), ::toupper);
}

std::string alphabet = "abcdefghijklmnopqrstuvwxyz";
std::string alphabetWithUpper;

#define BTN_1 0
#define BTN_2 1
#define BTN_3 2
#define BTN_4 3

void ReadButtons(bool* states, int num) {
  //Read all button states however you want
  states[BTN_1] = !digitalRead(0);
  states[BTN_2] = !digitalRead(2);
  states[BTN_3] = !digitalRead(15);
  states[BTN_4] = digitalRead(5);
}

EZButton _ezb(4, ReadButtons, 500, 100, 15);

#define DHTPIN 14
#define DHTTYPE DHT11
DHT dht(DHTPIN, DHTTYPE);

#define SEALEVELPRESSURE_HPA (1005)

#define SCREEN_WIDTH 128  // OLED display width, in pixels
#define SCREEN_HEIGHT 64  // OLED display height, in pixels

#define OLED_RESET -1        // Reset pin # (or -1 if sharing Arduino reset pin)
#define SCREEN_ADDRESS 0x3C  ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

Adafruit_VL53L0X lox = Adafruit_VL53L0X();

Adafruit_BME280 bme;

//SOCKETIO
void socketIOEvent(socketIOmessageType_t type, uint8_t* payload, size_t length) {
  switch (type) {
    case sIOtype_DISCONNECT:
      Serial.printf("[IOc] Disconnected!\n");
      break;
    case sIOtype_CONNECT:
      Serial.printf("[IOc] Connected to url: %s\n", payload);

      // join default namespace (no auto join in Socket.IO V3)
      SocketIO.send(sIOtype_CONNECT, "/");
      break;
    case sIOtype_EVENT:
      {

        DynamicJsonDocument doc(1024);
        DeserializationError error = deserializeJson(doc, payload, length);
        if (error) {
          Serial.print(F("deserializeJson() failed: "));
          Serial.println(error.c_str());
          return;
        }

        String eventName = doc[0];
        if (eventName == "requestData-from-esp") {
          DynamicJsonDocument doc2(1024);
          JsonArray array = doc2.to<JsonArray>();
          array.add("getData");
          JsonObject param1 = array.createNestedObject();
          param1["BME280_temp"] = bme.readTemperature();
          param1["BME280_humid"] = bme.readHumidity();
          param1["BME280_p"] = bme.readPressure() / 100.0F;
          param1["BME280_a"] = bme.readAltitude(SEALEVELPRESSURE_HPA);

          param1["DHT11_temp"] = dht.readTemperature();
          param1["DHT11_humid"] = dht.readHumidity();
          // param1["id"] = doc[1];

          String output;
          serializeJson(doc2, output);
          SocketIO.sendEVENT(output);
        }
      }
      break;
    case sIOtype_ACK:
      Serial.printf("[IOc] get ack: %u\n", length);
      break;
    case sIOtype_ERROR:
      Serial.printf("[IOc] get error: %u\n", length);
      break;
    case sIOtype_BINARY_EVENT:
      Serial.printf("[IOc] get binary: %u\n", length);
      break;
    case sIOtype_BINARY_ACK:
      Serial.printf("[IOc] get binary ack: %u\n", length);
      break;
  }
}

void setup() {
  Serial.begin(115200);


  // wait until serial port opens for native USB devices
  while (!Serial) {
    delay(1);
  }

  if (!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
    Serial.println(F("SSD1306 allocation failed"));
    for (;;)
      ;  // Don't proceed, loop forever
  }

  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(0, 0);
  display.print("Please wait!");
  display.display();



  delay(500);

  if (!lox.begin()) {
    Serial.println(F("Failed to boot VL53L0X"));
    while (1)
      ;
  }

  delay(500);

  if (!bme.begin(0x76)) {
    Serial.println("Could not find a valid BME280 sensor, check wiring!");
    while (1)
      ;
  }
  delay(500);

  dht.begin();



  pinMode(5, INPUT);
  pinMode(0, INPUT_PULLUP);
  pinMode(2, INPUT_PULLUP);
  pinMode(15, INPUT_PULLUP);
  _ezb.Subscribe(BTN_1, left_click, PRESSED);
  _ezb.Subscribe(BTN_2, right_click, PRESSED);
  _ezb.Subscribe(BTN_1, left_click, HOLD);
  _ezb.Subscribe(BTN_2, right_click, HOLD);
  _ezb.Subscribe(BTN_3, enter, PRESSED);
  _ezb.Subscribe(BTN_4, working_mode, PRESSED);

  WiFi.mode(WIFI_STA);

  toUpperCase(alphabet);
  alphabetWithUpper = "abcdefghijklmnopqrstuvwxyz" + alphabet + "1234567890,.!@#$%^&*()-=_+{}[];:<>/?\|";

  SocketIO.disconnect();
  SocketIO.begin("ahrixthinh.net", 81, "/socket.io/?EIO=4");
  SocketIO.onEvent(socketIOEvent);
}



//button
int working_state = 0;
int sensorMode = 0;
bool display_off = false;
unsigned long mode1 = 0;
//sound
unsigned long notetime = 0;
int thisNote = 0;
bool alarm_on = false;
bool alarm_toggle = false;
void loop() {
  _ezb.Loop();
  SocketIO.loop();

  if (working_state == 0) {
    scanWifi();
    scanWifi_draw();
    if (display_off) {
      display_off = false;
    }
  } else if (working_state == 1) {
    if (display_off) {
      display_off = false;
    }

    if (millis() - mode1 > 100) {
      VL53L0X_RangingMeasurementData_t measure;
      lox.rangingTest(&measure, false);

      display.clearDisplay();

      if (WiFi.status() != WL_CONNECTED) {
        display.drawBitmap(112, 2, bitmap_wifi, 14, 11, WHITE);
      } else {
        display.drawBitmap(112, 2, bitmap_wifi_connected, 14, 9, WHITE);
      }
      display.setTextColor(WHITE);

      if (sensorMode == 0) {
        display.drawBitmap(0, 24, bitmap_bme280, 128, 40, WHITE);


        display.setCursor(30, 4);
        display.print("BME280");

        display.setCursor(17, 27);
        display.printf("%.2f", bme.readTemperature());
        display.print(char(247));
        display.printf("C");

        display.setCursor(82, 27);
        display.printf("%.2f%%", bme.readHumidity());

        display.setCursor(17, 50);
        display.printf("%.0fhPa", bme.readPressure() / 100.0F);

        display.setCursor(82, 50);
        display.printf("%.1fM", bme.readAltitude(SEALEVELPRESSURE_HPA));
      } else if (sensorMode == 1) {
        display.drawBitmap(0, 24, bitmap_dht11, 128, 14, WHITE);

        display.setCursor(30, 4);
        display.print("DHT11");

        display.setCursor(17, 27);
        display.printf("%.2f", dht.readTemperature());
        display.print(char(247));
        display.printf("C");

        display.setCursor(82, 27);
        display.printf("%.2f%%", dht.readHumidity());
      } else {
        display.setCursor(20, 4);
        display.print("DS18B20 TO-92");

        display.setCursor(50, 30);
        display.print("RIP");
      }

      if (bme.readTemperature() > 45){
        alarm_on = true;
      }else{
        alarm_on = false;
        thisNote = 0;
      }
      // display.printf("Distance: %d mm\n\n", measure.RangeMilliMeter - 30);
      // display.printf("Temperature: %.2f", bme.readTemperature());
      // display.print(char(247));
      // display.printf("C\n\n");
      // display.printf("Temperature: %.2f", dht.readTemperature());
      // display.print(char(247));
      // display.printf("C\n\n");

      display.display();
      mode1 = millis();
    }

  } else if (working_state == 2) {
    if (!display_off) {
      display.clearDisplay();
      display.display();
    }
    display_off = true;
  } else {
    connectWifi();
  }

  alarm();
}




void wifi_draw(int n, int i, bool color) {
  if (!color) {
    display.setTextColor(WHITE);
    display.setCursor(1, i * 10 + 1);
    display.print(WiFi.SSID(n));
  } else {
    display.setTextColor(BLACK);
    display.setCursor(1, i * 10 + 1);
    display.print(WiFi.SSID(n));
  }
}

int select_position = 0;
int wifi_select = 0;
int wifi_numbers = 0;
std::string wifi_pass = "";
bool startScan = false;
void scanWifi() {

  if (!startScan) {
    wifi_numbers = WiFi.scanNetworks();
    startScan = true;
  }
}

void scanWifi_draw() {

  if (wifi_numbers == 0) {
    display.clearDisplay();
    display.setCursor(0, 0);
    display.print("No Wifi has been Found");
    display.display();
  } else if (wifi_numbers < 6) {
    if (wifi_select > wifi_numbers) {
      wifi_select = wifi_numbers - 1;
      select_position = wifi_numbers - 1;
    }
    display.clearDisplay();
    display.fillRect(0, select_position * 10, 128, 10, WHITE);

    for (int i = 0; i < wifi_numbers; i++) {
      wifi_draw(i, i, false);
    }


    wifi_draw(wifi_select, select_position, true);
    display.display();
  } else {
    if (wifi_select > wifi_numbers) {
      wifi_select = wifi_numbers - 1;
      select_position = 5;
    }
    display.clearDisplay();


    display.fillRect(0, select_position * 10, 128, 10, WHITE);
    wifi_draw(wifi_select - select_position, 0, false);
    wifi_draw(wifi_select - (select_position - 1), 1, false);
    wifi_draw(wifi_select - (select_position - 2), 2, false);
    wifi_draw(wifi_select - (select_position - 3), 3, false);
    wifi_draw(wifi_select - (select_position - 4), 4, false);
    wifi_draw(wifi_select - (select_position - 5), 5, false);

    wifi_draw(wifi_select, select_position, true);





    display.display();
  }
}

int char_position = 0;
void connectWifi() {
  display.clearDisplay();
  display.fillRect(60, 54, 10, 10, WHITE);
  display.setTextColor(WHITE);
  display.setCursor(1, 1);
  display.print(wifi_pass.c_str());
  display.setCursor(1, 55);
  display.setTextColor(WHITE);
  display.print(alphabetWithUpper[(char_position - 6 < 0) ? alphabetWithUpper.length() + (char_position - 6) : char_position - 6]);
  display.setCursor(11, 55);
  display.print(alphabetWithUpper[(char_position - 5 < 0) ? alphabetWithUpper.length() + (char_position - 5) : char_position - 5]);
  display.setCursor(21, 55);
  display.print(alphabetWithUpper[(char_position - 4 < 0) ? alphabetWithUpper.length() + (char_position - 4) : char_position - 4]);
  display.setCursor(31, 55);
  display.print(alphabetWithUpper[(char_position - 3 < 0) ? alphabetWithUpper.length() + (char_position - 3) : char_position - 3]);
  display.setCursor(41, 55);
  display.print(alphabetWithUpper[(char_position - 2 < 0) ? alphabetWithUpper.length() + (char_position - 2) : char_position - 2]);
  display.setCursor(51, 55);
  display.print(alphabetWithUpper[(char_position - 1 < 0) ? alphabetWithUpper.length() + (char_position - 1) : char_position - 1]);
  display.setCursor(61, 55);
  display.setTextColor(BLACK);
  display.print(alphabetWithUpper[char_position]);
  display.setCursor(71, 55);
  display.setTextColor(WHITE);
  display.print(alphabetWithUpper[(char_position + 1 >= alphabetWithUpper.length()) ? char_position + 1 - alphabetWithUpper.length() : char_position + 1]);
  display.setCursor(81, 55);
  display.print(alphabetWithUpper[(char_position + 2 >= alphabetWithUpper.length()) ? char_position + 2 - alphabetWithUpper.length() : char_position + 2]);
  display.setCursor(91, 55);
  display.print(alphabetWithUpper[(char_position + 3 >= alphabetWithUpper.length()) ? char_position + 3 - alphabetWithUpper.length() : char_position + 3]);
  display.setCursor(101, 55);
  display.print(alphabetWithUpper[(char_position + 4 >= alphabetWithUpper.length()) ? char_position + 4 - alphabetWithUpper.length() : char_position + 4]);
  display.setCursor(111, 55);
  display.print(alphabetWithUpper[(char_position + 5 >= alphabetWithUpper.length()) ? char_position + 5 - alphabetWithUpper.length() : char_position + 5]);
  display.setCursor(121, 55);
  display.print(alphabetWithUpper[(char_position + 6 >= alphabetWithUpper.length()) ? char_position + 5 - alphabetWithUpper.length() : char_position + 6]);
  display.display();
}

void working_mode() {
  (working_state + 1 > 2) ? working_state = 0 : working_state++;
  if (working_state == 0) {
    startScan = false;
    display.clearDisplay();
    display.setTextSize(1);
    display.setTextColor(WHITE);
    display.setCursor(0, 0);
    display.print("Please wait!");
    display.display();
  }
}


void left_click() {
  if (working_state == 0) {

    if (wifi_select - 1 >= 0) {
      wifi_select--;
      if (select_position - 1 >= 0) select_position--;
    }
  } else if (working_state == 1) {
    (sensorMode - 1 < 0) ? sensorMode = 2 : sensorMode--;
  } else if (working_state == 3) {
    (char_position - 1 < 0) ? char_position = alphabetWithUpper.length() - 1 : char_position--;
  }
}

void right_click() {
  if (working_state == 0) {

    if (wifi_select + 1 <= wifi_numbers - 1) {
      wifi_select++;
      if (select_position + 1 <= 5) select_position++;
    }
  } else if (working_state == 1) {
    (sensorMode + 1 > 2) ? sensorMode = 0 : sensorMode++;
  } else if (working_state == 3) {
    (char_position + 1 >= alphabetWithUpper.length()) ? char_position = 0 : char_position++;
  }
}

void enter() {
  if (working_state == 0) {
    working_state = 3;
    wifi_pass = "";
  } else if (working_state == 3) {
    if (alphabetWithUpper.substr(char_position, 1).compare("<") == 0) {
      if (wifi_pass.length() > 0) wifi_pass.pop_back();
    } else if (alphabetWithUpper.substr(char_position, 1).compare(">") == 0) {
      WiFi.disconnect();
      WiFi.begin(WiFi.SSID(wifi_select).c_str(), wifi_pass.c_str());

      unsigned long startConnection = millis();
      display.clearDisplay();
      display.setCursor(1, 1);
      display.print("Connecting");

      while (WiFi.status() != WL_CONNECTED && millis() - startConnection < 10000) {
        display.print(".");
        display.display();
        delay(100);
      }

      if (WiFi.status() != WL_CONNECTED) {
        display.print("Failed");
      } else {
        display.print("Connected");
        display.print(WiFi.localIP());
      }
      display.display();

      delay(2000);
      working_state = 0;
    } else {
      wifi_pass += alphabetWithUpper.substr(char_position, 1);
    }
  }
}


void alarm() {
  if (alarm_on) {
    if (millis() - notetime >= 1000 / noteDurations[thisNote] + 1000 / noteDurations[thisNote] * 0.2) {
      (thisNote + 1 > 9) ? thisNote = 0 : thisNote++;
      tone(17, melody[thisNote], 1000 / noteDurations[thisNote] + 1000 / noteDurations[thisNote] * 0.2);
      notetime = millis();
    }
    alarm_toggle = true;
  } else {
    if (alarm_toggle){
      tone(17, REST);
      alarm_toggle = false;
    }
  }
}