Dispositivo Inteligente de Desinfecção de Máscaras com UV-C e Calor – Controlado por Arduino
Componentes e Materiais
| Seeed Grove - Sensor de Temperatura Infravermelho | ×1 |
| Arduino UNO | ×1 |
| Seeed Base Shield V2 | ×1 |
| Seeed Grove - Sensor de Luz (P) v1.1 | ×1 |
| Adafruit Display Alfanumérico Quad 0.54" Branco c/ I2C Backpack | ×1 |
| Seeed Botão Domed 12mm | ×1 |
| Buzzer Piezoelétrico | ×1 |
| Fonte Parede 12VDC 1.2A Seeed | ×1 |
Sobre o Projeto
Dispositivo de Desinfecção de Máscaras
UV-C / Calor, Controlado por Arduino, para Desinfecção de Máscaras contra Coronavírus (SARS-CoV-2)

Projeto open source sob Creative Commons "Attribution-NonCommercial-ShareAlike" (CC BY-NC-SA).
Aviso Legal: Este documento enquadra-se na "Lei do Bom Samaritano".
Publicação original: needlab.org/face-masks-disinfection-device

Introdução
Máscaras FFP1 e FFP2 são elementos de proteção indispensáveis durante epidemias. São de uso único, mas em crises a reutilização é inevitável e mecanismos de desinfecção são necessários. Durante a pandemia de SARS-CoV-2, hospitais e centros de saúde implementaram diferentes métodos, geralmente envolvendo irradiação germicida ultravioleta (UVGI) e/ou calor. Porém, esses métodos não estão acessíveis a populações vulneráveis, onde a reutilização virou única opção. A necessidade aumenta com evidências de que SARS-CoV-2 permanece estável em máscaras cirúrgicas por até 7 dias.
Este projeto cria um dispositivo baixo custo e portátil que usa UVGI e calor seco para desinfetar máscaras de vírus SARS-CoV, facilmente reproduzível por quem precisa.
Instruções DIY para Construir o Dispositivo
Diagrama de Configuração do Dispositivo

- Temperatura mantida em 65±5°C
- Lâmpada deve emitir comprimento de onda UV-C
- Ciclo de desinfecção: mínimo 30 minutos (recomendação: não exceder 30 min para evitar degradação da máscara)

Dimensões do Dispositivo

Primeiros Testes de Calor
Construção do Sistema de Aquecimento
- Frigideira de 22cm diâmetro (compatível indução) com cabo removido
- Cobrir frigideira com papel alumínio para reflexão UV-C
- Furo de 20cm no centro da caixa/base do dispositivo
- 4 suportes metálicos para posicionar a frigideira (conforme imagem)

Importante: A frigideira não deve tocar a madeira da caixa (reduz eficiência térmica). Selecione diâmetro correto do furo e modele os suportes conforme diagrama:
Construção da Tampa Superior
Sistema UV-C

Fonte UV-C: lâmpada 11W de kit "Esterilizador para Aquário". Bulbo UV-C extraído e montado na tampa nas duas extremidades. Fixado com 4 furos na tampa, zip ties (abraçadeiras) e amortecimento macio. Superfície superior coberta com alumínio para reflexão da radiação UV.
Sinta-se livre para usar lâmpada UV-C de outras fontes. Não use vidro como substituto do tubo de quartzo — vidro bloqueia radiação UV.
⚠ AVISO CRÍTICO DE SEGURANÇA
Radiação UV-C é MUITO PERIGOSA para olhos e pele. A luz UV-C deve ser ligada APENAS quando a tampa estiver FECHADA e desligada quando o dispositivo estiver ABERTO.
Recomendações importantes de Horror Coder (comentários do post original):
"Sobre o perigo invisível do UVC: verifique se a caixa é realmente à prova de luz. A radiação visível do tubo germicida é subproduto (~3-4% da emissão total) — não confie nos olhos, há grande risco de vazamento não percebido. Teste colocando fonte de luz forte dentro (10x potência do tubo, ex: lanterna LED alta potência) e verifique vazamentos em ambiente totalmente escuro. Vede todos os furos, use vedação de espuma/bordas para evitar vazamento de UV-C para fora da caixa."
Cobertura das Superfícies com Papel Alumínio

Antes de instalar tubo UV-C e grade, cubra laterais e superfície superior da caixa com papel alumínio (reflete UV-C nas faces laterais, aumentando eficácia).
Dica: Fita dupla face para fixar alumínio nas superfícies; fita adesiva (silver tape) nas bordas.
Grade Metálica - Posicionamento das Máscaras
Máscaras ficam sobre grade metálica. Fiz grade com fio de cobre esmaltado a 30mm entre fios. Grade a 120mm da base. Fios passam por pequenos furos nas faces frontal e traseira da caixa.
Configurando Arduino e Sensores
Visão Geral do Arduino

Lista de Materiais (Bill of Materials)
- Arduino UNO Rev3 — Seeed Studio
- Grove Base Shield V2 — Seeed Studio
- Grove Sensor Temperatura Infravermelho — Seeed Studio
- Grove Sensor Luz (P) — Seeed Studio
- Botão Pressure — Seeed Studio
- Buzzer Piezo — Gotronic
- Display Alfanumérico Quad 0.54" I2C — Adafruit
- Fonte Parede 12VDC — Seeed Studio
Sensores de Temperatura e Luz
Veja também: Benchmarking de sensores de temperatura para Arduino
Controle pelo Arduino
Estados da máquina de estados:
- INIT: Display mostra temperatura. Aguarda atingir limiar (70°C) para iniciar contagem no estado COUNT.
- COUNT: Minutos decrescendo de 30 a 0 exibidos ao lado da temperatura. Se temperatura muito baixa ou luz UV desligada → estado ERR.
- END: Estado normal ao fim do tempo. Buzzer avisa. Pressione botão para voltar a INIT.
- ERR: Estado de erro (UV desligada/perdida ou temperatura baixa). Buzzer avisa. Pressione botão para voltar a INIT.
Alarmess
Se alarme ON: sequência de tons no buzzer + mensagens no display.
Condições de alarme: 1) Estado ERR (UV off ou temp baixa) 2) Temperatura alta demais (>75°C)

Código Fonte para Arduino
Bibliotecas Externas Necessárias
Adafruit_LEDBackpack.h— Adafruit LearnMetro.h— GitHub
Manual do Usuário

- Coloque a caixa sobre sua placa de indução (ou resistiva).
- Ligue a alimentação do Arduino.
- Feche a caixa e aqueça a 70-80% da potência da indução.
- Espere atingir 60°C. Reduza potência para 30%.
- Agora abra, coloque as máscaras dentro e feche.
- Pressione o botão para iniciar → tempo restante exibido (30 min).
- Aguarde tempo chegar a 00 min → sinal sonoro no buzzer.
- Para novo ciclo, pressione o botão (volta ao estado INIT).
Observação: Durante contagem (estado COUNT), o ponto entre Timer e Temperatura pisca a 1Hz.
Ciclos de Temperatura
Inativação Térmica de Vírus
Capacidade de eliminar microrganismos por calor úmido (<100°C) conhecida desde Pasteur. Este dispositivo usa calor seco, que elimina efetivamente infectividade do SARS-CoV. Ensaios mostram inativação considerável a 56°C por 30-90min, quase completa a 65°C por 20-60min, completa a 75°C por 30-45min. Estudo recente: SARS-CoV-2 perde toda infectividade detectável após 56°C por 30min ou 70°C por 5min.
Baseado nas evidências e considerando efeitos na funcionalidade das máscaras, definimos protocolo em 65°C por 30min.
Protocolos Germicidas em Máscaras
Desinfecção de máscaras eficaz contra vírus influenza usando UVGI ~1 J/cm², UVGI ~18 J/cm², ou calor úmido 65±5°C por 3h. Não há estudos com coronavírus em máscaras, mas como influenza também é vírus ssRNA, efeitos similares esperados.
Saiba Mais Sobre
- UVGI. Efeito germicida da luz UVC
- Efeitos prejudiciais da desinfecção física em máscaras
Método Recomendado para Desinfecção de Máscaras
Importante estabelecer bom procedimento: personalização, contagem de ciclos, embalagem de máscaras desinfetadas. Recomendamos inspirar no paper "N95 Filtering Facepiece Respirator Ultraviolet Germicidal Irradiation (UVGI) Process for Decontamination and Reuse" da Nebraska Medicine.
Conclusões
Considerando evidências e detalhes técnicos, protocolo definido em 30min de irradiação UVC + calor seco a 65±5°C. Tempo contado considerando aquecimento e intensidade de luz. UVC ou calor sozinhos com estas especificações já eliminam quase toda infectividade SARS-CoV-2; ação simultânea aumenta segurança.
Considerações de Segurança
- Radiação UVC prejudicial à pele e olhos. Lâmpada só liga com caixa fechada.
- Cuidado com partes metálicas quentes após aquecimento — risco de queimaduras.
Aviso Legal
Baseado em evidências científicas disponíveis, o protocolo provavelmente elimina quase toda infectividade SARS-CoV e torna máscaras muito mais seguras para reuso que sem desinfecção. Porém, Needlab e equipe não assumem responsabilidade pelo uso deste dispositivo. Foi projetado com boa vontade e melhor conhecimento, mas:
Nenhum teste laboratorial adequado foi feito para inativação de SARS-CoV-2 com este dispositivo, nem efeitos reais na capacidade de filtração das máscaras podem ser avaliados com confiança antecipadamente. O uso do dispositivo e deste guia é decisão livre.
Próximos Passos (V2)
- Aumentar dimensões para mais máscaras
- Arquivos para fresadora CNC e corte a laser
- 3 opções de aquecimento: indução, chapa elétrica simples, radiação infravermelha (com PID)
- Display LCD 2x16 para HMI
- Múltiplos modos: Calor+UV-C, só Calor, só UV-C
- Seleção de diferentes sensores de temperatura — benchmark

Buscamos validação do processo com laboratórios especializados.
Atualização 11 Junho: V2 com 12 máscaras FFP2/N95 internas
Vencemos prêmio OPT 1º lugar e trabalhamos com universidade no Marrocos para produção local.

Atualização 2 Setembro: V2 no Hackaday:
Equipe
Jean Noel Lefebvre, Daniel Moreno, Dr. Alejandra Duque, Dr. Felipe Gutiérrez Arango, Jason Knight, Maria Isabel Velez Isaza, Sameera Chukkapalli.

#COVID19DetectProtect
Publicação Original: needlab.org/face-masks-disinfection-device
Bibliografia
- CDC - Recommended Guidance for Extended Use and Limited Reuse of N95 Filtering Facepiece Respirators in Healthcare Settings (2019)
- Chin et al. - Stability of SARS-CoV-2 in different environmental conditions. medRxiv (2020)
- Tseng & Li - Inactivation of Viruses on Surfaces by UVGI. J Occup Environ Hyg (2007)
- Hackerfarm - HOWTO: NUKEMETER – Measuring UV-C Light Intensity (2020)
- van Doremalen et al. - Aerosol and Surface Stability of SARS-CoV-2. NEJM (2020)
- Kariwa et al. - Inactivation of SARS coronavirus. Jpn J Vet Res (2004)
- Duan et al. - Stability of SARS Coronavirus... Sensitivity to Heating and UV. Biomed Environ Sci (2003)
- Darnell et al. - Inactivation of the coronavirus SARS-CoV. J Virol Methods (2004)
- Ansaldi et al. - SARS-CoV, influenza A and syncitial respiratory virus resistance... (2004)
- Mills et al. - UVGI of influenza-contaminated N95. Am J Infect Control (2018)
- Lore et al. - Effectiveness of Three Decontamination Treatments against Influenza Virus. Ann Occup Hyg (2012)
- Lindsley et al. - Effects of UVGI on N95 Respirator Filtration Performance. J Occup Environ Hyg (2015)
- Viscusi et al. - Evaluation of Five Decontamination Methods for Filtering Facepiece Respirators. Ann Occup Hyg (2009)
- Bergman et al. - Evaluation of Multiple (3-Cycle) Decontamination Processing. J Eng Fiber Fabr (2010)
- Kampf et al. - Persistence of coronaviruses on inanimate surfaces and inactivation with biocidal agents. J Hosp Infect (2020)
Código
TheBox V1 (C/C++)
/*
* Autor: Jean Noel Lefebvre - www.ootsidebox.fr - 31 mar 2020
*
* Bibliotecas:
* https://learn.adafruit.com/adafruit-led-backpack/0-54-alphanumeric-9b21a470-83ad-459c-af02-209d8d82c462
* https://wiki.seeedstudio.com/Grove-Infrared_Temperature_Sensor/
* https://wiki.seeedstudio.com/Grove-Light_Sensor/
* https://github.com/thomasfredericks/Metro-Arduino-Wiring
*/
#include <Wire.h>
#include "Adafruit_LEDBackpack.h"
#include <math.h>
#include <Metro.h>
#define LIGHT_SENSOR A2
#define SUR_TEMP_PIN A0
#define OBJ_TEMP_PIN A1
#define BUZZER 3
#define BP 2
#define SEUIL_TEMP 59
#define HIGH_TEMP 75
#define SEUIL_LIGHT 60
#define TIMER 30
float temp_calibration = 0;
float objt_calibration = 0.000;
float temperature_range = 10;
float offset_vol = 0.014;
float tempValue = 0;
float objtValue = 0;
float current_temp = 0;
float temp = 0;
float temp1 = 0;
float temp2 = 0;
unsigned int temp3 = 0;
const float reference_vol = 0.500;
unsigned char clear_num = 0;
float R = 0;
float voltage = 0;
long res[100] = {
318300,302903,288329,274533,261471,249100,237381,226276,215750,205768,
196300,187316,178788,170691,163002,155700,148766,142183,135936,130012,
124400,119038,113928,109059,104420,100000,95788,91775,87950,84305,
80830,77517,74357,71342,68466,65720,63098,60595,58202,55916,
53730,51645,49652,47746,45924,44180,42511,40912,39380,37910,
36500,35155,33866,32631,31446,30311,29222,28177,27175,26213,
25290,24403,23554,22738,21955,21202,20479,19783,19115,18472,
17260,16688,16138,15608,15098,14608,14135,13680,13242,12819,
12412,12020,11642,11278,10926,10587,10260,9945,9641,9347,
9063,8789,8525,8270,8023,7785,7555,7333,7118,6911
};
float obj[13][12] = {
{ 0,-0.274,-0.58,-0.922,-1.301,-1.721,-2.183,-2.691,-3.247,-3.854,-4.516,-5.236},
{ 0.271,0,-0.303,-0.642,-1.018,-1.434,-1.894,-2.398,-2.951,-3.556,-4.215,-4.931},
{ 0.567,0.3,0,-0.335,-0.708,-1.121,-1.577,-2.078,-2.628,-3.229,-3.884,-4.597},
{ 0.891,0.628,0.331,0,-0.369,-0.778,-1.23,-1.728,-2.274,-2.871,-3.523,-4.232},
{ 1.244,0.985,0.692,0.365,0,-0.405,-0.853,-1.347,-1.889,-2.482,-3.13,-3.835},
{ 1.628,1.372,1.084,0.761,0.401,0,-0.444,-0.933,-1.47,-2.059,-2.702,-3.403},
{ 2.043,1.792,1.509,1.191,0.835,0.439,0,-0.484,-1.017,-1.601,-2.24,-2.936},
{ 2.491,2.246,1.968,1.655,1.304,0.913,0.479,0,-0.528,-1.107,-1.74,-2.431},
{ 2.975,2.735,2.462,2.155,1.809,1.424,0.996,0.522,0,-0.573,-1.201,-1.887},
{ 3.495,3.261,2.994,2.692,2.353,1.974,1.552,1.084,0.568,0,-0.622,-1.301},
{ 4.053,3.825,3.565,3.27,2.937,2.564,2.148,1.687,1.177,0.616,0,-0.673},
{ 4.651,4.43,4.177,3.888,3.562,3.196,2.787,2.332,1.829,1.275,0.666,0},
{ 5.29,5.076,4.83,4.549,4.231,3.872,3.47,3.023,2.527,1.98,1.379,0.72}
};
int Light;
float Heat;
int Timer = 0;
int Minute = 59;
Adafruit_AlphaNum4 alpha4 = Adafruit_AlphaNum4();
Metro ledMetro = Metro(1000);
enum States { INIT, COUNT, END, ERR };
int Automate = INIT;
bool TemperatureOK = false;
bool LightOK = false;
void setup() {
pinMode(BP, INPUT_PULLUP);
Serial.begin(9600);
analogReference(INTERNAL);
alpha4.begin(0x70);
alpha4.clear();
alpha4.writeDisplay();
PrintLed(alpha4, "TboX");
tone(3, 3000, 500);
delay(1000);
Automate = INIT;
}
void loop() {
static int Point = 1;
float T1 = measureSurTemp();
float T2 = measureObjectTemp();
Heat = T1 + 0;
if (ledMetro.check() == 1) {
#ifndef TEST
if (Automate == COUNT)
#endif
{
if (Point) Point = 0; else Point = 1;
Minute--;
if (Minute == 0) {
Minute = 59;
if (Timer) Timer--;
PrintSensors();
}
}
if (Automate == END) tone(3, 3000, 100);
if (Automate == ERR) tone(3, 300, 200);
}
#ifdef TEST
TemperatureOK = true;
#else
if (Heat >= SEUIL_TEMP) TemperatureOK = true; else TemperatureOK = false;
#endif
Light = analogRead(LIGHT_SENSOR) / 10;
if (Light >= SEUIL_LIGHT) LightOK = true; else LightOK = false;
if (Heat >= HIGH_TEMP) {
tone(3, 300, 200);
delay(500);
}
switch (Automate) {
case INIT:
Timer = 0;
if ((!digitalRead(BP)) && TemperatureOK) {
Automate = COUNT;
Timer = TIMER;
tone(3, 3000, 500);
}
if ((!digitalRead(BP)) && !TemperatureOK) {
PrintLed(alpha4, "lowT");
tone(3, 300, 200);
} else PrintLedVal(alpha4, Timer, (int)Heat, Point);
break;
case COUNT:
if (Timer == 0) Automate = END;
if (!LightOK || !TemperatureOK) Automate = ERR;
PrintLedVal(alpha4, Timer, (int)Heat, Point);
break;
case END:
if (!digitalRead(BP)) Automate = INIT;
PrintLed(alpha4, "END.");
break;
case ERR:
if (!digitalRead(BP)) Automate = INIT;
PrintLed(alpha4, "Err.");
break;
}
}
void PrintSensors() {
Serial.print(Timer); Serial.print(", ");
Serial.print((int)Heat); Serial.print(", ");
Serial.print(100); Serial.println();
}
float binSearch(long x) {
int low = 0, mid = 0, high = 100;
while (low <= high) {
mid = (low + high) / 2;
if (x < res[mid]) low = mid + 1;
else high = mid - 1;
}
return mid;
}
float arraysearch(float x, float y) {
int i = 0;
float tem_coefficient = 100;
i = (x / 10) + 1;
voltage = (float)y / tem_coefficient;
for (temp3 = 0; temp3 < 13; temp3++) {
if ((voltage > obj[temp3][i]) && (voltage < obj[temp3 + 1][i])) {
return temp3;
}
}
}
float measureSurTemp() {
unsigned char i = 0;
float current_temp1 = 0;
int signal = 0;
tempValue = 0;
for (i = 0; i < 10; i++) {
tempValue += analogRead(SUR_TEMP_PIN);
delay(10);
}
tempValue = tempValue / 10;
temp = tempValue * 1.1 / 1023;
R = 2000000 * temp / (2.50 - temp);
signal = binSearch(R);
current_temp = signal - 1 + temp_calibration + (res[signal - 1] - R) / (res[signal - 1] - res[signal]);
return current_temp;
}
float measureObjectTemp() {
unsigned char i = 0, j = 0;
float sur_temp = 0;
unsigned int array_temp = 0;
float temp1, temp2;
float final_temp = 0;
objtValue = 0;
for (i = 0; i < 10; i++) {
objtValue += analogRead(OBJ_TEMP_PIN);
delay(10);
}
objtValue = objtValue / 10;
temp1 = objtValue * 1.1 / 1023;
sur_temp = temp1 - (reference_vol + offset_vol);
array_temp = arraysearch(current_temp, sur_temp * 1000);
temp2 = current_temp;
temp1 = (temperature_range * voltage) / (obj[array_temp + 1][(int)(temp2 / 10) + 1] - obj[array_temp][(int)(temp2 / 10) + 1]);
final_temp = temp2 + temp1;
return final_temp;
}
void PrintLed(Adafruit_AlphaNum4 &alpha4, char _buffer[]) {
alpha4.writeDigitAscii(0, _buffer[0]);
alpha4.writeDigitAscii(1, _buffer[1]);
alpha4.writeDigitAscii(2, _buffer[2]);
alpha4.writeDigitAscii(3, _buffer[3]);
alpha4.writeDisplay();
Wire.endTransmission();
}
void PrintLedVal(Adafruit_AlphaNum4 &alpha4, int ValueG, int ValueD, boolean Point) {
char _buffer[] = "AB";
int P = Point ? 1 : 0;
itoa(ValueG, _buffer, 10);
if (ValueG <= 9) {
alpha4.writeDigitAscii(0, '0');
alpha4.writeDigitAscii(1, _buffer[0], P);
} else {
alpha4.writeDigitAscii(1, _buffer[1], P);
alpha4.writeDigitAscii(0, _buffer[0]);
}
itoa(ValueD, _buffer, 10);
if (ValueD <= 9) {
alpha4.writeDigitAscii(2, '0');
alpha4.writeDigitAscii(3, _buffer[0], 0);
} else {
alpha4.writeDigitAscii(3, _buffer[1], 0);
alpha4.writeDigitAscii(2, _buffer[0]);
}
alpha4.writeDisplay();
Wire.endTransmission();
}
GitHub - Biblioteca Metro
https://github.com/thomasfredericks/Metro-Arduino-Wiring
Esquemático
Processo de manufatura
- Tecnologia Tiristor: De SCR a TRIAC, GTO e UJT
- Escalando Provisionamento IoT: Estratégias Seguras e Eficientes para Onboarding de Dispositivos
- Acompanhando Avanços em Tecnologia de Dispositivos Médicos
- Construindo Estação Meteorológica Externa com Raspberry Pi 2 e ADS‑WS1
- Sistema de Controle de Temperatura Baseado em LM35 com Microcontrolador AT89S52
- Breakout Compacto DHT de Temperatura e Umidade para Raspberry Pi – ATtiny85 & DHT22/DHT11
- Chave de Boot Alimentada por Pico: Escolha Seu SO Antes de Ligar
- Segurança de Dados em Escaneamento Móvel: Por que Processamento On-Device Importa
- Atestado de Dispositivo: Como a GlobalPlatform Constrói Confiança no IoT
- Entendendo Acessórios de Dispositivos Médicos: Definições, Classificações e Impacto Regulatório