Boas-vindas ao WordPress. Esse é o seu primeiro post. Edite-o ou exclua-o, e então comece a escrever!
Categoria: Sem categoria
-

IoT + Cloud: Arquitetura em 3 camadas
Existe um problema clássico em projetos de IoT que qualquer engenheiro de telecom conhece bem: milhares, às vezes milhões, de dispositivos gerando dados no campo, e nenhuma capacidade real de processar tudo isso na borda. Sensor de temperatura industrial, câmera de vigilância, medidor de energia smart, veículo conectado. Cada um com sua restrição de memória, energia e processamento.
Cada um produzindo um fluxo constante de dados que simplesmente não cabe no hardware local.
A resposta natural é integrar IoT com Cloud Computing como uma divisão de responsabilidades bem definida: a borda coleta e transmite, a nuvem processa e analisa. O que parece simples no papel revela uma série de desafios de engenharia que ainda estão sendo resolvidos em 2025 e é exatamente sobre isso que este post trata.
A arquitetura em três camadas
A topologia canônica de uma solução cloud-based IoT se organiza em três camadas distintas.
Na base estão os dispositivos IoT, sensores, atuadores, câmeras, wearables, veículos conectados. Cada device tem um endereço IP único e capacidade de enviar e receber dados via rede, mas com restrições severas de processamento e energia.
Eles não foram feitos para pensar; foram feitos para perceber e enviar dados.
No meio fica a camada de coleta e agregação, o que o diagrama clássico chama de IoT Data Collection. É aqui que mora o gateway físico ou o middleware de software. Responsável por pré-processar, filtrar e comprimir os dados antes de enviá-los para a nuvem. Sem essa camada funcionando bem, você vai inundar o núcleo da rede com ruído desnecessário e estourar o budget de transferência de dados em semanas.
No topo, a camada cloud provê toda a infraestrutura elástica: computação virtualizada, armazenamento distribuído, analytics em escala, modelos de ML, digital twins.
Os dispositivos podem cobrir as mais diversas verticais de atuação. A mesma arquitetura de três camadas sustenta todos esses cenários, com variações no protocolo de comunicação (MQTT, CoAP, HTTP) e no middleware escolhido.
Desafios das arquiteturas de IoT-Cloud
A integração IoT-Cloud não é um problema resolvido. Existe uma lista bem documentada de questões que continuam sendo objeto de pesquisa ativa:
Segurança e privacidade encabeçam a lista. Dispositivos com hardware limitado são superfícies de ataque fáceis. A autorização adequada garantindo que só usuários autorizados acessem dados críticos continua sem solução padronizada.
Comunicação desnecessária de dados: sem pré-processamento inteligente no gateway, o volume de dados que sobe para a cloud gera delays inaceitáveis e custo desnecessário. O gateway precisa decidir o que vale a pena transmitir.
Deploy de IPv6: IPv4 não endereça todos os dispositivos de uma frota IoT relevante. A coexistência IPv4/IPv6 ainda traz riscos de segurança específicos
Alocação e gerenciamento de recursos, interoperabilidade entre plataformas, service discovery para frotas móveis, scaling com segurança proporcional e eficiência energética completam a lista. Cada um desses é um post separado esperando para ser escrito por aqui, ou um produto aguardando ser construído 😉.
Conclusão
Dez anos atrás, players como a AWS IoT mostraram que a integração IoT-Cloud saiu de experimento de laboratório para infraestrutura de missão crítica em escala global. A arquitetura de três camadas se provou padrão a ser seguido. Os problemas abertos se tornaram mais específicos e mais difíceis, o que é sinal de maturidade, não de fracasso do mercado.
Para quem projeta sistemas de IoT, a boa notícia é que as peças fundamentais estão disponíveis e bem documentadas hoje com AWS IoT, Azure Hub, ou on-prem tecnologias como EMQX, Kafka e afins.
A má notícia é que o diabo continua morando nos detalhes, segurança, interoperabilidade e gerenciamento de escala ainda exigem decisões de engenharia que nenhuma plataforma toma por você ou te entrega pronto hoje em dia.
-

Stack IoT MQTT mTLS → Kafka → ksqlDB
Por que on Premisse?
A maioria dos tutoriais de IoT começa com AWS IoT Core, Azure IoT Hub ou algum broker SaaS. São boas opções, hoje vou mostrar um arquitetura para empresas, como Operadoras, ou Enterprises que preferem rodar suas próprias cloud privadas. Ou em qualquer cloud em containers.
Esta stack foi construída com as seguintes premissas:
- Controle total sobre os dados
- mTLS obrigatório, nenhum dispositivo sem certificado válido consegue conectar
- Pipeline de streaming
- Custo operacional próximo de zero.
- Para ser justo neste item, O custo aqui são seus próprios servidores e seus analistas de TI. Analistas estes que precisaria ter do mesmo jeito para operar soluções em nuvens.
Uma arquitetura que faria sentido numa planta industrial, numa rede privativa ou isolada da internet.
Visão geral da arquitetura

Cada camada tem responsabilidade única.
- O EMQX não conhece o Kafka diretamente, ele autentica e controla as chaves mTLS dos dispositivos, valida quem pode postar em qual tópico e dispara uma rule de transporte de dados. Aqui ele faz o papel de Midleware/segunda camada citado neste post aqui
- O Kafka não conhece o dispositivo, ele só recebe mensagens com um tópico e um payload.
Camada 1: O dispositivo – M5StickC Plus2 com MicroPython
O cliente é um M5StickC Plus2 rodando MicroPython. Ele coleta dados de sensores e publica no tópico
sensors/device-001a cada intervalo configurável.A conexão usa mTLS: o dispositivo carrega três arquivos no filesystem interno,
ca.pem,cert.pemekey.pem. Sem esses certificados, a conexão é recusada na camada TLS antes mesmo de chegar ao MQTT.MQTT_HOST = "mqtt.mfs.eng.br" MQTT_PORT = 8883 MQTT_TOPIC = "sensors/device-001" DIR_CERTS = "certificate" FILE_CA = "ca.pem" FILE_CERT = "cert.pem" FILE_KEY = "key.pem"O payload publicado pelo dispositivo é um JSON com campos de sistema, rede, ambiente e identidade do hardware:
{ "clientid": "device-001", "host": "189.37.74.112:18983", "mqtt_topic": "sensors/device-001", "ts": 1774877350907, "pub_rec_date": 1774877350907, "payload": { "timestamp": "2026-03-30T13:29:10", "system": { "send_interval_seconds": 60, "send_count": 647, "is_charging": true, "client_id": "device-001", "battery_v": 4.246, "battery_pct": 100 }, "network": { "ssid": "MinhaRede", "rssi": -39, "mac": "00:4B:12:C4:B8:0C", "ip": "192.168.68.107" }, "env": { "temperature": 26.2, "pressure": 911.22, "humidity": 58.18, "altitude_est": 886.4 }, "device": { "unique_id": "004B12C4B80C", "micropython_version": "1.25.0", "machine": "M5STACK StickC PLUS2 with ESP32(SPIRAM)", "cpu_freq_mhz": 240, "chip": "esp32" } } }Depois eu faço um novo post explicando sobre certificados, mTLS e como gerar eles do lado do dispositivo e do servidor.
Camada 2: EMQX 5.0
Por que EMQX?
O EMQX 5 tem uma feature nativa que eu gosto muito: autenticação isolada por listener. Isso significa que você pode ter na mesma instância:
- Porta 8883: aceita apenas certificado de cliente (mTLS), sem usuário/senha
- Porta 1883: aceita apenas usuário/senha, sem TLS
- Porta 8083: WebSocket com usuário/senha
Cada listener tem sua própria cadeia de autenticação. Um dispositivo sem certificado não consegue conectar na 8883, mesmo que apresente credenciais válidas.
Configuração dos listener mTLS
# mTLS — dispositivos IoT listeners.ssl.default { bind = "0.0.0.0:8883" enable_authn = false ssl_options { cacertfile = "etc/certs/rootCA.crt" certfile = "etc/certs/server.crt" keyfile = "etc/certs/server.key" verify = verify_peer fail_if_no_peer_cert = true } } mqtt.peer_cert_as_clientid = cn mqtt.peer_cert_as_username = cnUsando o CN do certificado como identidade
Uma decisão de design importante: o EMQX pode extrair o Common Name do certificado de cliente e usá-lo como
clientideusernameautomaticamente.mqtt.peer_cert_as_clientid = cn mqtt.peer_cert_as_username = cnIsso significa que a identidade do dispositivo é o próprio certificado, não uma senha que pode vazar. O CN
device-001vira automaticamente o clientid na sessão MQTT.Camada 3: Kafka + ksqlDB
Kafka em KRaft
O Kafka roda sem Zookeeper usando KRaft, o modo nativo de consenso do Kafka desde a versão 3. Menos um processo para gerenciar, menos uma fonte de falha.
A rule SQL no EMQX seleciona os campos do payload e encaminha para a action Kafka:
SELECT timestamp as ts, clientid, peername as host, topic as mqtt_topic, publish_received_at as pub_rec_date, json_decode(payload) as p FROM "sensors/+"ksqlDB — Stream de entrada (TELEMETRY_RAW)
O stream de entrada mapeia o tópico
iot.telemetry.rawcom o schema completo do payload. Um aprendizado importante na prática: dentro deSTRUCT<>o ksqlDB não aceita backticks nemINTEGER, useINT. A palavratimestampfunciona normalmente dentro do STRUCT, ao contrário do que se esperaria.CREATE STREAM TELEMETRY_RAW ( clientid VARCHAR, host VARCHAR, mqtt_topic VARCHAR, ts BIGINT, pub_rec_date BIGINT, payload STRUCT< timestamp VARCHAR, system STRUCT< send_interval_seconds INT, send_count INT, is_charging BOOLEAN, client_id VARCHAR, battery_v DOUBLE, battery_pct INT >, network STRUCT< ssid VARCHAR, rssi INT, mac VARCHAR, ip VARCHAR >, env STRUCT< temperature DOUBLE, pressure DOUBLE, humidity DOUBLE, altitude_est DOUBLE >, device STRUCT< unique_id VARCHAR, ram_free_b BIGINT, ram_alloc_b BIGINT, micropython_version VARCHAR, machine VARCHAR, flash_size_kb INT, firmware VARCHAR, cpu_freq_mhz INT, chip VARCHAR > > ) WITH ( KAFKA_TOPIC = 'iot.telemetry.raw', VALUE_FORMAT = 'JSON', TIMESTAMP = 'ts' );ksqlDB — Stream derivado flat (SENSOR_RAW)
A partir do stream raw, criamos um stream flat com apenas as variáveis de ambiente, RSSI e identidade do dispositivo. O
clientidviradevicee tudo fica no mesmo nível, sem aninhamento.CREATE STREAM SENSOR_RAW WITH ( KAFKA_TOPIC = 'iot.telemetry.sensor', VALUE_FORMAT = 'JSON', PARTITIONS = 6 ) AS SELECT clientid AS device, ts, payload->network->rssi AS rssi, payload->env->temperature AS temperature, payload->env->pressure AS pressure, payload->env->humidity AS humidity, payload->env->altitude_est AS altitude_est FROM TELEMETRY_RAW EMIT CHANGES;O resultado no tópico
iot.telemetry.sensoré um JSON plano, fácil de consumir por qualquer sink:{ "DEVICE": "device-001", "TS": 1774877350907, "RSSI": -39, "TEMPERATURE": 26.2, "PRESSURE": 911.22, "HUMIDITY": 58.18, "ALTITUDE_EST": 886.4 }ksqlDB — Tabela de estatísticas diárias (SENSOR_DAILY_STATS)
Uma tabela com janela tumbling de 1 dia agrega mínimo, máximo e média de todas as variáveis por dispositivo. A chave da tabela é composta por
device+ janela, então cada dispositivo tem exatamente um registro por dia.CREATE TABLE SENSOR_DAILY_STATS WITH ( KAFKA_TOPIC = 'iot.telemetry.sensor.daily', VALUE_FORMAT = 'JSON', PARTITIONS = 6 ) AS SELECT device, WINDOWSTART AS window_start, WINDOWEND AS window_end, COUNT(*) AS total_records, MIN(temperature) AS temperature_min, MAX(temperature) AS temperature_max, ROUND(AVG(temperature), 2) AS temperature_avg, MIN(pressure) AS pressure_min, MAX(pressure) AS pressure_max, ROUND(AVG(pressure), 2) AS pressure_avg, MIN(humidity) AS humidity_min, MAX(humidity) AS humidity_max, ROUND(AVG(humidity), 2) AS humidity_avg, MIN(altitude_est) AS altitude_min, MAX(altitude_est) AS altitude_max, ROUND(AVG(altitude_est), 2) AS altitude_avg, MIN(rssi) AS rssi_min, MAX(rssi) AS rssi_max, ROUND(AVG(rssi), 2) AS rssi_avg FROM SENSOR_RAW WINDOW TUMBLING (SIZE 1 DAY) GROUP BY device EMIT CHANGES;Para consultar as estatísticas do dia de um dispositivo específico:
SELECT device, TIMESTAMPTOSTRING(window_start, 'yyyy-MM-dd') AS dia, temperature_min, temperature_max, temperature_avg, humidity_min, humidity_max, humidity_avg, pressure_min, pressure_max, pressure_avg, rssi_min, rssi_max, rssi_avg FROM SENSOR_DAILY_STATS WHERE device = 'device-001' EMIT CHANGES;O resultado é um pipeline reativo: quando o M5Stick publica, o dado atravessa EMQX → Kafka → ksqlDB em menos de um segundo, e as estatísticas diárias são atualizadas em tempo real.
Decisões de design e trade-offs
mTLS em vez de usuário/senha nos dispositivos: Certificados não podem ser adivinhados por força bruta. Um dispositivo comprometido pode ter seu certificado revogado na CA sem afetar os demais.
Kafka em vez de gravar direto no banco: O banco é um sink, não a fonte da verdade. Com Kafka no meio, é possível adicionar novos consumidores sem alterar o produtor.
ksqlDB em vez de consumidores customizados: Para agregações e transformações simples, SQL é suficiente e mais legível do que código Python ou Java.
Streams em camadas: O
TELEMETRY_RAWpreserva o schema completo do dispositivo. OSENSOR_RAWé o stream de trabalho, flat e leve. A tabelaSENSOR_DAILY_STATSentrega agregações prontas sem nenhuma consulta adicional.Conclusão
Esta stack não é a mais simples de configurar. Mas é a mais honesta para se rodar on Premisse.
O M5Stick poderia ser qualquer dispositivo IoT com suporte a mTLS.
O EMQX escala para milhões de conexões simultâneas mantendo a mesma configuração.
O Kafka absorve picos sem perda, desacopla a arquitetura entre escrita e leitura.
O ksqlDB processa em tempo real sem infraestrutura adicional.
-
Visualização de Mapas do IBGE com Python e Jupyter
Para aqueles interessados em visualizar mapas geográficos utilizando Python e manipular dados territoriais do Brasil, este tutorial oferece uma abordagem passo a passo. O objetivo é extrair e visualizar os dados geográficos disponibilizados pelo IBGE.
Entendendo os pacotes utilizados
from datetime import datetime import requests import pandas as pd import geopandas as gpd import matplotlib.pyplot as plt- requests: faz requisições web.
- pandas: manipulação de dados.
- geopandas: extensão do pandas para dados geográficos.
- matplotlib: visualização gráfica.
Extração dos dados
Os arquivos geográficos do IBGE são baixados diretamente via HTTP:
arquivos = { 'brasil': 'https://geoftp.ibge.gov.br/.../BR_Pais_2021.zip', 'rga':'https://geoftp.ibge.gov.br/.../BR_RG_Intermediarias_2021.zip', 'rgi':'https://geoftp.ibge.gov.br/.../BR_RG_Imediatas_2021.zip', 'rgme':'https://geoftp.ibge.gov.br/.../BR_Mesorregioes_2021.zip', 'rgmi':'https://geoftp.ibge.gov.br/.../BR_Microrregioes_2021.zip', 'uf': 'https://geoftp.ibge.gov.br/.../BR_UF_2021.zip', 'mun': 'https://geoftp.ibge.gov.br/.../BR_Municipios_2021.zip' }Cada arquivo representa um nível distinto de divisão territorial:
- brasil: contorno do país.
- rga: Regiões Geográficas Intermediárias.
- rgi: Regiões Geográficas Imediatas.
- rgme: Mesorregiões.
- rgmi: Microrregiões.
- uf: Unidades Federativas (estados).
- mun: Municípios (nível mais detalhado).
for i in arquivos: arquivo = i + ".zip" print("Coletando:", arquivos[i]) data = requests.get(arquivos[i]) with open("./input/"+arquivo, "wb") as file: file.write(data.content)Visualização dos Estados Brasileiros
df = gpd.read_file('zip://input/uf.zip') df.head()Filtrando somente a região Nordeste:
df[df['NM_REGIAO']=='Nordeste'].plot()Visualização dos Municípios
df = gpd.read_file('zip://input/mun.zip') mg = df[df['SIGLA'] == 'MG'] udi = df[df['NM_MUN'] == 'Uberlândia']fig, (ax1, ax2) = plt.subplots(1,2, figsize=(15,10)) mg.plot(ax=ax1, column="NM_MUN", cmap="YlGnBu") udi.plot(ax=ax2, edgecolor="k") ax1.set_title('Minas Gerais') ax2.set_title('Uberlândia') ax1.set_axis_off() ax2.set_axis_off() plt.tight_layout() plt.show()Exemplo mais complexo
Obtendo dados populacionais via API do IBGE e mesclando com os dados geográficos:
url = "http://servicodados.ibge.gov.br/api/v3/agregados/6579/periodos/2021/variaveis/9324?localidades=N6[N3[31]]" response = requests.get(url, verify=False) data = response.json() municipios_info = data[0]['resultados'][0]['series'] municipios_list = [] for info in municipios_info: id = info['localidade']['id'] nome = info['localidade']['nome'] municipio, estado = nome.split(" - ") populacao = int(info['serie']['2021']) municipios_list.append({ 'id': id, 'municipio': municipio, 'estado': estado, 'população': populacao }) df_pop = pd.DataFrame(municipios_list) merged = mg.set_index('CD_MUN').join(df_pop.set_index('id'))Plotando mapa temático:
vmin, vmax = 0, 500000 fig, ax = plt.subplots(figsize=(10,6)) merged.plot(column='população', cmap='YlGnBu', linewidth=0.8, ax=ax, edgecolor='0.8', vmin=vmin, vmax=vmax) ax.set_title('População por município em Minas Gerais') plt.show()Conclusão
Com Python, GeoPandas e dados públicos do IBGE, é possível construir visualizações geográficas poderosas, indo desde análises estaduais até mapas temáticos complexos.
-
Traefik: Gerenciando Aplicações Self-Hosted
Hospedar suas próprias aplicações web é uma tarefa desafiadora. Este post explora como o Traefik pode simplificar esse processo, funcionando como um gateway eficiente e um balanceador de carga moderno.
Configurando o DNS: O Primeiro Passo
Antes de implementar o Traefik, é crucial ter uma configuração de DNS sólida. Aqui está um exemplo real usando mfs.eng.br. Essa configuração garante que as solicitações sejam corretamente encaminhadas para o servidor:
Resource TTL Type Priority Data *.mfs.eng.br 86400 A 0 <IP_DO_SERVIDOR> mfs.eng.br 86400 A 0 <IP_DO_SERVIDOR> Por que o Traefik Importa?
O Traefik atua como um gateway eficiente para suas aplicações. Ele gerencia o tráfego, distribui requisições e detecta automaticamente novos containers Docker, criando rotas para eles sem necessidade de configuração manual.
SSL/TLS Automático: A integração com o Let’s Encrypt permite gerar e renovar certificados automaticamente, trazendo segurança sem fricção.
Hospedando Aplicações Self-Hosted
Se você hospeda suas próprias aplicações, o Traefik é seu melhor aliado. Ele automatiza tarefas críticas e simplifica a exposição das aplicações para a internet.
Abaixo está a configuração de um servidor Traefik completamente funcional com SSL automático:
version: "3.3" services: traefik: image: "traefik:v2.10" container_name: "traefik" command: - "--api.insecure=true" - "--log.level=DEBUG" - "--log.filePath=/logs/traefik.log" - "--accessLog.filePath=/logs/access.log" - "--accessLog.bufferingSize=100" - "--providers.docker=true" - "--providers.docker.exposedbydefault=true" - "--providers.docker.endpoint=unix:///var/run/docker.sock" - "--entrypoints.web.address=:80" - "--entrypoints.websecure.address=:443" - "--certificatesresolvers.myresolver.acme.httpchallenge=true" - "--certificatesresolvers.myresolver.acme.httpchallenge.entrypoint=web" - "--certificatesresolvers.myresolver.acme.email=<SEU_EMAIL>" - "--certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json" ports: - "80:80" - "443:443" - "127.0.0.1:8080:8080" extra_hosts: - "host.docker.internal:host-gateway" volumes: - "./letsencrypt:/letsencrypt" - "/var/run/docker.sock:/var/run/docker.sock:ro" - "./logs:/logs" networks: default: external: name: proxy_networkE aqui está um exemplo de aplicação configurada para ser exposta com domínio próprio via Traefik:
version: '3.8' services: web: image: nginx:alpine volumes: - ./html:/usr/share/nginx/html labels: - "traefik.enable=true" - "traefik.http.services.cltpj.loadbalancer.server.port=80" - "traefik.http.routers.cltpj.rule=Host(`clt-pj.mfs.eng.br`)" - "traefik.http.routers.cltpj.entrypoints=websecure" - "traefik.http.routers.cltpj.tls.certresolver=myresolver" - "traefik.http.routers.cltpj-http.rule=Host(`clt-pj.mfs.eng.br`)" - "traefik.http.routers.cltpj-http.entrypoints=web" - "traefik.http.routers.cltpj-http.middlewares=redirect-to-https@docker" - "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https" networks: default: external: name: proxy_networkConclusão
Adotar o Traefik para suas aplicações self-hosted significa economizar tempo, esforço e garantir segurança. É uma escolha inteligente para quem busca simplificar a gestão de aplicações web.
Espero que este guia tenha ajudado!
-
Explorando a placa Nucleo L476RG com microcontrolador STM32
A placa STM32 Nucleo L476RG oferece uma plataforma sólida para testar novas ideias e construir protótipos com microcontroladores STM32. Compatível com Arduino™ e com cabeçalhos ST Morpho, ela permite expansão fácil com uma variedade de shields.
Características do Microcontrolador
No centro da placa está o STM32L476RGT6 (LQFP64), equipado com:
- CPU ARM® Cortex®-M4 32-bit operando a até 80 MHz
- 1 MB de memória Flash
- 128 KB de SRAM
- ART Accelerator™ — execução direta da Flash sem atraso
- Interfaces de conectividade: SPI, I2C, USART, USB OTG
- Periféricos: timers, watchdogs, TRNG, interrupções externas via GPIO
Recursos da Nucleo
- Compatibilidade Arduino Uno R3 — suporte a shields padrão
- Headers ST Morpho — acesso total a todos os pinos do STM32
- ST-LINK/V2-1 integrado — não exige programador externo
Pinagem e Expansão
A pinagem detalhada da placa pode ser consultada em documentos do ARMmbed.
- Headers compatíveis com Arduino
- Headers ST Morpho para acesso completo aos I/Os
Shields Suportados e Compatibilidade
A placa suporta shields da ST e de terceiros, permitindo adicionar conectividade sem fio, sensores extras e diversas interfaces.
Glossário de Termos Técnicos
- Microcontrolador: computador compacto dedicado a tarefas específicas.
- GPIO: pinos configuráveis para entrada/saída digital.
- SPI: protocolo de comunicação rápida com periféricos.
- I2C: protocolo para comunicação com sensores de baixa velocidade.
-
Monitoramento Ambiental com STM32 Nucleo L476RG e DHT22: Um Guia Prático
A construção de projetos de monitoramento ambiental é fundamental para diversas aplicações, desde a agricultura até residências inteligentes. Neste artigo, exploramos a construção de um protótipo de sistema de visualização de temperatura e umidade usando o microcontrolador STM32 Nucleo L476RG, um sensor DHT22 e um display TFT MCUFRIEND_kbv, programados em C++ com o framework Arduino.
Objetivo do Projeto
O código proposto permite monitorar continuamente a temperatura e a umidade do ambiente, exibindo os resultados em tempo real em um display gráfico. Além disso, o sistema registra os valores máximos e mínimos das últimas 24h e apresenta um gráfico simples que ajuda a visualizar as tendências ao longo do tempo.
Hardware Necessário
- STM32 Nucleo L476RG – plataforma de prototipagem com bom equilíbrio entre desempenho e custo.
- DHT22 – sensor de temperatura e umidade, conhecido por precisão e durabilidade.
- Display TFT MCUFRIEND_kbv – compatível com diversos controladores gráficos, usado para visualização.
Pinagem

Sensor DHT22
- VCC: conectado ao pino 3.3V da placa STM32 Nucleo L476RG.
- GND: conectado ao pino GND da placa STM32.
- DHTPIN (PB7): pino de dados entre o DHT22 e a STM32.
Conexão do Display MCUFRIEND_kbv
- LCD_CS (A3): Chip Select, ativa/desativa o display no barramento.
- LCD_CD (A2): Command/Data.
- LCD_WR (A1): pino de escrita.
- LCD_RD (A0): pino de leitura.
- LCD_RESET (A4): pino de reset do display.
Configuração do Projeto no VSCode com PlatformIO
O arquivo
platformio.inidefine o ambiente e as bibliotecas necessárias:[env:nucleo_l476rg] platform = ststm32 board = nucleo_l476rg framework = arduino lib_deps = adafruit/DHT sensor library@^1.4.6 adafruit/Adafruit GFX Library@^1.11.9 prenticedavid/MCUFRIEND_kbv@^3.1.0-Beta adafruit/Adafruit ST7735 and ST7789 Library@^1.10.3Análise do Código-Fonte
Armazenamento de Dados das Últimas 24 Horas
Para monitorar as condições ambientais ao longo de um dia, o código utiliza arrays para armazenar as leituras de temperatura e umidade:
const int NUM_READINGS = 1440; // Total de leituras para 24 horas com intervalos de um minuto float tempReadings[NUM_READINGS]; // Leituras de temperatura float humidityReadings[NUM_READINGS]; // Leituras de umidade int readingIndex = 0; // Índice atual para nova leitura int readingsCount = 0; // Qtde efetiva de leituras registradasCada minuto uma nova leitura é inserida, e o índice é atualizado em esquema circular, mantendo sempre as últimas 24h de dados.
Visualização de Dados com Barras de Progresso
Para facilitar a visualização das leituras atuais em relação aos valores mínimos e máximos, o código utiliza barras de progresso dinâmicas:
void drawProgressBar(int x, int y, int width, int height, int value, int max, uint16_t barColor) { int filledWidth = (int)((width * value) / max); tft.fillRect(x, y, filledWidth, height, barColor); // Área preenchida tft.fillRect(x + filledWidth, y, width - filledWidth, height, BLACK); // Área vazia }Mapeamento de Cores para Temperatura e Umidade
As cores das barras mudam de acordo com os valores lidos, permitindo uma leitura visual rápida:
uint16_t getTemperatureColor(int temp) { if (temp >= 30) return RED; if (temp < 10) return BLUE; int red = map(temp, 10, 30, 0, 255); int blue = map(temp, 10, 30, 255, 0); return tft.color565(red, 0, blue); } uint16_t getHumidityColor(int humidity) { if (humidity <= 30) return RED; if (humidity > 60) return BLUE; int blue = map(humidity, 20, 90, 0, 255); int red = map(humidity, 20, 90, 255, 0); return tft.color565(red, 0, blue); }Uso de um Indicador Composto
A função
drawIndicadoragrupa elementos comuns para exibir o valor, mínimo, máximo e barra correspondente de forma compacta:void drawIndicador(int x, int y, float value, float min, float max, String indicador, String unidade, uint16_t cor) { tft.fillRect(x, y, 320, 70, BLACK); tft.setTextSize(2); tft.setCursor(x, y + 5); tft.setTextColor(cor); tft.print(indicador + ": " + String(value) + " " + unidade); tft.setTextColor(WHITE); tft.setCursor(x, y + 30); tft.setTextSize(1); tft.print("Min: " + String(min) + " | Max: " + String(max)); if (indicador == "Temperatura") { drawProgressBar(x, y + 45, 300, 20, value, 40, getTemperatureColor(value)); } else if (indicador == "Umidade") { drawProgressBar(x, y + 45, 300, 20, value, 100, getHumidityColor(value)); } }Visualização Gráfica das Últimas 24h
A visualização gráfica é fundamental para entender tendências de temperatura e umidade nas últimas 24 horas:
void drawTemperatureChart(int x, int y, int width, int height, float vector[], int tamanho, int iterator, uint16_t cor) { int y_ponto, x_ponto = 0; for (int i = 0; i < iterator; i++) { y_ponto = static_cast<int>(round((static_cast<float>(vector[i] - 15) / (40 - 15)) * height)); x_ponto = static_cast<int>(round((static_cast<float>(i) / static_cast<float>(tamanho)) * static_cast<float>(width))); tft.drawPixel(x + x_ponto, y + height - y_ponto, cor); } } void drawHumidityChart(int x, int y, int width, int height, float vector[], int tamanho, int iterator, uint16_t cor) { int y_ponto, x_ponto = 0; for (int i = 0; i < iterator; i++) { y_ponto = static_cast<int>(round((static_cast<float>(vector[i]) / 100.0) * height)); x_ponto = static_cast<int>(round((static_cast<float>(i) / static_cast<float>(tamanho)) * static_cast<float>(width))); tft.drawPixel(x + x_ponto, y + height - y_ponto, cor); } }Essas funções mapeiam os vetores de leituras para coordenadas de pixels, permitindo um gráfico compacto dentro dos limites físicos do display.
Código Completo
Abaixo está o código completo de exemplo usado no projeto. Ele integra leitura do DHT22, renderização no display TFT e armazenamento de um histórico de 24 horas:
#include <Arduino.h> #include <Adafruit_Sensor.h> #include <DHT.h> #include <DHT_U.h> #include <Adafruit_GFX.h> // Biblioteca gráfica base #include <MCUFRIEND_kbv.h> #define DHTPIN PB7 #define DHTTYPE DHT22 // Pinos do display #define LCD_CS A3 #define LCD_CD A2 #define LCD_WR A1 #define LCD_RD A0 #define LCD_RESET A4 // Definição de cores #define BLACK 0x0000 #define BLUE 0x001F #define RED 0xF800 #define GREEN 0x07E0 #define CYAN 0x07FF #define MAGENTA 0xF81F #define YELLOW 0xFFE0 #define WHITE 0xFFFF #define RGB(r, g, b) (((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3)) #define GREY RGB(127, 127, 127) #define DARKGREY RGB(64, 64, 64) #define TURQUOISE RGB(0, 128, 128) #define PINK RGB(255, 128, 192) #define OLIVE RGB(128, 128, 0) #define PURPLE RGB(128, 0, 128) #define AZURE RGB(0, 128, 255) #define ORANGE RGB(255, 128, 64) // DHT_Unified para obter metadados do sensor DHT_Unified dht(DHTPIN, DHTTYPE); MCUFRIEND_kbv tft; uint32_t delayMS; const int NUM_READINGS = 1440; float tempReadings[NUM_READINGS]; float humidityReadings[NUM_READINGS]; int readingIndex = 0; int readingsCount = 0; float tempMin = 500; float tempMax = -100; float humidityMin = 100; float humidityMax = 0; // Função para obter a cor baseada na temperatura uint16_t getTemperatureColor(int temp) { if (temp >= 30) return RED; if (temp < 10) return BLUE; int red = map(temp, 10, 30, 0, 255); int blue = map(temp, 10, 30, 255, 0); return tft.color565(red, 0, blue); } // Função para obter a cor baseada na umidade uint16_t getHumidityColor(int humidity) { if (humidity <= 30) return RED; if (humidity > 60) return BLUE; int blue = map(humidity, 20, 90, 0, 255); int red = map(humidity, 20, 90, 255, 0); return tft.color565(red, 0, blue); } // Barra de progresso void drawProgressBar(int x, int y, int width, int height, int value, int max, uint16_t barColor) { int filledWidth = (int)((width * value) / max); tft.fillRect(x, y, filledWidth, height, barColor); tft.fillRect(x + filledWidth, y, width - filledWidth, height, BLACK); } // Indicador completo (valor + min/max + barra) void drawIndicador(int x, int y, float value, float min, float max, String indicador, String unidade, uint16_t cor) { tft.fillRect(x, y, 320, 70, BLACK); tft.setTextSize(2); tft.setCursor(x, y + 5); tft.setTextColor(cor); tft.print(indicador + ": " + String(value) + " " + unidade); tft.setTextColor(WHITE); tft.setCursor(x, y + 30); tft.setTextSize(1); tft.print("Min: " + String(min) + " | Max: " + String(max)); if (indicador == "Temperatura") { drawProgressBar(x, y + 45, 300, 20, value, 40, getTemperatureColor(value)); } else if (indicador == "Umidade") { drawProgressBar(x, y + 45, 300, 20, value, 100, getHumidityColor(value)); } } // Gráfico de temperatura void drawTemperatureChart(int x, int y, int width, int height, float vector[], int tamanho, int iterator, uint16_t cor) { int y_ponto, x_ponto = 0; for (int i = 0; i < iterator; i++) { y_ponto = static_cast<int>(round((static_cast<float>(vector[i] - 15) / (40 - 15)) * height)); x_ponto = static_cast<int>(round((static_cast<float>(i) / static_cast<float>(tamanho)) * static_cast<float>(width))); tft.drawPixel(x + x_ponto, y + height - y_ponto, cor); } } // Gráfico de umidade void drawHumidityChart(int x, int y, int width, int height, float vector[], int tamanho, int iterator, uint16_t cor) { int y_ponto, x_ponto = 0; for (int i = 0; i < iterator; i++) { y_ponto = static_cast<int>(round((static_cast<float>(vector[i]) / 100) * height)); x_ponto = static_cast<int>(round((static_cast<float>(i) / static_cast<float>(tamanho)) * static_cast<float>(width))); tft.drawPixel(x + x_ponto, y + height - y_ponto, cor); } } void setup() { tft.reset(); uint16_t identifier = tft.readID(); tft.begin(identifier); tft.setRotation(1); tft.fillScreen(BLACK); tft.setTextColor(WHITE); tft.setTextSize(2); Serial.begin(9600); while (!Serial); delay(1000); dht.begin(); Serial.println(F("Iniciando DHT22")); sensor_t sensor; dht.temperature().getSensor(&sensor); Serial.println(F("------------------------------------")); Serial.println(F("Temperature Sensor")); Serial.print (F("Sensor Type: ")); Serial.println(sensor.name); Serial.print (F("Driver Ver: ")); Serial.println(sensor.version); Serial.print (F("Unique ID: ")); Serial.println(sensor.sensor_id); Serial.print (F("Max Value: ")); Serial.print(sensor.max_value); Serial.println(F("°C")); Serial.print (F("Min Value: ")); Serial.print(sensor.min_value); Serial.println(F("°C")); Serial.print (F("Resolution: ")); Serial.print(sensor.resolution); Serial.println(F("°C")); Serial.println(F("------------------------------------")); dht.humidity().getSensor(&sensor); Serial.println(F("Humidity Sensor")); Serial.print (F("Sensor Type: ")); Serial.println(sensor.name); Serial.print (F("Driver Ver: ")); Serial.println(sensor.version); Serial.print (F("Unique ID: ")); Serial.println(sensor.sensor_id); Serial.print (F("Max Value: ")); Serial.print(sensor.max_value); Serial.println(F("%")); Serial.print (F("Min Value: ")); Serial.print(sensor.min_value); Serial.println(F("%")); Serial.print (F("Resolution: ")); Serial.print(sensor.resolution); Serial.println(F("%")); Serial.println(F("------------------------------------")); Serial.print (F("Min Delay: ")); Serial.print(sensor.min_delay / 1000 / 1000); Serial.println(F("s")); Serial.println(F("------------------------------------")); Serial.print (F("Display Height: ")); Serial.println(tft.height()); Serial.print (F("Display Width: ")); Serial.println(tft.width()); delayMS = 60 * 1000; } void loop() { sensors_event_t event; // Temperatura dht.temperature().getEvent(&event); float tempValue = isnan(event.temperature) ? 0 : event.temperature; // Umidade dht.humidity().getEvent(&event); float humidityValue = isnan(event.relative_humidity) ? 0 : event.relative_humidity; // Atualiza buffers circulares tempReadings[readingIndex] = tempValue; humidityReadings[readingIndex] = humidityValue; readingIndex = (readingIndex + 1) % NUM_READINGS; readingsCount = min(readingsCount + 1, NUM_READINGS); // Recalcula min e max tempMin = tempMax = tempReadings[0]; humidityMin = humidityMax = humidityReadings[0]; for (int i = 0; i < readingsCount; i++) { tempMin = min(tempMin, tempReadings[i]); tempMax = max(tempMax, tempReadings[i]); humidityMin = min(humidityMin, humidityReadings[i]); humidityMax = max(humidityMax, humidityReadings[i]); } // Desenho no display if (!isnan(tempValue)) { drawIndicador(10, 5, tempValue, tempMin, tempMax, "Temperatura", "C", BLUE); drawTemperatureChart(10, 160, 300, 60, tempReadings, NUM_READINGS, readingsCount, BLUE); } if (!isnan(humidityValue)) { drawIndicador(10, 80, humidityValue, humidityMin, humidityMax, "Umidade", "%", GREEN); drawHumidityChart(10, 160, 300, 60, humidityReadings, NUM_READINGS, readingsCount, GREEN); } delay(delayMS); }Conclusão
Este projeto mostra como combinar o STM32 Nucleo L476RG, o sensor DHT22 e um display TFT para criar um sistema completo de monitoramento ambiental com histórico de 24h e visualização gráfica. A mesma abordagem pode ser estendida para outros sensores e formas de comunicação, como Wi-Fi, MQTT e dashboards em nuvem.
-
Monitoramento Ambiental com DHT22, ESP32 e InfluxDB
O objetivo aqui é construir um sistema que coleta dados de temperatura e umidade usando o sensor DHT22 e os envia para um servidor InfluxDB para armazenamento e análise, juntamente com um servidor Grafana. O ESP32 atua conectando o sensor ao Wi-Fi e gerenciando a comunicação com o InfluxDB.
Hardware Necessário
- ESP32 — Microcontrolador com Wi-Fi e Bluetooth integrados.
- DHT22 — Sensor de temperatura e umidade de baixo custo.
- Conexão Wi-Fi — Necessária para envio dos dados.

Pinagem
Sensor DHT22:
- VCC: 3.3V do ESP32
- GND: GND do ESP32
- DHTPIN: GPIO configurado no código (definido como
18)
Configuração do Projeto no VSCode com PlatformIO
[env:upesy_wroom] platform = espressif32 board = upesy_wroom framework = arduino lib_deps = adafruit/DHT sensor library@^1.4.6 arduino-libraries/NTPClient@3.1.0 tobiasschuerg/ESP8266 Influxdb@^3.13.1Análise do Código Fonte
Declaração do DHT22
#include <Adafruit_Sensor.h> #include <DHT.h> #define DHTPIN 18 #define DHTTYPE DHT22 DHT dht(DHTPIN, DHTTYPE);Conexão com o Wi-Fi
#include <WiFi.h> #include <WiFiUdp.h> const char* ssid = "MINHA_WIFI"; const char* password = "MINHA_SENHA"; WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(2500); Serial.println("Conectando à rede WiFi..."); } Serial.println("Conectado à rede WiFi");Declaração do InfluxDB e Inicialização
#include <InfluxDbClient.h> #define INFLUXDB_URL "http://influx.mfs.eng.br:8086" #define INFLUXDB_DB_NAME "clima" #define INFLUXDB_USER "esp32" #define INFLUXDB_PASSWORD "esp32_password" InfluxDBClient client(INFLUXDB_URL, INFLUXDB_DB_NAME); Point sensor("clima"); client.setConnectionParamsV1(INFLUXDB_URL, INFLUXDB_DB_NAME, INFLUXDB_USER, INFLUXDB_PASSWORD);Coletando Dados do DHT22
float tempValue = dht.readTemperature(); float humidityValue = dht.readHumidity(); if (!isnan(tempValue) && !isnan(humidityValue)) { Serial.print("Temperatura: "); Serial.println(tempValue); Serial.print("Umidade: "); Serial.println(humidityValue); }Envio de Dados para o InfluxDB
sensor.clearFields(); sensor.addField("temperature", tempValue); sensor.addField("humidity", humidityValue); if (!client.writePoint(sensor)) { Serial.print("InfluxDB write failed: "); Serial.println(client.getLastErrorMessage()); }Vantagens do InfluxDB
- Banco de dados de séries temporais — ideal para dados contínuos.
- Escalabilidade — lida bem com grandes volumes de dados.
- Integração perfeita com Grafana.
Visualização no Grafana
Dashboard de exemplo:
Link para o painel do Grafana
Código Completo
Repositório do projeto:
https://gitlab.com/mfs.eng.br/hardware-quirks/temperatura_esp32#include <Arduino.h> #include <Adafruit_Sensor.h> #include <DHT.h> #include <WiFi.h> #include <NTPClient.h> #include <WiFiUdp.h> #include <InfluxDbClient.h> #include "config.h" // Código completo omitido aqui — incluído no repositórioReferências
-
SBC vs. SBM: Diferenças Entre Single Board Computer e Single Board Microcontroller
Este artigo apresenta, de forma direta e comparativa, as diferenças fundamentais entre dois tipos de dispositivos amplamente utilizados em computação embarcada: os SBCs (Single Board Computers) e os SBMs (Single Board Microcontrollers).
SBC – Single Board Computer
Um single-board computer (computador de placa única) é um computador completo construído em uma única placa de circuito, incluindo processador, memória, armazenamento e interfaces de entrada/saída. Diferente dos microcontroladores, os SBCs executam sistemas operacionais completos e podem funcionar como computadores de propósito geral.
Características
- Processador: Capaz de rodar sistemas operacionais completos.
- Memória: RAM + armazenamento persistente (eMMC, SSD, microSD).
- Interfaces de E/S: USB, HDMI, Ethernet, Wi-Fi, Bluetooth, GPIOs.
- Sistema Operacional: Linux, Android ou versões leves de Windows.
Exemplos de SBCs
- Raspberry Pi
- BeagleBone Black
SBM – Single Board Microcontroller
Um single-board microcontroller é um computador em uma única placa contendo um microcontrolador — um chip compacto que combina processador, memória e periféricos. São usados para tarefas específicas em sistemas embarcados, com foco em eficiência energética e controle determinístico.
Características
- Processador: Microcontrolador dedicado a tarefas específicas.
- Memória: Flash (programas) + SRAM (dados temporários).
- Periféricos: GPIOs, ADCs, PWMs, UART, SPI, I2C.
- Baixo consumo: Totalmente otimizado para energia.
- Aplicações específicas: Automação, IoT, controle e sensores.
Exemplos de SBMs
- Arduino
- ESP8266 / ESP32
- STM32 Nucleo L476RG
Resumo Final
SBCs funcionam como mini-computadores completos capazes de rodar sistemas operacionais. SBMs funcionam como microcontroladores especializados para controle de hardware e tarefas determinísticas. A escolha depende do tipo de projeto: “computação generalista” → SBC; “controle e IoT” → SBM.
-
Comandos Linux para gestão de Hardware
Tentei colocar aqui os comandos que utilizo para verificar as informações de hardware nos sistemas Linux que administro. Incluí instruções sobre como obter dados de CPU, memória, discos, controladores USB, adaptadores de rede, entre outros componentes.
lscpu
O comando
lscpureporta informações sobre a CPU e unidades de processamento. Ele não possui opções adicionais ou funcionalidades.$ lscpu Architecture: x86_64 CPU op-mode(s): 32-bit, 64-bit Byte Order: Little Endian CPU(s): 4 On-line CPU(s) list: 0-3 Thread(s) per core: 1 Core(s) per socket: 4 Socket(s): 1 NUMA node(s): 1 Vendor ID: GenuineIntel CPU family: 6 Model: 23 Stepping: 10 CPU MHz: 1998.000 BogoMIPS: 5302.48 Virtualization: VT-x L1d cache: 32K L1i cache: 32K L2 cache: 2048K NUMA node0 CPU(s): 0-3lshw – Listar Hardware
O
lshwé uma ferramenta geral que reporta informações detalhadas sobre múltiplos componentes de hardware, como CPU, memória, discos, controladores USB, adaptadores de rede, etc. Ele extrai informações de diferentes arquivos no/proc.$ lshw -short H/W path Device Class Description =================================================== system () /0 bus DG35EC /0/0 processor Intel(R) Core(TM)2 Quad CPU Q8400 @ 2.66GHz /0/0/1 memory 2MiB L2 cache /0/0/3 memory 32KiB L1 cache /0/2 memory 32KiB L1 cache /0/4 memory 64KiB BIOS /0/14 memory 8GiB System Memory /0/14/0 memory 2GiB DIMM DDR2 Synchronous 667 MHz (1.5 ns) /0/14/1 memory 2GiB DIMM DDR2 Synchronous 667 MHz (1.5 ns) /0/14/2 memory 2GiB DIMM DDR2 Synchronous 667 MHz (1.5 ns) /0/14/3 memory 2GiB DIMM DDR2 Synchronous 667 MHz (1.5 ns) /0/100 bridge 82G35 Express DRAM Controller /0/100/2 display 82G35 Express Integrated Graphics Controller /0/100/2.1 display 82G35 Express Integrated Graphics Controller /0/100/19 eth0 network 82566DC Gigabit Network Connectionhwinfo – Informações de Hardware
O
hwinfoé uma ferramenta de detecção de hardware que pode relatar informações detalhadas sobre vários componentes de hardware.$ hwinfo --short cpu: Intel(R) Core(TM)2 Quad CPU Q8400 @ 2.66GHz, 2000 MHz Intel(R) Core(TM)2 Quad CPU Q8400 @ 2.66GHz, 2000 MHz Intel(R) Core(TM)2 Quad CPU Q8400 @ 2.66GHz, 2666 MHz Intel(R) Core(TM)2 Quad CPU Q8400 @ 2.66GHz, 2666 MHz keyboard: /dev/input/event2 AT Translated Set 2 keyboard mouse: /dev/input/mice Microsoft Basic Optical Mouse v2.0 graphics card: Intel 965G-1 Intel 82G35 Express Integrated Graphics Controller sound: Intel 82801H (ICH8 Family) HD Audio Controllerlspci – Listar PCI
O comando
lspcilista todos os barramentos PCI e detalhes sobre os dispositivos conectados a eles.$ lspci 00:00.0 Host bridge: Intel Corporation 82G35 Express DRAM Controller (rev 03) 00:02.0 VGA compatible controller: Intel Corporation 82G35 Express Integrated Graphics Controller (rev 03) 00:02.1 Display controller: Intel Corporation 82G35 Express Integrated Graphics Controller (rev 03) 00:19.0 Ethernet controller: Intel Corporation 82566DC Gigabit Network Connection (rev 02)lsscsi – Listar Dispositivos SCSI
O
lsscsilista dispositivos SCSI/SATA como discos rígidos e unidades ópticas.$ lsscsi [3:0:0:0] disk ATA ST3500418AS CC38 /dev/sda [4:0:0:0] cd/dvd SONY DVD RW DRU-190A 1.63 /dev/sr0lsusb – Listar Dispositivos USB
O comando
lsusbmostra os controladores USB e detalhes sobre os dispositivos conectados a eles. Use a opção-v(verbose) para informações detalhadas.$ lsusb Bus 002 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub Bus 007 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub Bus 006 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub Bus 005 Device 002: ID 045e:00cb Microsoft Corp. Basic Optical Mouse v2.0lsblk – Listar Dispositivos de Bloco
lsblklista informações sobre todos os dispositivos de bloco, como partições de discos rígidos e outros dispositivos de armazenamento.$ lsblk NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT sda 8:0 0 465.8G 0 disk ├─sda1 8:1 0 70G 0 part ├─sda2 8:2 0 1K 0 part ├─sda5 8:5 0 97.7G 0 part /media/4668484A68483B47 ├─sda6 8:6 0 97.7G 0 part / ├─sda7 8:7 0 1.9G 0 part [SWAP] └─sda8 8:8 0 198.5G 0 part /media/13f35f59-f023-4d98-b06f-9dfaebefd6c1 sr0 11:0 1 1024M 0 romInxi
O
inxié um script bash que coleta detalhes de hardware de várias fontes e comandos no sistema, gerando um relatório compreensível.$ inxi -Fx System: Host: fedora Kernel: 6.9.8-200.fc40.x86_64 arch: x86_64 bits: 64 compiler: gcc v: 2.41-37.fc40 Desktop: KDE Plasma v: 6.1.3 Distro: Fedora Linux 40 (KDE Plasma) Machine: Type: Laptop System: Dell product: Inspiron 7560 v: N/A serial: <superuser required> Mobo: Dell model: 09WC1G v: A01 serial: <superuser required> UEFI: Dell v: 1.15.0 date: 07/23/2021 Battery: ID-1: BAT0 charge: 5.7 Wh (100.0%) condition: 5.7/42.0 Wh (13.7%) volts: 12.4 min: 11.4 model: SMP DELL Y3F7Y6B status: full Device-1: wacom_battery_0 model: Wacom Intuos S 2 charge: 100% status: full CPU: Info: dual core model: Intel Core i7-7500U bits: 64 type: MT MCP arch: Amber/Kaby Lake note: check rev: 9 cache: L1: 128 KiB L2: 512 KiB L3: 4 MiB Speed (MHz): avg: 800 high: 801 min/max: 400/3500 cores: 1: 801 2: 800 3: 800 4: 800 bogomips: 23199 Flags: avx avx2 ht lm nx pae sse sse2 sse3 sse4_1 sse4_2 ssse3 vmx Graphics: Device-1: Intel HD Graphics 620 vendor: Dell driver: i915 v: kernel arch: Gen-9.5 bus-ID: 00:02.0 Device-2: NVIDIA GM108M [GeForce 940MX] vendor: Dell driver: nouveau v: kernel arch: Maxwell bus-ID: 01:00.0 Device-3: Microdia Integrated_Webcam_HD driver: uvcvideo type: USB bus-ID: 1-5:4 Display: wayland server: Xwayland v: 24.1.1 compositor: kwin_wayland driver: N/A resolution: 1920x1080 API: EGL v: 1.5 drivers: iris,nouveau,swrast platforms: active: wayland,x11,surfaceless,device inactive: gbm API: OpenGL v: 4.6 compat-v: 4.3 vendor: intel mesa v: 24.1.4 glx-v: 1.4 direct-render: yes renderer: Mesa Intel HD Graphics 620 (KBL GT2) API: Vulkan v: 1.3.283 drivers: N/A surfaces: xcb,xlib,wayland devices: 2 Audio: Device-1: Intel Sunrise Point-LP HD Audio vendor: Dell driver: snd_hda_intel v: kernel bus-ID: 00:1f.3 API: ALSA v: k6.9.8-200.fc40.x86_64 status: kernel-api Server-1: PipeWire v: 1.0.7 status: active Network: Device-1: Qualcomm Atheros QCA6174 802.11ac Wireless Network Adapter vendor: Dell driver: ath10k_pci v: kernel bus-ID: 02:00.0 temp: 36.0 C IF: wlp2s0 state: up mac: 12:49:3c:d5:b5:cf Device-2: Realtek RTL8111/8168/8211/8411 PCI Express Gigabit Ethernet vendor: Dell driver: r8169 v: kernel port: d000 bus-ID: 03:00.0 IF: enp3s0 state: down mac: 84:7b:eb:f9:87:69 Bluetooth: Device-1: Qualcomm Atheros driver: btusb v: 0.8 type: USB bus-ID: 1-8:6 Report: btmgmt ID: hci0 rfk-id: 0 state: up address: A8:6B:AD:DE:14:AA bt-v: 4.2 lmp-v: 8 Drives: Local Storage: total: 231.03 GiB used: 27.75 GiB (12.0%) ID-1: /dev/sda vendor: Gigabyte model: GP-GSTFS31120GNTD size: 111.79 GiB ID-2: /dev/sdb vendor: LITE-ON model: L8H-128V2G-11 M.2 2280 128GB size: 119.24 GiB Partition: ID-1: / size: 37.25 GiB used: 27.25 GiB (73.2%) fs: btrfs dev: /dev/sda4 ID-2: /boot size: 965.9 MiB used: 466.6 MiB (48.3%) fs: ext4 dev: /dev/sda3 ID-3: /boot/efi size: 598.8 MiB used: 44.9 MiB (7.5%) fs: vfat dev: /dev/sda2 Swap: ID-1: swap-1 type: zram size: 8 GiB used: 33.2 MiB (0.4%) dev: /dev/zram0 Sensors: System Temperatures: cpu: 56.0 C pch: 47.5 C mobo: 45.0 C sodimm: SODIMM C Fan Speeds (rpm): cpu: 2539 Info: Memory: total: 16 GiB available: 15.51 GiB used: 8.06 GiB (52.0%) Processes: 274 Uptime: 22h 5m Init: systemd target: graphical (5) Packages: 15 Compilers: gcc: 14.1.1 Shell: Bash v: 5.2.26 inxi: 3.3.34 muller@fedora:~$df – Espaço em Disco
O comando
dfrelata várias partições, seus pontos de montagem e o espaço usado e disponível em cada uma.$ df -H Filesystem Size Used Avail Use% Mounted on /dev/sda6 104G 26G 73G 26% / none 4.1k 0 4.1k 0% /sys/fs/cgroup udev 4.2G 4.1k 4.2G 1% /dev tmpfs 837M 1.6M 835M 1% /runPydf – df em Python
O
pydfé uma versão aprimorada dodfescrita em Python, que exibe saída colorida.Para instalar:
$ pip install pydfPara utilizar:
$ pydf Filesystem Size Used Avail Use% Mounted on /dev/sda6 96G 23G 68G 24.4 [#.....] / /dev/sda8 195G 138G 47G 70.6 [####..] /media/13f35f59-f023-4d98-b06f-9dfaebefd6cfdisk
O
fdiské uma ferramenta para modificar partições em discos rígidos e pode ser usada para listar informações de partições.$ fdisk -l Disk /dev/sda: 500.1 GB, 500107862016 bytes 255 heads, 63 sectors/track, 60801 cylinders, total 976773168 sectors Units = sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disk identifier: 0x30093008 Device Boot Start End Blocks Id System /dev/sda1 * 63 146801969 73400953+ 7 HPFS/NTFS/exFAT /dev/sda2 146802031 976771071 414984520+ f W95 Ext'd (LBA) /dev/sda5 146802033 351614654 102406311 7 HPFS/NTFS/exFAT /dev/sda6 351614718 556427339 102406311 83 Linux /dev/sda7 556429312 560427007 1998848 82 Linux swap / Solaris /dev/sda8 560429056 976771071 208171008 83 Linuxmount
O comando
mounté usado para montar/desmontar e visualizar sistemas de arquivos montados.$ mount | column -t /dev/sda6 on / type ext4 (rw,errors=remount-ro) proc on /proc type proc (rw,noexec,nosuid,nodev) sysfs on /sys type sysfs (rw,noexec,nosuid,nodev) udev on /dev type devtmpfs (rw,mode=0755) devpts on /dev/pts type devpts (rw,noexec,nosuid,gid=5,mode=0620) tmpfs on /run type tmpfs (rw,noexec,nosuid,size=10%,mode=0755)free – Verificar Memória RAM
Verifique a quantidade de RAM usada, livre e total no sistema com o comando
free.$ free -m total used free shared buffers cached Mem: 7975 5865 2110 0 24 622 -/+ buffers/cache: 5218 2757 Swap: 1951 921 1030dmidecode
O comando
dmidecodeextrai informações de hardware lendo dados das estruturas SMBOIS (também chamadas de tabelas DMI).# Informações sobre o processador/CPU $ dmidecode -t processor # Informações sobre a memória/RAM $ dmidecode -t memory # Detalhes do BIOS $ dmidecode -t biosArquivos
/procMuitos arquivos virtuais no diretório
/proccontêm informações sobre hardware e configurações.# Informações sobre a CPU $ cat /proc/cpuinfo # Informações sobre a memória $ cat /proc/meminfo # Informações sobre o Linux/kernel $ cat /proc/version # Dispositivos SCSI/SATA $ cat /proc/scsi/scsi # Partições $ cat /proc/partitionshdparm
O comando
hdparmobtém informações sobre dispositivos SATA como discos rígidos.$ hdparm -i /dev/sda /dev/sda: Model=ST3500418AS, FwRev=CC38, SerialNo= Config={ HardSect NotMFM HdSw>15uSec Fixed DTR>10Mbs RotSpdTol>.5% } RawCHS=16383/16/63, TrkSize=0, SectSize=0, ECCbytes=4 BuffType=unknown, BuffSize=16384kB, MaxMultSect=16, MultSect=16 CurCHS=16383/16/63, CurSects=16514064, LBA=yes, LBAsects=976773168 IORDY=on/off, tPIO={min:120,w/IORDY:120}, tDMA={min:120,rec:120} PIO modes: pio0 pio1 pio2 pio3 pio4 DMA modes: mdma0 mdma1 mdma2 UDMA modes: udma0 udma1 udma2 udma3 udma4 udma5 *udma6 AdvancedPM=no WriteCache=enabled Drive conforms to: unknown: ATA/ATAPI-4,5,6,7Disclaimer
A lógica adotada para este manual foi baseada nas necessidades ao longo da minha carreira para fazer troubleshooting de problemas de aplicações que culminaram em causa raiz relacionada ao hardware do sistema ou problemas que tive ao montar e desmontar notebooks e computadores.