#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <RTClib.h>
#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);
RTC_DS3231 rtc;
unsigned long initialTime;
bool initialDisplayActive = true; // Variável para controlar o estado de exibição inicial
// Referência do estado dos olhos
int ref_eye_height = 30; // tamanho olho
int ref_eye_width = 30; // tamanho olho
int ref_space_between_eye = 10;
int ref_corner_radius = 20; // canto dos olhos arredondados
// Estado atual dos olhos
int left_eye_height = ref_eye_height; // tamanho olho
int left_eye_width = ref_eye_width; // tamanho olho
int left_eye_x = 32; // posição dos olhos
int left_eye_y = 32; // posição dos olhos
int right_eye_x = 32 + ref_eye_width + ref_space_between_eye; // desenha o olho direito no estágio inicial
int right_eye_y = 32;
int right_eye_height = ref_eye_height;
int right_eye_width = ref_eye_width;
void display_info(float soil_moisture, float temperature) {
display.clearDisplay();
// Configura o texto
int textSize = 1; // Tamanho do texto reduzido
int lineSpacing = 12; // Espaço entre linhas
display.setTextSize(textSize);
display.setTextColor(SSD1306_WHITE);
// Exibe umidade do solo
int yPosition = 1;
display.setCursor(2, yPosition);
display.print("Umidade: ");
display.print(soil_moisture);
display.print(" %");
// Exibe temperatura
yPosition += lineSpacing;
display.setCursor(2, yPosition);
display.print("Temperatura: ");
display.print(temperature);
display.print(" C");
// Atualiza o display
display.display();
}
void draw_eyes(bool update = true) {
display.clearDisplay();
// Desenha a partir do centro
int x = int(left_eye_x - left_eye_width / 2);
int y = int(left_eye_y - left_eye_height / 2);
display.fillRoundRect(x, y, left_eye_width, left_eye_height, ref_corner_radius, SSD1306_WHITE);
x = int(right_eye_x - right_eye_width / 2);
y = int(right_eye_y - right_eye_height / 2);
display.fillRoundRect(x, y, right_eye_width, right_eye_height, ref_corner_radius, SSD1306_WHITE);
if (update) {
display.display();
}
}
void center_eyes(bool update = true) {
// Move olhos para o centro do display, definido por SCREEN_WIDTH, SCREEN_HEIGHT
left_eye_height = ref_eye_height;
left_eye_width = ref_eye_width;
right_eye_height = ref_eye_height;
right_eye_width = ref_eye_width;
left_eye_x = SCREEN_WIDTH / 2 - ref_eye_width / 2 - ref_space_between_eye / 2;
left_eye_y = SCREEN_HEIGHT / 2;
right_eye_x = SCREEN_WIDTH / 2 + ref_eye_width / 2 + ref_space_between_eye / 2;
right_eye_y = SCREEN_HEIGHT / 2;
draw_eyes(update);
}
void blink(int speed = 12) {
draw_eyes();
for (int i = 0; i < 3; i++) {
left_eye_height = left_eye_height - speed;
right_eye_height = right_eye_height - speed;
draw_eyes();
delay(1);
}
for (int i = 0; i < 3; i++) {
left_eye_height = left_eye_height + speed;
right_eye_height = right_eye_height + speed;
draw_eyes();
delay(1);
}
}
void sleep() {
left_eye_height = 3;
right_eye_height = 3;
draw_eyes(true);
delay(1000);
// Exibir "ZzZzZ" no display com efeito de sono
// Limpa apenas a área de desenho do display
display.setTextSize(1.5); // Tamanho do texto
display.setTextColor(SSD1306_WHITE); // Cor do texto
// Escrever "ZzZzZ" com efeito de sono
display.setCursor(95, 18); // Posição inicial para começar a escrever
display.print("Z"); // Exibe o primeiro "Zz"
display.display(); // Atualiza o conteúdo do display
delay(800); // Aguarda um tempo maior para o primeiro "Zz"
display.setCursor(102, 8); // Posição para o próximo "Zz"
display.print("Z"); // Exibe o segundo "Zz"
display.display(); // Atualiza o conteúdo do display
delay(800); // Aguarda um tempo maior para o segundo "Zz"
display.setCursor(110, 0); // Posição para o último "Zz"
display.print("Z"); // Exibe o terceiro "Zz"
display.display(); // Atualiza o conteúdo do display
delay(2000); // Aguarda um período maior para o efeito de sono
}
void wakeup() {
sleep();
for (int h = 0; h <= ref_eye_height; h += 2) {
left_eye_height = h;
right_eye_height = h;
draw_eyes(true);
}
}
void happy_eye() {
center_eyes(false);
// Desenha triângulo invertido sobre a parte inferior do olho
int offset = ref_eye_height / 2;
for (int i = 0; i < 10; i++) {
display.fillTriangle(left_eye_x - left_eye_width / 2 - 1, left_eye_y + offset,
left_eye_x + left_eye_width / 2 + 1, left_eye_y + 5 + offset,
left_eye_x - left_eye_width / 2 - 1, left_eye_y + left_eye_height + offset,
SSD1306_BLACK);
display.fillTriangle(right_eye_x + right_eye_width / 2 + 1, right_eye_y + offset,
right_eye_x - left_eye_width / 2 - 1, right_eye_y + 5 + offset,
right_eye_x + right_eye_width / 2 + 1, right_eye_y + right_eye_height + offset,
SSD1306_BLACK);
offset -= 2;
display.display();
delay(1);
}
display.display();
delay(1000);
}
void angry_eye() {
center_eyes(false);
// Desenha triângulo invertido sobre a parte superior do olho
int offset = -ref_eye_height / 1.5;
for (int i = 0; i < 10; i++) {
// Olho esquerdo
display.fillTriangle(left_eye_x - left_eye_width / -2 - 1, left_eye_y + offset,
left_eye_x + left_eye_width / 2 + 1, left_eye_y - -7 + offset,
left_eye_x - left_eye_width / 2 - 1, left_eye_y - left_eye_height + offset,
SSD1306_BLACK);
// Olho direito
display.fillTriangle(right_eye_x + right_eye_width / -2 + 1, right_eye_y + offset,
right_eye_x - right_eye_width / 2 - 1, right_eye_y - -7 + offset,
right_eye_x + right_eye_width / 2 + 1, right_eye_y - right_eye_height + offset,
SSD1306_BLACK);
offset += 2;
display.display();
delay(1);
}
display.display();
delay(1000);
}
void saccade(int direction_x, int direction_y) {
// Movimento rápido do olho, sem mudança de tamanho. Fica na posição após o movimento
int direction_x_movement_amplitude = 8;
int direction_y_movement_amplitude = 6;
int blink_amplitude = 8;
for (int i = 0; i < 1; i++) {
left_eye_x += direction_x_movement_amplitude * direction_x;
right_eye_x += direction_x_movement_amplitude * direction_x;
left_eye_y += direction_y_movement_amplitude * direction_y;
right_eye_y += direction_y_movement_amplitude * direction_y;
right_eye_height -= blink_amplitude;
left_eye_height -= blink_amplitude;
draw_eyes();
delay(1);
}
for (int i = 0; i < 1; i++) {
left_eye_x += direction_x_movement_amplitude * direction_x;
right_eye_x += direction_x_movement_amplitude * direction_x;
left_eye_y += direction_y_movement_amplitude * direction_y;
right_eye_y += direction_y_movement_amplitude * direction_y;
right_eye_height += blink_amplitude;
left_eye_height += blink_amplitude;
draw_eyes();
delay(1);
}
}
void move_right_big_eye() {
move_big_eye(1);
}
void move_left_big_eye() {
move_big_eye(-1);
}
void move_big_eye(int direction)
{
//direction == -1 : move left
//direction == 1 : move right
int direction_oversize = 1;
int direction_movement_amplitude = 2;
int blink_amplitude = 5;
for (int i = 0; i < 3; i++)
{
left_eye_x += direction_movement_amplitude * direction;
right_eye_x += direction_movement_amplitude * direction;
right_eye_height -= blink_amplitude;
left_eye_height -= blink_amplitude;
if (direction > 0)
{
right_eye_height += direction_oversize;
right_eye_width += direction_oversize;
}
else
{
left_eye_height += direction_oversize;
left_eye_width += direction_oversize;
}
draw_eyes();
delay(1);
}
for (int i = 0; i < 3; i++)
{
left_eye_x += direction_movement_amplitude * direction;
right_eye_x += direction_movement_amplitude * direction;
right_eye_height += blink_amplitude;
left_eye_height += blink_amplitude;
if (direction > 0)
{
right_eye_height += direction_oversize;
right_eye_width += direction_oversize;
}
else
{
left_eye_height += direction_oversize;
left_eye_width += direction_oversize;
}
draw_eyes();
delay(1);
}
delay(1000);
for (int i = 0; i < 3; i++)
{
left_eye_x -= direction_movement_amplitude * direction;
right_eye_x -= direction_movement_amplitude * direction;
right_eye_height -= blink_amplitude;
left_eye_height -= blink_amplitude;
if (direction > 0)
{
right_eye_height -= direction_oversize;
right_eye_width -= direction_oversize;
}
else
{
left_eye_height -= direction_oversize;
left_eye_width -= direction_oversize;
}
draw_eyes();
delay(1);
}
for (int i = 0; i < 3; i++)
{
left_eye_x -= direction_movement_amplitude * direction;
right_eye_x -= direction_movement_amplitude * direction;
right_eye_height += blink_amplitude;
left_eye_height += blink_amplitude;
if (direction > 0)
{
right_eye_height -= direction_oversize;
right_eye_width -= direction_oversize;
}
else
{
left_eye_height -= direction_oversize;
left_eye_width -= direction_oversize;
}
draw_eyes();
delay(1);
}
}
void move_right_big_eye_diagonal_down()
{
move_big_eye_diagonal(1,1);
}
void move_left_big_eye_diagonal_down()
{
move_big_eye_diagonal(-1,1);
}
void move_right_big_eye_diagonal_up()
{
move_big_eye_diagonal(1,-1);
}
void move_left_big_eye_diagonal_up()
{
move_big_eye_diagonal(-1,-1);
}
void move_big_eye_diagonal(int direction_x, int direction_y)
{
//direction_x == -1 : move left
//direction_x == 1 : move right
//direction_y == -1 : move up
//direction_y == 1 : move down
int direction_oversize = 1;
int direction_movement_amplitude = 2;
int blink_amplitude = 5;
for (int i = 0; i < 3; i++)
{
left_eye_x += direction_movement_amplitude * direction_x;
right_eye_x += direction_movement_amplitude * direction_x;
left_eye_y += direction_movement_amplitude * direction_y;
right_eye_y += direction_movement_amplitude * direction_y;
right_eye_height -= blink_amplitude;
left_eye_height -= blink_amplitude;
if (direction_x > 0 || direction_y != 0)
{
right_eye_height += direction_oversize;
right_eye_width += direction_oversize;
}
else
{
left_eye_height += direction_oversize;
left_eye_width += direction_oversize;
}
draw_eyes();
delay(1);
}
for (int i = 0; i < 3; i++)
{
left_eye_x += direction_movement_amplitude * direction_x;
right_eye_x += direction_movement_amplitude * direction_x;
left_eye_y += direction_movement_amplitude * direction_y;
right_eye_y += direction_movement_amplitude * direction_y;
right_eye_height += blink_amplitude;
left_eye_height += blink_amplitude;
if (direction_x > 0 || direction_y != 0)
{
right_eye_height += direction_oversize;
right_eye_width += direction_oversize;
}
else
{
left_eye_height += direction_oversize;
left_eye_width += direction_oversize;
}
draw_eyes();
delay(1);
}
delay(1000);
for (int i = 0; i < 3; i++)
{
left_eye_x -= direction_movement_amplitude * direction_x;
right_eye_x -= direction_movement_amplitude * direction_x;
left_eye_y -= direction_movement_amplitude * direction_y;
right_eye_y -= direction_movement_amplitude * direction_y;
right_eye_height -= blink_amplitude;
left_eye_height -= blink_amplitude;
if (direction_x > 0 || direction_y != 0)
{
right_eye_height -= direction_oversize;
right_eye_width -= direction_oversize;
}
else
{
left_eye_height -= direction_oversize;
left_eye_width -= direction_oversize;
}
draw_eyes();
delay(1);
}
for (int i = 0; i < 3; i++)
{
left_eye_x -= direction_movement_amplitude * direction_x;
right_eye_x -= direction_movement_amplitude * direction_x;
left_eye_y -= direction_movement_amplitude * direction_y;
right_eye_y -= direction_movement_amplitude * direction_y;
right_eye_height += blink_amplitude;
left_eye_height += blink_amplitude;
if (direction_x > 0 || direction_y != 0)
{
right_eye_height -= direction_oversize;
right_eye_width -= direction_oversize;
}
else
{
left_eye_height -= direction_oversize;
left_eye_width -= direction_oversize;
}
draw_eyes();
delay(1);
}
}
void angry_eye_tedio()
{
center_eyes(false);
//draw inverted triangle over eye upper part
int offset = -ref_eye_height / 2;
for (int i = 0; i < 10; i++)
{
// Left eye
display.fillTriangle(left_eye_x - left_eye_width / 2 - 1, left_eye_y + offset,
left_eye_x + left_eye_width / 2 + 1, left_eye_y - 5 + offset,
left_eye_x - left_eye_width / 2 - 1, left_eye_y - left_eye_height + offset,
SSD1306_BLACK);
// Right eye
display.fillTriangle(right_eye_x + right_eye_width / 2 + 1, right_eye_y + offset,
right_eye_x - right_eye_width / 2 - 1, right_eye_y - 5 + offset,
right_eye_x + right_eye_width / 2 + 1, right_eye_y - right_eye_height + offset,
SSD1306_BLACK);
offset += 2; // Move the triangle upwards by decreasing the offset
display.display();
delay(1);
}
display.display();
delay(1000);
}
void angry_eye_triste()
{
center_eyes(false);
//draw inverted triangle over eye upper part
int offset = -ref_eye_height / 1.5;
for (int i = 0; i < 9; i++)
{
// Left eye
display.fillTriangle(left_eye_x - left_eye_width / 2 - 1, left_eye_y + offset,
left_eye_x + left_eye_width / 2 + 1, left_eye_y - 5 + offset,
left_eye_x - left_eye_width / 2 - 1, left_eye_y - left_eye_height + offset,
SSD1306_BLACK);
// Right eye
display.fillTriangle(right_eye_x + right_eye_width / 2 + 1, right_eye_y + offset,
right_eye_x - right_eye_width / 2 - 1, right_eye_y - 5 + offset,
right_eye_x + right_eye_width / 2 + 1, right_eye_y - right_eye_height + offset,
SSD1306_BLACK);
offset += 2; // Move the triangle upwards by decreasing the offset
display.display();
delay(1);
}
}
// Variável global para rastrear a animação atual
int current_animation = 0;
void setup() {
// Inicializa o display com o endereço I2C 0x3C (para o 128x64)
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println(F("SSD1306 allocation failed"));
for (;;);
}
display.display();
delay(2000); // Pausa de 2 segundos
// Limpa o buffer
display.clearDisplay();
display.display();
Serial.begin(9600);
initialTime = millis(); // Marca o tempo inicial
}
bool isSleeping = false;
void loop() {
// Leitura de sensores
int humidity = readHumidity(); // Função que lê o valor da umidade
int light = readLight(); // Função que lê o valor da luz
Serial.print("Light Value: ");
Serial.println(light); // Imprime o valor da "luz" no monitor serial
delay(1000); // Aguarda 1 segundo antes de ler novamente
Serial.print("U% Value: ");
Serial.println(humidity); // Imprime o valor da "luz" no monitor serial
delay(1000); // Aguarda 1 segundo antes de ler novamente
// Exibição inicial por 1 minuto
if (initialDisplayActive) {
display_info(70.0, 30.0); // Exemplo de valores
if (millis() - initialTime >= 1000) { // Ajuste para 1 minuto (60000 ms)
initialDisplayActive = false; // Desativa o estado de exibição inicial após 1 minuto
}
delay(1000); // Atualiza a exibição a cada segundo
return;
}
// Verificação de luz para entrar ou sair do modo de sleep
if (light < 10) {
if (!isSleeping) {
isSleeping = true;
sleep();
sleep();
sleep();
}
// Sair da função loop, não executar mais nada
return;
} else {
if (isSleeping) {
wakeup();
isSleeping = false;
}
}
// Verifica se a umidade é menor que 70%
if (humidity < 70) {
// Maior chance de executar angry_eye_triste()
if (random(100) < 40) { // 40% de chance de executar angry_eye_triste()
angry_eye_triste();
delay(10000); // Mantém por mais tempo
blink(10);
delay(2000); // Adiciona um atraso para permitir que a animação seja visível
} else { // 60% de chance de executar outras funções de movimentação
int random_function = random(6); // Seleciona aleatoriamente entre as funções de movimentação excluindo happy_eye()
if (random_function == 0) {
move_right_big_eye();
} else if (random_function == 1) {
move_left_big_eye();
} else if (random_function == 2) {
move_right_big_eye_diagonal_up();
} else if (random_function == 3) {
move_right_big_eye_diagonal_down();
} else if (random_function == 4) {
blink(10);
} else if (random_function == 5) {
blink(10);
}
delay(2000); // Adiciona um atraso para permitir que a animação seja visível
}
} else {
// Maior chance de executar happy_eye()
if (random(100) < 20) { // 40% de chance de executar happy_eye()
happy_eye();
delay(10000); // Mantém por mais tempo
blink(10);
delay(2000); // Adiciona um atraso para permitir que a animação seja visível
} else { // 60% de chance de executar outras funções de movimentação
int random_function = random(6); // Seleciona aleatoriamente entre as funções de movimentação excluindo happy_eye()
if (random_function == 0) {
move_right_big_eye();
} else if (random_function == 1) {
move_left_big_eye();
} else if (random_function == 2) {
move_right_big_eye_diagonal_up();
} else if (random_function == 3) {
move_right_big_eye_diagonal_down();
} else if (random_function == 4) {
blink(10);
} else if (random_function == 5) {
blink(10);
}
delay(2000); // Adiciona um atraso para permitir que a animação seja visível
}
}}
// Funções fictícias para leitura de sensores (substitua pelas reais)
int readHumidity() {
int sensorValue = analogRead(A1);
return sensorValue; // Exemplo
}
int readLight() {
// Leitura do valor do potenciômetro (simulando leitura de luz)
int sensorValue = analogRead(A0);
return sensorValue;
}