Project note

Finally project is up and running

Finally project is up and running: 🚚 Finally! Finally my water hose has arrived — I had to wait a long time to be able to continue. • IoT • pcb, lcd

4 tags
Tags

🚚 Finally!

Finally my water hose has arrived — I had to wait a long time to be able to continue.


😿 Mistakes (things that went sideways)

  • While waiting, I kept the project in the living room on the sofa table. One of my cats ran through the wiring and disconnected most of the cables.
  • I forgot to push the latest changes to my git repo. :(

🔧 Recovery & planning

I spent a couple of days recreating most of the build, making it cat‑safe with glued-down wiring, and refining the final shape of the system.


📡 Ultrasonic Sensor

At first I wanted to display a water percentage compared to what remains in the tank. After thinking it through, it feels better to simply display how many centimeters remain in the tank.

💻 Firmware (Arduino)

cpp
#include <LiquidCrystal_I2C.h>
#include <Wire.h>

#define TCAADDR 0x70  // TCA9548A Encoder address

LiquidCrystal_I2C lcd(0x27, 16, 2);  // I2C address 0x27, 16 columns, 2 rows

// Letters/messages
String Message_1 = "Mindre &auml;n 5%";
String Message_2 = "Mindre 20%";
String Message_3 = "Mindre &auml;n 75%";
String Message_4 = "Mer &auml;n 75%";
String Message_end = "Vatten i tank";

// Water tank pins
int trigPin = 9;             // TRIG pin
int echoPin = 8;             // ECHO pin
float duration_us, distance_cm;

/* -----( Custom Swedish characters )----- */
byte AwithRing[8] = { // ĂĽ
  B00100, B01010, B01110, B00001, B01111, B10001, B01111,
};
byte AwithDots[8] = { // ä
  B01010, B00000, B01110, B00001, B01111, B10001, B01111,
};
byte OwithDots[8] = { // Ăś
  B01010, B00000, B01110, B10001, B10001, B10001, B01110,
};
byte BigAwithRing[8] = { // Å
  0b00100, 0b01010, 0b01110, 0b10001, 0b11111, 0b10001, 0b10001, 0b00000
};
byte BigAwithDots[8] = { // Ä
  0b01010, 0b00000, 0b01110, 0b10001, 0b11111, 0b10001, 0b10001, 0b00000
};
byte BigOwithDots[8] = { // Ö
  0b01010, 0b01110, 0b10001, 0b10001, 0b10001, 0b10001, 0b01110, 0b00000
};

void setup() {
  Serial.begin(9600);
  lcd.init();
  lcd.backlight();

  // Tank pins
  pinMode(trigPin, OUTPUT);  // trigger pin as output
  pinMode(echoPin, INPUT);   // echo pin as input
}

void loop() {
  // repeatedly render the small tank screen
  screenSmallTank();
}

void tcaselect(uint8_t i) {
  if (i > 7) return;
  Wire.beginTransmission(TCAADDR);
  Wire.write(1 << i);
  Wire.endTransmission();
}

void screenSmallTank() {
  String Message_1 = "Mindre &auml;n ---> ";
  String Message_2 = "i Tank";

  Wire.begin();
  tcaselect(3);
  lcd.begin(16, 4);

  lcd.setCursor(1, 0);
  lcd.createChar(1, AwithRing);     // ĂĽ
  lcd.createChar(2, AwithDots);     // ä
  lcd.createChar(3, OwithDots);     // Ăś
  lcd.createChar(4, BigAwithRing);  // Å
  lcd.createChar(5, BigAwithDots);  // Ä
  lcd.createChar(6, BigOwithDots);  // Ö

  // generate 10 Âľs pulse to TRIG pin
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);

  // measure duration of pulse from ECHO pin
  duration_us = pulseIn(echoPin, HIGH);

  // calculate the distance (speed of sound ~ 0.034 cm/Âľs -> divide by 2 for round-trip)
  distance_cm = 0.017 * duration_us;

  lcd.clear();
  lcd.setCursor(1, 0);              // first row
  Message_1.replace("&auml;", "\2");
  lcd.print(Message_1);

  lcd.setCursor(1, 1);              // second row
  lcd.print(distance_cm);
  lcd.print(" cm ");
  lcd.print(Message_2);

  delay(5000);
}

🌱 Soil Moisture with Relay & Water Pumps

I’ve decided to treat each soil‑moisture + relay + pump as its own module. Each plant has unique properties, and I’ve seen inconsistent behavior when looping over objects, so I’m prototyping per‑plant handlers first.

🧪 Recent test snippet

cpp
// MAP
// Planta [0] Hylla hĂśger hĂśrn.
// Planta [1] Hylla vänster.
// Planta [2] Pinträd hÜger sida fÜnster.
// Planta [3] Hängande i gardinstüng i mitten.
// Planta [4] Ogräsplanta näst längst in till vänster.
// Planta [5] Ogräsplanta längst in vänster.
// Planta [6] Bonsai träd pü golv

// Planta [0]
#define SOIL_MOISTURE_0 A0   // Arduino pin that connects to AOUT pin of moisture sensor

// constants won't change
const int RELAY_1_PIN = A12; // Arduino pin that connects to relay IN
int SOIL_MOISTURE_0_THRESHOLD_DRY = 550;
int SOIL_MOISTURE_0_THRESHOLD_PERFECT = 450;
int SOIL_MOISTURE_0_THRESHOLD_WET = 390;

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

  // Plant [0]
  pinMode(RELAY_1_PIN, OUTPUT);
  pinMode(SOIL_MOISTURE_0, INPUT);
}

void loop() {
  // Keep the water pump off by default
  digitalWrite(RELAY_1_PIN, LOW); // turn off pump
  delay(1000);
}

void PlantZero() {
  Serial.print("Moisture: ");
  int SOIL_MOISTURE_0_VALUE = analogRead(SOIL_MOISTURE_0);

  if (SOIL_MOISTURE_0_VALUE > SOIL_MOISTURE_0_THRESHOLD_DRY) {
    Serial.println(SOIL_MOISTURE_0_VALUE);
    Serial.println("SOIL_MOISTURE_0 = DRY");
    digitalWrite(RELAY_1_PIN, HIGH); // turn on pump 5 seconds
  } else if (SOIL_MOISTURE_0_VALUE > SOIL_MOISTURE_0_THRESHOLD_WET &&
             SOIL_MOISTURE_0_VALUE < SOIL_MOISTURE_0_THRESHOLD_PERFECT) {
    Serial.println("SOIL_MOISTURE_0 = PERFECT");
    digitalWrite(RELAY_1_PIN, LOW);  // turn off pump
  } else if (SOIL_MOISTURE_0_VALUE < SOIL_MOISTURE_0_THRESHOLD_WET) {
    Serial.println("SOIL_MOISTURE_0 = WET");
    digitalWrite(RELAY_1_PIN, LOW);  // turn off pump
  }
}