#include <Adafruit_NeoPixel.h>
#include <WiFi.h>
#include <PubSubClient.h>
#include <Servo.h>
// Define pin numbers
#define PHOTORESISTOR_PIN A0
#define NEOPIXEL_PIN 6
#define NUM_PIXELS 12
#define TRIGGER_PIN 7
#define ECHO_PIN 8
#define STEP_PIN1 9
#define STEP_PIN2 10
#define STEP_PIN3 11
#define STEP_PIN4 12
#define SERVO_PIN 13
#define SWITCH_PIN 14
// Wi-Fi credentials
const char* ssid = "wokwi-GUEST";
const char* password = "";
// Thinger.io MQTT credentials
const char* mqtt_server = "mqtt.thinger.io";
const int mqtt_port = 1883;
const char* mqtt_client_id = "esp32"; // Ganti dengan Device ID dari Thinger.io
const char* mqtt_user = "piteung27"; // Ganti dengan Username dari Thinger.io
const char* mqtt_password = "in!LyaOO$NKk7r8V"; // Ganti dengan Device Credentials dari Thinger.io
const char* mqtt_topic_publish_light = "smart_aquarium_sister/light";
const char* mqtt_topic_publish_water = "smart_aquarium_sister/water";
WiFiClient espClient;
PubSubClient client(espClient);
Adafruit_NeoPixel pixels(NUM_PIXELS, NEOPIXEL_PIN, NEO_GRB + NEO_KHZ800);
Servo servo;
bool isNeoOn = false;
bool isMotorRunning = false;
void setup() {
Serial.begin(115200);
Serial.println("Setup started");
// Setup pins
pinMode(TRIGGER_PIN, OUTPUT);
pinMode(ECHO_PIN, INPUT);
pinMode(SWITCH_PIN, INPUT);
for (int pin : {STEP_PIN1, STEP_PIN2, STEP_PIN3, STEP_PIN4}) {
pinMode(pin, OUTPUT);
}
// Setup NeoPixel
pixels.begin();
pixels.show();
// Setup Servo
servo.attach(SERVO_PIN);
// Setup Wi-Fi
setup_wifi();
// Setup MQTT
client.setServer(mqtt_server, mqtt_port);
client.setCallback(mqtt_callback);
Serial.println("Setup completed");
}
void loop() {
if (!client.connected()) {
reconnect();
}
client.loop();
// Read light intensity and control NeoPixel LED ring
controlNeoPixel(0, 80);
// Check switch status to feed fish
if (digitalRead(SWITCH_PIN) == HIGH) {
Serial.println("Feeding the fish...");
feedFish(90);
publish_status(mqtt_topic_publish_light, "Fish fed");
}
// Measure and control water level
Serial.println("Checking water level...");
int waterLevel = measureDistance();
Serial.print("Measured Water Level: ");
Serial.print(waterLevel);
Serial.println(" cm");
controlStepperMotor(20, 80);
publish_status(mqtt_topic_publish_water, String("Water Level: ") + waterLevel + " cm");
delay(2000); // Add delay before next iteration
}
void setup_wifi() {
delay(10);
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println();
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
}
void reconnect() {
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
if (client.connect(mqtt_client_id, mqtt_user, mqtt_password)) {
Serial.println("connected");
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
delay(5000);
}
}
}
void mqtt_callback(char* topic, byte* payload, unsigned int length) {
Serial.print("Message arrived [");
Serial.print(topic);
Serial.print("] ");
for (unsigned int i = 0; i < length; i++) {
Serial.print((char)payload[i]);
}
Serial.println();
}
void publish_status(const char* topic, String status) {
client.publish(topic, status.c_str());
}
int get_light_percentage() {
int raw_value = analogRead(PHOTORESISTOR_PIN);
float percentage = (raw_value / 1023.0) * 100.0;
Serial.print("Raw light sensor value: ");
Serial.print(raw_value);
Serial.print(", Light Percentage: ");
Serial.print(percentage);
Serial.println("%");
return constrain(percentage, 0, 100);
}
void controlNeoPixel(int intensityThreshold_low, int intensityThreshold_high) {
int intensity = get_light_percentage();
Serial.print("Light Percentage: ");
Serial.print(intensity);
Serial.println("%");
if (intensity > intensityThreshold_low && intensity < intensityThreshold_high) {
Serial.println("Adjusting NeoPixel brightness");
int brightness = 255 - int(255 * (intensity - intensityThreshold_low) / (intensityThreshold_high - intensityThreshold_low));
isNeoOn = true;
for (int i = 0; i < NUM_PIXELS; i++) {
pixels.setPixelColor(i, pixels.Color(brightness, 0, 0));
}
} else {
Serial.println("NeoPixel LEDs off");
isNeoOn = false;
for (int i = 0; i < NUM_PIXELS; i++) {
pixels.setPixelColor(i, pixels.Color(0, 0, 0));
}
}
pixels.show();
}
int measureDistance() {
digitalWrite(TRIGGER_PIN, LOW);
delayMicroseconds(2);
digitalWrite(TRIGGER_PIN, HIGH);
delayMicroseconds(10);
digitalWrite(TRIGGER_PIN, LOW);
long duration = pulseIn(ECHO_PIN, HIGH);
int distance = duration * 0.034 / 2;
Serial.print("Distance: ");
Serial.print(distance);
Serial.println(" cm");
return distance;
}
void controlStepperMotor(int distanceThreshold, int stepsToMove) {
int distance = measureDistance();
if (distance > distanceThreshold) {
Serial.println("Water level is low. Starting stepper motor movement.");
isMotorRunning = true;
int steps[4][4] = {
{1, 0, 0, 1}, // Step 1
{0, 1, 0, 1}, // Step 2
{0, 1, 1, 0}, // Step 3
{1, 0, 1, 0} // Step 4
};
int stepperPins[4] = {STEP_PIN1, STEP_PIN2, STEP_PIN3, STEP_PIN4}; // Define an array of stepper motor pins
for (int i = 0; i < stepsToMove; i++) {
for (int step = 0; step < 4; step++) {
for (int pin = 0; pin < 4; pin++) {
digitalWrite(stepperPins[pin], steps[step][pin]);
}
delay(3);
}
}
Serial.println("Stepper motor movement complete.");
} else {
Serial.println("Water level is sufficient.");
isMotorRunning = false;
for (int pin : {STEP_PIN1, STEP_PIN2, STEP_PIN3, STEP_PIN4}) {
digitalWrite(pin, LOW);
}
}
}
void feedFish(int angle) {
servo.write(angle);
delay(1000);
servo.write(0);
delay(1000);
Serial.println("The fish has been fed.");
}