{"id":61,"date":"2026-10-10T14:59:21","date_gmt":"2026-10-10T14:59:21","guid":{"rendered":"https:\/\/sfelectronica.com\/bit\/?p=61"},"modified":"2026-10-10T15:06:17","modified_gmt":"2026-10-10T15:06:17","slug":"estacao-termo-estacao-ambiental-redonda-com-esp32-bme280-e-display-gc9a01","status":"publish","type":"post","link":"https:\/\/sfelectronica.com\/bit\/estacao-termo-estacao-ambiental-redonda-com-esp32-bme280-e-display-gc9a01\/","title":{"rendered":"Esta\u00e7\u00e3o Termo: esta\u00e7\u00e3o ambiental redonda com ESP32, BME280 e display GC9A01"},"content":{"rendered":"\n\n\n\n\n<p class=\"hbc-lede wp-block-paragraph\"><strong>A Esta\u00e7\u00e3o Termo<\/strong> mede o ambiente da casa num s\u00f3 s\u00edtio: temperatura, humidade relativa e absoluta, ponto de orvalho, press\u00e3o e altitude, calculadas a partir de um \u00fanico <strong>BME280<\/strong> e apresentadas num <strong>display redondo de 1,28 polegadas<\/strong>. Um <strong>ESP32<\/strong> com <strong>ESPHome<\/strong> desenha tudo, sincroniza a hora com o Home Assistant e apaga o ecr\u00e3 quando ningu\u00e9m est\u00e1 a ver. Tudo local, sem nuvem e sem subscri\u00e7\u00f5es.<\/p>\n\n\n\n<div class=\"hbc-specs\">\n\n\t<div class=\"hbc-specs__item\"><span class=\"hbc-specs__key\">Projeto<\/span><span class=\"hbc-specs__val\">Esta\u00e7\u00e3o Termo (Esta\u00e7\u00e3o RC)<\/span><\/div>\n\n\t<div class=\"hbc-specs__item\"><span class=\"hbc-specs__key\">Hardware<\/span><span class=\"hbc-specs__val\">ESP32 \u00b7 BME280 \u00b7 Display GC9A01 1,28&#8243; \u00b7 Tecla<\/span><\/div>\n\n\t<div class=\"hbc-specs__item\"><span class=\"hbc-specs__key\">Firmware<\/span><span class=\"hbc-specs__val\">ESPHome (min. 2024.6.0)<\/span><\/div>\n\n\t<div class=\"hbc-specs__item\"><span class=\"hbc-specs__key\">Plataforma<\/span><span class=\"hbc-specs__val\">Home Assistant<\/span><\/div>\n\n\t<div class=\"hbc-specs__item\"><span class=\"hbc-specs__key\">Ficheiro<\/span><span class=\"hbc-specs__val\">estacao_termo.yaml<\/span><\/div>\n\n\t<div class=\"hbc-specs__item\"><span class=\"hbc-specs__key\">Rede<\/span><span class=\"hbc-specs__val\">IP est\u00e1tico 192.168.1.238 \u00b7 captive portal<\/span><\/div>\n\n\t<div class=\"hbc-specs__item\"><span class=\"hbc-specs__key\">Nuvem<\/span><span class=\"hbc-specs__val\">Nenhuma \u2014 100% local<\/span><\/div>\n\n<\/div>\n\n\n\n<div class=\"hbc-toc\">\n\n\t<p class=\"hbc-toc__title\">Neste artigo<\/p>\n\n\t<ol>\n\n\t\t<li><a href=\"#visao-geral\">Vis\u00e3o geral do sistema<\/a><\/li>\n\n\t\t<li><a href=\"#hardware\">Hardware e esquema de liga\u00e7\u00e3o<\/a><\/li>\n\n\t\t<li><a href=\"#gpio\">Mapeamento dos GPIO<\/a><\/li>\n\n\t\t<li><a href=\"#yaml\">O YAML, bloco a bloco<\/a><\/li>\n\n\t\t<li><a href=\"#rede\">Rede, gest\u00e3o e atualiza\u00e7\u00f5es<\/a><\/li>\n\n\t\t<li><a href=\"#instalacao\">Instala\u00e7\u00e3o passo a passo<\/a><\/li>\n\n\t\t<li><a href=\"#home-assistant\">No Home Assistant<\/a><\/li>\n\n\t\t<li><a href=\"#diagnostico\">Diagn\u00f3stico e boas pr\u00e1ticas<\/a><\/li>\n\n\t\t<li><a href=\"#conclusao\">Conclus\u00e3o<\/a><\/li>\n\n\t<\/ol>\n\n<\/div>\n\n\n\n<h2 id=\"visao-geral\" class=\"wp-block-heading\">Vis\u00e3o geral do sistema<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">A ideia \u00e9 ter uma <strong>esta\u00e7\u00e3o meteorol\u00f3gica de interior<\/strong> que responda a duas perguntas: como est\u00e1 o ar da casa agora, e o que \u00e9 preciso fazer a respeito disso. Um \u00fanico <strong>BME280<\/strong> d\u00e1 temperatura, press\u00e3o e humidade relativa; o YAML faz o resto \u2014 humidade absoluta em g\/m\u00b3, ponto de orvalho e altitude calculadas a partir desses tr\u00eas valores, sem sensores adicionais.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">O que distingue o projeto n\u00e3o \u00e9 o sensor, \u00e9 a <strong>forma como apresenta os dados<\/strong>: um display redondo de 1,28 polegadas onde o fundo \u00e9 uma imagem desenhada \u00e0 m\u00e3o (setores, \u00edcones, zonas) e o ESPHome escreve apenas os n\u00fameros por cima. O resultado l\u00ea-se de relance \u2014 temperatura em destaque no topo, hora por baixo, humidade \u00e0 esquerda, g\/m\u00b3 e ponto de orvalho \u00e0 direita, press\u00e3o e altitude na base \u2014 com o estado <em>Online\/Offline<\/em> sempre vis\u00edvel.<\/p>\n\n\n\n<ul class=\"wp-block-list hbc-stats\">\n<li><strong>240\u00d7240<\/strong><span> <\/span><span>Display redondo GC9A01A de 1,28&#8243;, SPI a 20\u00a0MHz<\/span><\/li>\n\n\n\n<li><strong>6<\/strong><span> <\/span><span>Grandezas no ecr\u00e3: temperatura, humidade, orvalho, g\/m\u00b3, press\u00e3o e altitude<\/span><\/li>\n\n\n\n<li><strong>60s <\/strong><span>Intervalo de leitura do BME280 (com offset de calibra\u00e7\u00e3o)<\/span><\/li>\n\n\n\n<li><strong>0<\/strong><span> <\/span><span>Servi\u00e7os externos ou depend\u00eancia da nuvem<\/span><\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">O ecr\u00e3 n\u00e3o est\u00e1 sempre ligado: uma <strong>tecla<\/strong> acorda a retroilumina\u00e7\u00e3o a 100%, e depois de 20 segundos o display volta a baixar e a apagar-se sozinho. A retroilumina\u00e7\u00e3o \u00e9 tamb\u00e9m uma entidade <em>light<\/em> no Home Assistant, portanto d\u00e1 para ligar, desligar e regular a luminosidade \u00e0 dist\u00e2ncia \u2014 ou por automa\u00e7\u00e3o, sem tocar em nada.<\/p>\n\n\n\n<h2 id=\"hardware\" class=\"wp-block-heading\">Hardware e esquema de liga\u00e7\u00e3o<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">A lista de materiais \u00e9 curta \u2014 o projeto \u00e9 barato porque \u00e9 essencial:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Placa ESP32<\/strong> (<code>board: esp32dev<\/code>) \u2014 sobram pinos para o SPI, o I\u00b2C, a tecla e a retroilumina\u00e7\u00e3o.<\/li>\n\n\n\n<li><strong>BME280<\/strong> \u2014 temperatura, press\u00e3o e humidade relativa num \u00fanico chip, por I\u00b2C. Cuidado: o <strong>BMP280<\/strong> \u00e9 quase igual e <em>n\u00e3o mede humidade<\/em> \u2014 n\u00e3o confundir as siglas na compra.<\/li>\n\n\n\n<li><strong>Display redondo TENSTAR ROBOT de 1,28&#8243;<\/strong> \u2014 240\u00d7240 pixels, controlador <strong>GC9A01A<\/strong>, interface SPI at\u00e9 20\u00a0MHz, com retroilumina\u00e7\u00e3o pr\u00f3pria.<\/li>\n\n\n\n<li><strong>Tecla<\/strong> de contacto com <em>pull-up<\/em> externo de 10\u00a0k\u03a9 \u2014 o GPIO usado \u00e9 de entrada pura e n\u00e3o tem resist\u00eancias internas.<\/li>\n\n\n\n<li><strong>Dois ficheiros de <em>assets<\/em><\/strong> ao lado do YAML: a imagem de fundo do ecr\u00e3 (<code>icons\/imageround.png<\/code>) e a fonte <code>Helvetica.ttf<\/code>. Sem eles, o ESPHome nem compila.<\/li>\n\n\n\n<li><strong>Fonte 5\u00a0V<\/strong> \u2014 o regulador 3,3\u00a0V da pr\u00f3pria placa alimenta o display e o sensor; CAIXA com janela redonda ou suporte de bancada.<\/li>\n<\/ul>\n\n\n\n<figure class=\"wp-block-figure hbc-screen\"><img decoding=\"async\" src=\"https:\/\/sfelectronica.com\/bit\/wp-content\/uploads\/2026\/10\/estacao-termo-esquema-ligacao.png\" alt=\"Esquema de liga\u00e7\u00e3o da Esta\u00e7\u00e3o Termo: fonte de 5 V, ESP32, BME280 por I\u00b2C, display redondo GC9A01A por SPI, tecla, retroilumina\u00e7\u00e3o e liga\u00e7\u00e3o ao Home Assistant.\" width=\"1200\" height=\"760\" loading=\"lazy\" \/><figcaption>Liga\u00e7\u00e3o completa: ESP32 ao centro, sensor \u00e0 esquerda, display e tecla \u00e0 direita<\/figcaption><\/figure>\n\n\n\n<div class=\"hbc-callout hbc-callout--warn\">\n\t<span class=\"hbc-callout__icon\">!<\/span>\n\t<p><strong>Tr\u00eas erros de bancada que custam uma tarde:<\/strong> alimentar o display a 5&nbsp;V (os m\u00f3dulos GC9A01 queimam \u2014 usa o 3,3&nbsp;V da placa); esquecer o <em>pull-up<\/em> da tecla no <code>GPIO35<\/code>, que \u00e9 <em>input-only<\/em> e n\u00e3o tem resist\u00eancia interna; e montar o BME280 coladinho ao ESP32, onde l\u00ea sempre 2\u20133&nbsp;\u00b0C a mais.<\/p>\n<\/div>\n\n\n\n<h2 id=\"gpio\" class=\"wp-block-heading\">Mapeamento dos GPIO<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Nove pinos em uso, divididos por barramentos \u2014 SPI para o ecr\u00e3, I\u00b2C para o sensor e dois pinos avulsos para a retroilumina\u00e7\u00e3o e a tecla:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table><thead><tr><th>Sinal<\/th><th>GPIO<\/th><th>Dire\u00e7\u00e3o<\/th><th>Fun\u00e7\u00e3o<\/th><\/tr><\/thead><tbody><tr><td><strong>SPI MOSI<\/strong><\/td><td>GPIO27<\/td><td>Sa\u00edda<\/td><td>Dados do display (sem MISO \u2014 \u00e9 write-only)<\/td><\/tr><tr><td><strong>SPI CLK<\/strong><\/td><td>GPIO14<\/td><td>Sa\u00edda<\/td><td>Clock SPI a 20&nbsp;MHz<\/td><\/tr><tr><td><strong>SPI CS<\/strong><\/td><td>GPIO33<\/td><td>Sa\u00edda<\/td><td>Chip select do GC9A01A<\/td><\/tr><tr><td><strong>SPI DC<\/strong><\/td><td>GPIO25<\/td><td>Sa\u00edda<\/td><td>Distin\u00e7\u00e3o dados\/comandos<\/td><\/tr><tr><td><strong>SPI RST<\/strong><\/td><td>GPIO26<\/td><td>Sa\u00edda<\/td><td>Reset do controlador<\/td><\/tr><tr><td><strong>I\u00b2C SDA<\/strong><\/td><td>GPIO21<\/td><td>Bidirecional<\/td><td>BME280 (endere\u00e7o 0x76)<\/td><\/tr><tr><td><strong>I\u00b2C SCL<\/strong><\/td><td>GPIO22<\/td><td>Sa\u00edda<\/td><td>Rel\u00f3gio do barramento<\/td><\/tr><tr><td><strong>Backlight<\/strong><\/td><td>GPIO32<\/td><td>Sa\u00edda PWM (LEDC)<\/td><td>Retroilumina\u00e7\u00e3o \u2014 entidade <em>light<\/em><\/td><\/tr><tr><td><strong>Tecla<\/strong><\/td><td>GPIO35<\/td><td>Entrada (<em>inverted<\/em>)<\/td><td>Acorda e apaga o ecr\u00e3<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">N\u00e3o h\u00e1 fio MISO no SPI porque o display nunca devolve dados: escreve e cala-se, o que tamb\u00e9m permite correr o barramento ao ritmo m\u00e1ximo sem seguran\u00e7as. O I\u00b2C \u00e9 o cl\u00e1ssico <code>SDA 21<\/code> \/ <code>SCL 22<\/code> com <code>scan: true<\/code>, para que o endere\u00e7o apare\u00e7a no log na primeira arrancada.<\/p>\n\n\n\n<h2 id=\"yaml\" class=\"wp-block-heading\">O YAML, bloco a bloco<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">O <code>estacao_termo.yaml<\/code> separa-se bem: primeiro o ecr\u00e3, depois os sensores, depois as contas e por fim a retroilumina\u00e7\u00e3o. Estes s\u00e3o os excertos que interessam:<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">O display redondo: GC9A01A sobre SPI<\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">spi:\n  mosi_pin: GPIO27\n  clk_pin: GPIO14\n\nspi_device:\n  id: spidev\n  data_rate: <span class=\"hljs-number\">20<\/span>MHz\n\ndisplay:\n  - platform: ili9xxx\n    model: gc9a01a\n    invert_colors: <span class=\"hljs-keyword\">true<\/span>\n    auto_clear_enabled: <span class=\"hljs-keyword\">false<\/span>\n    id: gca901_display\n    cs_pin: GPIO33\n    dc_pin: GPIO25\n    reset_pin: GPIO26\n    rotation: <span class=\"hljs-number\">180<\/span>\n    lambda: |-\n      it.image(<span class=\"hljs-number\">0<\/span>, <span class=\"hljs-number\">0<\/span>, id(img_back));\n\n      it.strftime(<span class=\"hljs-number\">33<\/span>, <span class=\"hljs-number\">65<\/span>, id(helvetica_18), id(my_green), TextAlign::LEFT,\n                  <span class=\"hljs-string\">\"%Y-%m-%d  %H:%M:%S\"<\/span>, id(esptime).now());\n\n      it.printf(<span class=\"hljs-number\">97<\/span>, <span class=\"hljs-number\">25<\/span>, id(helvetica_24), <span class=\"hljs-string\">\"%.1f \u00b0C\"<\/span>, id(bme280_temperature).state);\n      it.printf(<span class=\"hljs-number\">46<\/span>, <span class=\"hljs-number\">112<\/span>, id(helvetica_24), <span class=\"hljs-string\">\"%.1f %%\"<\/span>, id(bme280_humidity).state);\n\n      <span class=\"hljs-keyword\">if<\/span> (id(system_status).state) {\n        it.<span class=\"hljs-keyword\">print<\/span>(<span class=\"hljs-number\">135<\/span>, <span class=\"hljs-number\">1<\/span>, id(helvetica_12), id(my_green), TextAlign::TOP_RIGHT, <span class=\"hljs-string\">\"Online\"<\/span>);\n      } <span class=\"hljs-keyword\">else<\/span> {\n        it.<span class=\"hljs-keyword\">print<\/span>(<span class=\"hljs-number\">135<\/span>, <span class=\"hljs-number\">1<\/span>, id(helvetica_12), id(my_red), TextAlign::TOP_RIGHT, <span class=\"hljs-string\">\"Offline\"<\/span>);\n      }<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div class=\"hbc-callout hbc-callout--tip\">\n\t<span class=\"hbc-callout__icon\">OK<\/span>\n\t<p><strong>Porqu\u00ea <code>auto_clear_enabled: false<\/code>?<\/strong> Porque o fundo do ecr\u00e3 \u00e9 uma imagem que n\u00e3o muda: em vez de o ESPHome limpar o buffer a cada <em>refresh<\/em> e voltar a desenhar tudo (vis\u00edvel como um relampejo), mant\u00e9m-se o buffer e escrevem-se apenas os n\u00fameros que mudam. Menos trabalho de CPU, ecr\u00e3 mais est\u00e1vel \u2014 e \u00e9 por isso que a <code>lambda<\/code> come\u00e7a sempre com <code>it.image(...)<\/code>.<\/p>\n<\/div>\n\n\n\n<p class=\"wp-block-paragraph\">As restantes linhas do ecr\u00e3 seguem o mesmo padr\u00e3o \u2014 press\u00e3o em (20,&nbsp;160), altitude em (135,&nbsp;160), humidade absoluta em (160,&nbsp;105) e ponto de orvalho em (160,&nbsp;130) \u2014 todas com <code>it.printf<\/code> e as coordenadas afinadas para assentar nas zonas do fundo.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">O fundo \u00e9 uma imagem, n\u00e3o c\u00f3digo<\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">image:\n  - file: <span class=\"hljs-string\">\"icons\/imageround.png\"<\/span>\n    id: img_back\n    type: RGB\n    transparency: alpha_channel\n\nfont:\n  - file: <span class=\"hljs-string\">\"Helvetica.ttf\"<\/span>\n    id: helvetica_24\n    size: <span class=\"hljs-number\">24<\/span>\n  <span class=\"hljs-comment\"># helvetica_18, helvetica_14 e helvetica_12 no mesmo padr\u00e3o<\/span>\n\ncolor:\n  - id: my_green\n    red: <span class=\"hljs-number\">0<\/span>%\n    green: <span class=\"hljs-number\">100<\/span>%\n    blue: <span class=\"hljs-number\">0<\/span>%\n  <span class=\"hljs-comment\"># my_red, my_yellow, my_blue e my_gray no mesmo padr\u00e3o<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">A imagem de fundo traz os setores, os \u00edcones (term\u00f3metro, gota, montanha, b\u00fassola) e as molduras prontas \u2014 o ESPHome s\u00f3 recebe a tarefa de p\u00f4r o texto certo em cada zona. Fazer o desenho num editor e deixar ao firmware apenas os n\u00fameros \u00e9 muito mais simples do que tentar construir a interface toda com <code>it.line()<\/code> e <code>it.rectangle()<\/code>.<\/p>\n\n\n\n<figure class=\"wp-block-figure hbc-screen\"><img decoding=\"async\" src=\"https:\/\/sfelectronica.com\/bit\/wp-content\/uploads\/2026\/10\/estacao-termo-inline-1.png\" alt=\"Ecr\u00e3 da Esta\u00e7\u00e3o Termo: imagem de fundo com temperatura, humidade, ponto de orvalho, humidade absoluta, press\u00e3o, altitude, data e hora.\" width=\"240\" height=\"240\" loading=\"lazy\" \/><figcaption>O resultado no ecr\u00e3: imagem de fundo com os valores do BME280 escritos por cima<\/figcaption><\/figure>\n\n\n\n<div class=\"hbc-callout hbc-callout--tip\">\n\t<span class=\"hbc-callout__icon\">OK<\/span>\n\t<p>O ficheiro de imagem tem de ficar na pasta do projeto, em <code>icons\/imageround.png<\/code>, e a fonte em <code>Helvetica.ttf<\/code> ao lado do YAML \u2014 o ESPHome copia ambos para a placa na compila\u00e7\u00e3o. Se mudares o fundo, mant\u00e9m a mesma janela circular de 240\u00d7240 e refaz s\u00f3 as coordenadas do texto.<\/p>\n<\/div>\n\n\n\n<h3 class=\"wp-block-heading\">O BME280 e o que ele d\u00e1 de borla<\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">i2c:\n  sda: <span class=\"hljs-number\">21<\/span>\n  <span class=\"hljs-attr\">scl<\/span>: <span class=\"hljs-number\">22<\/span>\n  <span class=\"hljs-attr\">scan<\/span>: <span class=\"hljs-literal\">true<\/span>\n  <span class=\"hljs-attr\">id<\/span>: bus_a\n\n<span class=\"hljs-attr\">sensor<\/span>:\n  - platform: bme280_i2c\n    <span class=\"hljs-attr\">temperature<\/span>:\n      name: <span class=\"hljs-string\">\"BME Temperatura\"<\/span>\n      <span class=\"hljs-attr\">oversampling<\/span>: <span class=\"hljs-number\">1<\/span>x\n      <span class=\"hljs-attr\">filters<\/span>:\n        - offset: <span class=\"hljs-number\">-2<\/span>\n      <span class=\"hljs-attr\">id<\/span>: bme280_temperature\n    <span class=\"hljs-attr\">pressure<\/span>:\n      name: <span class=\"hljs-string\">\"BME Press\u00e3o\"<\/span>\n      <span class=\"hljs-attr\">oversampling<\/span>: <span class=\"hljs-number\">1<\/span>x\n      <span class=\"hljs-attr\">id<\/span>: bme280_pressure\n    <span class=\"hljs-attr\">humidity<\/span>:\n      name: <span class=\"hljs-string\">\"BME280 Humidade Relativa\"<\/span>\n      <span class=\"hljs-attr\">oversampling<\/span>: <span class=\"hljs-number\">1<\/span>x\n      <span class=\"hljs-attr\">id<\/span>: bme280_humidity\n    <span class=\"hljs-attr\">address<\/span>: <span class=\"hljs-number\">0x76<\/span>\n    <span class=\"hljs-attr\">update_interval<\/span>: <span class=\"hljs-number\">60<\/span>s<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Tr\u00eas valores por um chip s\u00f3, com <code>oversampling: 1x<\/code> para leituras r\u00e1pidas e um <code>offset: \u22122<\/code> aplicado \u00e0 temperatura \u2014 o suficiente para corrigir o calor que o pr\u00f3prio m\u00f3dulo devolve. O endere\u00e7o <code>0x76<\/code> \u00e9 o do m\u00f3dulo em quest\u00e3o; muitos BME280 v\u00eam de f\u00e1brica em <code>0x77<\/code>, por isso vale a pena deixar o <code>scan: true<\/code> ligado pelo menos na primeira arrancada.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Grandezas derivadas: altitude, g\/m\u00b3 e ponto de orvalho<\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">sensor:\n  - platform: template\n    <span class=\"hljs-attr\">name<\/span>: <span class=\"hljs-string\">\"Altitude\"<\/span>\n    <span class=\"hljs-attr\">id<\/span>: bme_altitude\n    <span class=\"hljs-attr\">lambda<\/span>: |-\n      <span class=\"hljs-keyword\">const<\/span> float STANDARD_SEA_LEVEL_PRESSURE = <span class=\"hljs-number\">1013.25<\/span>; <span class=\"hljs-comment\">\/\/ em hPa<\/span>\n      <span class=\"hljs-keyword\">return<\/span> ((id(bme280_temperature).state + <span class=\"hljs-number\">273.15<\/span>) \/ <span class=\"hljs-number\">0.0065<\/span>) *\n        (powf((STANDARD_SEA_LEVEL_PRESSURE \/ id(bme280_pressure).state), <span class=\"hljs-number\">0.190234<\/span>) - <span class=\"hljs-number\">1<\/span>);\n    update_interval: <span class=\"hljs-number\">60<\/span>s\n    <span class=\"hljs-attr\">unit_of_measurement<\/span>: <span class=\"hljs-string\">'m'<\/span>\n    <span class=\"hljs-attr\">icon<\/span>: <span class=\"hljs-string\">'mdi:signal'<\/span>\n\n  - platform: absolute_humidity\n    <span class=\"hljs-attr\">name<\/span>: <span class=\"hljs-string\">\"Humidade Absoluta\"<\/span>\n    <span class=\"hljs-attr\">id<\/span>: bme_humidadeabs\n    <span class=\"hljs-attr\">temperature<\/span>: bme280_temperature\n    <span class=\"hljs-attr\">humidity<\/span>: bme280_humidity\n\n  - platform: template\n    <span class=\"hljs-attr\">name<\/span>: <span class=\"hljs-string\">\"Ponto Orvalho\"<\/span>\n    <span class=\"hljs-attr\">id<\/span>: bme_orvalho\n    <span class=\"hljs-attr\">lambda<\/span>: |-\n      <span class=\"hljs-keyword\">return<\/span> (<span class=\"hljs-number\">243.5<\/span>*(log(id(bme280_humidity).state\/<span class=\"hljs-number\">100<\/span>)+((<span class=\"hljs-number\">17.67<\/span>*id(bme280_temperature).state)\/\n      (<span class=\"hljs-number\">243.5<\/span>+id(bme280_temperature).state)))\/(<span class=\"hljs-number\">17.67<\/span>-log(id(bme280_humidity).state\/<span class=\"hljs-number\">100<\/span>)-\n      ((<span class=\"hljs-number\">17.67<\/span>*id(bme280_temperature).state)\/(<span class=\"hljs-number\">243.5<\/span>+id(bme280_temperature).state))));\n    unit_of_measurement: \u00b0C\n    <span class=\"hljs-attr\">icon<\/span>: <span class=\"hljs-string\">'mdi:thermometer-alert'<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div class=\"hbc-callout\">\n\t<span class=\"hbc-callout__icon\">i<\/span>\n\t<p><strong>Porque o ponto de orvalho?<\/strong> \u00c9 a temperatura a que o ar satura e a \u00e1gua passa a condensar \u2014 janelas molhadas de manh\u00e3, espelhos emba\u00e7ados, bolor nos cantos. Se a temperatura de uma superf\u00edcie ficar <em>abaixo<\/em> do ponto de orvalho medido, a\u00ed \u00e9 que a condensa\u00e7\u00e3o acontece. \u00c9 a grandeza que transforma um mostrador bonito numa ferramenta \u00fatil, e sai de gra\u00e7a das mesmas duas medi\u00e7\u00f5es. O mesmo com a humidade absoluta em g\/m\u00b3: \u00e9 ela que diz quanto \u00e9 que o ar realmente leva de \u00e1gua, independentemente da temperatura.<\/p>\n<\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Retroilumina\u00e7\u00e3o e tecla<\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">output:\n  - platform: ledc\n    <span class=\"hljs-attr\">pin<\/span>: GPIO32\n    <span class=\"hljs-attr\">id<\/span>: backlight\n\n<span class=\"hljs-attr\">light<\/span>:\n  - platform: monochromatic\n    <span class=\"hljs-attr\">output<\/span>: backlight\n    <span class=\"hljs-attr\">name<\/span>: <span class=\"hljs-string\">\"Backlight\"<\/span>\n    <span class=\"hljs-attr\">id<\/span>: luzback\n\n<span class=\"hljs-attr\">binary_sensor<\/span>:\n  - platform: status\n    <span class=\"hljs-attr\">name<\/span>: <span class=\"hljs-string\">\"Node Status\"<\/span>\n    <span class=\"hljs-attr\">id<\/span>: system_status\n  - platform: gpio\n    <span class=\"hljs-attr\">pin<\/span>:\n      number: GPIO35\n      <span class=\"hljs-attr\">inverted<\/span>: <span class=\"hljs-literal\">true<\/span>\n    <span class=\"hljs-attr\">name<\/span>: <span class=\"hljs-string\">\"Tecla\"<\/span>\n    <span class=\"hljs-attr\">id<\/span>: tdisplay_button_input_1\n    <span class=\"hljs-attr\">on_click<\/span>:\n      then:\n        - light.turn_on:\n            id: luzback\n            <span class=\"hljs-attr\">brightness<\/span>: <span class=\"hljs-number\">100<\/span>%\n            transition_length: <span class=\"hljs-number\">2<\/span>s\n        - delay: <span class=\"hljs-number\">20<\/span>s\n        - light.turn_on:\n            id: luzback\n            <span class=\"hljs-attr\">brightness<\/span>: <span class=\"hljs-number\">15<\/span>%\n            transition_length: <span class=\"hljs-number\">60<\/span>s<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">O truque \u00e9 o LEDC: o mesmo GPIO que alimenta a retroilumina\u00e7\u00e3o \u00e9 gerido como uma entidade <em>light<\/em>, o que d\u00e1 tr\u00eas coisas de uma vez \u2014 brilho regul\u00e1vel no Home Assistant, transi\u00e7\u00f5es suaves e uma sequ\u00eancia por automa\u00e7\u00e3o. Aqui a sequ\u00eancia \u00e9 simples: um clique acende a 100% com transi\u00e7\u00e3o de 2 s e, 20 segundos depois, o ecr\u00e3 come\u00e7a a baixar e a apagar-se \u2014 sem ningu\u00e9m precisar de se lembrar de o desligar.<\/p>\n\n\n\n<div class=\"hbc-callout hbc-callout--tip\">\n\t<span class=\"hbc-callout__icon\">OK<\/span>\n\t<p><strong>Nota de implementa\u00e7\u00e3o:<\/strong> no ficheiro original a sequ\u00eancia termina com um <code>light.turn_off<\/code> imediatamente a seguir ao fade de 60&nbsp;s, o que o corta antes de terminar. Se quiseres que o ecr\u00e3 afade at\u00e9 0 ao longo de um minuto, remove o <code>turn_off<\/code> e deixa s\u00f3 o <code>light.turn_on<\/code> com <code>brightness: 0%<\/code> e <code>transition_length: 60s<\/code>.<\/p>\n<\/div>\n\n\n\n<h2 id=\"rede\" class=\"wp-block-heading\">Rede, gest\u00e3o e atualiza\u00e7\u00f5es<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Como nos outros projetos deste blog, a esta\u00e7\u00e3o vive inteiramente na rede local:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>IP est\u00e1tico<\/strong> \u2014 <code>192.168.1.238<\/code>, com <em>gateway<\/em> e DNS em <code>192.168.1.254<\/code>. O endere\u00e7o nunca muda, o que torna o dispositivo previs\u00edvel para automa\u00e7\u00f5es e para o <em>web server<\/em>.<\/li>\n\n\n\n<li><strong>Captive portal<\/strong> \u2014 configur\u00e1vel por telem\u00f3vel se o Wi-Fi n\u00e3o estiver presente (com a ressalva do ponto seguinte).<\/li>\n\n\n\n<li><strong>Improv Serial<\/strong> \u2014 provisionamento de Wi-Fi pela porta s\u00e9rie, a primeira vez ou depois de um reset.<\/li>\n\n\n\n<li><strong>OTA<\/strong> \u2014 atualiza\u00e7\u00f5es sem cabo, direto do ESPHome no Home Assistant.<\/li>\n\n\n\n<li><strong>Web Server<\/strong> \u2014 p\u00e1gina local com sensores e logs, \u00fatil para diagn\u00f3stico sem abrir o HA.<\/li>\n\n\n\n<li><strong>API nativo<\/strong> \u2014 liga\u00e7\u00e3o direta ao Home Assistant, incluindo o rel\u00f3gio usado no ecr\u00e3.<\/li>\n\n\n\n<li><strong>dashboard_import<\/strong> \u2014 o dispositivo pode ser importado como pacote no ESPHome Dashboard.<\/li>\n<\/ul>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">wifi<\/span>:\n  <span class=\"hljs-selector-tag\">ssid<\/span>: <span class=\"hljs-selector-tag\">SF_24E<\/span>\n  <span class=\"hljs-selector-tag\">password<\/span>: \"\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\"\n  <span class=\"hljs-selector-tag\">manual_ip<\/span>:\n    <span class=\"hljs-selector-tag\">static_ip<\/span>: 192<span class=\"hljs-selector-class\">.168<\/span><span class=\"hljs-selector-class\">.1<\/span><span class=\"hljs-selector-class\">.238<\/span>\n    <span class=\"hljs-selector-tag\">gateway<\/span>: 192<span class=\"hljs-selector-class\">.168<\/span><span class=\"hljs-selector-class\">.1<\/span><span class=\"hljs-selector-class\">.254<\/span>\n    <span class=\"hljs-selector-tag\">subnet<\/span>: 255<span class=\"hljs-selector-class\">.255<\/span><span class=\"hljs-selector-class\">.255<\/span><span class=\"hljs-selector-class\">.0<\/span>\n    <span class=\"hljs-selector-tag\">dns1<\/span>: 192<span class=\"hljs-selector-class\">.168<\/span><span class=\"hljs-selector-class\">.1<\/span><span class=\"hljs-selector-class\">.254<\/span>\n  <span class=\"hljs-selector-id\">#ap<\/span>: {}\n\n<span class=\"hljs-selector-tag\">captive_portal<\/span>:\n\n<span class=\"hljs-selector-tag\">web_server<\/span>:\n\n<span class=\"hljs-selector-tag\">ota<\/span>:\n  <span class=\"hljs-selector-tag\">-<\/span> <span class=\"hljs-selector-tag\">platform<\/span>: <span class=\"hljs-selector-tag\">esphome<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div class=\"hbc-callout hbc-callout--warn\">\n\t<span class=\"hbc-callout__icon\">!<\/span>\n\t<p><strong>Duas notas de rede:<\/strong> o Access Point de emerg\u00eancia est\u00e1 <strong>comentado<\/strong> (<code>#ap: {}<\/code>) \u2014 sem ele, o <code>captive_portal<\/code> n\u00e3o tem por onde servir a p\u00e1gina de configura\u00e7\u00e3o e, se trocares de router ou mudares a palavra-passe, s\u00f3 recuperas o dispositivo por USB ou pela porta s\u00e9rie. E a palavra-passe do Wi-Fi est\u00e1 em texto no ficheiro: mant\u00e9m o <code>estacao_termo.yaml<\/code> fora de reposit\u00f3rios p\u00fablicos e define <code>api: encryption_key<\/code> e <code>ota: password<\/code> antes de o publicares.<\/p>\n<\/div>\n\n\n\n<h2 id=\"instalacao\" class=\"wp-block-heading\">Instala\u00e7\u00e3o passo a passo<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Do ficheiro em branco \u00e0 esta\u00e7\u00e3o montada, em seis passos:<\/p>\n\n\n\n<ol class=\"wp-block-list hbc-steps\">\n<li><strong>Junta os <em>assets<\/em>.<\/strong> Cria a pasta <code>icons\/<\/code> ao lado do <code>estacao_termo.yaml<\/code>, mete l\u00e1 o <code>imageround.png<\/code> e copia o <code>Helvetica.ttf<\/code> para a raiz do projeto. Sem estes dois ficheiros, a compila\u00e7\u00e3o falha antes de chegar ao resto.<\/li>\n\n\n\n<li><strong>Liga a fia\u00e7\u00e3o.<\/strong> Display por SPI (5 fios + 3,3\u00a0V e GND), BME280 por I\u00b2C (2 fios + 3,3\u00a0V e GND) e tecla entre o GPIO35 e o GND, com o <em>pull-up<\/em> de 10\u00a0k\u03a9 para os 3,3\u00a0V.<\/li>\n\n\n\n<li><strong>Grava e confirma o barramento.<\/strong> Adiciona o dispositivo no ESPHome, ajusta SSID, palavra-passe e IP e envia. No log, procura a linha do <code>i2c scan<\/code> \u2014 tem de l\u00e1 estar o <code>0x76<\/code>.<\/li>\n\n\n\n<li><strong>Aceita no Home Assistant.<\/strong> Surgem no minuto seguinte seis sensores, o <em>light<\/em> da retroilumina\u00e7\u00e3o, a tecla e o estado do n\u00f3.<\/li>\n\n\n\n<li><strong>Calibra.<\/strong> Compara a temperatura com um term\u00f3metro de refer\u00eancia e ajusta o <code>offset<\/code>; se a altitude der errada, troca os 1013,25\u00a0hPa do padr\u00e3o pela press\u00e3o m\u00e9dia do teu local.<\/li>\n\n\n\n<li><strong>Monta e testa.<\/strong> BME280 afastado do calor do ESP32, display \u00e0 vista e tecla acess\u00edvel. Clica: o ecr\u00e3 acende, e sozinho apaga-se passados os 20 segundos.<\/li>\n<\/ol>\n\n\n\n<h2 id=\"home-assistant\" class=\"wp-block-heading\">No Home Assistant<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">A esta\u00e7\u00e3o n\u00e3o \u00e9 um gadget que s\u00f3 serve para olhar: cada valor que aparece no ecr\u00e3 \u00e9 uma entidade no Home Assistant, pronta para gr\u00e1ficos, automa\u00e7\u00f5es e alertas.<\/p>\n\n\n\n<div class=\"hbc-features\">\n\n\t<div class=\"hbc-feature\">\n\t\t<span class=\"hbc-feature__num\">01<\/span>\n\t\t<h3 class=\"hbc-feature__title\">Seis sensores, uma entidade de estado<\/h3>\n\t\t<p><em>BME Temperatura<\/em>, <em>BME Press\u00e3o<\/em>, <em>BME280 Humidade Relativa<\/em>, <em>Altitude<\/em>, <em>Humidade Absoluta<\/em> e <em>Ponto Orvalho<\/em> \u2014 mais <em>Wifi signal<\/em>, <em>Uptime<\/em> e <em>Node Status<\/em> para diagn\u00f3stico. \u00c9 o suficiente para montar um cart\u00e3o de ambiente completo sem comprar mais nada.<\/p>\n\t<\/div>\n\n\t<div class=\"hbc-feature\">\n\t\t<span class=\"hbc-feature__num\">02<\/span>\n\t\t<h3 class=\"hbc-feature__title\">A retroilumina\u00e7\u00e3o \u00e9 uma luz<\/h3>\n\t\t<p>A entidade <strong>light.backlight<\/strong> aceita brilho como qualquer l\u00e2mpada inteligente. D\u00e1 para a ligar quando algu\u00e9m entra na sala, a escurecer \u00e0 noite ou a acender quando a humidade passa de um limite \u2014 sem escrever uma linha no ESPHome.<\/p>\n\t<\/div>\n\n\t<div class=\"hbc-feature\">\n\t\t<span class=\"hbc-feature__num\">03<\/span>\n\t\t<h3 class=\"hbc-feature__title\">A hora no ecr\u00e3 vem do HA<\/h3>\n\t\t<p>O <code>time<\/code> usa a plataforma <code>homeassistant<\/code>: o rel\u00f3gio do display \u00e9 o mesmo do HA, sem NTP e sem desvios entre o que o ecr\u00e3 mostra e o que as automa\u00e7\u00f5es registam no logbook.<\/p>\n\t<\/div>\n\n\t<div class=\"hbc-feature\">\n\t\t<span class=\"hbc-feature__num\">04<\/span>\n\t\t<h3 class=\"hbc-feature__title\">Estado vis\u00edvel e p\u00e1gina web local<\/h3>\n\t\t<p>O <em>Online\/Offline<\/em> no canto do ecr\u00e3 \u00e9 a entidade <code>status<\/code>, e o <em>web server<\/em> do ESPHome permite abrir <code>192.168.1.238<\/code> no browser e ver sensores e logs mesmo quando o Home Assistant est\u00e1 em manuten\u00e7\u00e3o.<\/p>\n\t<\/div>\n\n<\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Automa\u00e7\u00f5es que valem a pena<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Alerta de condensa\u00e7\u00e3o<\/strong> \u2014 se o <em>Ponto Orvalho<\/em> subir acima de uma temperatura de refer\u00eancia (paredes frias, vidros), notifica\u00e7\u00e3o para arejar ou ligar o exaustor.<\/li>\n\n\n\n<li><strong>Conforto de humidade<\/strong> \u2014 abaixo de 35% avisa para ar seco; acima de 65%, sugere ventila\u00e7\u00e3o antes de o bolor aparecer.<\/li>\n\n\n\n<li><strong>Backlight autom\u00e1tico<\/strong> \u2014 liga o ecr\u00e3 \u00e0 hora de acordar e apaga-o \u00e0 noite, em vez de esperar pelo clique da tecla.<\/li>\n\n\n\n<li><strong>Hist\u00f3rico do ar<\/strong> \u2014 exporta temperatura, humidade e orvalho para InfluxDB\/Grafana e tens a curva do inverno inteiro, com a condensa\u00e7\u00e3o a aparecer nos gr\u00e1ficos antes de aparecer nas janelas.<\/li>\n<\/ul>\n\n\n\n<h2 id=\"diagnostico\" class=\"wp-block-heading\">Diagn\u00f3stico e boas pr\u00e1ticas<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Se algo n\u00e3o bater certo, estes seis pontos cobrem os problemas reais deste projeto:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>O ecr\u00e3 fica preto ou com as cores trocadas.<\/strong> Confirma os 3,3\u00a0V, os cinco fios SPI e os pinos <code>cs_pin<\/code>, <code>dc_pin<\/code> e <code>reset_pin<\/code>. Se aparecer a imagem mas invertida, mexe em <code>invert_colors<\/code> e <code>rotation<\/code> \u2014 o m\u00f3dulo montado de cabe\u00e7a para baixo precisa dos 180\u00b0.<\/li>\n\n\n\n<li><strong><code>Communication with BME280 failed<\/code> no log.<\/strong> O endere\u00e7o padr\u00e3o do ESPHome \u00e9 <code>0x77<\/code> e o do m\u00f3dulo pode ser <code>0x76<\/code> (ou vice-versa); l\u00ea a sa\u00edda do <code>scan: true<\/code> e corrige. Verifica tamb\u00e9m as resist\u00eancias de <em>pull-up<\/em> no SDA\/SCL e, em modo I\u00b2C, que o pino CSB do chip est\u00e1 nos 3,3\u00a0V.<\/li>\n\n\n\n<li><strong>A temperatura l\u00ea sempre alta.<\/strong> \u00c9 o cl\u00e1ssico <em>self-heating<\/em>: o BME280 perto do ESP32 e da fonte. Afasta-o alguns cent\u00edmetros, mede contra um term\u00f3metro de refer\u00eancia e afina o <code>offset<\/code> em vez de acreditar no n\u00famero que sai da caixa.<\/li>\n\n\n\n<li><strong>A altitude d\u00e1 0\u00a0m.<\/strong> A f\u00f3rmula divide pela press\u00e3o: se o sensor de press\u00e3o estiver em <code>NAN<\/code>, o resultado cai a zero. Confirma a entidade <code>id(bme280_pressure)<\/code> e, se for de prop\u00f3sito, ajusta o <code>STANDARD_SEA_LEVEL_PRESSURE<\/code> \u00e0 press\u00e3o m\u00e9dia do teu local.<\/li>\n\n\n\n<li><strong>A tecla n\u00e3o acorda o ecr\u00e3.<\/strong> O <code>GPIO35<\/code> \u00e9 de entrada pura, sem <em>pull-up<\/em> interno: sem a resist\u00eancia externa de 10\u00a0k\u03a9, o pino flutua e o <code>inverted: true<\/code> nunca dispara.<\/li>\n\n\n\n<li><strong>A compila\u00e7\u00e3o falha \u00e0 procura de <code>icons\/imageround.png<\/code> ou de <code>Helvetica.ttf<\/code>.<\/strong> Os caminhos s\u00e3o relativos \u00e0 pasta do projeto do ESPHome \u2014 confirma a estrutura antes de suspeitar do YAML.<\/li>\n<\/ol>\n\n\n\n<div class=\"hbc-callout hbc-callout--tip\">\n\t<span class=\"hbc-callout__icon\">OK<\/span>\n\t<p>O <em>backup<\/em> deste projeto s\u00e3o <strong>tr\u00eas coisas<\/strong>: o <code>estacao_termo.yaml<\/code>, o <code>imageround.png<\/code> e o <code>Helvetica.ttf<\/code>. Guarda os tr\u00eas juntos \u2014 recuperar a esta\u00e7\u00e3o noutro ESP32 \u00e9 s\u00f3 copiar a pasta e gravar.<\/p>\n<\/div>\n\n\n\n<h2 id=\"conclusao\" class=\"wp-block-heading\">Conclus\u00e3o<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">A <strong>Esta\u00e7\u00e3o Termo<\/strong> prova que um mostrador de ambiente n\u00e3o precisa de ser um ecr\u00e3 retangular com n\u00fameros empilhados: com um display redondo de poucos euros, uma imagem de fundo bem desenhada e a <em>lambda<\/em> certa, obt\u00e9m-se um painel que se l\u00ea de relance e que qualquer pessoa em casa sabe interpretar \u2014 temperatura, humidade, hora e basta.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Por baixo da capa est\u00e1 o que interessa: um BME280 a medir de 60 em 60 segundos, tr\u00eas grandezas calculadas no pr\u00f3prio firmware, retroilumina\u00e7\u00e3o que se apaga sozinha e todas as entidades no Home Assistant para as automa\u00e7\u00f5es que forem precisas. \u00c9 replic\u00e1vel ao fim de uma tarde \u2014 copia o <code>estacao_termo.yaml<\/code>, mete os dois <em>assets<\/em> na pasta certa e ajusta o <code>offset<\/code> ao teu caso. Tudo local, tudo teu.<\/p>\n\n\n\n<div class=\"hbc-cta\">\n\t<h3>Quer montar o teu?<\/h3>\n\t<p>A documenta\u00e7\u00e3o do ESPHome cobre o controlador GC9A01, o sensor BME280 e o componente de imagem \u2014 e o YAML deste artigo serve de ponto de partida.<\/p>\n\t<div class=\"hbc-cta__actions\">\n\t\t<a class=\"holo-btn\" href=\"https:\/\/esphome.io\/components\/display\/ili9xxx.html\" target=\"_blank\" rel=\"noopener\">ESPHome \u00b7 ILI9xxx \/ GC9A01<\/a>\n\t\t<a class=\"holo-btn\" href=\"https:\/\/esphome.io\/components\/sensor\/bme280.html\" target=\"_blank\" rel=\"noopener\">ESPHome \u00b7 BME280<\/a>\n\t\t<a class=\"holo-btn\" href=\"https:\/\/esphome.io\/components\/image.html\" target=\"_blank\" rel=\"noopener\">ESPHome \u00b7 Imagens<\/a>\n\t<\/div>\n<\/div>\n\n\n","protected":false},"excerpt":{"rendered":"","protected":false},"author":1,"featured_media":73,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"pagelayer_contact_templates":[],"_pagelayer_content":"","footnotes":""},"categories":[12,5],"tags":[16,21,22,17,13,23],"class_list":["post-61","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-esphome","category-home-assistant","tag-automacao","tag-bme280","tag-display","tag-esp32","tag-esphome","tag-gc9a01"],"_links":{"self":[{"href":"https:\/\/sfelectronica.com\/bit\/wp-json\/wp\/v2\/posts\/61","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/sfelectronica.com\/bit\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/sfelectronica.com\/bit\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/sfelectronica.com\/bit\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/sfelectronica.com\/bit\/wp-json\/wp\/v2\/comments?post=61"}],"version-history":[{"count":5,"href":"https:\/\/sfelectronica.com\/bit\/wp-json\/wp\/v2\/posts\/61\/revisions"}],"predecessor-version":[{"id":75,"href":"https:\/\/sfelectronica.com\/bit\/wp-json\/wp\/v2\/posts\/61\/revisions\/75"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/sfelectronica.com\/bit\/wp-json\/wp\/v2\/media\/73"}],"wp:attachment":[{"href":"https:\/\/sfelectronica.com\/bit\/wp-json\/wp\/v2\/media?parent=61"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/sfelectronica.com\/bit\/wp-json\/wp\/v2\/categories?post=61"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/sfelectronica.com\/bit\/wp-json\/wp\/v2\/tags?post=61"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}