Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/.idea/
10 changes: 10 additions & 0 deletions REST-API-cliente-mqtt-consultas/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
FROM python:3.11-slim
WORKDIR /

COPY . .
COPY requirements.txt requirements.txt

RUN pip install -r requirements.txt
RUN apt-get update && apt-get install -y tzdata

EXPOSE 8000
Binary file not shown.
27 changes: 27 additions & 0 deletions REST-API-cliente-mqtt-consultas/docker-compose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
services:
mongodb:
image: mongo:latest
restart: always
ports:
- "27017:27017"
environment:
MONGO_INITDB_ROOT_USERNAME: admin
MONGO_INITDB_ROOT_PASSWORD: secret
TZ: America/Sao_Paulo
volumes:
- mongo_data:/data/db
web:
build:
dockerfile: Dockerfile
ports:
- "8000:8000"
environment:
- DB_URI=mongodb://admin:secret@mongodb:27017
- DB_NAME=meu_banco
- COLLECTION_NAME=minha_colecao
command: uvicorn main:app --host 0.0.0.0 --port 8000
depends_on:
- mongodb

volumes:
mongo_data:
129 changes: 129 additions & 0 deletions REST-API-cliente-mqtt-consultas/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
from repositories.MongoEnvironmentalDataRepository import MongoEnvironmentalDataRepository
from models.EnvironmentalData import EnvironmentalData
from datetime import datetime, time
from bson.json_util import dumps
import json
import os
from dotenv import load_dotenv
from contextlib import asynccontextmanager
import pytz
from fastapi import FastAPI, HTTPException

from fastapi_mqtt import FastMQTT, MQTTConfig

load_dotenv()

uri = os.getenv("DB_URI")
db_name = os.getenv("DB_NAME")
collection_name = os.getenv("COLLECTION_NAME")
#taskkill /f /im python.exe

mqtt_config = MQTTConfig(
host="lsdi.ufma.br",
port=1883,
keepalive=60
)
fast_mqtt = FastMQTT(config=mqtt_config)

@asynccontextmanager
async def _lifespan(_app: FastAPI):
await fast_mqtt.mqtt_startup()
yield
await fast_mqtt.mqtt_shutdown()

app = FastAPI(lifespan=_lifespan)
repository = MongoEnvironmentalDataRepository(uri, db_name, collection_name)

@fast_mqtt.on_connect()
def connect(client, flags, rc, properties):
client.subscribe("mhub/MHUB_SALAS/service_topic/HMSoft") # subscribing mqtt topic
print("Connected: ", client, flags, rc, properties)

@app.get("/")
async def root():
return "Server está funcionando"

@app.get("/instante")
async def get_medicao_instante(data: datetime = datetime.now()) -> str:
if data.tzinfo is None: # Data sem fuso horario
sao_paulo = pytz.timezone("America/Sao_Paulo") # Assume que a data recebida é UTC-3
data = sao_paulo.localize(data).astimezone(pytz.utc) # Converte pra UTC
else:
data = data.astimezone(pytz.utc)

env_data_dict = await repository.get_by_instante(data)
if env_data_dict == dict():
raise HTTPException(status_code=404, detail="Dados não encontrados")

timestamp = env_data_dict["timestamp"]

env_data_dict["timestamp"] = timestamp.astimezone( # Convertendo o dado de volta pra UTC-3
pytz.timezone("America/Sao_Paulo")
).isoformat()

env_data_dict.pop("_id") # Manda o dado sem id
return dumps(env_data_dict)

@app.get("/recente")
async def get_mais_recente() -> str:
env_data_dict = await repository.get_mais_recente() # Isso faz sentido?
if not env_data_dict:
raise HTTPException(status_code=404, detail="Dados não encontrados")

timestamp = env_data_dict["timestamp"]
env_data_dict["timestamp"] = timestamp.astimezone(
pytz.timezone("America/Sao_Paulo")
).isoformat()

env_data_dict.pop("_id")
return dumps(env_data_dict)

@app.get("/intervalo")
async def get_medicao_intervalo(inicio: datetime = datetime.combine(datetime.now(), time.min),
fim: datetime = datetime.combine(datetime.now(), time.max)) -> str:
if inicio.tzinfo is None:
sao_paulo = pytz.timezone("America/Sao_Paulo")
inicio = sao_paulo.localize(inicio).astimezone(pytz.utc)
else:
inicio = inicio.astimezone(pytz.utc)

if fim.tzinfo is None:
sao_paulo = pytz.timezone("America/Sao_Paulo")
fim = sao_paulo.localize(fim).astimezone(pytz.utc)
else:
fim = fim.astimezone(pytz.utc)

env_data_list = await repository.get_by_intervalo(inicio, fim)
if env_data_list == list():
raise HTTPException(status_code=404, detail="Dados não encontrados")

for env_data in env_data_list:
timestamp = env_data["timestamp"]
env_data["timestamp"] = timestamp.astimezone( # Convertendo de volta pra UTC-3
pytz.timezone("America/Sao_Paulo")
).isoformat()

for env_data in env_data_list: # Removendo IDs
env_data.pop("_id")

return dumps(env_data_list)


@fast_mqtt.on_message()
async def message(client, topic, payload, qos, properties):
msg = payload.decode()
print("Received message: ", topic, msg, qos, properties)
data = json.loads(msg) # Transformando pra dicionario
service_values = data.get("serviceValue", [])

env_data = EnvironmentalData(
timestamp=datetime.now(pytz.utc),
temperatura=service_values[0],
umidade=service_values[1],
gas=service_values[2]
)
await repository.insert_one(env_data)

@fast_mqtt.on_disconnect()
def disconnect(client, packet, exc=None):
print("Disconnected")
20 changes: 9 additions & 11 deletions SensorData.py → ...qtt-consultas/models/EnvironmentalData.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
from pydantic import BaseModel
from datetime import datetime


class EnvironmentalData(BaseModel):
timestamp: datetime = datetime.now()
local: str | None = None
temperatura: float | None = None
umidade: float | None = None
gas: bool | None = None
luminosidade: float | None = None
from pydantic import BaseModel
from datetime import datetime

class EnvironmentalData(BaseModel):
timestamp: datetime
temperatura: float | None = None
umidade: float | None = None
gas: bool | None = None
luminosidade: float | None = None
ruido: float | None = None
Empty file.
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
from abc import ABC, abstractmethod
from datetime import datetime
from models.EnvironmentalData import EnvironmentalData

# Classe abstrata de persistência e recuperação de dados do ambiente
class EnvironmentalDataRepository(ABC):

@abstractmethod
def insert_one(self, data: EnvironmentalData) -> any:
pass

@abstractmethod
def get_by_intervalo(self, inicio: datetime, fim: datetime) -> list[EnvironmentalData]:
pass

@abstractmethod
def get_mais_recente(self) -> EnvironmentalData:
pass

@abstractmethod
def get_by_instante(self, data: datetime) -> EnvironmentalData:
pass
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
from repositories.EnvironmentalDataRepository import EnvironmentalDataRepository
from models.EnvironmentalData import EnvironmentalData
from datetime import datetime
from pymongo import AsyncMongoClient

class MongoEnvironmentalDataRepository(EnvironmentalDataRepository):
def __init__(self, uri: str, db_name: str, collection_name: str) -> None:
self.client = AsyncMongoClient(uri, tz_aware=True)
self.db = self.client[db_name]
self.collection = self.db.get_collection(collection_name)

async def insert_one(self, data: EnvironmentalData) -> str:
resp = await self.collection.insert_one(data.model_dump(exclude_none=True))
return str(resp.inserted_id)

async def get_by_intervalo(self, inicio: datetime, fim: datetime) -> list[dict]:
filtro = {
"timestamp": {
"$gte": inicio,
"$lte": fim
}
}
cursor = self.collection.find(filtro)
documentos = await cursor.to_list()
return documentos if documentos else list()

async def get_by_instante(self, data: datetime) -> dict:
anterior = await self.collection.find_one(
{"timestamp": {"$lte": data}},
sort=[("timestamp", -1)]
)
return anterior if anterior else dict()

async def get_mais_recente(self) -> dict:
doc = await self.collection.find_one(sort=[("timestamp", -1)])
return doc if doc else dict()
Empty file.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file added REST-API-cliente-mqtt-consultas/requirements.txt
Binary file not shown.
7 changes: 0 additions & 7 deletions db.py

This file was deleted.

92 changes: 0 additions & 92 deletions main.py

This file was deleted.

16 changes: 0 additions & 16 deletions requirements.txt

This file was deleted.