Welcome to Hackster!
Hackster is a community dedicated to learning hardware, from beginner to pro. Join us, it's free!
ElectronLux NCPCS
Published © GPL3+

FREE E Tag Project LOVE 4 ALL https://www. ncpcs. com/collar/

Small Light "Open Source" Programmable Dog or Cat maybe Luggage identification tags that you can create yourself from two parts an sum code.

BeginnerWork in progress30 minutes59

Things used in this project

Hardware components

XIAO ESP32C3
Seeed Studio XIAO ESP32C3
×1
Monochrome 0.91”128x32 I2C OLED Display with Chip Pad
DFRobot Monochrome 0.91”128x32 I2C OLED Display with Chip Pad
×1

Software apps and online services

Arduino IDE
Arduino IDE

Hand tools and fabrication machines

Solder Wire, Lead Free
Solder Wire, Lead Free

Story

Read more

Custom parts and enclosures

Assembled Part 3D drawing

Solid if the Dog Tag for making enclosures.. Please send us a copy of cool new boxes that might help save our pets.. https://www.ncpcs.com/collar/

Sketchfab still processing.

Schematics

Programmable Electronic Tag Assembly

Pet Identification Tag.. Designed to be SMALL fit on any collar, making it versatile and easy to use. The hardware utilizes an affordable XIAO ESP32C3, a switch for power (if a battery is used), a 1" i2C OLED for displaying messages, and a 3D printed enclosure. The cat model is the same device in a smaller enclosure, without a battery or switch to save weight.

Code

Electronic Dog Tag Project

Arduino
Open Source Free Dog Tag Project https://www.ncpcs.com/collar/
#include <WiFi.h>
#include <WebServer.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <EEPROM.h>

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 32
#define OLED_RESET -1
#define EEPROM_SIZE 2048

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

const char* ssid = "DogTag";
const char* password = "nameAdog";

IPAddress local_IP(10, 0, 0, 15);
IPAddress gateway(10, 0, 0, 1);
IPAddress subnet(255, 255, 255, 0);

WebServer server(80);

String displayText[10] = {"Connect to DogTag", "in WiFi", "go to", "10.0.0.15", "in a Browser", "PASSWORD", "nameAdog", "Thanks", "www.ncpcs.com", ""};
int displayTime[10] = {2, 2, 2, 2, 2, 2, 2, 2, 2, 2};
String textSize[10] = {"Small", "Small", "Small", "Small", "Small", "Small", "Small", "Small", "Small", "Small"};

bool disableWiFiAfter5Minutes = false;
unsigned long wifiDisableTime = 0;

void handleRoot() {
  String html = "<html><head><style>"
                "body { background-color: blue; color: white; font-family: Arial, sans-serif; }"
                "h1 { text-align: center; }"
                "form { display: flex; flex-direction: column; align-items: center; }"
                "table { border-collapse: collapse; }"
                "td, th { border: 1px solid white; padding: 5px; text-align: center; }"
                "input[type='text'] { width: 300px; padding: 5px; }"
                "input[type='number'] { width: 60px; padding: 5px; }"
                "select { width: 100px; padding: 5px; }"
                "input[type='submit'] { padding: 10px 20px; margin-top: 10px; }"
                "</style></head><body>"
                "<h1>Tag Text uploader</h1>"
                "<form action=\"/update\" method=\"post\">"
                "<table><tr><th>Word</th><th>Text Size</th><th>Time (s)</th></tr>";

  for (int i = 0; i < 10; i++) {
    html += "<tr><td><input type='text' name='text" + String(i) + "' maxlength='80' value='" + displayText[i] + "'></td>"
            "<td><select name='size" + String(i) + "'>"
            "<option value='Small'" + (textSize[i] == "Small" ? " selected" : "") + ">Small</option>"
            "<option value='Medium'" + (textSize[i] == "Medium" ? " selected" : "") + ">Medium</option>"
            "<option value='Large'" + (textSize[i] == "Large" ? " selected" : "") + ">Large</option>"
            "</select></td>"
            "<td><input type='number' name='time" + String(i) + "' value='" + displayTime[i] + "' min='1' max='10'></td></tr>";
  }

  html += "</table><br>"
          "<input type='checkbox' id='disableWifi' name='disableWifi' value='true'";
  if (disableWiFiAfter5Minutes) {
    html += " checked";
  }
  html += "> Disable WiFi after 5 minutes<br>"
          "<input type='submit' value='Update'>"
          "</form>"
          "</body></html>";
  server.send(200, "text/html", html);
}

void handleUpdate() {
  for (int i = 0; i < 10; i++) {
    if (server.hasArg("text" + String(i))) {
      displayText[i] = server.arg("text" + String(i));
    } else {
      displayText[i] = "";
    }
    if (server.hasArg("size" + String(i))) {
      textSize[i] = server.arg("size" + String(i));
    } else {
      textSize[i] = "Small";
    }
    int timeValue = server.hasArg("time" + String(i)) ? server.arg("time" + String(i)).toInt() : 2;
    displayTime[i] = max(timeValue, 1);
  }

  disableWiFiAfter5Minutes = server.hasArg("disableWifi");

  saveSettings();
  updateDisplay();
  server.sendHeader("Location", "/");
  server.send(303);
}

void handleDisableWiFi() {
  if (disableWiFiAfter5Minutes) {
    WiFi.disconnect();
  }
  server.send(200, "text/html", "<html><body><h1>WiFi Disabled</h1></body></html>");
}

void initializeEEPROM() {
  int addr = 0;
  Serial.println("Initializing EEPROM with default values...");
  for (int i = 0; i < 10; i++) {
    for (int j = 0; j < displayText[i].length(); j++) {
      EEPROM.write(addr++, displayText[i][j]);
    }
    EEPROM.write(addr++, '\0');
    EEPROM.write(addr++, displayTime[i]);
    for (int j = 0; j < textSize[i].length(); j++) {
      EEPROM.write(addr++, textSize[i][j]);
    }
    EEPROM.write(addr++, '\0');
  }
  EEPROM.write(addr++, disableWiFiAfter5Minutes ? 1 : 0);
  EEPROM.commit();
  Serial.println("EEPROM initialized with default values.");
}

void saveSettings() {
  int addr = 0;
  Serial.println("Saving settings to EEPROM...");
  for (int i = 0; i < 10; i++) {
    for (int j = 0; j < displayText[i].length(); j++) {
      EEPROM.write(addr++, displayText[i][j]);
    }
    EEPROM.write(addr++, '\0');
    EEPROM.write(addr++, displayTime[i]);
    for (int j = 0; j < textSize[i].length(); j++) {
      EEPROM.write(addr++, textSize[i][j]);
    }
    EEPROM.write(addr++, '\0');
  }
  EEPROM.write(addr++, disableWiFiAfter5Minutes ? 1 : 0);
  EEPROM.commit();
  Serial.println("Settings saved to EEPROM.");
}

void loadSettings() {
  int addr = 0;
  Serial.println("Loading settings from EEPROM...");
  for (int i = 0; i < 10; i++) {
    char textBuf[81];
    int j = 0;
    char c;
    while ((c = EEPROM.read(addr++)) != '\0' && j < 80) {
      textBuf[j++] = c;
    }
    textBuf[j] = '\0';
    displayText[i] = String(textBuf);
    Serial.print("Loaded text["); Serial.print(i); Serial.print("]: "); Serial.println(displayText[i]);

    displayTime[i] = EEPROM.read(addr++);
    displayTime[i] = max(displayTime[i], 1);
    Serial.print("Loaded time["); Serial.print(i); Serial.print("]: "); Serial.println(displayTime[i]);

    char sizeBuf[7];
    j = 0;
    while ((c = EEPROM.read(addr++)) != '\0' && j < 6) {
      sizeBuf[j++] = c;
    }
    sizeBuf[j] = '\0';
    textSize[i] = String(sizeBuf);
    Serial.print("Loaded size["); Serial.print(i); Serial.print("]: "); Serial.println(textSize[i]);
  }
  disableWiFiAfter5Minutes = EEPROM.read(addr++) == 1;
  Serial.println("Settings loaded successfully.");
}

void setup() {
  Serial.begin(115200);
  delay(2000); // Wait for serial to initialize properly

  // Debug message to check if serial communication works
  Serial.println("Serial communication test...");

  // Debug message before EEPROM initialization
  Serial.println("Starting EEPROM initialization...");

  // Initialize EEPROM
  if (!EEPROM.begin(EEPROM_SIZE)) {
    Serial.println("Failed to initialize EEPROM!");
  } else {
    Serial.println("EEPROM initialized successfully.");
  }

  // Check if EEPROM has been initialized
  if (EEPROM.read(0) == 255) { // Assuming first byte is a good indicator
    initializeEEPROM();
  }

  // Debug message before Wi-Fi initialization
  Serial.println("Starting Wi-Fi initialization...");

  WiFi.softAPConfig(local_IP, gateway, subnet);
  if (WiFi.softAP(ssid, password)) {
    Serial.println("Access point created");
    Serial.print("IP Address: ");
    Serial.println(WiFi.softAPIP());
  } else {
    Serial.println("Failed to create access point");
  }

  // Debug message before HTTP server initialization
  Serial.println("Starting HTTP server initialization...");

  server.on("/", handleRoot);
  server.on("/update", HTTP_POST, handleUpdate);
  server.on("/disable-wifi", handleDisableWiFi);
  server.begin();
  Serial.println("HTTP server started");

  // Initialize I2C with custom SDA and SCL pins
  Wire.begin(9, 10); // SDA, SCL

  // Debug message before display initialization
  Serial.println("Initializing display...");

  // Initialize display
  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    Serial.println(F("SSD1306 allocation failed"));
    for (;;);
  }
  Serial.println(F("SSD1306 allocation successful"));

  // Clear the display buffer
  display.clearDisplay();

  // Load settings from EEPROM
  loadSettings();

  // If WiFi is set to disable, schedule it
  if (disableWiFiAfter5Minutes) {
    wifiDisableTime = millis() + 300000; // 5 minutes
  }
}

void displayWordByWord() {
  for (int i = 0; i < 10; i++) {
    if (displayText[i].length() > 0) {
      displayWord(displayText[i], textSize[i], displayTime[i]);
    }
  }
}

void displayWord(String text, String size, int time) {
  display.clearDisplay();
  if (size == "Large") {
    display.setTextSize(3);
  } else if (size == "Medium") {
    display.setTextSize(2);
  } else {
    display.setTextSize(1);
  }
  display.setTextColor(SSD1306_WHITE);

  if (size == "Small") {
    String line1 = "";
    String line2 = "";
    String line3 = "";
    splitText(text, line1, line2, line3);

    int16_t x1, y1;
    uint16_t w, h;
    display.getTextBounds(line1, 0, 0, &x1, &y1, &w, &h);
    int16_t x1_pos = (SCREEN_WIDTH - w) / 2;
    int16_t y1_pos = 0;

    display.getTextBounds(line2, 0, 0, &x1, &y1, &w, &h);
    int16_t x2_pos = (SCREEN_WIDTH - w) / 2;
    int16_t y2_pos = 11;

    display.getTextBounds(line3, 0, 0, &x1, &y1, &w, &h);
    int16_t x3_pos = (SCREEN_WIDTH - w) / 2;
    int16_t y3_pos = 22;

    display.setCursor(x1_pos, y1_pos);
    display.println(line1);
    display.setCursor(x2_pos, y2_pos);
    display.println(line2);
    display.setCursor(x3_pos, y3_pos);
    display.println(line3);

    display.display();
  } else {
    int16_t x1, y1;
    uint16_t w, h;
    display.getTextBounds(text, 0, 0, &x1, &y1, &w, &h);
    int16_t x = (SCREEN_WIDTH - w) / 2;
    int16_t y = (SCREEN_HEIGHT - h) / 2;

    display.setCursor(x, y);
    display.println(text);
    display.display();
  }

  delay(time * 1000);
}

void splitText(String text, String &line1, String &line2, String &line3) {
  int16_t x1, y1;
  uint16_t w, h;
  display.setTextSize(1);

  String tempLine = "";
  String word = "";
  for (char c : text) {
    if (c == ' ') {
      display.getTextBounds(tempLine + " " + word, 0, 0, &x1, &y1, &w, &h);
      if (w > SCREEN_WIDTH) {
        if (line1 == "") {
          line1 = tempLine;
        } else if (line2 == "") {
          line2 = tempLine;
        } else {
          line3 = tempLine;
        }
        tempLine = word;
      } else {
        tempLine += " " + word;
      }
      word = "";
    } else {
      word += c;
    }
  }
  if (word.length() > 0) {
    display.getTextBounds(tempLine + " " + word, 0, 0, &x1, &y1, &w, &h);
    if (w > SCREEN_WIDTH) {
      if (line1 == "") {
        line1 = tempLine;
        line2 = word;
      } else if (line2 == "") {
        line2 = tempLine;
        line3 = word;
      } else {
        line3 = tempLine + " " + word;
      }
    } else {
      if (line1 == "") {
        line1 = tempLine + " " + word;
      } else if (line2 == "") {
        line2 = tempLine + " " + word;
      } else {
        line3 = tempLine + " " + word;
      }
    }
  } else {
    if (line1 == "") {
      line1 = tempLine;
    } else if (line2 == "") {
      line2 = tempLine;
    } else {
      line3 = tempLine;
    }
  }
}

void updateDisplay() {
  display.clearDisplay();
  display.display();
  displayWordByWord();
}

void loop() {
  server.handleClient();
  displayWordByWord();  // Continuously display the words

  if (disableWiFiAfter5Minutes && millis() > wifiDisableTime) {
    WiFi.disconnect();
    disableWiFiAfter5Minutes = false; // Reset the flag
  }
}

Credits

ElectronLux NCPCS
1 project • 0 followers
Contact

Comments

Please log in or sign up to comment.