Compare commits

..

No commits in common. "main" and "portal-top" have entirely different histories.

20 changed files with 206 additions and 565 deletions

0
assoc
View File

0
auth
View File

0
cd
View File

0
git
View File

View File

@ -16,8 +16,6 @@ idf_component_register(
"i2c_helper.c"
"display.c"
"ui.c"
"net_weather.c"
"buzzer.c"
INCLUDE_DIRS
"include"
@ -30,6 +28,5 @@ idf_component_register(
json
driver
esp_http_server
esp_http_client
)

View File

@ -1,26 +0,0 @@
#include "driver/gpio.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_rom_sys.h"
#define BUZ_GPIO GPIO_NUM_19
void buzzer_init(void)
{
gpio_reset_pin(BUZ_GPIO);
gpio_set_direction(BUZ_GPIO, GPIO_MODE_OUTPUT);
}
void buzzer_beep(uint32_t ms)
{
const int period_us = 500; // ~2 kHz
int cycles = (ms * 1000) / period_us;
for (int i = 0; i < cycles; i++) {
gpio_set_level(BUZ_GPIO, 1);
esp_rom_delay_us(period_us / 2);
gpio_set_level(BUZ_GPIO, 0);
esp_rom_delay_us(period_us / 2);
}
}

View File

@ -1,37 +1,19 @@
// display.c (HT16K33 14-seg / 4 dígitos)
// TOP = 0x71 | BOTTOM = 0x70
// I2C_PORT = I2C_NUM_0
//
// MODO "SAFE":
// - Se I2C não estiver instalado, ou se não existir display, ignora tudo (sem spam)
// - display_init() NUNCA aborta o firmware (devolve ESP_OK e deixa display disabled)
#include "driver/i2c.h"
#include "esp_log.h"
#include "esp_err.h"
#include "display.h"
#include <stdint.h>
#include <stdbool.h>
#define I2C_PORT I2C_NUM_0
// Endereços reais
#define DISP_TOP_ADDR 0x71
#define DISP_BOTTOM_ADDR 0x70
#define DISP_TOP_ADDR 0x71 // display superior
#define DISP_BOTTOM_ADDR 0x70 // display inferior
static uint16_t rotate180(uint16_t m);
static const char *TAG = "DISPLAY";
const char *TAG = "DISPLAY";
// =======================================================
// FLAG GLOBAL
// =======================================================
static bool s_display_enabled = false;
void display_temperature_bottom(float temp);
void display_set_enabled(bool en) { s_display_enabled = en; }
bool display_is_enabled(void) { return s_display_enabled; }
// =======================================================
// MAPA DE SEGMENTOS (igual ao teu)
// MAPA DE SEGMENTOS (mantido igual ao teu)
// =======================================================
#define SEG_A (1 << 0)
@ -56,264 +38,131 @@ bool display_is_enabled(void) { return s_display_enabled; }
#define SEG_G (SEG_ML | SEG_MR)
static uint16_t charset(char c);
// =======================================================
// FUNÇÕES I2C (internas)
// FUNÇÕES GENÉRICAS PARA QUALQUER DISPLAY
// =======================================================
static inline bool i2c_driver_is_installed(void)
static void disp_send_cmd(uint8_t addr, uint8_t cmd)
{
// truque simples: tenta criar um cmd e dar begin "vazio" é overkill.
// Mais seguro: tenta uma escrita curta e ver se dá INVALID_STATE.
// Aqui vamos só confiar na primeira escrita do display_init().
return true;
i2c_master_write_to_device(I2C_PORT, addr, &cmd, 1, 20 / portTICK_PERIOD_MS);
}
static esp_err_t disp_send_cmd(uint8_t addr, uint8_t cmd)
static void disp_raw(uint8_t addr, int pos, uint16_t mask)
{
return i2c_master_write_to_device(I2C_PORT, addr, &cmd, 1, pdMS_TO_TICKS(50));
}
static esp_err_t disp_raw(uint8_t addr, int pos, uint16_t mask)
{
if (pos < 0 || pos > 3) return ESP_ERR_INVALID_ARG;
if (pos < 0 || pos > 3) return;
uint8_t buf[3];
buf[0] = (uint8_t)(pos * 2);
buf[1] = (uint8_t)(mask & 0xFF);
buf[2] = (uint8_t)((mask >> 8) & 0xFF);
buf[0] = pos * 2;
buf[1] = mask & 0xFF;
buf[2] = (mask >> 8) & 0xFF;
return i2c_master_write_to_device(I2C_PORT, addr, buf, sizeof(buf), pdMS_TO_TICKS(50));
i2c_master_write_to_device(I2C_PORT, addr, buf, 3, 20 / portTICK_PERIOD_MS);
}
static esp_err_t disp_clear(uint8_t addr)
static void disp_clear(uint8_t addr)
{
uint8_t buf[17] = {0};
buf[0] = 0x00;
return i2c_master_write_to_device(I2C_PORT, addr, buf, sizeof(buf), pdMS_TO_TICKS(50));
i2c_master_write_to_device(I2C_PORT, addr, buf, sizeof(buf), 20 / portTICK_PERIOD_MS);
}
// =======================================================
// INIT (SAFE)
// INIT PARA OS DOIS DISPLAYS (TOP 0x71 | BOTTOM 0x70)
// =======================================================
esp_err_t display_init(void)
void display_init(void)
{
// por defeito: desligado
s_display_enabled = false;
// Se o driver I2C não estiver instalado, a primeira chamada vai dar INVALID_STATE.
// Nós tratamos isso como "não há display nesta board" e seguimos sem logs.
const uint8_t cmd1 = 0x21; // oscillator ON
const uint8_t cmd2 = 0x81; // display ON, blink OFF
const uint8_t cmd3 = 0xEF; // brightness MAX
esp_err_t err;
uint8_t cmd1 = 0x21; // oscillator ON
uint8_t cmd2 = 0x81; // display ON, blink OFF
uint8_t cmd3 = 0xEF; // brightness MAX
// TOP
err = disp_send_cmd(DISP_TOP_ADDR, cmd1);
if (err == ESP_ERR_INVALID_STATE) return ESP_OK; // I2C não instalado -> ignora
if (err != ESP_OK) return ESP_OK; // display ausente/cabos -> ignora
err = disp_send_cmd(DISP_TOP_ADDR, cmd2);
if (err != ESP_OK) return ESP_OK;
err = disp_send_cmd(DISP_TOP_ADDR, cmd3);
if (err != ESP_OK) return ESP_OK;
err = disp_clear(DISP_TOP_ADDR);
if (err != ESP_OK) return ESP_OK;
disp_send_cmd(DISP_TOP_ADDR, cmd1);
disp_send_cmd(DISP_TOP_ADDR, cmd2);
disp_send_cmd(DISP_TOP_ADDR, cmd3);
disp_clear(DISP_TOP_ADDR);
// BOTTOM
err = disp_send_cmd(DISP_BOTTOM_ADDR, cmd1);
if (err != ESP_OK) return ESP_OK;
disp_send_cmd(DISP_BOTTOM_ADDR, cmd1);
disp_send_cmd(DISP_BOTTOM_ADDR, cmd2);
disp_send_cmd(DISP_BOTTOM_ADDR, cmd3);
disp_clear(DISP_BOTTOM_ADDR);
err = disp_send_cmd(DISP_BOTTOM_ADDR, cmd2);
if (err != ESP_OK) return ESP_OK;
err = disp_send_cmd(DISP_BOTTOM_ADDR, cmd3);
if (err != ESP_OK) return ESP_OK;
err = disp_clear(DISP_BOTTOM_ADDR);
if (err != ESP_OK) return ESP_OK;
// OK -> ativa display
s_display_enabled = true;
ESP_LOGI(TAG, "📟 Displays OK: TOP=0x%02X BOTTOM=0x%02X", DISP_TOP_ADDR, DISP_BOTTOM_ADDR);
return ESP_OK;
ESP_LOGI(TAG, "📟 Displays inicializados: TOP=0x71 BOTTOM=0x70");
}
// =======================================================
// RAW / CLEAR (com guard)
// =======================================================
// =======================================================
// RAW PARA TOP E BOTTOM
// =======================================================
void display_raw_top(int pos, uint16_t mask)
{
if (!s_display_enabled) return;
esp_err_t err = disp_raw(DISP_TOP_ADDR, pos, mask);
if (err != ESP_OK) {
// se o driver desaparecer a meio, desativa e cala
if (err == ESP_ERR_INVALID_STATE) s_display_enabled = false;
// opcional: não logar para evitar spam
// ESP_LOGE(TAG, "raw_top falhou: %s", esp_err_to_name(err));
}
int p = 3 - pos; // inverter ordem dos dígitos
uint16_t m = rotate180(mask); // rodar segmentos
disp_raw(DISP_TOP_ADDR, p, m);
}
void display_raw_bottom(int pos, uint16_t mask)
{
if (!s_display_enabled) return;
esp_err_t err = disp_raw(DISP_BOTTOM_ADDR, pos, mask);
if (err != ESP_OK) {
if (err == ESP_ERR_INVALID_STATE) s_display_enabled = false;
// opcional: não logar
}
disp_raw(DISP_BOTTOM_ADDR, pos, mask);
}
void display_clear_top(void)
{
if (!s_display_enabled) return;
esp_err_t err = disp_clear(DISP_TOP_ADDR);
if (err != ESP_OK) {
if (err == ESP_ERR_INVALID_STATE) s_display_enabled = false;
}
disp_clear(DISP_TOP_ADDR);
}
void display_clear_bottom(void)
{
if (!s_display_enabled) return;
esp_err_t err = disp_clear(DISP_BOTTOM_ADDR);
if (err != ESP_OK) {
if (err == ESP_ERR_INVALID_STATE) s_display_enabled = false;
}
disp_clear(DISP_BOTTOM_ADDR);
}
// =====================
// ROTATE 180 para 14 segmentos REAL
// (mapa correto para o teu HT16K33)
// =====================
static uint16_t rotate180(uint16_t m)
{
uint16_t r = 0;
// A (topo) <-> D (baixo)
if (m & SEG_A) r |= SEG_D;
if (m & SEG_D) r |= SEG_A;
// B (top-right) <-> E (bottom-left)
if (m & SEG_B) r |= SEG_E;
if (m & SEG_E) r |= SEG_B;
// C (bottom-right) <-> F (top-left)
if (m & SEG_C) r |= SEG_F;
if (m & SEG_F) r |= SEG_C;
// Meio vertical ML ↔ MR
if (m & SEG_ML) r |= SEG_MR;
if (m & SEG_MR) r |= SEG_ML;
// Alfanuméricos topo TL/TM/TR ↔ BL/BM/BR
if (m & SEG_TL) r |= SEG_BL;
if (m & SEG_BL) r |= SEG_TL;
if (m & SEG_TM) r |= SEG_BM;
if (m & SEG_BM) r |= SEG_TM;
if (m & SEG_TR) r |= SEG_BR;
if (m & SEG_BR) r |= SEG_TR;
// DP é DP (ponto)
if (m & SEG_DP) r |= SEG_DP;
return r;
}
// =======================================================
// TEXTO / CHARS
// =======================================================
void display_char_top(int pos, char c)
{
if (!s_display_enabled) return;
display_raw_top(pos, charset(c));
}
void display_char_bottom(int pos, char c)
{
if (!s_display_enabled) return;
display_raw_bottom(pos, charset(c));
}
void display_text_top(const char *txt)
{
if (!s_display_enabled) return;
for (int i = 0; i < 4; i++) {
char c = (txt && txt[i]) ? txt[i] : ' ';
display_char_top(i, c);
}
}
void display_text_bottom(const char *txt)
{
if (!s_display_enabled) return;
for (int i = 0; i < 4; i++) {
char c = (txt && txt[i]) ? txt[i] : ' ';
display_char_bottom(i, c);
}
}
// =======================================================
// NÚMEROS
// =======================================================
static const uint16_t digit_mask[10] =
{
[0] = SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F,
[1] = SEG_B | SEG_C,
[2] = SEG_A | SEG_B | SEG_G | SEG_E | SEG_D,
[3] = SEG_A | SEG_B | SEG_G | SEG_C | SEG_D,
[4] = SEG_F | SEG_G | SEG_B | SEG_C,
[5] = SEG_A | SEG_F | SEG_G | SEG_C | SEG_D,
[6] = SEG_A | SEG_F | SEG_G | SEG_E | SEG_D | SEG_C,
[7] = SEG_A | SEG_B | SEG_C,
[8] = SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F | SEG_G,
[9] = SEG_A | SEG_B | SEG_C | SEG_D | SEG_F | SEG_G,
};
void display_digit_top(int pos, uint8_t val)
{
if (!s_display_enabled) return;
if (val > 9) val = 0;
display_raw_top(pos, digit_mask[val]);
}
void display_digit_bottom(int pos, uint8_t val)
{
if (!s_display_enabled) return;
if (val > 9) val = 0;
display_raw_bottom(pos, digit_mask[val]);
}
void display_number_top(int num)
{
if (!s_display_enabled) return;
if (num < 0) num = 0;
if (num > 9999) num = 9999;
display_digit_top(3, (uint8_t)(num % 10));
display_digit_top(2, (uint8_t)((num / 10) % 10));
display_digit_top(1, (uint8_t)((num / 100) % 10));
display_digit_top(0, (uint8_t)((num / 1000) % 10));
}
void display_number_bottom(int num)
{
if (!s_display_enabled) return;
if (num < 0) num = 0;
if (num > 9999) num = 9999;
display_digit_bottom(3, (uint8_t)(num % 10));
display_digit_bottom(2, (uint8_t)((num / 10) % 10));
display_digit_bottom(1, (uint8_t)((num / 100) % 10));
display_digit_bottom(0, (uint8_t)((num / 1000) % 10));
}
// =======================================================
// RELÓGIO (HH:MM com DP no meio)
// =======================================================
void display_set_time_top(int horas, int minutos)
{
if (!s_display_enabled) return;
if (horas < 0) horas = 0;
if (horas > 99) horas = 99;
if (minutos < 0) minutos = 0;
if (minutos > 59) minutos = 59;
int h1 = horas / 10;
int h2 = horas % 10;
int m1 = minutos / 10;
int m2 = minutos % 10;
uint16_t mid = digit_mask[h2] | SEG_DP;
display_digit_top(0, (uint8_t)h1);
display_raw_top(1, mid);
display_digit_top(2, (uint8_t)m1);
display_digit_top(3, (uint8_t)m2);
}
// =======================================================
// CHARSET (igual ao teu)
// CHARSET — mantido EXACTAMENTE como o teu
// =======================================================
static uint16_t charset(char c)
@ -332,7 +181,7 @@ static uint16_t charset(char c)
case '8': return SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F | SEG_G;
case '9': return SEG_A | SEG_B | SEG_C | SEG_D | SEG_F | SEG_G;
// LETRAS
// LETRAS COMPLETAS (mantidas)
case 'A': case 'a': return SEG_A | SEG_B | SEG_C | SEG_E | SEG_F | SEG_G;
case 'B': case 'b': return SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F | SEG_G;
case 'C': case 'c': return SEG_A | SEG_F | SEG_E | SEG_D;
@ -370,55 +219,113 @@ static uint16_t charset(char c)
}
}
void display_debug_segment(uint16_t bitmask)
{
(void)bitmask;
// opcional: podes mostrar um padrão fixo se display estiver ativo
// if (!display_is_enabled()) return;
// display_raw_top(0, bitmask);
}
// =======================================================
// TEMPERATURA (BOTTOM) ex: 23.5
// DISPLAY CARACTER / TEXTO
// =======================================================
void display_temperature_bottom(float temp)
void display_char_top(int pos, char c)
{
if (!s_display_enabled) return;
display_raw_top(pos, charset(c));
}
// limites práticos
if (temp > 99.9f) temp = 99.9f;
if (temp < -9.9f) temp = -9.9f;
void display_char_bottom(int pos, char c)
{
disp_raw(DISP_BOTTOM_ADDR, pos, charset(c));
}
bool neg = false;
if (temp < 0) {
neg = true;
temp = -temp;
}
int inteiro = (int)temp;
int decimal = (int)((temp - inteiro) * 10 + 0.5f);
display_clear_bottom();
if (neg) {
// formato: C-5.2 (raro, mas pronto)
display_char_bottom(0, 'C');
display_raw_bottom(1, SEG_G); // '-'
display_raw_bottom(2, digit_mask[inteiro] | SEG_DP);
display_digit_bottom(3, decimal);
} else {
if (inteiro >= 10) {
// formato: C13.8
display_char_bottom(0, 'C');
display_digit_bottom(1, inteiro / 10);
display_raw_bottom(2, digit_mask[inteiro % 10] | SEG_DP);
display_digit_bottom(3, decimal);
} else {
// formato: C 7.2
display_char_bottom(0, 'C');
display_raw_bottom(1, 0);
display_raw_bottom(2, digit_mask[inteiro] | SEG_DP);
display_digit_bottom(3, decimal);
}
void display_text_top(const char *txt)
{
for (int i = 0; i < 4; i++) {
char c = txt[i] ? txt[i] : ' ';
display_char_top(i, c);
}
}
void display_text_bottom(const char *txt)
{
for (int i = 0; i < 4; i++) {
char c = txt[i] ? txt[i] : ' ';
display_char_bottom(i, c);
}
}
// =======================================================
// DISPLAY DE NÚMEROS (igual ao teu)
// =======================================================
static const uint16_t digit_mask[10] =
{
[0] = SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F,
[1] = SEG_B | SEG_C,
[2] = SEG_A | SEG_B | SEG_G | SEG_E | SEG_D,
[3] = SEG_A | SEG_B | SEG_G | SEG_C | SEG_D,
[4] = SEG_F | SEG_G | SEG_B | SEG_C,
[5] = SEG_A | SEG_F | SEG_G | SEG_C | SEG_D,
[6] = SEG_A | SEG_F | SEG_G | SEG_E | SEG_D | SEG_C,
[7] = SEG_A | SEG_B | SEG_C,
[8] = SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F | SEG_G,
[9] = SEG_A | SEG_B | SEG_C | SEG_D | SEG_F | SEG_G,
};
void display_digit_top(int pos, uint8_t val)
{
if (val > 9) val = 0;
display_raw_top(pos, digit_mask[val]);
}
void display_digit_bottom(int pos, uint8_t val)
{
if (val > 9) val = 0;
disp_raw(DISP_BOTTOM_ADDR, pos, digit_mask[val]);
}
void display_number_top(int num)
{
if (num < 0) num = 0;
if (num > 9999) num = 9999;
display_digit_top(3, num % 10);
display_digit_top(2, (num / 10) % 10);
display_digit_top(1, (num / 100) % 10);
display_digit_top(0, (num / 1000) % 10);
}
void display_number_bottom(int num)
{
if (num < 0) num = 0;
if (num > 9999) num = 9999;
display_digit_bottom(3, num % 10);
display_digit_bottom(2, (num/10) % 10);
display_digit_bottom(1, (num/100) % 10);
display_digit_bottom(0, (num/1000) % 10);
}
// =======================================================
// display_set_time() — mantém SEG_DP no sítio certo
// =======================================================
void display_set_time_top(int horas, int minutos)
{
if (horas < 0) horas = 0;
if (horas > 99) horas = 99;
if (minutos < 0) minutos = 0;
if (minutos > 59) minutos = 59;
int h1 = horas / 10;
int h2 = horas % 10;
int m1 = minutos / 10;
int m2 = minutos % 10;
uint16_t mid = digit_mask[h2] | SEG_DP;
display_digit_top(0, h1);
display_raw_top(1, mid);
display_digit_top(2, m1);
display_digit_top(3, m2);
}

View File

@ -1,86 +1,20 @@
#include "driver/i2c.h"
#include "esp_err.h"
#include "esp_log.h"
#include "driver/gpio.h"
#include "esp_rom_sys.h"
#define SDA_PIN 21
#define SCL_PIN 22
#define I2C_PORT I2C_NUM_0
static const char *TAG_I2C = "I2C";
static void i2c_bus_reset(void)
void i2c_init(void)
{
// Solta o bus: gera 9 clocks em SCL para libertar SDA se algum escravo ficou preso
gpio_config_t io = {
.pin_bit_mask = (1ULL << SDA_PIN) | (1ULL << SCL_PIN),
.mode = GPIO_MODE_OUTPUT_OD,
.pull_up_en = GPIO_PULLUP_ENABLE,
.pull_down_en = GPIO_PULLDOWN_DISABLE,
.intr_type = GPIO_INTR_DISABLE
};
gpio_config(&io);
gpio_set_level(SDA_PIN, 1);
gpio_set_level(SCL_PIN, 1);
esp_rom_delay_us(5);
for (int i = 0; i < 9; i++) {
gpio_set_level(SCL_PIN, 0);
esp_rom_delay_us(5);
gpio_set_level(SCL_PIN, 1);
esp_rom_delay_us(5);
}
// STOP
gpio_set_level(SDA_PIN, 0);
esp_rom_delay_us(5);
gpio_set_level(SCL_PIN, 1);
esp_rom_delay_us(5);
gpio_set_level(SDA_PIN, 1);
esp_rom_delay_us(5);
// devolve os pinos ao I2C driver depois
}
esp_err_t i2c_init(void)
{
// se já estava instalado, limpa e volta a instalar
i2c_driver_delete(I2C_PORT);
i2c_bus_reset();
i2c_config_t cfg = {
.mode = I2C_MODE_MASTER,
.sda_io_num = SDA_PIN,
.scl_io_num = SCL_PIN,
.sda_pullup_en = GPIO_PULLUP_ENABLE,
.scl_pullup_en = GPIO_PULLUP_ENABLE,
.master.clk_speed = 100000, // começa seguro
.clk_flags = 0
.master.clk_speed = 400000
};
esp_err_t err;
err = i2c_param_config(I2C_PORT, &cfg);
if (err != ESP_OK) {
ESP_LOGE(TAG_I2C, "i2c_param_config falhou: %s", esp_err_to_name(err));
return err;
}
err = i2c_driver_install(I2C_PORT, cfg.mode, 0, 0, 0);
if (err != ESP_OK && err != ESP_ERR_INVALID_STATE) {
ESP_LOGE(TAG_I2C, "i2c_driver_install falhou: %s", esp_err_to_name(err));
return err;
}
ESP_LOGI(TAG_I2C, "I2C OK (SDA=%d SCL=%d) freq=100kHz", SDA_PIN, SCL_PIN);
return ESP_OK;
i2c_param_config(I2C_PORT, &cfg);
i2c_driver_install(I2C_PORT, cfg.mode, 0, 0, 0);
}

View File

@ -1,8 +0,0 @@
#pragma once
#include <stdint.h>
// inicializa o buzzer (PWM / GPIO19)
void buzzer_init(void);
// bip simples em milissegundos
void buzzer_beep(uint32_t ms);

View File

@ -1,7 +1,5 @@
#pragma once
#include <stdint.h>
#include "esp_err.h"
#include <stdbool.h>
// =======================================================
// ENDEREÇOS I2C (definidos no .c)
@ -10,7 +8,7 @@
// BOTTOM = 0x70
// Inicialização dos dois displays
esp_err_t display_init(void);
void display_init(void);
// =======================================================
// RAW ACCESS (usa 16 bits de segmentos)
@ -20,8 +18,6 @@ void display_raw_bottom(int pos, uint16_t mask);
void display_clear_top(void);
void display_clear_bottom(void);
void display_set_enabled(bool en);
bool display_is_enabled(void);
// =======================================================
// TEXTO E CARACTERES
@ -45,7 +41,6 @@ void display_number_bottom(int num);
// RELÓGIO (HH:MM com DP entre horas)
// =======================================================
void display_set_time_top(int horas, int minutos);
void display_temperature_bottom(float temp);
// =======================================================
// DEBUG

View File

@ -1,4 +1,3 @@
#pragma once
#include "esp_err.h"
esp_err_t i2c_init(void);
void i2c_init(void);

View File

@ -1,4 +0,0 @@
#pragma once
#include <stdbool.h>
bool net_weather_update(float *out_temp);

View File

@ -32,16 +32,6 @@
#include "display.h"
#include <stdbool.h>
#include "net_weather.h"
#include "buzzer.h"
esp_err_t i2c_init(void);
esp_err_t display_init(void);
bool modo_bloqueado = false; // definição oficial
#define SDA_PIN 21
@ -58,37 +48,6 @@ typedef struct {
} contadores_t;
static void weather_task(void *arg)
{
float temp;
ESP_LOGI("WEATHER", "🌡️ weather_task arrancou");
// 🔥 leitura IMEDIATA (antes do delay)
ESP_LOGI("WEATHER", "🌐 a pedir temperatura (primeira vez)");
if (net_weather_update(&temp)) {
ESP_LOGI("WEATHER", "🌡️ temperatura recebida: %.1f", temp);
display_temperature_bottom(temp);
} else {
ESP_LOGE("WEATHER", "❌ net_weather_update falhou");
}
while (1) {
vTaskDelay(pdMS_TO_TICKS(15 * 60 * 1000));
ESP_LOGI("WEATHER", "🌐 a pedir temperatura (loop)");
if (net_weather_update(&temp)) {
ESP_LOGI("WEATHER", "🌡️ temperatura recebida: %.1f", temp);
display_temperature_bottom(temp);
} else {
ESP_LOGE("WEATHER", "❌ net_weather_update falhou");
}
}
}
// ============================
// Task contador simples
// ============================
@ -124,10 +83,6 @@ static void on_wifi_connected(void) {
ESP_LOGI(TAG, "🎬 Iniciando tasks LED e Créditos...");
xTaskCreate(led_task, "led_task", 8192, NULL, 5, NULL);
xTaskCreate(creditos_task, "creditos_task", 8192, NULL, 5, NULL);
// 🌡️ TASK DO TEMPO (AQUI!)
ESP_LOGI(TAG, "🌡️ Iniciando task de temperatura (Open-Meteo)");
xTaskCreate(weather_task, "weather_task", 4096, NULL, 4, NULL);
}
@ -181,37 +136,25 @@ void ht16_test()
i2c_master_write_to_device(I2C_PORT, 0x70, buf, sizeof(buf), 20 / portTICK_PERIOD_MS);
}
//************************************************************** */
void i2c_scan(void)
void i2c_scan()
{
printf("\n--- A fazer scan ao I2C ---\n");
int found = 0;
for (uint8_t addr = 1; addr < 0x7F; addr++) {
// --- SCAN I2C ---
for (uint8_t addr = 1; addr < 127; addr++) {
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, (addr << 1) | I2C_MASTER_WRITE, true);
i2c_master_stop(cmd);
esp_err_t r = i2c_master_cmd_begin(I2C_PORT, cmd, pdMS_TO_TICKS(50));
esp_err_t r = i2c_master_cmd_begin(I2C_PORT, cmd, 20 / portTICK_PERIOD_MS);
i2c_cmd_link_delete(cmd);
if (r == ESP_OK) {
printf("✅ I2C encontrado: 0x%02X\n", addr);
found++;
} else if (r == ESP_ERR_TIMEOUT) {
printf("⏱️ TIMEOUT no addr 0x%02X (bus preso?)\n", addr);
break; // não vale a pena continuar
printf("ENCONTRADO I2C: 0x%02X\n", addr);
}
}
if (!found) {
printf("❌ Nenhum dispositivo I2C encontrado\n");
}
}
// ============================
// MAIN
// ============================
@ -242,25 +185,12 @@ void app_main(void) {
// 1) Inicializa I2C (não aborta)
esp_err_t ei = i2c_init();
if (ei != ESP_OK) {
printf("i2c_init falhou: %s\n", esp_err_to_name(ei));
}
// 2) Scan I2C (ver o que existe no barramento)
i2c_init(); // <- o helper entra aqui
display_init(); // <- inicializa o HT16K33
i2c_scan();
// 3) Inicializa displays SEM abortar (para não rebootar em loop)
esp_err_t ed = display_init();
printf("display_init = %s\n", esp_err_to_name(ed));
// 4) Teste simples no display (se existir)
display_text_top("INIT");
// 🔔 6) buzzer (AQUI!)
buzzer_init();
buzzer_beep(500);
display_text_top("INIT");
// -------- Wi-Fi --------

View File

@ -1,80 +0,0 @@
#include "esp_http_client.h"
#include "esp_log.h"
#include <string.h>
#include <stdlib.h>
#include "buzzer.h"
static const char *TAG = "WEATHER";
static bool parse_temperature_from_json(const char *json, float *out_temp)
{
if (!json || !out_temp) return false;
// 1) ir para o bloco "current"
const char *p = strstr(json, "\"current\"");
if (!p) return false;
// 2) procurar temperature_2m DENTRO de current
p = strstr(p, "\"temperature_2m\"");
if (!p) return false;
// 3) ir para o valor
p = strchr(p, ':');
if (!p) return false;
*out_temp = strtof(p + 1, NULL);
return true;
}
bool net_weather_update(float *out_temp)
{
char buf[512];
esp_http_client_config_t cfg = {
.url = "http://api.open-meteo.com/v1/forecast?latitude=38.75&longitude=-9.125&current=temperature_2m",
.method = HTTP_METHOD_GET,
.transport_type = HTTP_TRANSPORT_OVER_TCP,
.timeout_ms = 10000,
.user_agent = "esp32-weather",
};
ESP_LOGI(TAG, "➡️ HTTP init");
esp_http_client_handle_t client = esp_http_client_init(&cfg);
if (!client) {
ESP_LOGE(TAG, "❌ http_client_init falhou");
return false;
}
esp_err_t err = esp_http_client_open(client, 0);
if (err != ESP_OK) {
ESP_LOGE(TAG, "❌ http_client_open falhou: %s", esp_err_to_name(err));
esp_http_client_cleanup(client);
return false;
}
int content_length = esp_http_client_fetch_headers(client);
ESP_LOGI(TAG, "📦 content-length = %d", content_length);
int len = esp_http_client_read(client, buf, sizeof(buf) - 1);
if (len <= 0) {
ESP_LOGE(TAG, "❌ http_client_read falhou");
esp_http_client_close(client);
esp_http_client_cleanup(client);
return false;
}
buf[len] = 0;
ESP_LOGI(TAG, "📩 JSON: %s", buf);
esp_http_client_close(client);
esp_http_client_cleanup(client);
if (!parse_temperature_from_json(buf, out_temp)) {
ESP_LOGE(TAG, "❌ parse_temperature_from_json falhou");
return false;
}
return true;
}

0
prof
View File

0
run
View File

View File

@ -602,7 +602,7 @@ CONFIG_ESP_EVENT_POST_FROM_IRAM_ISR=y
# ESP HTTP client
#
CONFIG_ESP_HTTP_CLIENT_ENABLE_HTTPS=y
CONFIG_ESP_HTTP_CLIENT_ENABLE_BASIC_AUTH=y
# CONFIG_ESP_HTTP_CLIENT_ENABLE_BASIC_AUTH is not set
# CONFIG_ESP_HTTP_CLIENT_ENABLE_DIGEST_AUTH is not set
# end of ESP HTTP client

View File

@ -317,14 +317,14 @@ CONFIG_ESPTOOLPY_FLASHFREQ_40M=y
# CONFIG_ESPTOOLPY_FLASHFREQ_20M is not set
CONFIG_ESPTOOLPY_FLASHFREQ="40m"
# CONFIG_ESPTOOLPY_FLASHSIZE_1MB is not set
# CONFIG_ESPTOOLPY_FLASHSIZE_2MB is not set
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
CONFIG_ESPTOOLPY_FLASHSIZE_2MB=y
# CONFIG_ESPTOOLPY_FLASHSIZE_4MB is not set
# CONFIG_ESPTOOLPY_FLASHSIZE_8MB is not set
# CONFIG_ESPTOOLPY_FLASHSIZE_16MB is not set
# CONFIG_ESPTOOLPY_FLASHSIZE_32MB is not set
# CONFIG_ESPTOOLPY_FLASHSIZE_64MB is not set
# CONFIG_ESPTOOLPY_FLASHSIZE_128MB is not set
CONFIG_ESPTOOLPY_FLASHSIZE="4MB"
CONFIG_ESPTOOLPY_FLASHSIZE="2MB"
# CONFIG_ESPTOOLPY_HEADER_FLASHSIZE_UPDATE is not set
CONFIG_ESPTOOLPY_BEFORE_RESET=y
# CONFIG_ESPTOOLPY_BEFORE_NORESET is not set

0
sta
View File

3
tatus
View File

@ -1,3 +0,0 @@
c5aeddc (HEAD -> main, tag: portal-top, origin/main, origin/HEAD) chore: ignore vscode settings
0d828ca wifi: portal Wi-Fi top com scan, clear_wifi MQTT e fluxo limpo STA/AP
4d28d62 commit final pc2