MCU.TEC geral Estudo e caso de uso do Ollama em computador de borda e MCU

Estudo e caso de uso do Ollama em computador de borda e MCU

Este artigo apresenta de maneira didática e prática o uso do Ollama, uma ferramenta de código aberto para criação e gerenciamento de modelos de inteligência artificial generativa, integrada com Python em um computador de borda. Este computador é capaz de interagir via Bluetooth com uma placa Nucleo-WB09KE, para coleta e transmissão de dados provenientes de sensores em tempo real. Como exemplo prático, abordaremos a leitura e envio de dados de um sensor DHT22, como temperatura e umidade, usando padrões de projeto reconhecidos na literatura de sistemas embarcados e tempo real.

Para garantir clareza e robustez no código, utilizaremos os padrões de projeto Proxy e Observer/Listener, baseados em referências consagradas como os livros “Design Patterns for Embedded Systems in C” e “Real-Time Design Patterns”, ambos de Bruce Powel Douglass. O padrão Proxy será empregado para encapsular adequadamente o acesso ao hardware específico, enquanto o Observer será utilizado para gerenciar a comunicação de eventos e mudanças de estado entre as tarefas de firmware e o computador de borda. O artigo também detalhará como converter o texto gerado pelo Ollama em áudio para reprodução via alto-falantes, criando uma experiência interativa e amigável para o usuário final.

Problema a ser Resolvido

No desenvolvimento de sistemas embarcados integrados com inteligência artificial generativa, frequentemente encontramos desafios relacionados à complexidade da interação entre diferentes componentes, tais como microcontroladores, sensores, computadores de borda e interfaces de usuário. Um problema comum é a falta de organização estrutural, clareza e facilidade de manutenção do código, especialmente quando se integra diferentes tecnologias como comunicação sem fio, processamento local de dados e feedback em áudio para usuários.

No cenário proposto, precisamos resolver alguns desafios específicos: um computador de borda equipado com Ollama deve se comunicar via Bluetooth com uma placa STM32 Nucleo-WB09KE, que coleta informações ambientais através de um sensor DHT22 (temperatura e umidade). Esses dados precisam ser acessados de maneira confiável e rápida pelo computador de borda, que por sua vez irá gerar mensagens compreensíveis para o usuário e convertê-las em áudio para reprodução em alto-falantes. Além disso, o computador de borda deve interagir com o usuário de forma amigável, cumprimentando-o ao iniciar o sistema e despedindo-se quando o software for encerrado.

Outro aspecto importante é a necessidade de uma arquitetura robusta e escalável, capaz de acomodar futuros sensores adicionais, novos algoritmos de IA e outras formas de interação sem causar grandes alterações no código-fonte ou afetar o desempenho e a estabilidade do sistema. Além disso, existe a necessidade de manter separação clara das responsabilidades entre as diferentes partes do sistema (firmware, hardware, software de IA e interface com o usuário), facilitando testes unitários e garantindo fácil manutenção e expansão futura.

Para solucionar esses problemas de forma estruturada e eficaz, adotaremos padrões de projeto conhecidos da literatura especializada. O padrão Proxy será utilizado para encapsular o acesso ao sensor DHT22 e à comunicação Bluetooth, permitindo a transparência no acesso ao hardware e a troca futura dos periféricos sem necessidade de alterar o restante do sistema. Já o padrão Observer/Listener ajudará na comunicação assíncrona, notificando eficientemente o computador de borda sobre novos dados recebidos ou mudanças de estado relevantes ocorridas na placa STM32.

Estrutura do Padrão

Neste projeto, utilizaremos dois padrões essenciais: Proxy e Observer/Listener. Cada um tem funções específicas e complementares para garantir a eficiência, robustez e manutenção simplificada do sistema proposto. A seguir detalhamos a estrutura de cada padrão e como eles serão utilizados para resolver os desafios apresentados.

1. Estrutura do Padrão Proxy

O padrão Proxy é utilizado para controlar e encapsular o acesso a recursos externos ou internos do sistema, como sensores e interfaces de comunicação. Sua estrutura típica é composta por:

  • Subject (Interface ou Classe Abstrata): Define a interface que será implementada tanto pelo objeto real quanto pelo proxy.
  • RealSubject: Classe concreta que realiza o acesso direto ao hardware ou recurso (por exemplo, leitura direta do sensor DHT22).
  • Proxy: Classe intermediária que encapsula e controla o acesso ao objeto real, adicionando funcionalidades extras, tais como verificação de acesso, conversão de formatos ou gerenciamento de comunicação.

Aplicado ao nosso contexto, teremos uma classe Proxy chamada SensorProxy, que implementa a interface abstrata SensorInterface, com operações básicas como getTemperature() e getHumidity(). Essas operações internas serão delegadas à classe DHT22Sensor, que representa o objeto real (RealSubject).

Exemplo simplificado em C:

/* Interface abstrata do sensor */
typedef struct {
    float (*getTemperature)(void);
    float (*getHumidity)(void);
} SensorInterface;

/* Implementação RealSubject: Sensor DHT22 */
float DHT22_getTemperature(void);
float DHT22_getHumidity(void);

SensorInterface DHT22Sensor = {
    .getTemperature = DHT22_getTemperature,
    .getHumidity = DHT22_getHumidity
};

/* Proxy para encapsulamento de acesso */
float SensorProxy_getTemperature(void);
float SensorProxy_getHumidity(void);

SensorInterface SensorProxy = {
    .getTemperature = SensorProxy_getTemperature,
    .getHumidity = SensorProxy_getHumidity
};

No proxy, é possível adicionar verificação de erros, conversão de unidades, ou mesmo comunicação remota via Bluetooth com o computador de borda.


2. Estrutura do Padrão Observer/Listener

O padrão Observer/Listener permite que um objeto (Subject) notifique outros objetos (Observers ou Listeners) automaticamente sobre mudanças de estado ou novos eventos ocorridos, facilitando comunicação assíncrona. Sua estrutura básica envolve:

  • Subject: Mantém uma lista de observadores e notifica-os sobre mudanças.
  • Observer (Listener): Define uma interface para objetos interessados em receber notificações sobre eventos.

No nosso projeto, o firmware no STM32 usará o padrão Observer para notificar o computador de borda sempre que novos dados forem coletados do sensor DHT22. O computador de borda atua como Observer, recebendo notificações periódicas do firmware (Subject).

Exemplo simplificado em C no firmware da placa Nucleo-WB09KE:

/* Interface Listener para notificação de dados do sensor */
typedef void (*SensorListener)(float temperature, float humidity);

/* Subject: SensorDataNotifier */
#define MAX_LISTENERS 5
SensorListener listeners[MAX_LISTENERS];
int num_listeners = 0;

void registerListener(SensorListener listener) {
    if (num_listeners < MAX_LISTENERS) {
        listeners[num_listeners++] = listener;
    }
}

void notifyListeners(float temperature, float humidity) {
    for (int i = 0; i < num_listeners; i++) {
        listeners[i](temperature, humidity);
    }
}

/* Exemplo de chamada após leitura do sensor */
void sensorReadingTask(void) {
    float temp = DHT22_getTemperature();
    float hum = DHT22_getHumidity();
    
    notifyListeners(temp, hum);
}

O computador de borda atuará como Observer, registrando-se no firmware como Listener e recebendo notificações periódicas dos dados atualizados.


Integração com Ollama e Processamento de Áudio (Computador de Borda)

No computador de borda, Python integrará Ollama para gerar texto interativo, que será convertido em áudio para reprodução. Uma estrutura simplificada é:

  • Gerador Ollama: Processa dados recebidos do STM32 e gera mensagens interativas.
  • Conversor Texto-para-Fala: Converte o texto gerado em áudio.

Exemplo simplificado em Python:

import ollama
import pyttsx3

def gerar_mensagem(temperatura, umidade):
    prompt = f"Informe ao usuário a temperatura de {temperatura} graus Celsius e a umidade de {umidade}%."
    response = ollama.chat(model='llama3', messages=[{'role': 'user', 'content': prompt}])
    return response['message']['content']

def reproduzir_audio(texto):
    engine = pyttsx3.init()
    engine.say(texto)
    engine.runAndWait()

# Callback recebendo dados via Bluetooth
def dados_recebidos(temperatura, umidade):
    texto = gerar_mensagem(temperatura, umidade)
    reproduzir_audio(texto)

# Exemplo de inicialização do Listener (Observer)
registrar_listener_bluetooth(dados_recebidos)

# Mensagens ao iniciar e sair do software
reproduzir_audio("Bem-vindo ao sistema inteligente.")
# Ao sair:
reproduzir_audio("Obrigado por utilizar nosso sistema. Até breve.")

Essa estrutura claramente organizada e dividida entre padrões Proxy e Observer permitirá um desenvolvimento eficiente, fácil manutenção e excelente escalabilidade para expansão futura.

Papéis de Colaboração (Collaborations Roles)

Os padrões Proxy e Observer/Listener utilizados no projeto possuem papéis bem definidos que desempenham funções específicas para promover clareza, escalabilidade e manutenção simplificada do sistema. Vamos detalhar os papéis envolvidos nestes padrões, destacando a interação entre eles e como se aplicam na prática ao nosso sistema.

Papéis do Padrão Proxy

  • SensorInterface (Subject):
    É uma interface abstrata que define a forma padrão de acesso aos dados do sensor, garantindo que tanto o objeto real quanto o proxy ofereçam as mesmas operações. Esta interface garante transparência ao cliente do sensor, independentemente do mecanismo ou hardware específico utilizado.
  • DHT22Sensor (RealSubject):
    Classe concreta que implementa diretamente as operações definidas pela SensorInterface. É responsável pela comunicação física com o sensor DHT22, realizando leituras reais de temperatura e umidade.
  • SensorProxy (Proxy):
    Classe intermediária que implementa a mesma interface (SensorInterface) e atua como um controlador do acesso ao sensor. Esta classe pode adicionar funcionalidades importantes, tais como a validação dos dados, conversão de unidades, comunicação remota (via Bluetooth), e gerenciamento de erros. Dessa forma, o Proxy permite alterar facilmente o objeto real sem afetar o restante do sistema.
  • SensorClient (Cliente):
    Cliente que utiliza a interface fornecida pelo Proxy para acessar os dados do sensor, sem precisar se preocupar com detalhes específicos do hardware ou das comunicações envolvidas.

Papéis do Padrão Observer/Listener

  • Subject (SensorDataNotifier):
    Mantém uma lista de objetos interessados (listeners ou observadores) e notifica-os automaticamente sempre que um novo evento ocorre, como uma nova leitura dos dados do sensor. Gerencia o registro e remoção de observadores e dispara notificações apropriadas para os observadores registrados.
  • Observer (Listener / BluetoothListener):
    Interface que define um callback (função de retorno), utilizada por qualquer objeto que deseja receber notificações automáticas de eventos específicos. No nosso contexto, o computador de borda desempenha esse papel ao registrar-se como Listener para ser informado sempre que novos dados ambientais forem coletados pelo STM32.
  • ConcreteObserver (Computador de Borda):
    Implementa a interface Observer. No contexto deste projeto, ele utiliza os dados recebidos para alimentar o Ollama, gerando mensagens interativas e transformando-as em áudio para o usuário. Desta forma, o ConcreteObserver está diretamente ligado às funcionalidades de processamento de IA generativa e reprodução de áudio.
  • Event:
    Classe representando os eventos enviados pelo Subject para os Observers. No exemplo do projeto, os eventos contêm dados ambientais (temperatura e umidade) coletados periodicamente pelo firmware do STM32.

Papéis Adicionais (Micro-padrões para Expansões Futuras):

Para promover escalabilidade e fácil manutenção, podemos ainda destacar alguns papéis adicionais que podem emergir futuramente:

  • DataValidator (Micro-padrão Validator):
    Responsável pela validação e verificação dos dados coletados, evitando erros e garantindo integridade das informações.
  • BluetoothGateway (Micro-padrão Gateway):
    Responsável por encapsular completamente a comunicação Bluetooth, facilitando a adição de outros protocolos ou métodos de comunicação no futuro.
  • AudioSynthesizer (Micro-padrão Façade):
    Uma interface simplificada que abstrai as operações complexas relacionadas à geração de áudio a partir de texto, permitindo futuramente a utilização de diferentes mecanismos de síntese sem impacto nos demais componentes.
  • AIChatProcessor (Micro-padrão Strategy):
    Abstração que permite a integração simplificada de diferentes modelos generativos, tais como modelos locais ou remotos, sem alterar o código que depende diretamente do mecanismo de geração de mensagens.

Esses papéis são propostos para tornar o sistema mais flexível, expansível e modular, podendo evoluir para atender a novas demandas sem gerar impacto negativo no código já implementado.

Consequências

A utilização dos padrões Proxy e Observer/Listener, bem como os micro-padrões sugeridos, traz vantagens significativas e algumas consequências importantes que precisam ser consideradas no desenvolvimento do sistema embarcado integrado com inteligência generativa (Ollama). A seguir, detalhamos as principais consequências observadas ao adotar essa abordagem de projeto estruturada.

Consequências Positivas:

1. Clareza e Manutenção Simplificada:
O uso do padrão Proxy simplifica o código ao encapsular a interação direta com o sensor e hardware. Alterações futuras no hardware, sensores ou protocolos são isoladas no Proxy, não afetando o restante do sistema, o que reduz o esforço de manutenção.

2. Reutilização e Portabilidade:
Ao definir interfaces claras e bem abstraídas para acesso aos dados (por meio de Proxy e Observer), o sistema ganha em portabilidade. Assim, é possível reutilizar facilmente módulos como sensores ou comunicação sem necessidade de alterações profundas no código.

3. Comunicação Eficiente e Assíncrona:
O padrão Observer garante notificações imediatas e eficientes ao computador de borda sobre novos dados recebidos do firmware, evitando consultas constantes (polling) que poderiam gerar sobrecarga no sistema e desperdício de recursos computacionais.

4. Facilidade de Expansão e Escalabilidade:
Ao adotar micro-padrões como Validator, Gateway, Façade e Strategy, a adição de novos componentes, sensores, modelos de IA e interfaces de comunicação pode ser feita rapidamente. A arquitetura modular permite integrar facilmente novas funcionalidades sem grandes refatorações.

5. Robustez e Confiabilidade:
Padrões de projeto estabelecem estruturas testadas e validadas pela comunidade. A utilização desses padrões contribui diretamente para maior robustez e confiabilidade do sistema, além de reduzir riscos associados ao desenvolvimento customizado e não estruturado.

6. Melhor Experiência para o Usuário:
A integração com Ollama e o feedback em áudio melhoram significativamente a experiência do usuário final, proporcionando interações naturais e compreensíveis, com informações claramente apresentadas.


Consequências Negativas e Pontos de Atenção:

1. Complexidade Inicial:
O uso desses padrões, embora beneficie significativamente a manutenção e escalabilidade do sistema, pode introduzir complexidade adicional no estágio inicial do projeto. Para equipes menores ou menos experientes, pode ser necessário um período de aprendizado ou adaptação para a correta aplicação dos padrões.

2. Sobrecarga de Memória e Processamento:
Em sistemas embarcados com restrições severas de recursos, padrões como Proxy e Observer podem introduzir pequena sobrecarga devido às camadas adicionais de abstração e à necessidade de armazenamento e gerenciamento das listas de observadores.

3. Latência em Comunicação:
Embora o padrão Observer evite o polling contínuo, ainda existe um tempo associado à notificação e processamento dos eventos. Se não implementado corretamente, pode haver um leve aumento na latência do sistema. É importante planejar adequadamente a arquitetura e avaliar se essa latência é aceitável no contexto da aplicação.

4. Potencial Coupling Excessivo:
Se os papéis definidos pelos padrões não forem corretamente isolados, o sistema pode sofrer acoplamento excessivo entre os componentes, prejudicando a modularidade e dificultando futuras expansões ou manutenções. A implementação rigorosa dos papéis definidos é essencial para evitar esse problema.


Estratégias para Mitigar Consequências Negativas:

Para reduzir os pontos negativos e maximizar os benefícios, sugerimos algumas estratégias práticas:

  • Realizar treinamentos específicos sobre padrões de projeto para a equipe envolvida, garantindo compreensão clara dos conceitos e implementações.
  • Avaliar previamente a capacidade computacional da plataforma embarcada e otimizar a implementação dos padrões sempre que possível, para garantir que a sobrecarga seja mínima.
  • Fazer testes de desempenho regulares, especialmente sobre comunicação e notificações, monitorando latência e ajustando parâmetros do sistema conforme necessário.
  • Aplicar testes unitários rigorosos e revisões de código frequentes, garantindo que cada componente cumpra estritamente seu papel definido pelos padrões.

Ao considerar esses pontos com atenção, os padrões Proxy e Observer, aliados aos micro-padrões complementares sugeridos, oferecem uma solução robusta, flexível e sustentável para a integração de inteligência artificial generativa com sistemas embarcados e IoT.

Estratégias de Implementação

Para que a implementação dos padrões Proxy e Observer no projeto com Ollama, computador de borda e STM32 Nucleo-WB09KE seja eficaz e sem complicações, recomendamos estratégias claras, baseadas nas melhores práticas da engenharia de software embarcado. A seguir detalhamos estas estratégias, destacando o passo a passo recomendado para a implementação prática e bem-sucedida dos padrões e integrações sugeridos.

1. Implementação Gradual e Incremental

Uma abordagem incremental é recomendada ao implementar padrões complexos:

  • Comece pelo Padrão Proxy, encapsulando o acesso ao sensor DHT22. Inicialmente, implemente e valide a comunicação direta com o hardware. Só após confirmação da funcionalidade básica, adicione a camada Proxy com funcionalidades adicionais como validação de dados e comunicação Bluetooth.
  • Em seguida, implemente o Padrão Observer, registrando inicialmente um único observer simples que imprime os dados recebidos. Após validação, adicione o observer real, que é o computador de borda utilizando o Ollama.

2. Definição Clara de Interfaces

Interfaces bem definidas são a base da implementação robusta dos padrões de projeto:

  • Utilize arquivos .h separados para interfaces (abstratas), mantendo-as bem documentadas com comentários explicativos. A utilização de interfaces abstratas facilita testes unitários e permite mudanças de implementação sem impacto nos usuários dessas interfaces.

Exemplo de interface clara em C:

// SensorInterface.h

#ifndef SENSOR_INTERFACE_H
#define SENSOR_INTERFACE_H

/**
 * Obtém a temperatura atual em graus Celsius.
 * @return Temperatura em Celsius.
 */
float getTemperature(void);

/**
 * Obtém a umidade atual em percentual (%).
 * @return Umidade relativa (%).
 */
float getHumidity(void);

#endif

3. Encapsulamento Rigoroso das Camadas

Separe claramente as camadas de firmware, comunicação, processamento de IA, e interface com o usuário:

  • O firmware no STM32 não deve ter conhecimento dos detalhes internos do Ollama ou da síntese de voz. Seu papel limita-se a leitura dos sensores e notificação dos eventos.
  • O computador de borda não precisa saber detalhes específicos do firmware ou do sensor, apenas espera notificações padronizadas.

Exemplo de organização sugerida:

Projeto/
├── firmware/
│   ├── drivers/       # Código para acesso ao DHT22
│   ├── proxy/         # Implementação Proxy
│   ├── observer/      # Implementação Observer
│   └── bluetooth/     # Comunicação Bluetooth
└── edge_computer/
    ├── ollama/        # Processamento de IA
    ├── audio/         # Conversão texto-áudio
    ├── listener/      # Observer Listener Bluetooth
    └── main.py        # Aplicação principal

4. Implementação da Comunicação Bluetooth Robusta

A comunicação via Bluetooth é um ponto sensível; sugerimos:

  • Definir claramente protocolos de comunicação (formato JSON ou outro padrão leve), com validação de pacotes enviados e recebidos.
  • Implementar rotinas robustas de reconexão automática em caso de perda temporária de comunicação.

Exemplo básico em formato JSON para envio do sensor:

{
    "sensor": "DHT22",
    "temperature": 25.3,
    "humidity": 55.4,
    "timestamp": 1713374823
}

5. Integração com Ollama e Processamento de Áudio

  • A interface Python que integra o Ollama deve ser desacoplada do sistema Bluetooth através de callbacks ou listeners assíncronos, conforme definido pelo padrão Observer.
  • Use bibliotecas maduras e bem testadas para conversão texto-áudio (e.g., pyttsx3, gTTS) visando robustez e desempenho.

Exemplo prático de integração em Python:

import ollama
import pyttsx3

class AIProcessor:
    def __init__(self, model='llama3'):
        self.model = model
        self.engine = pyttsx3.init()

    def generate_message(self, temp, hum):
        prompt = f"A temperatura atual é de {temp} graus Celsius e a umidade relativa é {hum}%. Informe isso ao usuário de forma amigável."
        response = ollama.chat(
            model=self.model,
            messages=[{'role': 'user', 'content': prompt}]
        )
        return response['message']['content']

    def speak(self, message):
        self.engine.say(message)
        self.engine.runAndWait()

# Listener recebendo dados do Bluetooth
def on_sensor_data_received(data):
    ai_processor = AIProcessor()
    message = ai_processor.generate_message(data['temperature'], data['humidity'])
    ai_processor.speak(message)

6. Validação e Testes Unitários

  • Testes unitários para cada camada e padrão são essenciais. Garanta testes automatizados usando frameworks adequados, como Unity ou Ceedling em C, e pytest ou unittest em Python.
  • Testes de integração entre firmware e computador de borda devem simular situações reais de operação, incluindo casos extremos (alta frequência de eventos, desconexões intermitentes, valores inválidos etc.).

7. Tratamento Cuidadoso das Exceções

Implemente rotinas para capturar e lidar com exceções tanto no firmware quanto no computador de borda, garantindo que o sistema nunca fique em um estado inconsistente ou imprevisível.

Exemplo de tratamento básico em Python:

try:
    message = ai_processor.generate_message(temp, hum)
except Exception as e:
    message = "Desculpe, ocorreu um problema ao gerar a mensagem."
    print(f"Erro ao gerar mensagem: {e}")

ai_processor.speak(message)

Seguindo essas estratégias, a implementação dos padrões Proxy e Observer/Listener no projeto será mais robusta, clara, escalável e de fácil manutenção. Essas estratégias também aumentam a qualidade e confiabilidade do sistema final.

Modelo de Amostragem

Neste modelo de amostragem, apresentaremos um exemplo completo e integrado, ilustrando claramente como aplicar os padrões Proxy e Observer/Listener, além da integração com Ollama no computador de borda, para a comunicação via Bluetooth com uma placa STM32 Nucleo-WB09KE lendo dados do sensor DHT22.

Este exemplo prático permitirá compreender claramente as interações entre os componentes e validar a eficácia dos padrões utilizados.


Estrutura Geral do Sistema

O sistema completo pode ser resumido na seguinte estrutura de comunicação e processamento:

  • STM32 Nucleo-WB09KE (Firmware em C)
    • Proxy para encapsular a leitura do sensor DHT22.
    • Observer (Listener) para notificar automaticamente o computador de borda via Bluetooth.
  • Computador de Borda (Python com Ollama e conversor de áudio)
    • Observer (Listener) recebendo notificações Bluetooth.
    • Ollama gerando mensagens interativas com base nos dados do sensor.
    • Sistema de áudio reproduzindo as mensagens geradas para o usuário.

Código Exemplo Simplificado (Firmware STM32 em C)

Interface Sensor (SensorInterface.h)

#ifndef SENSOR_INTERFACE_H
#define SENSOR_INTERFACE_H

float getTemperature(void);
float getHumidity(void);

#endif

RealSubject (DHT22Sensor.c)

#include "SensorInterface.h"

float getTemperature(void) {
    // código real para leitura do sensor DHT22
    return DHT22_read_temperature();
}

float getHumidity(void) {
    return DHT22_read_humidity();
}

Proxy (SensorProxy.c)

#include "SensorInterface.h"

float getTemperature(void) {
    float temp = DHT22_read_temperature();
    return (temp > -40 && temp < 80) ? temp : -999.0; // Validação básica
}

float getHumidity(void) {
    float hum = DHT22_read_humidity();
    return (hum >= 0 && hum <= 100) ? hum : -999.0; // Validação básica
}

Observer (BluetoothNotifier.c)

#include "BluetoothNotifier.h"
#include "SensorInterface.h"
#include <stdio.h>

void notifySensorData(void) {
    float temp = getTemperature();
    float hum = getHumidity();
    
    char json[128];
    sprintf(json, "{\"temperature\":%.2f,\"humidity\":%.2f}", temp, hum);
    Bluetooth_Send(json);
}

// Esta função é chamada por um timer (por exemplo, a cada 1 segundo)
void periodicSensorTask(void) {
    notifySensorData();
}

Código Exemplo Simplificado (Computador de Borda Python com Ollama)

listener.py (Observer Bluetooth)

import bluetooth
import json
from ai_processor import AIProcessor

def listen_for_sensor_data():
    ai_processor = AIProcessor()
    socket = bluetooth.BluetoothSocket(bluetooth.RFCOMM)
    socket.connect(('xx:xx:xx:xx:xx:xx', 1))

    try:
        while True:
            data = socket.recv(1024)
            sensor_data = json.loads(data.decode('utf-8'))
            temp = sensor_data['temperature']
            hum = sensor_data['humidity']
            ai_processor.process_and_speak(temp, hum)
    except Exception as e:
        print("Erro na comunicação Bluetooth:", e)
    finally:
        socket.close()

if __name__ == "__main__":
    print("Bem-vindo ao sistema inteligente.")
    listen_for_sensor_data()

ai_processor.py (Integração Ollama e áudio)

import ollama
import pyttsx3

class AIProcessor:
    def __init__(self, model='llama3'):
        self.model = model
        self.engine = pyttsx3.init()

    def generate_message(self, temp, hum):
        prompt = f"Crie uma mensagem amigável informando a temperatura de {temp:.1f} graus Celsius e a umidade de {hum:.1f}%."
        response = ollama.chat(
            model=self.model,
            messages=[{'role': 'user', 'content': prompt}]
        )
        return response['message']['content']

    def process_and_speak(self, temp, hum):
        if temp == -999.0 or hum == -999.0:
            message = "Não foi possível obter uma leitura válida do sensor. Por favor, verifique o dispositivo."
        else:
            message = self.generate_message(temp, hum)
        
        print("Mensagem gerada:", message)
        self.engine.say(message)
        self.engine.runAndWait()

    def close_system(self):
        self.engine.say("Obrigado por utilizar nosso sistema. Até breve.")
        self.engine.runAndWait()

Testes do Sistema Completo

Para validar a implementação, sugerimos as seguintes etapas práticas de teste:

  • Teste isolado do Proxy:
    Validar leituras corretas do sensor, com valores esperados e tratamento adequado dos valores inválidos.
  • Teste do Observer Bluetooth:
    Validar a comunicação Bluetooth estável e correta, incluindo reconexões automáticas.
  • Teste integrado com Ollama:
    Verificar geração correta e clara das mensagens e reprodução adequada dos áudios.
  • Testes de exceção e robustez:
    Realizar testes com desconexões propositais do Bluetooth, falhas do sensor e falhas do Ollama, garantindo comportamento previsível e seguro.

Resultados Esperados

Com este modelo de amostragem completo e funcional, esperamos obter:

  • Comunicação robusta e transparente entre sensor, firmware e computador de borda.
  • Mensagens amigáveis e naturais ao usuário final.
  • Arquitetura modular e expansível, com capacidade fácil de incorporar novos sensores ou funcionalidades adicionais no futuro.

Esse exemplo prático oferece um modelo para validação e ponto de partida para a evolução contínua do sistema embarcado integrado com inteligência generativa.


0 0 votos
Classificação do artigo
Inscrever-se
Notificar de
guest
0 Comentários
mais antigos
mais recentes Mais votado
Feedbacks embutidos
Ver todos os comentários

Related Post

0
Adoraria saber sua opinião, comente.x