{"id":40,"date":"2026-10-05T15:27:47","date_gmt":"2026-10-05T15:27:47","guid":{"rendered":"https:\/\/sfelectronica.com\/bit\/?p=40"},"modified":"2026-10-05T15:27:47","modified_gmt":"2026-10-05T15:27:47","slug":"controlador-temperatura-inversor-rack-esphome","status":"publish","type":"post","link":"https:\/\/sfelectronica.com\/bit\/controlador-temperatura-inversor-rack-esphome\/","title":{"rendered":"CtrlTemperatura: controlo de temperatura do inversor solar e do rack com ESPHome"},"content":{"rendered":"\r\n<p class=\"hbc-lede wp-block-paragraph\"><strong>O CtrlTemperatura<\/strong> mant\u00e9m o inversor solar e o rack onde vive o Home Assistant dentro da faixa t\u00e9rmica certa: um <strong>ESP32<\/strong> a correr <strong>ESPHome<\/strong> l\u00ea tr\u00eas fontes de temperatura, comanda dois ventiladores em PWM com um <strong>controlo PID com autotune<\/strong> e sinaliza o estado num LED RGB. Tudo local, sem nuvem e sem subscri\u00e7\u00f5es.<\/p>\r\n\r\n\r\n\r\n\r\n\r\n<div class=\"hbc-specs\">\r\n\r\n\t<div class=\"hbc-specs__item\"><span class=\"hbc-specs__key\">Projeto<\/span><span class=\"hbc-specs__val\">CtrlTemperatura<\/span><\/div>\r\n\r\n\t<div class=\"hbc-specs__item\"><span class=\"hbc-specs__key\">Hardware<\/span><span class=\"hbc-specs__val\">ESP32 \u00b7 DS18B20 \u00b7 LED RGB \u00b7 2 ventiladores PWM<\/span><\/div>\r\n\r\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>\r\n\r\n\t<div class=\"hbc-specs__item\"><span class=\"hbc-specs__key\">Plataforma<\/span><span class=\"hbc-specs__val\">Home Assistant<\/span><\/div>\r\n\r\n\t<div class=\"hbc-specs__item\"><span class=\"hbc-specs__key\">Ficheiro<\/span><span class=\"hbc-specs__val\">Monitor-Temp.yaml<\/span><\/div>\r\n\r\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.235 \u00b7 AP + captive portal<\/span><\/div>\r\n\r\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>\r\n\r\n<\/div>\r\n\r\n\r\n\r\n\r\n\r\n<div class=\"hbc-toc\">\r\n\r\n\t<p class=\"hbc-toc__title\">Neste artigo<\/p>\r\n\r\n\t<ol>\r\n\r\n\t\t<li><a href=\"#visao-geral\">Vis\u00e3o geral do sistema<\/a><\/li>\r\n\r\n\t\t<li><a href=\"#hardware\">Hardware e esquema de liga\u00e7\u00e3o<\/a><\/li>\r\n\r\n\t\t<li><a href=\"#gpio\">Mapeamento dos GPIO<\/a><\/li>\r\n\r\n\t\t<li><a href=\"#yaml\">O YAML, bloco a bloco<\/a><\/li>\r\n\r\n\t\t<li><a href=\"#rede\">Rede, gest\u00e3o e atualiza\u00e7\u00f5es<\/a><\/li>\r\n\r\n\t\t<li><a href=\"#instalacao\">Instala\u00e7\u00e3o passo a passo<\/a><\/li>\r\n\r\n\t\t<li><a href=\"#home-assistant\">No Home Assistant<\/a><\/li>\r\n\r\n\t\t<li><a href=\"#diagnostico\">Diagn\u00f3stico e boas pr\u00e1ticas<\/a><\/li>\r\n\r\n\t\t<li><a href=\"#conclusao\">Conclus\u00e3o<\/a><\/li>\r\n\r\n\t<\/ol>\r\n\r\n<\/div>\r\n\r\n\r\n\r\n<h2 class=\"wp-block-heading\" id=\"visao-geral\">Vis\u00e3o geral do sistema<\/h2>\r\n\r\n\r\n\r\n\r\n\r\n<p class=\"wp-block-paragraph\">A ideia \u00e9 simples: em vez de ligar e desligar ventiladores \u00e0s cegas, <strong>mede-se nos dois pontos que interessam e deixa-se um PID a decidir a velocidade<\/strong>. O inversor solar \u00e9 o ponto quente da instala\u00e7\u00e3o e o rack \u00e9 o ponto fr\u00e1gil \u2014 se a Raspberry Pi arrefecer mal, arrefece o Home Assistant todo.<\/p>\r\n\r\n\r\n\r\n\r\n\r\n<p class=\"wp-block-paragraph\">O <strong>CtrlTemperatura<\/strong> junta dois controladores independentes na mesma placa:<\/p>\r\n\r\n\r\n\r\n\r\n\r\n<ul class=\"wp-block-list\">\r\n\t<li><strong>Inversor \u2014 termostato PID<\/strong> (entidade <em>climate<\/em>): usa a m\u00e9dia entre o DS18B20 colado ao dissipador e a temperatura de radiador lida do inversor no Home Assistant, e comanda o ventilador do inversor em velocidade vari\u00e1vel, com setpoint de 35&nbsp;\u00b0C.<\/li>\r\n\t<li><strong>Rack \u2014 m\u00e1quina de estados<\/strong>: a cada 2 segundos l\u00ea a temperatura da CPU do Raspberry Pi e troca de faixa \u2014 abaixo de 40&nbsp;\u00b0C, LED verde e ventilador parado; entre 40 e 45&nbsp;\u00b0C, LED azul a pulsar e ventilador a 50%; acima de 45&nbsp;\u00b0C, LED vermelho em alerta e ventilador a 100%.<\/li>\r\n<\/ul>\r\n\r\n\r\n\r\n\r\n\r\n<ul class=\"hbc-stats wp-block-list\">\r\n\t<li><strong>2<\/strong><span>Ventiladores em PWM: inversor (PID) e rack (por estados)<\/span><\/li>\r\n\t<li><strong>35 \u00b0C<\/strong><span>Setpoint do PID, com deadband de \u22121,0 a +0,4&nbsp;\u00b0C<\/span><\/li>\r\n\t<li><strong>3<\/strong><span>Fontes de temperatura: DS18B20, inversor e CPU (HA)<\/span><\/li>\r\n\t<li><strong>0<\/strong><span>Servi\u00e7os externos ou depend\u00eancia da nuvem<\/span><\/li>\r\n<\/ul>\r\n\r\n\r\n\r\n\r\n\r\n<p class=\"wp-block-paragraph\">No Home Assistant o termostato aparece como um <strong>termostato a s\u00e9rio<\/strong>: cart\u00e3o nativo, setpoint ajust\u00e1vel, ligar e desligar, e um bot\u00e3o de <em>autotune<\/em> que afina os ganhos PID por conta pr\u00f3pria. Os par\u00e2metros Kp, Ki, Kd e os limites do <em>deadband<\/em> s\u00e3o entidades <em>number<\/em> com persist\u00eancia \u2014 d\u00e1 para calibrar em produ\u00e7\u00e3o sem regravar firmware.<\/p>\r\n\r\n\r\n\r\n<h2 class=\"wp-block-heading\" id=\"hardware\">Hardware e esquema de liga\u00e7\u00e3o<\/h2>\r\n\r\n\r\n\r\n\r\n\r\n<p class=\"wp-block-paragraph\">A lista de materiais cabe num punhado de componentes e usa a alimenta\u00e7\u00e3o que o rack j\u00e1 tem:<\/p>\r\n\r\n\r\n\r\n\r\n\r\n<ul class=\"wp-block-list\">\r\n\t<li><strong>Placa ESP32<\/strong> (<code>board: esp32dev<\/code>) \u2014 com cinco sa\u00eddas PWM em uso, o ESP8266 n\u00e3o dava conta.<\/li>\r\n\t<li><strong>DS18B20<\/strong> com resist\u00eancia de <em>pull-up<\/em> de 4,7&nbsp;k\u03a9 \u2014 fixo ao dissipador do inversor, com cabo blindado, \u00e9 a fonte de temperatura de refer\u00eancia do PID.<\/li>\r\n\t<li><strong>LED RGB<\/strong> (catodo comum) com tr\u00eas resist\u00eancias de 220\u2013330&nbsp;\u03a9 \u2014 o sem\u00e1foro do rack, vis\u00edvel de longe.<\/li>\r\n\t<li><strong>Dois ventiladores 12&nbsp;V<\/strong> \u2014 um para a caixa do rack e outro para for\u00e7ar o ar no inversor.<\/li>\r\n\t<li><strong>Dois MOSFETs N de l\u00f3gica<\/strong> (IRLZ44N, AO3400 ou m\u00f3dulos j\u00e1 isolados) \u2014 os GPIO n\u00e3o arrastam ventilador nenhum por si.<\/li>\r\n\t<li><strong>Fonte 12&nbsp;V<\/strong> com regulador a 5&nbsp;V para a placa e caixa de montagem no rack.<\/li>\r\n<\/ul>\r\n\r\n\r\n\r\n\r\n\r\n<figure class=\"wp-block-figure hbc-screen\"><img decoding=\"async\" src=\"https:\/\/sfelectronica.com\/bit\/wp-content\/uploads\/2026\/10\/monitor-temp-esquema-ligacao.png\" alt=\"Esquema de liga\u00e7\u00e3o do CtrlTemperatura: fonte de 12 V, ESP32, DS18B20 no dissipador, LED RGB, dois ventiladores em PWM e liga\u00e7\u00e3o ao Home Assistant.\" width=\"1200\" height=\"760\" loading=\"lazy\" \/><figcaption>Liga\u00e7\u00e3o completa: ESP32 ao centro, sensores \u00e0 esquerda, sa\u00eddas PWM \u00e0 direita<\/figcaption><\/figure>\r\n\r\n\r\n\r\n\r\n\r\n<div class=\"hbc-callout hbc-callout--warn\">\r\n\t<span class=\"hbc-callout__icon\">!<\/span>\r\n\t<p><strong>Nota de hardware:<\/strong> o <code>GPIO12<\/code> \u00e9 um pino de arranque (<em>strapping<\/em>) do ESP32 \u2014 se estiver em n\u00edvel alto no momento do <em>boot<\/em>, o chip arranca com a leitura da <em>flash<\/em> errada. Tira o gate do MOSFET do ventilador do rack a esse pino com um divisor de tens\u00e3o (ou usa outro GPIO) e garante que o ventilador n\u00e3o contraalimenta a placa pela linha de 5&nbsp;V.<\/p>\r\n\t<p>Trabalha com o inversor <strong>desligado da rede<\/strong> antes de mexer no dissipador, e isola o inv\u00f3lucro do DS18B20 do metal com mica ou composto termocondutor \u2014 a carca\u00e7a costuma estar ligada \u00e0 terra do sinal.<\/p>\r\n<\/div>\r\n\r\n\r\n\r\n<h2 class=\"wp-block-heading\" id=\"gpio\">Mapeamento dos GPIO<\/h2>\r\n\r\n\r\n\r\n\r\n\r\n<p class=\"wp-block-paragraph\">Seis pinos em uso, todos fixados no YAML e sem partilhas:<\/p>\r\n\r\n\r\n\r\n\r\n\r\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>1-Wire<\/strong> (<code>temp_inversorexterno<\/code>)<\/td><td>GPIO25<\/td><td>Entrada<\/td><td>Temperatura do dissipador do inversor (DS18B20)<\/td><\/tr><tr><td><strong>LED Vermelho<\/strong><\/td><td>GPIO16<\/td><td>Sa\u00edda PWM (LEDC 1&nbsp;kHz)<\/td><td>Sem\u00e1foro do rack: alerta \u2265&nbsp;45&nbsp;\u00b0C<\/td><\/tr><tr><td><strong>LED Verde<\/strong><\/td><td>GPIO17<\/td><td>Sa\u00edda PWM (LEDC 1&nbsp;kHz)<\/td><td>Sem\u00e1foro do rack: normal &lt;&nbsp;40&nbsp;\u00b0C<\/td><\/tr><tr><td><strong>LED Azul<\/strong><\/td><td>GPIO18<\/td><td>Sa\u00edda PWM (LEDC 1&nbsp;kHz)<\/td><td>Sem\u00e1foro do rack: aviso 40\u201345&nbsp;\u00b0C<\/td><\/tr><tr><td><strong>out_vent<\/strong> (rack)<\/td><td>GPIO12<\/td><td>Sa\u00edda PWM 500&nbsp;Hz<\/td><td>Ventilador da caixa, m\u00edn.&nbsp;20% \u2014 0 \/ 50 \/ 100%<\/td><\/tr><tr><td><strong>out_inversor<\/strong><\/td><td>GPIO14<\/td><td>Sa\u00edda PWM 200&nbsp;Hz<\/td><td>Ventilador do inversor, m\u00edn.&nbsp;30% \u2014 sa\u00edda do PID<\/td><\/tr><\/tbody><\/table><\/figure>\r\n\r\n\r\n\r\n\r\n\r\n<p class=\"wp-block-paragraph\">Das tr\u00eas temperaturas, s\u00f3 uma tem fia\u00e7\u00e3o: as outras duas j\u00e1 existem no Home Assistant \u2014 a do inversor vem da integra\u00e7\u00e3o do fabricante (<code>sensor.inverter_temperature_radiator<\/code>) e a da CPU do <em>System Monitor<\/em> (<code>sensor.system_monitor_temperatura_do_processador<\/code>) \u2014 e s\u00e3o lidas pelo componente <code>homeassistant<\/code>. Mais barato do que comprar dois sensores e mais \u00fatil, porque fica tudo no mesmo gr\u00e1fico.<\/p>\r\n\r\n\r\n\r\n\r\n\r\n<h2 class=\"wp-block-heading\" id=\"yaml\">O YAML, bloco a bloco<\/h2>\r\n\r\n\r\n\r\n\r\n\r\n<p class=\"wp-block-paragraph\">O <code>Monitor-Temp.yaml<\/code> \u00e9 denso, mas est\u00e1 organizado por fun\u00e7\u00f5es. Estes s\u00e3o os excertos que interessam, do sensor ao ventilador:<\/p>\r\n\r\n\r\n\r\n\r\n\r\n<h3 class=\"wp-block-heading\">A temperatura m\u00e9dia que alimenta o PID<\/h3>\r\n\r\n\r\n\r\n\r\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\">sensor:\r\n  - platform: dallas_temp\r\n    name: Temperatura Dissipador\r\n    id: temp_inversorexterno\r\n    update_interval: <span class=\"hljs-number\">5<\/span>s\r\n\r\n  - platform: homeassistant\r\n    entity_id: sensor.inverter_temperature_radiator\r\n    id: current_temperature\r\n    name: Temp Inversor Lida\r\n\r\n  - platform: template\r\n    name: Temperatura Media\r\n    id: temperatura_media\r\n    update_interval: <span class=\"hljs-number\">5<\/span>s\r\n    lambda: |-\r\n      float sum = <span class=\"hljs-number\">0<\/span>;\r\n      uint16_t cnt = <span class=\"hljs-number\">0<\/span>;\r\n      <span class=\"hljs-keyword\">if<\/span> (!std::isnan(id(temp_inversorexterno).state)) {\r\n        sum += id(temp_inversorexterno).state;\r\n        cnt += <span class=\"hljs-number\">1<\/span>;\r\n      }\r\n      <span class=\"hljs-keyword\">if<\/span> (!std::isnan(id(current_temperature).state)) {\r\n        sum += id(current_temperature).state;\r\n        cnt += <span class=\"hljs-number\">1<\/span>;\r\n      }\r\n      <span class=\"hljs-keyword\">if<\/span> (cnt == <span class=\"hljs-number\">0<\/span>) {\r\n        <span class=\"hljs-keyword\">return<\/span> NAN;\r\n      } <span class=\"hljs-keyword\">else<\/span> {\r\n        <span class=\"hljs-keyword\">return<\/span> (sum \/ cnt);\r\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>\r\n\r\n\r\n\r\n\r\n<div class=\"hbc-callout hbc-callout--tip\">\r\n\t<span class=\"hbc-callout__icon\">OK<\/span>\r\n\t<p>A <em>lambda<\/em> ignora valores inv\u00e1lidos e s\u00f3 devolve <code>NAN<\/code> quando <strong>nenhum<\/strong> dos sensores est\u00e1 dispon\u00edvel. Assim, uma falha pontual do integrador do inversor n\u00e3o puxa o PID para baixo nem o faz ventilar com um n\u00famero inventado.<\/p>\r\n<\/div>\r\n\r\n\r\n\r\n<h3 class=\"wp-block-heading\">O termostato PID com deadband<\/h3>\r\n\r\n\r\n\r\n\r\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">climate<\/span>:\r\n  <span class=\"hljs-selector-tag\">-<\/span> <span class=\"hljs-selector-tag\">platform<\/span>: <span class=\"hljs-selector-tag\">pid<\/span>\r\n    <span class=\"hljs-selector-tag\">name<\/span>: \"<span class=\"hljs-selector-tag\">Ventilador<\/span> <span class=\"hljs-selector-tag\">Inversor<\/span>\"\r\n    <span class=\"hljs-selector-tag\">id<\/span>: <span class=\"hljs-selector-tag\">console_thermostat<\/span>\r\n    <span class=\"hljs-selector-tag\">sensor<\/span>: <span class=\"hljs-selector-tag\">temperatura_media<\/span>\r\n    <span class=\"hljs-selector-tag\">default_target_temperature<\/span>: 35\u00b0<span class=\"hljs-selector-tag\">C<\/span>\r\n    <span class=\"hljs-selector-tag\">cool_output<\/span>: <span class=\"hljs-selector-tag\">proxy_output<\/span>\r\n\r\n    <span class=\"hljs-selector-tag\">control_parameters<\/span>:\r\n      <span class=\"hljs-selector-tag\">kp<\/span>: 0<span class=\"hljs-selector-class\">.3<\/span>\r\n      <span class=\"hljs-selector-tag\">ki<\/span>: 0<span class=\"hljs-selector-class\">.0015<\/span>\r\n      <span class=\"hljs-selector-tag\">kd<\/span>: 0\r\n      <span class=\"hljs-selector-tag\">max_integral<\/span>: 0<span class=\"hljs-selector-class\">.0<\/span>\r\n      <span class=\"hljs-selector-tag\">derivative_averaging_samples<\/span>: 5\r\n\r\n    <span class=\"hljs-selector-tag\">deadband_parameters<\/span>:\r\n      <span class=\"hljs-selector-tag\">threshold_high<\/span>: 0<span class=\"hljs-selector-class\">.4<\/span>\u00b0<span class=\"hljs-selector-tag\">C<\/span>\r\n      <span class=\"hljs-selector-tag\">threshold_low<\/span>: <span class=\"hljs-selector-tag\">-1<\/span><span class=\"hljs-selector-class\">.0<\/span>\u00b0<span class=\"hljs-selector-tag\">C<\/span>\r\n      <span class=\"hljs-selector-tag\">ki_multiplier<\/span>: 0<span class=\"hljs-selector-class\">.04<\/span>\r\n      <span class=\"hljs-selector-tag\">deadband_output_averaging_samples<\/span>: 15<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><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>\r\n\r\n\r\n\r\n\r\n<p class=\"wp-block-paragraph\">Duas decis\u00f5es aqui fazem a diferen\u00e7a. A primeira \u00e9 a <strong>deadband<\/strong>: entre \u22121,0&nbsp;\u00b0C e +0,4&nbsp;\u00b0C em volta do setpoint, o controlador n\u00e3o reage a cada oscila\u00e7\u00e3o \u2014 mant\u00e9m a velocidade m\u00e9dia e s\u00f3 reduz a a\u00e7\u00e3o integral (<code>ki_multiplier<\/code>). Sem isto, o ventilador estaria a acelerar e abrandar o dia inteiro por causa de meio grau. A segunda \u00e9 <code>max_integral: 0.0<\/code>, que elimina o <em>windup<\/em>: o termo integral n\u00e3o acumula enquanto n\u00e3o h\u00e1 espa\u00e7o para resfriar.<\/p>\r\n\r\n\r\n\r\n\r\n\r\n<p class=\"wp-block-paragraph\">A cada altera\u00e7\u00e3o de estado, o YAML publica os termos <strong>P<\/strong>, <strong>I<\/strong>, <strong>D<\/strong>, o erro e a sa\u00edda como sensores pr\u00f3prios. \u00c9 a diferen\u00e7a entre \u00abacho que o PID est\u00e1 a funcionar\u00bb e <em>ver<\/em> a corre\u00e7\u00e3o a acontecer no gr\u00e1fico.<\/p>\r\n\r\n\r\n\r\n\r\n\r\n<h3 class=\"wp-block-heading\">Proxy de sa\u00edda: PID e controlo manual no mesmo PWM<\/h3>\r\n\r\n\r\n\r\n\r\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\">output:\r\n  - platform: ledc\r\n    <span class=\"hljs-attr\">pin<\/span>: GPIO14\r\n    <span class=\"hljs-attr\">frequency<\/span>: <span class=\"hljs-number\">200<\/span> Hz\r\n    <span class=\"hljs-attr\">min_power<\/span>: <span class=\"hljs-number\">30<\/span>%\r\n    max_power: <span class=\"hljs-number\">100<\/span>%\r\n    zero_means_zero: <span class=\"hljs-literal\">true<\/span>\r\n    <span class=\"hljs-attr\">id<\/span>: out_inversor\r\n\r\n  - platform: template\r\n    <span class=\"hljs-attr\">id<\/span>: proxy_output\r\n    <span class=\"hljs-attr\">type<\/span>: float\r\n    <span class=\"hljs-attr\">write_action<\/span>:\r\n      lambda: |-\r\n        float write_val =\r\n          (id(vent_inversor).state) ?\r\n            id(vent_inversor).speed \/ <span class=\"hljs-number\">100.0<\/span>:\r\n            write_val = state * <span class=\"hljs-number\">1.0<\/span>;\r\n        id(out_inversor).set_level(write_val);\r\n        id(fan_speed_pwm_voltage).publish_state(write_val * <span class=\"hljs-number\">100.0<\/span>);\r\n\r\nfan:\r\n  - platform: speed\r\n    <span class=\"hljs-attr\">output<\/span>: proxy_output\r\n    <span class=\"hljs-attr\">name<\/span>: <span class=\"hljs-string\">\"Ventilador Inversor\"<\/span>\r\n    <span class=\"hljs-attr\">id<\/span>: vent_inversor\r\n    <span class=\"hljs-attr\">restore_mode<\/span>: RESTORE_DEFAULT_OFF<\/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>\r\n\r\n\r\n\r\n\r\n<div class=\"hbc-callout\">\r\n\t<span class=\"hbc-callout__icon\">i<\/span>\r\n\t<p><strong>Quem manda no ventilador?<\/strong> A sa\u00edda do PID passa por um <em>proxy<\/em>: enquanto a entidade <strong>Ventilador Inversor<\/strong> est\u00e1 ligada no Home Assistant, manda a velocidade que escolheres \u00e0 m\u00e3o; quando a desligas, o PWM volta a seguir o que o termostato calcular. \u00c9 um <em>override<\/em> manual sem nunca desligar o PID. Os limites <code>min_power: 30%<\/code> e <code>zero_means_zero<\/code> garantem que o ventilador n\u00e3o tenta arrancar com tens\u00e3o insuficiente nem gira quando devia estar parado.<\/p>\r\n<\/div>\r\n\r\n\r\n\r\n<h3 class=\"wp-block-heading\">Estados do rack: tr\u00eas faixas, tr\u00eas cores<\/h3>\r\n\r\n\r\n\r\n\r\n\r\n<p class=\"wp-block-paragraph\">O ventilador da caixa n\u00e3o precisa de PID \u2014 precisa de reagir depressa. Um <em>interval<\/em> de 2 segundos avalia a temperatura da CPU e s\u00f3 age quando a faixa muda:<\/p>\r\n\r\n\r\n\r\n\r\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml\">interval:\r\n  - interval: 2s\r\n    then:\r\n      - lambda: |-\r\n          if (id(temperatura_sistema).state <span class=\"hljs-tag\">&lt; <span class=\"hljs-attr\">40<\/span> &amp;&amp; <span class=\"hljs-attr\">id<\/span>(<span class=\"hljs-attr\">muda_estado<\/span>) != <span class=\"hljs-string\">1)<\/span> {\r\n            <span class=\"hljs-attr\">id<\/span>(<span class=\"hljs-attr\">muda_estado<\/span>) = <span class=\"hljs-string\">1;<\/span>\r\n            <span class=\"hljs-attr\">id<\/span>(<span class=\"hljs-attr\">rgbLED<\/span>)<span class=\"hljs-attr\">.turn_on<\/span>()<span class=\"hljs-attr\">.set_rgb<\/span>(<span class=\"hljs-attr\">0<\/span>, <span class=\"hljs-attr\">1<\/span>, <span class=\"hljs-attr\">0<\/span>)\r\n              <span class=\"hljs-attr\">.set_brightness<\/span>(<span class=\"hljs-attr\">1.0<\/span>)\r\n              <span class=\"hljs-attr\">.set_effect<\/span>(\"<span class=\"hljs-attr\">extra_slow_pulse<\/span>\")<span class=\"hljs-attr\">.perform<\/span>();\r\n            <span class=\"hljs-attr\">id<\/span>(<span class=\"hljs-attr\">vent_rack<\/span>)<span class=\"hljs-attr\">.turn_off<\/span>()<span class=\"hljs-attr\">.perform<\/span>();\r\n          } <span class=\"hljs-attr\">else<\/span> <span class=\"hljs-attr\">if<\/span> (<span class=\"hljs-attr\">id<\/span>(<span class=\"hljs-attr\">temperatura_sistema<\/span>)<span class=\"hljs-attr\">.state<\/span> &gt;<\/span>= 40\r\n                     &amp;&amp; id(temperatura_sistema).state <span class=\"hljs-tag\">&lt; <span class=\"hljs-attr\">45<\/span>\r\n                     &amp;&amp; <span class=\"hljs-attr\">id<\/span>(<span class=\"hljs-attr\">muda_estado<\/span>) != <span class=\"hljs-string\">2)<\/span> {\r\n            <span class=\"hljs-attr\">id<\/span>(<span class=\"hljs-attr\">muda_estado<\/span>) = <span class=\"hljs-string\">2;<\/span>\r\n            <span class=\"hljs-attr\">id<\/span>(<span class=\"hljs-attr\">rgbLED<\/span>)<span class=\"hljs-attr\">.turn_on<\/span>()<span class=\"hljs-attr\">.set_rgb<\/span>(<span class=\"hljs-attr\">0<\/span>, <span class=\"hljs-attr\">0<\/span>, <span class=\"hljs-attr\">1<\/span>)\r\n              <span class=\"hljs-attr\">.set_brightness<\/span>(<span class=\"hljs-attr\">1.0<\/span>)\r\n              <span class=\"hljs-attr\">.set_effect<\/span>(\"<span class=\"hljs-attr\">slow_pulse<\/span>\")<span class=\"hljs-attr\">.perform<\/span>();\r\n            <span class=\"hljs-attr\">auto<\/span> <span class=\"hljs-attr\">call<\/span> = <span class=\"hljs-string\">id(vent_rack).turn_on();<\/span>\r\n              <span class=\"hljs-attr\">call.set_speed<\/span>(<span class=\"hljs-attr\">50<\/span>);\r\n              <span class=\"hljs-attr\">call.perform<\/span>();\r\n          } <span class=\"hljs-attr\">else<\/span> <span class=\"hljs-attr\">if<\/span> (<span class=\"hljs-attr\">id<\/span>(<span class=\"hljs-attr\">temperatura_sistema<\/span>)<span class=\"hljs-attr\">.state<\/span> &gt;<\/span>= 45\r\n                     &amp;&amp; id(muda_estado) != 3) {\r\n            id(muda_estado) = 3;\r\n            id(rgbLED).turn_on().set_rgb(1, 0, 0)\r\n              .set_brightness(1.0)\r\n              .set_effect(\"fast_pulse\").perform();\r\n            auto call = id(vent_rack).turn_on();\r\n              call.set_speed(100);\r\n              call.perform();\r\n          }<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\r\n\r\n\r\n\r\n\r\n<p class=\"wp-block-paragraph\">A vari\u00e1vel global <code>muda_estado<\/code> \u00e9 o que evita o ru\u00eddo: sem ela, o bloco estaria a mandar comandos de luz e de ventilador de 2 em 2 segundos sem necessidade. Com ela, cada faixa dispara exatamente uma vez \u2014 e o LED j\u00e1 entra no efeito certo (pulso lento verde, pulsar azul, alerta vermelho) de cada vez que a temperatura cruza um limite.<\/p>\r\n\r\n\r\n\r\n\r\n\r\n<h3 class=\"wp-block-heading\">Afina\u00e7\u00e3o sem regravar firmware<\/h3>\r\n\r\n\r\n\r\n\r\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">number:\r\n  - platform: template\r\n    name: kp\r\n    icon: mdi:chart-bell-curve\r\n    restore_value: <span class=\"hljs-keyword\">true<\/span>\r\n    initial_value: <span class=\"hljs-number\">0.3<\/span>\r\n    min_value: <span class=\"hljs-number\">0<\/span>\r\n    max_value: <span class=\"hljs-number\">50<\/span>\r\n    step: <span class=\"hljs-number\">0.001<\/span>\r\n    set_action:\r\n      - lambda: id(console_thermostat).set_kp(x);\r\n  <span class=\"hljs-comment\"># ki, kd, Deadband Threshold Low\/High e Deadband ki Multiplier<\/span>\r\n  <span class=\"hljs-comment\"># seguem exatamente o mesmo padr\u00e3o<\/span>\r\n\r\nbutton:\r\n  - platform: template\r\n    name: <span class=\"hljs-string\">\"PID Climate Autotune\"<\/span>\r\n    on_press:\r\n      - climate.pid.autotune: console_thermostat<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><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>\r\n\r\n\r\n\r\n\r\n<div class=\"hbc-callout hbc-callout--tip\">\r\n\t<span class=\"hbc-callout__icon\">OK<\/span>\r\n\t<p><strong>Ordem de trabalho para afinar:<\/strong> carrega no bot\u00e3o <em>PID Climate Autotune<\/em> com o sistema est\u00e1vel e deixa o ESPHome correr o procedimento at\u00e9 dar o resultado; copia depois os valores sugeridos para os par\u00e2metros do <code>climate<\/code> e para os <code>initial_value<\/code> dos n\u00fameros. Como todos t\u00eam <code>restore_value: true<\/code>, sobrevivem a rein\u00edcios \u2014 mas se os puseres s\u00f3 nos n\u00fameros, perdem-se no <em>boot<\/em> seguinte.<\/p>\r\n<\/div>\r\n\r\n\r\n\r\n<h2 class=\"wp-block-heading\" id=\"rede\">Rede, gest\u00e3o e atualiza\u00e7\u00f5es<\/h2>\r\n\r\n\r\n\r\n\r\n\r\n<p class=\"wp-block-paragraph\">Como nos outros projetos deste blog, nada aqui depende de um servidor de fabricante. A configura\u00e7\u00e3o de rede garante:<\/p>\r\n\r\n\r\n\r\n\r\n\r\n<ul class=\"wp-block-list\">\r\n\t<li><strong>IP est\u00e1tico<\/strong> \u2014 o controlador vive sempre em <code>192.168.1.235<\/code>, com <em>gateway<\/em> e DNS em <code>192.168.1.254<\/code>. Sem reservas DHCP a mudarem o endere\u00e7o e a quebrarem automa\u00e7\u00f5es.<\/li>\r\n\t<li><strong>Access Point de emerg\u00eancia<\/strong> \u2014 com <code>ap: {}<\/code> e <code>captive_portal<\/code>, se a rede principal cair o dispositivo abre o seu pr\u00f3prio Wi-Fi e permite reconfigurar as credenciais pelo telem\u00f3vel.<\/li>\r\n\t<li><strong>Improv Serial<\/strong> \u2014 provisionamento de Wi-Fi pela porta s\u00e9rie, \u00fatil na primeira configura\u00e7\u00e3o ou em bancada.<\/li>\r\n\t<li><strong>OTA<\/strong> \u2014 atualiza\u00e7\u00f5es de firmware sem tocar no cabo, a partir do ESPHome no Home Assistant.<\/li>\r\n\t<li><strong>Web Server<\/strong> \u2014 interface local para consultar temperatura, PID e logs sem abrir o Home Assistant.<\/li>\r\n\t<li><strong>API nativo<\/strong> \u2014 liga\u00e7\u00e3o direta ao Home Assistant, sem MQTT obrigat\u00f3rio.<\/li>\r\n\t<li><strong>dashboard_import<\/strong> \u2014 o dispositivo pode ser importado como pacote no ESPHome Dashboard, com o YAML completo.<\/li>\r\n<\/ul>\r\n\r\n\r\n\r\n\r\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>:\r\n  <span class=\"hljs-selector-tag\">ssid<\/span>: <span class=\"hljs-selector-tag\">SF_24G<\/span>\r\n  <span class=\"hljs-selector-tag\">password<\/span>: \"\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\"\r\n  <span class=\"hljs-selector-tag\">manual_ip<\/span>:\r\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\">.235<\/span>\r\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>\r\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>\r\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>\r\n  <span class=\"hljs-selector-tag\">ap<\/span>: {}\r\n\r\n<span class=\"hljs-selector-tag\">captive_portal<\/span>:\r\n\r\n<span class=\"hljs-selector-tag\">web_server<\/span>:\r\n<span class=\"hljs-selector-tag\">ota<\/span>:\r\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>\r\n\r\n\r\n\r\n\r\n<div class=\"hbc-callout hbc-callout--warn\">\r\n\t<span class=\"hbc-callout__icon\">!<\/span>\r\n\t<p><strong>Antes de publicar o YAML:<\/strong> a palavra-passe do Wi-Fi est\u00e1 em texto no ficheiro \u2014 mant\u00e9m o <code>Monitor-Temp.yaml<\/code> fora de reposit\u00f3rios p\u00fablicos. Define ainda <code>api: encryption_key<\/code> para cifrar a liga\u00e7\u00e3o ao Home Assistant e <code>ota: password<\/code> para proteger as atualiza\u00e7\u00f5es, e reserva o IP <code>192.168.1.235<\/code> no router para n\u00e3o haver conflitos.<\/p>\r\n<\/div>\r\n\r\n\r\n\r\n<h2 class=\"wp-block-heading\" id=\"instalacao\">Instala\u00e7\u00e3o passo a passo<\/h2>\r\n\r\n\r\n\r\n\r\n\r\n<p class=\"wp-block-paragraph\">Do ficheiro em branco ao rack a arrefecer sozinho, em seis passos:<\/p>\r\n\r\n\r\n\r\n\r\n\r\n<ol class=\"hbc-steps wp-block-list\">\r\n\t<li><strong>Monta em bancada.<\/strong> ESP32 + DS18B20 + LED RGB + os dois MOSFETs numa protoboard, com o ventilador do inversor ligado. Testa a faixa verde, a azul e a vermelha com um secador a aquecer o sensor.<\/li>\r\n\t<li><strong>Grava o firmware.<\/strong> Adiciona o dispositivo no ESPHome (<em>Add Device<\/em>), corrige o SSID, a palavra-passe e o IP est\u00e1tico e envia por USB ou OTA.<\/li>\r\n\t<li><strong>Aceita no Home Assistant.<\/strong> O dispositivo aparece em <em>Dispositivos &amp; Servi\u00e7os<\/em>; no minuto seguinte tens o termostato <em>Ventilador Inversor<\/em>, os dois ventiladores, o LED e todas as entidades de PID dispon\u00edveis.<\/li>\r\n\t<li><strong>Confirma as temperaturas vindas do HA.<\/strong> <code>sensor.inverter_temperature_radiator<\/code> e <code>sensor.system_monitor_temperatura_do_processador<\/code> t\u00eam de existir e estar com valor \u2014 sem elas, o PID trabalha s\u00f3 com o DS18B20 e o rack fica sem faixas.<\/li>\r\n\t<li><strong>Instala no rack.<\/strong> DS18B20 no dissipador, ventiladores aos MOSFETs, LED em lugar vis\u00edvel e fia\u00e7\u00e3o afastada da pot\u00eancia. Verifica que a placa n\u00e3o \u00e9 alimentada pelo ventilador.<\/li>\r\n\t<li><strong>Afina e cria o dashboard.<\/strong> Carrega em <em>PID Climate Autotune<\/em>, acompanha os sensores P\/I\/D, e s\u00f3 depois monta o painel e as automa\u00e7\u00f5es da sec\u00e7\u00e3o seguinte.<\/li>\r\n<\/ol>\r\n\r\n\r\n\r\n<h2 class=\"wp-block-heading\" id=\"home-assistant\">No Home Assistant<\/h2>\r\n\r\n\r\n\r\n\r\n\r\n<p class=\"wp-block-paragraph\">Depois de pareado, o dispositivo entrega um conjunto de entidades pronto a usar \u2014 e \u00e9 no dashboard que o projeto ganha valor:<\/p>\r\n\r\n\r\n\r\n\r\n\r\n<div class=\"hbc-features\">\r\n\r\n\t<div class=\"hbc-feature\">\r\n\t\t<span class=\"hbc-feature__num\">01<\/span>\r\n\t\t<h3 class=\"hbc-feature__title\">Termostato nativo<\/h3>\r\n\t\t<p>A entidade <strong>climate.ventilador_inversor<\/strong> usa o cart\u00e3o de termostato do Home Assistant: muda o setpoint, liga e desliga, l\u00ea a temperatura atual e v\u00ea o modo autom\u00e1tico. Para o utilizador, \u00e9 um arrefecedor como qualquer outro \u2014 s\u00f3 que decidido por ti.<\/p>\r\n\t<\/div>\r\n\r\n\t<div class=\"hbc-feature\">\r\n\t\t<span class=\"hbc-feature__num\">02<\/span>\r\n\t\t<h3 class=\"hbc-feature__title\">Telemetria do controlador<\/h3>\r\n\t\t<p>Os sensores <em>p term<\/em>, <em>i term<\/em>, <em>d term<\/em>, <em>output value<\/em>, <em>error value<\/em> e <em>is in deadband<\/em> transformam o PID numa caixa transparente: d\u00e1 para grafar a sa\u00edda e perceber, em segundos, se a afina\u00e7\u00e3o est\u00e1 certa.<\/p>\r\n\t<\/div>\r\n\r\n\t<div class=\"hbc-feature\">\r\n\t\t<span class=\"hbc-feature__num\">03<\/span>\r\n\t\t<h3 class=\"hbc-feature__title\">Sem\u00e1foro do rack<\/h3>\r\n\t\t<p>A luz <strong>Estado Rack<\/strong> (verde, azul e vermelho com efeitos de pulso) e a velocidade do <strong>Ventilador Caixa<\/strong> num s\u00f3 cart\u00e3o. V\u00eas o estado do rack sem ler um \u00fanico n\u00famero \u2014 e podes for\u00e7ar a velocidade \u00e0 m\u00e3o quando quiseres.<\/p>\r\n\t<\/div>\r\n\r\n\t<div class=\"hbc-feature\">\r\n\t\t<span class=\"hbc-feature__num\">04<\/span>\r\n\t\t<h3 class=\"hbc-feature__title\">Temperaturas partilhadas<\/h3>\r\n\t\t<p>O controlador l\u00ea a temperatura do inversor e da CPU que j\u00e1 est\u00e3o no Home Assistant e devolve a m\u00e9dia e o estado ao mesmo s\u00edtio. Zero sensores duplicados, zero integra\u00e7\u00f5es extra, hist\u00f3rico todo no mesmo s\u00edtio.<\/p>\r\n\t<\/div>\r\n\r\n<\/div>\r\n\r\n\r\n\r\n\r\n\r\n<h3 class=\"wp-block-heading\">Automa\u00e7\u00f5es que valem a pena<\/h3>\r\n\r\n\r\n\r\n\r\n\r\n<p class=\"wp-block-paragraph\">Com as entidades expostas, o resto \u00e9 comum:<\/p>\r\n\r\n\r\n\r\n\r\n\r\n<ul class=\"wp-block-list\">\r\n\t<li><strong>Alerta de calor<\/strong> \u2014 quando a temperatura da CPU passar dos 45&nbsp;\u00b0C (LED vermelho), notifica\u00e7\u00e3o no telem\u00f3vel e registo no logbook.<\/li>\r\n\t<li><strong>Hist\u00f3rico em gr\u00e1fico<\/strong> \u2014 exporta a <em>output value<\/em> do PID e as tr\u00eas temperaturas para InfluxDB\/Grafana e tens a curva t\u00e9rmica do ver\u00e3o inteiro.<\/li>\r\n\t<li><strong>Modo sil\u00eancio<\/strong> \u2014 \u00e0 noite, limita a velocidade m\u00e1xima do ventilador do rack a 50% e avisa se a temperatura continuar a subir.<\/li>\r\n\t<li><strong>Watchdog<\/strong> \u2014 se o <em>uptime<\/em> do controlador reiniciar sem aviso ou o sinal Wi-Fi cair abaixo de um limiar, recebes aviso antes de o rack aquecer sem supervis\u00e3o.<\/li>\r\n<\/ul>\r\n\r\n\r\n\r\n<h2 class=\"wp-block-heading\" id=\"diagnostico\">Diagn\u00f3stico e boas pr\u00e1ticas<\/h2>\r\n\r\n\r\n\r\n\r\n\r\n<p class=\"wp-block-paragraph\">Quando o sistema n\u00e3o se comporta como esperado, estes cinco pontos resolvem quase tudo:<\/p>\r\n\r\n\r\n\r\n\r\n\r\n<ol class=\"wp-block-list\">\r\n\t<li><strong>O PID n\u00e3o converge ou oscila sempre.<\/strong> Corre o <em>autotune<\/em> com o sistema est\u00e1vel, verifica se <code>Temperatura Media<\/code> est\u00e1 a variar com naturalidade e confirma que n\u00e3o mexeste nos n\u00fameros <em>enquanto<\/em> o autotune estava a correr \u2014 ele escreve por cima.<\/li>\r\n\t<li><strong><code>Temperatura Media<\/code> fica em <em>unknown<\/em>.<\/strong> Os dois sensores de origem est\u00e3o em <code>NAN<\/code>: abre o log do ESPHome e confirma o <code>entity_id<\/code> de cada um, e v\u00ea se a integra\u00e7\u00e3o do inversor e o <em>System Monitor<\/em> est\u00e3o vivos no Home Assistant.<\/li>\r\n\t<li><strong>O ventilador n\u00e3o arranca ou ronca.<\/strong> Sobe o <code>min_power<\/code>, confirma a frequ\u00eancia PWM e a ponte MOSFET (gate a 3,3&nbsp;V exige um MOSFET de l\u00f3gica). Se for um ventilador de 4 fios de computador, tens de subir a frequ\u00eancia para a faixa que ele espera \u2014 200\/500&nbsp;Hz \u00e9 para modelos de 2\u20133 fios.<\/li>\r\n\t<li><strong>O LED n\u00e3o muda de cor.<\/strong> Confirma o catodo comum (comum ao GND) e as resist\u00eancias; se as cores estiverem trocadas, os efeitos do <em>light<\/em> aparecem invertidos.<\/li>\r\n\t<li><strong>O rack n\u00e3o muda de faixa.<\/strong> A temperatura de origem \u00e9 <code>sensor.system_monitor_temperatura_do_processador<\/code>: se a entidade n\u00e3o existir, o <em>interval<\/em> n\u00e3o deteta transi\u00e7\u00e3o e o LED fica preso na \u00faltima cor. Confirma o nome exato da entidade.<\/li>\r\n<\/ol>\r\n\r\n\r\n\r\n\r\n\r\n<div class=\"hbc-callout hbc-callout--tip\">\r\n\t<span class=\"hbc-callout__icon\">OK<\/span>\r\n\t<p>Antes de qualquer altera\u00e7\u00e3o ao <code>Monitor-Temp.yaml<\/code>, exporta uma c\u00f3pia. O ESPHome guarda o hist\u00f3rico de vers\u00f5es no Home Assistant, mas um ficheiro de backup em local seguro torna qualquer regress\u00e3o instant\u00e2nea \u2014 e a calibra\u00e7\u00e3o feita com autotune n\u00e3o se refaz num minuto.<\/p>\r\n<\/div>\r\n\r\n\r\n\r\n\r\n\r\n<h2 class=\"wp-block-heading\" id=\"conclusao\">Conclus\u00e3o<\/h2>\r\n\r\n\r\n\r\n\r\n\r\n<p class=\"wp-block-paragraph\">O <strong>CtrlTemperatura<\/strong> mostra que proteger o inversor solar e o rack do Home Assistant n\u00e3o exige um controlador industrial nem sensores caros: um ESP32, um DS18B20, um LED e dois ventiladores com MOSFET chegam para ter arrefecimento <strong>proporcional, previs\u00edvel e vis\u00edvel<\/strong> \u2014 PID para quem precisa de resposta fina, estados simples para quem precisa de reagir depressa.<\/p>\r\n\r\n\r\n\r\n\r\n\r\n<p class=\"wp-block-paragraph\">\u00c9 um projeto replic\u00e1vel: copia o <code>Monitor-Temp.yaml<\/code>, ajusta os GPIO e os <code>entity_id<\/code> \u00e0s tuas entidades, corre o autotune e tens o teu rack e o teu inversor monitorizados ao fim de uma tarde. Tudo local, tudo teu.<\/p>\r\n\r\n\r\n\r\n\r\n\r\n<div class=\"hbc-cta\">\r\n\t<h3>Quer montar o teu?<\/h3>\r\n\t<p>A documenta\u00e7\u00e3o do ESPHome cobre o termostato PID, os ventiladores em velocidade e as sa\u00eddas PWM do ESP32 \u2014 e o YAML deste artigo serve de ponto de partida.<\/p>\r\n\t<div class=\"hbc-cta__actions\">\r\n\t\t<a class=\"holo-btn\" href=\"https:\/\/esphome.io\/components\/climate\/pid.html\" target=\"_blank\" rel=\"noopener\">ESPHome \u00b7 PID Climate<\/a>\r\n\t\t<a class=\"holo-btn\" href=\"https:\/\/esphome.io\/components\/fan\/speed.html\" target=\"_blank\" rel=\"noopener\">ESPHome \u00b7 Speed Fan<\/a>\r\n\t\t<a class=\"holo-btn\" href=\"https:\/\/esphome.io\/components\/output\/ledc.html\" target=\"_blank\" rel=\"noopener\">ESP32 \u00b7 LEDC Output<\/a>\r\n\t<\/div>\r\n<\/div>\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n","protected":false},"excerpt":{"rendered":"<p>Um ESP32 com ESPHome regula a temperatura do inversor solar e do rack do Home Assistant: PID com autotune, PWM nos dois ventiladores, LED de estado e sensores partilhados com o HA \u2014 local e sem nuvem.<\/p>\n","protected":false},"author":0,"featured_media":39,"comment_status":"closed","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[12,5],"tags":[16,17,13,19,20],"class_list":["post-40","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-esphome","category-home-assistant","tag-automacao","tag-esp32","tag-esphome","tag-inversor-solar","tag-pid"],"_links":{"self":[{"href":"https:\/\/sfelectronica.com\/bit\/wp-json\/wp\/v2\/posts\/40","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"}],"replies":[{"embeddable":true,"href":"https:\/\/sfelectronica.com\/bit\/wp-json\/wp\/v2\/comments?post=40"}],"version-history":[{"count":1,"href":"https:\/\/sfelectronica.com\/bit\/wp-json\/wp\/v2\/posts\/40\/revisions"}],"predecessor-version":[{"id":41,"href":"https:\/\/sfelectronica.com\/bit\/wp-json\/wp\/v2\/posts\/40\/revisions\/41"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/sfelectronica.com\/bit\/wp-json\/wp\/v2\/media\/39"}],"wp:attachment":[{"href":"https:\/\/sfelectronica.com\/bit\/wp-json\/wp\/v2\/media?parent=40"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/sfelectronica.com\/bit\/wp-json\/wp\/v2\/categories?post=40"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/sfelectronica.com\/bit\/wp-json\/wp\/v2\/tags?post=40"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}