Doornect O projeto que desenvolvemos é um sistema de automação de portas baseado em IoT, construído com uma STM Nucleo e uma Node MCU. Esta solução oferece a conveniência do controle remoto e a segurança de um sistema de bloqueio personalizado, utilizando-se de conexões WiFi e interfaces web para permitir integração efetiva com outros dispositivos IoT.
A porta é controlada por um motor mas devido a versatilidade da Nucleo ele pode ser outras coisas incluindo uma trava magnética, e em nosso protótipo utilizamos um servo para demonstrar a operação. A abertura da porta pode ser realizada digitando-se um código na interface, mas a flexibilidade do sistema permite a adição de outras formas de autenticação, como sensores NFC ou leitores de impressão digital.
Para adicionar a funcionalidade IoT ao sistema, a porta é equipada com um Node MCU ligado a um RTDB Firebase. Isso permite que a porta seja controlada a partir de qualquer lugar através de uma interface web, oferecendo a possibilidade de ativação remota, bloqueio seguro para evitar aberturas indesejadas (um recurso que apelidamos de "Lockdown") e até desativação para permitir livre passagem, como durante uma festa ou evento.
A porta também é equipada com LEDs que fornecem feedback visual sobre o seu status - se está fechada, aberta ou desconectada da rede. Um sensor de presença foi integrado para evitar o fechamento da porta enquanto alguém está passando, melhorando a segurança e prevenindo acidentes. Além disso, um buzzer foi incluído para fornecer feedback audível quando a senha é inserida.
Este projeto oferece uma solução completa, versátil e modular para a automação de portas, utilizando a IoT para oferecer maior controle, conveniência e segurança. Esperamos que esta solução inspire outros a explorar ainda mais as possibilidades da IoT na automação residencial e comercial.Resumo: Sistema para automatização e integração IoT de portas, permitindo fazer o controle de entrada e manuseio a distância via uma interface web, além de permitir a integração com outros sistemas IoT via cloud.
Código:O nosso código foi dividido em dois, um para a placa NodeMCU e outro para a placa STM32 Nucleo. No código do NodeMCU foi feita a conexão e a leitura dos dados presentes no Firebase, além de alterar os dados do mesmo.Node MCU ESP8266: Primeiramente são definidas duas variáveis, “door_status” e “lockdown_status”, para que sejam armazenados os valores do estado da porta, se está aberta ou fechada, e o estado do lockdown, se a funcionalidade de está ativa ou não. Após isso, vai justamente ser feita essa busca pelo valor do lockdown no firebase, e irá armazenar na variável criada. Caso o valor seja “false”, ou seja, a função lockdown está desativada, o código irá funcionar normalmente, e caso o valor seja “true”, o programa fica sem realizar nenhuma ação. Considerando que essa funcionalidade está desativada, o programa irá pegar no Firebase o estado da porta e armazenar na variável “door_status”, para em seguida analisar o seu valor. Caso a porta esteja com o estado de aberta, o programa deve realizar as funções para abrir a porta, e para começar esse processo, será enviado para a placa Núcleo, por serial, o caractere “o”, e isso irá iniciar a execução da placa Núcleo, como será visto na próxima seção. Além disso, a placa Node também irá ficar com o seu serial disponível, para caso ela receba algum valor da placa Nucleo, ela consiga armazená-lo e realizar as devidas ações. Dependendo de qual valor receber, a Node irá abrir ou fechar a porta, e sempre vai estar atenta, caso no meio da abertura, ou fechamento, ela receba um comando para fechar, ou abrir. Além do valor recebido na leitura serial, também está sendo feito o uso da variável “once”, para garantir que, quando solicitada a abertura, por exemplo, será realizada a abertura apenas uma vez, antes de fechar novamente.
void loop() {
if (millis() - dataMillis > 100) {
dataMillis = millis();
bool door_status = false;
bool lockdown_status = false;
Serial.printf("Getting lockdown info... %s\n", Firebase.RTDB.getInt( & fbdo, "/lockdown", & lockdown_status) ? String(lockdown_status).c_str() : fbdo.errorReason().c_str());
if (lockdown_status == false) {
Serial.printf("Get door info... %s\n", Firebase.RTDB.getBool( & fbdo, "/Door", & door_status) ? String(door_status).c_str() : fbdo.errorReason().c_str());
if(door_status == true) {
SSerial.write('o');
} else if (door_status == false) {
SSerial.write('c');
}
if (SSerial.available()) {
nucleo = SSerial.read();
if (nucleo == 'o' && once == 0) {
//Serial.printf("Abrindo porta... %s\n", Firebase.RTDB.setBool( & fbdo, "/Door", true) ? "ok" : fbdo.errorReason().c_str());
once = 1;
for (pos; pos < 180; pos += 1) {
if (SSerial.read() == 'c') {
Serial.printf("\n\n\nMANDOU FECHAR QUANDO TAVA ABRINDO\n\n\n");
Serial.printf("Abrindo porta... %s\n", Firebase.RTDB.setBool( & fbdo, "/Door", false) ? "ok" : fbdo.errorReason().c_str());
nucleo = 'c';
break;
}
myservo.write(pos); // tell servo to go to position in variable 'pos'
delay(1); // waits 15 ms for the servo to reach the position
}
}
if (nucleo == 'c' && once == 1) {
Serial.printf("\n\n\nMANDOU FECHAR DE FAT\n\n\n");
Serial.printf("Fechando porta... %s\n", Firebase.RTDB.setBool( & fbdo, "/Door", false) ? "ok" : fbdo.errorReason().c_str());
once = 0;
for (pos; pos >= 0; pos -= 1) {
if (SSerial.read() == 'o' && once == 0) {
Serial.printf("Abrindo porta... %s\n", Firebase.RTDB.setBool( & fbdo, "/Door", true) ? "ok" : fbdo.errorReason().c_str());
nucleo = 'o';
once = 1;
break;
}
myservo.write(pos); // tell servo to go to position in variable 'pos'
delay(1); // waits 15 ms for the servo to reach the position
}
}
}
} else if (lockdown_status == true) {
Serial.printf("Abrindo porta... %s\n", Firebase.RTDB.setBool( & fbdo, "/Door", false) ? "ok" : fbdo.errorReason().c_str());
}
}
}STM32 Nucleo: No nosso código da STM32 Nucleo, foram criadas 5 tasks para o funcionamento do programa. Essas tasks vão ser responsáveis por abrir e fechar a porta, para iniciar o funcionamento da mesma, para gerenciar o tempo de abertura da porta, e a última task vai verificar se a senha digitada pelo usuário está correta, para então dar início ao processo de abertura.
xTaskCreate(
cli,
"serialRcvr",
configMINIMAL_STACK_SIZE,
&ck,
1,
NULL);
xTaskCreate(
openGate,
"opengateAdm",
configMINIMAL_STACK_SIZE,
&ck,
1,
NULL);
xTaskCreate(
closeGate,
"closegateAdm",
configMINIMAL_STACK_SIZE,
&ck,
1,
NULL);
xTaskCreate(
gateSensor,
"gatesensor",
configMINIMAL_STACK_SIZE,
&ck,
1,
NULL);
xTaskCreate(
checkPass,
"checkPass",
configMINIMAL_STACK_SIZE,
&ck,
1,
NULL);Inicialmente, o programa vai esperar por alguma mensagem vinda da placa Node. Quando a mensagem for o caractere ‘o’, indicando que a porta deve ser aberta, é iniciado a execução das funções. Primeiramente será aceso o led verde, indicando que a porta foi aberta, depois o fluxo do código é redirecionado para a função de abertura do portão. Nessa função será enviado por serial o caractere ‘o’ para a Node, e com isso o motor servo começa a girar para abrir a porta. Em seguida, o código é redirecionado para a função “gateSensor”, onde o programa irá deixar a porta aberta por alguns segundos, antes de redirecionar para a próxima função. Na “gateSensor”, será implementado um potenciômetro para controlar o tempo em que o portão irá ficar aberto, e além disso, também tem um sensor para verificar se não tem nenhum objeto no caminho da porta. Caso tenha, o tempo de abertura é estendido até que o objeto seja removido.
int16_t readVoltage(void){
HAL_ADC_Start(&hadc1);
HAL_ADC_PollForConversion(&hadc1, HAL_MAX_DELAY);
return HAL_ADC_GetValue(&hadc1);
}
void sendChar(unsigned char c){
unsigned char pChar = c;
HAL_UART_Transmit(&huart1, &pChar,1 ,HAL_MAX_DELAY );
}
char readChar(int uart_number){
unsigned char caracter;
if(uart_number == 1){
while(HAL_UART_Receive(&huart1, &caracter, 1, HAL_MAX_DELAY) != HAL_OK);
}
else if(uart_number == 2){
while(HAL_UART_Receive(&huart2, &caracter, 1, HAL_MAX_DELAY) != HAL_OK);
}
return caracter;
}
void openGate(void * vParam)
{
int *ck = (int *)vParam;
while(1)
{
if(*ck == 1){
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, 0);// BUZZER
sendChar('o');
vTaskDelay(180);
*ck = 2;
}
}
}void gateSensor(void * vParam)
{
int *ck = (int *)vParam;
float power = 5;
while(1)
{
if(*ck == 2){
// int vol = readVoltage();
// vol = power * vol / 4095;
// int delay = vol*2000 + 2000;
int delay = 4000;
while(delay > 0)
{
// if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_6) == 1){// SENSOR
// HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, 1);// BUZZER
// delay++;
// } else if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_6) == 0){
// HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, 0);// BUZZER
// }
vTaskDelay(1);
delay--;
}
if(delay == 0){
*ck = 3;
}
}
}
}void cli(void * vParam)
{
int *ck = (int *)vParam;
int pinpad = 0;
*ck = 0;
unsigned char caracter;
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_7, 0);// Verde
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, 1);// Vermelho
while(1)
{
caracter = readChar(1);
if((caracter == 'o' || pinpad == 1) && *ck == 0) {
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_7, 1);// VERDE
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, 0);
*ck = 1;
} else if (*ck==0){
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, 0);
vTaskDelay(100);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, 1);
}
}
}
void checkPass(void *vParam) {
int *ck = (int *)vParam;
while(1){
int botao = HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_6);
if(botao == 1){// SENSOR
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, 1);// BUZZER
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_7, 1);// VERDE
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, 0);
*ck = 1;
} else if(botao == 0){
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, 0);// BUZZER
}
}
}Quando esse tempo acabar, o programa irá ser redirecionado para a função de fechamento da porta. Nesta função será enviado o caractere ‘c’ para a Node ativar o motor para fechar a porta. Além disso, caso algo entre no caminho da porta, será ativado o sensor e um buzzer, e o programa será redirecionado para a função de abertura da porta, voltando no fluxo do programa. Caso o portão feche normalmente, além de enviar o caractere ‘c’, o programa também retorna ao seu estado inicial, esperando o comando da Node para iniciar novamente a abertura.
void closeGate(void * vParam)
{
int *ck = (int *)vParam;
while(1)
{
if(*ck == 3){
// int delay = 2000;
// int reset = 2000;
// while(delay > 0){
// if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_6) == 1){
// HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, 1);// BUZZER
// *ck = 1;
// }
// if(*ck != 3){
// delay = reset;// FALTA ARRCHAMENTO
// }
// vTaskDelay(1);
// delay--;
// }
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_7, 0);// Verde
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, 1);// Vermelho
sendChar('c');
vTaskDelay(2000);
*ck = 0;
}
}
}A imagem abaixo mostra toda a configuração dos pinos que utilizamos no STM32 Nucleo, sendo eles os pinos: PA10, PA9, PA8, PC7, PB10, PA7, PA0 e PA6.
Front: O desenvolvimento do front foi feito como prova de conceito, para mostrar como a ligação com o RTDB Firebase pode ser utilizado para comunicar-se com outros dispositivos IoT fazendo uma rede inteligente ou até para controlar o próprio sistema da porta via um app ou interface web. Nos usamos um simples Javascript para controlar um site hospedado na AWS para controlar alguns aspectos básicos do sistema, como abrir a porta, desligar o sistema ou coloca-lo em lockdown onde a porta seria trancada e inacessível localmente. Também foi adicionado uma função de envio de SMS para um usuário especifico toda vez que a porta fosse aberta, usando a API da Twilio que permite criar envios automáticos de SMS, WhatsApp e ate ligação, isso é mais um exemplo da versatilidade que o sistema pode ter.
Próximos Passos: Encouramos alguns problemas no desenvolvimento com tempo limitado desse projeto, o maior deles sendo a ligação do servo com a Nucelo. Por algum motivo ainda desconhecido não conseguimos conectar o servo motor a placa Nucleo, por isso tentamos usa-lo com a Node MCU usando o framework do Plataform.io, que por sua parte também mostrou um erro estranho ao tentar usar as bibliotecas do Arudino e também não consegui interagir com o servo. Esse problema so foi resolvido ao adaptar e mover todo o codigo da Node do Plataform.io para a IDE do Arduino, la o motor Servo funcionou, mas todo esse processo nos custou tempo valioso. Por conta disso não conseguimos desenvolver todas as partes do projeto que gostaríamos, como o acesso local através de senha usando o pinpad, controlar o tempo na qual a porta fica aberta usando o potenciomento, impedir que a porta feche enquanto alguém através com o sensor de presença e o uso melhor do buzzer pelo sistema. Todos os casos de uso foram indenizados e a prototipação na placa foi pensada, mas devido ao tempo curto não conseguimos incluir essas funcionalidades extras no nosso código e no protótipo final.












Comments