From 288a4a6079dc315599204a9a00f649c82c987e07 Mon Sep 17 00:00:00 2001 From: Breno Vidigal <96669455+FlamingDev@users.noreply.github.com> Date: Sun, 1 Jun 2025 20:36:19 -0300 Subject: [PATCH 01/20] Delete SensorData.py --- SensorData.py | 12 ------------ 1 file changed, 12 deletions(-) delete mode 100644 SensorData.py diff --git a/SensorData.py b/SensorData.py deleted file mode 100644 index 18e4e1f..0000000 --- a/SensorData.py +++ /dev/null @@ -1,12 +0,0 @@ -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 - ruido: float | None = None \ No newline at end of file From c90f77dfeaaa0e6adaa704d98443def375b46d37 Mon Sep 17 00:00:00 2001 From: Breno Vidigal <96669455+FlamingDev@users.noreply.github.com> Date: Sun, 1 Jun 2025 20:36:40 -0300 Subject: [PATCH 02/20] Delete db.py --- db.py | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 db.py diff --git a/db.py b/db.py deleted file mode 100644 index dce4cfe..0000000 --- a/db.py +++ /dev/null @@ -1,7 +0,0 @@ -from pymongo.mongo_client import MongoClient -from pymongo.server_api import ServerApi -import os - -uri = os.getenv("MONGODB_URI") -# Create a new client and connect to the server -client = MongoClient(uri, server_api=ServerApi('1')) \ No newline at end of file From 6b841662ebd556debd7aacde828d8e63b5ac00d6 Mon Sep 17 00:00:00 2001 From: Breno Vidigal <96669455+FlamingDev@users.noreply.github.com> Date: Sun, 1 Jun 2025 20:37:20 -0300 Subject: [PATCH 03/20] Delete main.py --- main.py | 92 --------------------------------------------------------- 1 file changed, 92 deletions(-) delete mode 100644 main.py diff --git a/main.py b/main.py deleted file mode 100644 index 3f0c264..0000000 --- a/main.py +++ /dev/null @@ -1,92 +0,0 @@ -from fastapi import HTTPException - -from fastapi import FastAPI - -from db import uri, client -from datetime import datetime -from SensorData import EnvironmentalData -from bson.json_util import dumps -import json - -db = client["sensor_data"] -collection = db.get_collection("monitoramento_ambiental") -app = FastAPI() -from datetime import timedelta -#taskkill /f /im python.exe - -def query_media_dia(local, inicio, fim): - # Retorna um documento que tem a média da temperatura, umidade, luminosidade e ruído daquele dia específico - return [ - {"$match": { - "local": local, - "timestamp": {"$gte": inicio, "$lte": fim} - }}, - { - "$group": { - "_id": None, - "temp_avg": { - "$avg": "$temperatura" - }, - "umi_avg": { - "$avg": "$umidade" - }, - "lumi_avg": { - "$avg": "$luminosidade" - }, - "ruido_avg": { - "$avg": "$ruido" - } - } - } - ] - - - -def query_document_at_datetime(local: str, data: datetime): - INTERVALO = 2 - margem = timedelta(seconds=INTERVALO) - inicio = data - margem - fim = data + margem - - print(margem) - print(inicio) - print(fim) - # Retorna um documento daquele local que esteja dentro do intervalo inicio-fim - return { - "local": local, - "timestamp": { - "$gte": inicio, - "$lte": fim - } - } - - -@app.get("/media") -async def get_medicao_media_dia(local: str, data: datetime): - inicio = datetime.combine(data.date(), datetime.min.time()) - fim = datetime.combine(data.date(), datetime.max.time()) - result = json.loads(dumps(collection.aggregate(query_media_dia(local, inicio, fim)))) - - if result: - return result[0] - else: - raise HTTPException(status_code=404, detail="Medição não encontrada nessa data") - -@app.get("/instante") -async def get_medicao_instante(local: str, data: datetime): - result = collection.find_one(query_document_at_datetime(local, data)) - if result is None: - raise HTTPException(status_code=404, detail="Medição não encontrada nesse instante") - return json.loads(dumps(result)) - -@app.post("/novo") -async def insert(s: EnvironmentalData): - try: - resp = collection.insert_one(s.dict(exclude_none=True)) - return str(resp.inserted_id) - except Exception as e: - raise HTTPException(status_code=500, detail=str(e)) - -@app.get("/teste") -async def teste(): - print(uri) \ No newline at end of file From e46001baf9590b4483d90bd121b5c035c9792ee8 Mon Sep 17 00:00:00 2001 From: Breno Vidigal <96669455+FlamingDev@users.noreply.github.com> Date: Sun, 1 Jun 2025 20:37:48 -0300 Subject: [PATCH 04/20] Add files via upload --- EnvironmentalData.py | 14 +++++ EnvironmentalDataRepository.py | 18 +++++++ MongoEnvironmentalDataRepository.py | 22 ++++++++ main.py | 80 +++++++++++++++++++++++++++++ 4 files changed, 134 insertions(+) create mode 100644 EnvironmentalData.py create mode 100644 EnvironmentalDataRepository.py create mode 100644 MongoEnvironmentalDataRepository.py create mode 100644 main.py diff --git a/EnvironmentalData.py b/EnvironmentalData.py new file mode 100644 index 0000000..dfb3a03 --- /dev/null +++ b/EnvironmentalData.py @@ -0,0 +1,14 @@ +from pydantic import BaseModel +from datetime import datetime + +from pydantic.v1.dataclasses import dataclass + +@dataclass +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 + ruido: float | None = None \ No newline at end of file diff --git a/EnvironmentalDataRepository.py b/EnvironmentalDataRepository.py new file mode 100644 index 0000000..4452944 --- /dev/null +++ b/EnvironmentalDataRepository.py @@ -0,0 +1,18 @@ +from abc import ABC, abstractmethod +from dataclasses import dataclass +from datetime import datetime +from SensorData 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[int]: + pass + + @abstractmethod + def get_by_instante(self, data: datetime) -> EnvironmentalData: + pass diff --git a/MongoEnvironmentalDataRepository.py b/MongoEnvironmentalDataRepository.py new file mode 100644 index 0000000..b41c285 --- /dev/null +++ b/MongoEnvironmentalDataRepository.py @@ -0,0 +1,22 @@ +from repository import EnvironmentalDataRepository +from pymongo.server_api import ServerApi +from SensorData import EnvironmentalData +from datetime import datetime +from pymongo import AsyncMongoClient + + +class MongoEnvironmentalDataRepository(EnvironmentalDataRepository): + def __init__(self, uri: str, db_name: str, collection_name: str): + self.client = AsyncMongoClient(uri) + self.db = self.client[db_name] + self.collection = self.db.get_collection(collection_name) + + async def insert_one(self, data: EnvironmentalData) -> any: + resp = await self.collection.insert_one(data.dict(exclude_none=True)) + return str(resp.inserted_id) + + def get_by_intervalo(self, inicio: datetime, fim: datetime) -> list[EnvironmentalData]: + pass + + def get_by_instante(self, data: datetime) -> dict: + pass \ No newline at end of file diff --git a/main.py b/main.py new file mode 100644 index 0000000..363d910 --- /dev/null +++ b/main.py @@ -0,0 +1,80 @@ +from SensorDataRepository import MongoEnvironmentalDataRepository +from SensorData import EnvironmentalData +from fastapi import HTTPException, Depends +from gmqtt import Client as MQTTClient + +from fastapi import FastAPI +from datetime import datetime +from bson.json_util import dumps +import json +from datetime import timedelta +import os +from dotenv import load_dotenv +import asyncio +from contextlib import asynccontextmanager +from typing import Any + +from fastapi import FastAPI + +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, + username="breno.vidigal@lsdi.ufma.br", + password="carlos16522" +) +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("#") # subscribing mqtt topic + print("Connected: ", client, flags, rc, properties) + +@app.get("/root") +async def get_root(): + return "Server está funcionando" + +@app.get("/instante") +async def get_medicao_instante(data: datetime): + return repository.get_by_instante(data) + +@app.get("/intervalo") +async def get_medicao_intervalo(inicio: datetime, fim: datetime): + return repository.get_by_intervalo(inicio, fim) + +@app.post("/novo") +async def insert(data: EnvironmentalData): # Persiste a medição e retorna o id daquele objeto no banco + resp = await repository.insert_one(data) + return resp + +@app.get("/teste") +async def teste(): + print(uri) + +@fast_mqtt.on_message() +async def message(client, topic, payload, qos, properties): + print("Received message: ",topic, payload.decode(), qos, properties) + +@app.post("/ffff") +async def func(): + fast_mqtt.publish("/HMSoft", "Hello from Fastapi") #publishing mqtt topic + + return {"result": True,"message":"Published" } \ No newline at end of file From 899c771ae3194b195a194785bb7e55f826149bc0 Mon Sep 17 00:00:00 2001 From: Breno Vidigal <96669455+FlamingDev@users.noreply.github.com> Date: Mon, 2 Jun 2025 09:33:30 -0300 Subject: [PATCH 05/20] Add files via upload --- EnvironmentalDataRepository.py | 2 +- MongoEnvironmentalDataRepository.py | 4 ++-- main.py | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/EnvironmentalDataRepository.py b/EnvironmentalDataRepository.py index 4452944..a5ebc55 100644 --- a/EnvironmentalDataRepository.py +++ b/EnvironmentalDataRepository.py @@ -1,7 +1,7 @@ from abc import ABC, abstractmethod from dataclasses import dataclass from datetime import datetime -from SensorData import EnvironmentalData +from EnvironmentalData import EnvironmentalData # Classe abstrata de persistência e recuperação de dados do ambiente class EnvironmentalDataRepository(ABC): diff --git a/MongoEnvironmentalDataRepository.py b/MongoEnvironmentalDataRepository.py index b41c285..5d505ef 100644 --- a/MongoEnvironmentalDataRepository.py +++ b/MongoEnvironmentalDataRepository.py @@ -1,6 +1,6 @@ -from repository import EnvironmentalDataRepository +from EnvironmentalDataRepository import EnvironmentalDataRepository from pymongo.server_api import ServerApi -from SensorData import EnvironmentalData +import EnvironmentalData from datetime import datetime from pymongo import AsyncMongoClient diff --git a/main.py b/main.py index 363d910..6778afd 100644 --- a/main.py +++ b/main.py @@ -1,5 +1,5 @@ -from SensorDataRepository import MongoEnvironmentalDataRepository -from SensorData import EnvironmentalData +from MongoEnvironmentalDataRepository import MongoEnvironmentalDataRepository +from EnvironmentalData import EnvironmentalData from fastapi import HTTPException, Depends from gmqtt import Client as MQTTClient From 78ee9f368e6ce3cc942fb0754858c58f92ce8439 Mon Sep 17 00:00:00 2001 From: Breno Vidigal <96669455+FlamingDev@users.noreply.github.com> Date: Mon, 2 Jun 2025 18:26:50 -0300 Subject: [PATCH 06/20] Add files via upload --- requirements.txt | Bin 278 -> 814 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/requirements.txt b/requirements.txt index e2078d3ebdc7dd2431d4468f9e078f8eac34accc..e37fa3d3a716dcd52348f6f808e31e91ebcc5d16 100644 GIT binary patch literal 814 zcmZWn?M}i#5S-s8K1vBk73GJ|LYlUeMtTB8BQLMc>~j5(T#l04+1Z`h{rxErc|LGK z!CRw3#_ttJ{_pX|v%~@~yh}XdfvCu6%M8Vy_`aFMdd4D3i)ZL?BG+YL30M=mGM*9# zqDs75^wr)|jgssK-ZQIpyr~OSTU&O;Dm{C=l6_BPG|YiYYUZ_;&NF$}p< zUlA9nLQcvh^`lw~PDa!EkJ%C@U+V##Lv?*7LU-n7!{0RDV2IS$=y=BJbB9%T?5}5M zEp|LdoChbJ8^xXj0>x$35{~Y{}Ko4ShBDnmVL9OMQKVcTBm9ZqQA$f5XW76*W<`sBuXAmvah*@(7^>d z6M3f+f`^-mG*fzpa0S~$nadWJ*fu@%X5hN+G8GQN9?>yYi7T}^;u+AI3Gq<9#%W-U zI>64X`w&?uwICw+zj04x%guETth!6##{q**8!FQ{HaG;WF?wv9vxo*1sMml#Li{+9 hg5@OC$Qo+*8{G3pGFSEWTMyc4&Ff8i^H_9V^%ri0Q|ABx From d4134da364db4049f08597eacbff51e344ef3b6f Mon Sep 17 00:00:00 2001 From: Breno Vidigal <96669455+FlamingDev@users.noreply.github.com> Date: Thu, 5 Jun 2025 08:06:02 -0300 Subject: [PATCH 07/20] Add files via upload --- EnvironmentalData.py | 4 ---- EnvironmentalDataRepository.py | 2 +- MongoEnvironmentalDataRepository.py | 24 +++++++++++++++---- main.py | 36 ++++++++++++++++++++--------- 4 files changed, 45 insertions(+), 21 deletions(-) diff --git a/EnvironmentalData.py b/EnvironmentalData.py index dfb3a03..8cc8de7 100644 --- a/EnvironmentalData.py +++ b/EnvironmentalData.py @@ -1,12 +1,8 @@ from pydantic import BaseModel from datetime import datetime -from pydantic.v1.dataclasses import dataclass - -@dataclass class EnvironmentalData(BaseModel): timestamp: datetime = datetime.now() - local: str | None = None temperatura: float | None = None umidade: float | None = None gas: bool | None = None diff --git a/EnvironmentalDataRepository.py b/EnvironmentalDataRepository.py index a5ebc55..63b8e87 100644 --- a/EnvironmentalDataRepository.py +++ b/EnvironmentalDataRepository.py @@ -10,7 +10,7 @@ def insert_one(self, data: EnvironmentalData) -> any: pass @abstractmethod - def get_by_intervalo(self, inicio: datetime, fim: datetime) -> list[int]: + def get_by_intervalo(self, inicio: datetime, fim: datetime) -> list[EnvironmentalData]: pass @abstractmethod diff --git a/MongoEnvironmentalDataRepository.py b/MongoEnvironmentalDataRepository.py index 5d505ef..1293d15 100644 --- a/MongoEnvironmentalDataRepository.py +++ b/MongoEnvironmentalDataRepository.py @@ -3,7 +3,9 @@ import EnvironmentalData from datetime import datetime from pymongo import AsyncMongoClient - +from bson.json_util import dumps +import bson +import json class MongoEnvironmentalDataRepository(EnvironmentalDataRepository): def __init__(self, uri: str, db_name: str, collection_name: str): @@ -15,8 +17,20 @@ async def insert_one(self, data: EnvironmentalData) -> any: resp = await self.collection.insert_one(data.dict(exclude_none=True)) return str(resp.inserted_id) - def get_by_intervalo(self, inicio: datetime, fim: datetime) -> list[EnvironmentalData]: - pass + async def get_by_intervalo(self, inicio: datetime, fim: datetime) -> list[EnvironmentalData]: + filtro = { + "timestamp": { + "$gte": inicio, + "$lte": fim + } + } + cursor = await self.collection.find(filtro) + documentos = await cursor.to_list() + return dumps(documentos) - def get_by_instante(self, data: datetime) -> dict: - pass \ No newline at end of file + async def get_by_instante(self, data: datetime = datetime.now()) -> dict: + anterior = await self.collection.find_one( + {"timestamp": {"$lte": data}}, + sort=[("timestamp", -1)] + ) + print(dumps(anterior)) \ No newline at end of file diff --git a/main.py b/main.py index 6778afd..47049a7 100644 --- a/main.py +++ b/main.py @@ -20,6 +20,10 @@ load_dotenv() +print(os.getenv("DB_URI")) +print(os.getenv("DB_NAME")) +print(os.getenv("COLLECTION_NAME")) + uri = os.getenv("DB_URI"); db_name = os.getenv("DB_NAME") collection_name = os.getenv("COLLECTION_NAME") @@ -28,9 +32,7 @@ mqtt_config = MQTTConfig( host="lsdi.ufma.br", port=1883, - keepalive=60, - username="breno.vidigal@lsdi.ufma.br", - password="carlos16522" + keepalive=60 ) fast_mqtt = FastMQTT(config=mqtt_config) @@ -45,7 +47,7 @@ async def _lifespan(_app: FastAPI): @fast_mqtt.on_connect() def connect(client, flags, rc, properties): - client.subscribe("#") # subscribing mqtt topic + client.subscribe("mhub/MHUB_SALA_ETS/service_topic/HMSoft") # subscribing mqtt topic print("Connected: ", client, flags, rc, properties) @app.get("/root") @@ -54,15 +56,12 @@ async def get_root(): @app.get("/instante") async def get_medicao_instante(data: datetime): - return repository.get_by_instante(data) + resp = await repository.get_by_instante(data) + return resp @app.get("/intervalo") async def get_medicao_intervalo(inicio: datetime, fim: datetime): - return repository.get_by_intervalo(inicio, fim) - -@app.post("/novo") -async def insert(data: EnvironmentalData): # Persiste a medição e retorna o id daquele objeto no banco - resp = await repository.insert_one(data) + resp = await repository.get_by_intervalo(inicio, fim) return resp @app.get("/teste") @@ -71,7 +70,22 @@ async def teste(): @fast_mqtt.on_message() async def message(client, topic, payload, qos, properties): - print("Received message: ",topic, payload.decode(), 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(), + 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") @app.post("/ffff") async def func(): From af64df1d31dde7f0d4a1cc718427b9add55b612f Mon Sep 17 00:00:00 2001 From: Lucas Santos Silva Date: Thu, 5 Jun 2025 14:03:08 -0300 Subject: [PATCH 08/20] feat: adding docker file and docker compose --- .gitignore | 1 + app/Dockerfile | 9 + .../EnvironmentalData.py | 18 +- .../EnvironmentalDataRepository.py | 36 ++-- .../MongoEnvironmentalDataRepository.py | 71 ++++--- app/__init__.py | 0 main.py => app/main.py | 185 +++++++++--------- docker-compose.yaml | 26 +++ 8 files changed, 190 insertions(+), 156 deletions(-) create mode 100644 .gitignore create mode 100644 app/Dockerfile rename EnvironmentalData.py => app/EnvironmentalData.py (97%) rename EnvironmentalDataRepository.py => app/EnvironmentalDataRepository.py (88%) rename MongoEnvironmentalDataRepository.py => app/MongoEnvironmentalDataRepository.py (83%) create mode 100644 app/__init__.py rename main.py => app/main.py (84%) create mode 100644 docker-compose.yaml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..85e7c1d --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/.idea/ diff --git a/app/Dockerfile b/app/Dockerfile new file mode 100644 index 0000000..e2b4959 --- /dev/null +++ b/app/Dockerfile @@ -0,0 +1,9 @@ +FROM python:3.11-slim +WORKDIR /app + +COPY app/ app/ +COPY requirements.txt app/requirements.txt + +RUN pip install -r app/requirements.txt + +EXPOSE 8000 \ No newline at end of file diff --git a/EnvironmentalData.py b/app/EnvironmentalData.py similarity index 97% rename from EnvironmentalData.py rename to app/EnvironmentalData.py index 8cc8de7..c7abd64 100644 --- a/EnvironmentalData.py +++ b/app/EnvironmentalData.py @@ -1,10 +1,10 @@ -from pydantic import BaseModel -from datetime import datetime - -class EnvironmentalData(BaseModel): - timestamp: datetime = datetime.now() - 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 = datetime.now() + temperatura: float | None = None + umidade: float | None = None + gas: bool | None = None + luminosidade: float | None = None ruido: float | None = None \ No newline at end of file diff --git a/EnvironmentalDataRepository.py b/app/EnvironmentalDataRepository.py similarity index 88% rename from EnvironmentalDataRepository.py rename to app/EnvironmentalDataRepository.py index 63b8e87..6d814a7 100644 --- a/EnvironmentalDataRepository.py +++ b/app/EnvironmentalDataRepository.py @@ -1,18 +1,18 @@ -from abc import ABC, abstractmethod -from dataclasses import dataclass -from datetime import datetime -from 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_by_instante(self, data: datetime) -> EnvironmentalData: - pass +from abc import ABC, abstractmethod +from dataclasses import dataclass +from datetime import datetime +from app.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_by_instante(self, data: datetime) -> EnvironmentalData: + pass diff --git a/MongoEnvironmentalDataRepository.py b/app/MongoEnvironmentalDataRepository.py similarity index 83% rename from MongoEnvironmentalDataRepository.py rename to app/MongoEnvironmentalDataRepository.py index 1293d15..efdfbf3 100644 --- a/MongoEnvironmentalDataRepository.py +++ b/app/MongoEnvironmentalDataRepository.py @@ -1,36 +1,35 @@ -from EnvironmentalDataRepository import EnvironmentalDataRepository -from pymongo.server_api import ServerApi -import EnvironmentalData -from datetime import datetime -from pymongo import AsyncMongoClient -from bson.json_util import dumps -import bson -import json - -class MongoEnvironmentalDataRepository(EnvironmentalDataRepository): - def __init__(self, uri: str, db_name: str, collection_name: str): - self.client = AsyncMongoClient(uri) - self.db = self.client[db_name] - self.collection = self.db.get_collection(collection_name) - - async def insert_one(self, data: EnvironmentalData) -> any: - resp = await self.collection.insert_one(data.dict(exclude_none=True)) - return str(resp.inserted_id) - - async def get_by_intervalo(self, inicio: datetime, fim: datetime) -> list[EnvironmentalData]: - filtro = { - "timestamp": { - "$gte": inicio, - "$lte": fim - } - } - cursor = await self.collection.find(filtro) - documentos = await cursor.to_list() - return dumps(documentos) - - async def get_by_instante(self, data: datetime = datetime.now()) -> dict: - anterior = await self.collection.find_one( - {"timestamp": {"$lte": data}}, - sort=[("timestamp", -1)] - ) - print(dumps(anterior)) \ No newline at end of file +from app.EnvironmentalDataRepository import EnvironmentalDataRepository +from app.EnvironmentalData import EnvironmentalData +from datetime import datetime +from pymongo import AsyncMongoClient +from bson.json_util import dumps + + +class MongoEnvironmentalDataRepository(EnvironmentalDataRepository): + def __init__(self, uri: str, db_name: str, collection_name: str): + self.client = AsyncMongoClient(uri) + self.db = self.client[db_name] + self.collection = self.db.get_collection(collection_name) + + async def insert_one(self, data: EnvironmentalData) -> any: + resp = await self.collection.insert_one(data.dict(exclude_none=True)) + return str(resp.inserted_id) + + async def get_by_intervalo(self, inicio: datetime, fim: datetime) -> list[EnvironmentalData]: + filtro = { + "timestamp": { + "$gte": inicio, + "$lte": fim + } + } + cursor = await self.collection.find(filtro) + documentos = await cursor.to_list() + return dumps(documentos) + + async def get_by_instante(self, data: datetime = datetime.now()) -> dict: + anterior = await self.collection.find_one( + {"timestamp": {"$lte": data}}, + sort=[("timestamp", -1)] + ) + print(dumps(anterior)) + return dumps(anterior) \ No newline at end of file diff --git a/app/__init__.py b/app/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/main.py b/app/main.py similarity index 84% rename from main.py rename to app/main.py index 47049a7..a12f62c 100644 --- a/main.py +++ b/app/main.py @@ -1,94 +1,93 @@ -from MongoEnvironmentalDataRepository import MongoEnvironmentalDataRepository -from EnvironmentalData import EnvironmentalData -from fastapi import HTTPException, Depends -from gmqtt import Client as MQTTClient - -from fastapi import FastAPI -from datetime import datetime -from bson.json_util import dumps -import json -from datetime import timedelta -import os -from dotenv import load_dotenv -import asyncio -from contextlib import asynccontextmanager -from typing import Any - -from fastapi import FastAPI - -from fastapi_mqtt import FastMQTT, MQTTConfig - -load_dotenv() - -print(os.getenv("DB_URI")) -print(os.getenv("DB_NAME")) -print(os.getenv("COLLECTION_NAME")) - -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_SALA_ETS/service_topic/HMSoft") # subscribing mqtt topic - print("Connected: ", client, flags, rc, properties) - -@app.get("/root") -async def get_root(): - return "Server está funcionando" - -@app.get("/instante") -async def get_medicao_instante(data: datetime): - resp = await repository.get_by_instante(data) - return resp - -@app.get("/intervalo") -async def get_medicao_intervalo(inicio: datetime, fim: datetime): - resp = await repository.get_by_intervalo(inicio, fim) - return resp - -@app.get("/teste") -async def teste(): - print(uri) - -@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(), - 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") - -@app.post("/ffff") -async def func(): - fast_mqtt.publish("/HMSoft", "Hello from Fastapi") #publishing mqtt topic - +from app.MongoEnvironmentalDataRepository import MongoEnvironmentalDataRepository +from app.EnvironmentalData import EnvironmentalData +from fastapi import HTTPException, Depends +from gmqtt import Client as MQTTClient + +from fastapi import FastAPI +from datetime import datetime, timedelta +from bson.json_util import dumps +import json +import os +from dotenv import load_dotenv +import asyncio +from contextlib import asynccontextmanager +from typing import Any + +from fastapi import FastAPI + +from fastapi_mqtt import FastMQTT, MQTTConfig + +load_dotenv() + +print(os.getenv("DB_URI")) +print(os.getenv("DB_NAME")) +print(os.getenv("COLLECTION_NAME")) + +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_SALA_ETS/service_topic/HMSoft") # subscribing mqtt topic + print("Connected: ", client, flags, rc, properties) + +@app.get("/root") +async def get_root(): + return "Server está funcionando" + +@app.get("/instante") +async def get_medicao_instante(data: datetime = datetime.now()): + resp = await repository.get_by_instante() + return resp + +@app.get("/intervalo") +async def get_medicao_intervalo(inicio: datetime, fim: datetime): + resp = await repository.get_by_intervalo(inicio, fim) + return resp + +@app.get("/teste") +async def teste(): + print(uri) + +@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(), + 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") + +@app.post("/ffff") +async def func(): + fast_mqtt.publish("/HMSoft", "Hello from Fastapi") #publishing mqtt topic + return {"result": True,"message":"Published" } \ No newline at end of file diff --git a/docker-compose.yaml b/docker-compose.yaml new file mode 100644 index 0000000..75a1923 --- /dev/null +++ b/docker-compose.yaml @@ -0,0 +1,26 @@ +services: + mongodb: + image: mongo:latest + restart: always + ports: + - "27017:27017" + environment: + MONGO_INITDB_ROOT_USERNAME: admin + MONGO_INITDB_ROOT_PASSWORD: secret + volumes: + - mongo_data:/data/db + web: + build: + dockerfile: app/Dockerfile + ports: + - "8000:8000" + environment: + - DB_URI=mongodb://admin:secret@mongodb:27017 + - DB_NAME=meu_banco + - COLLECTION_NAME=minha_colecao + command: uvicorn app.main:app --host 0.0.0.0 --port 8000 + depends_on: + - mongodb + +volumes: + mongo_data: \ No newline at end of file From 80e0696cd63b21c33e4ff8d2e9f549910dc5e701 Mon Sep 17 00:00:00 2001 From: Breno Vidigal Date: Fri, 6 Jun 2025 12:16:17 -0300 Subject: [PATCH 09/20] =?UTF-8?q?corre=C3=A7=C3=A3o=20data=20UTC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/Dockerfile | 1 + app/EnvironmentalDataRepository.py | 1 - app/MongoEnvironmentalDataRepository.py | 2 +- app/main.py | 16 ++++++---------- docker-compose.yaml | 2 ++ requirements.txt | Bin 814 -> 842 bytes 6 files changed, 10 insertions(+), 12 deletions(-) diff --git a/app/Dockerfile b/app/Dockerfile index e2b4959..6f19b9c 100644 --- a/app/Dockerfile +++ b/app/Dockerfile @@ -5,5 +5,6 @@ COPY app/ app/ COPY requirements.txt app/requirements.txt RUN pip install -r app/requirements.txt +RUN apt-get update && apt-get install -y tzdata EXPOSE 8000 \ No newline at end of file diff --git a/app/EnvironmentalDataRepository.py b/app/EnvironmentalDataRepository.py index 6d814a7..515ba66 100644 --- a/app/EnvironmentalDataRepository.py +++ b/app/EnvironmentalDataRepository.py @@ -1,5 +1,4 @@ from abc import ABC, abstractmethod -from dataclasses import dataclass from datetime import datetime from app.EnvironmentalData import EnvironmentalData # Classe abstrata de persistência e recuperação de dados do ambiente diff --git a/app/MongoEnvironmentalDataRepository.py b/app/MongoEnvironmentalDataRepository.py index efdfbf3..eeb9165 100644 --- a/app/MongoEnvironmentalDataRepository.py +++ b/app/MongoEnvironmentalDataRepository.py @@ -26,7 +26,7 @@ async def get_by_intervalo(self, inicio: datetime, fim: datetime) -> list[Enviro documentos = await cursor.to_list() return dumps(documentos) - async def get_by_instante(self, data: datetime = datetime.now()) -> dict: + async def get_by_instante(self, data) -> dict: anterior = await self.collection.find_one( {"timestamp": {"$lte": data}}, sort=[("timestamp", -1)] diff --git a/app/main.py b/app/main.py index a12f62c..a55ce4c 100644 --- a/app/main.py +++ b/app/main.py @@ -1,17 +1,12 @@ from app.MongoEnvironmentalDataRepository import MongoEnvironmentalDataRepository from app.EnvironmentalData import EnvironmentalData -from fastapi import HTTPException, Depends -from gmqtt import Client as MQTTClient -from fastapi import FastAPI -from datetime import datetime, timedelta -from bson.json_util import dumps +from datetime import datetime import json import os +import pytz from dotenv import load_dotenv -import asyncio from contextlib import asynccontextmanager -from typing import Any from fastapi import FastAPI @@ -55,7 +50,7 @@ async def get_root(): @app.get("/instante") async def get_medicao_instante(data: datetime = datetime.now()): - resp = await repository.get_by_instante() + resp = await repository.get_by_instante(data) return resp @app.get("/intervalo") @@ -73,13 +68,14 @@ async def message(client, topic, payload, qos, properties): print("Received message: ", topic, msg, qos, properties) data = json.loads(msg) # Transformando pra dicionario service_values = data.get("serviceValue", []) - + fuso_brasil = pytz.timezone('America/Sao_Paulo') env_data = EnvironmentalData( - timestamp=datetime.now(), + timestamp=datetime.now(fuso_brasil), temperatura=service_values[0], umidade=service_values[1], gas=service_values[2] ) + print("AAAAAAAAA {}".format(env_data.timestamp)) await repository.insert_one(env_data) @fast_mqtt.on_disconnect() diff --git a/docker-compose.yaml b/docker-compose.yaml index 75a1923..9624438 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -4,9 +4,11 @@ services: 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: diff --git a/requirements.txt b/requirements.txt index e37fa3d3a716dcd52348f6f808e31e91ebcc5d16..f823caadf4d6c5c2cec450dcc24ffb09269eec0b 100644 GIT binary patch delta 35 ncmZ3-c8YC743l^PLnT8ALluK95E?NU0I?~99)r>3aHi`3n#Bj_ delta 11 ScmX@bwvKH>4AbNarb_@C&jfM+ From 1de180c958f9c61e653f044c664f7431bd883124 Mon Sep 17 00:00:00 2001 From: Breno Vidigal <96669455+FlamingDev@users.noreply.github.com> Date: Mon, 9 Jun 2025 19:46:12 -0300 Subject: [PATCH 10/20] Add files via upload --- MongoEnvironmentalDataRepository.py | 32 ++++++++++++ main.py | 81 +++++++++++++++++++++++++++++ 2 files changed, 113 insertions(+) create mode 100644 MongoEnvironmentalDataRepository.py create mode 100644 main.py diff --git a/MongoEnvironmentalDataRepository.py b/MongoEnvironmentalDataRepository.py new file mode 100644 index 0000000..3f3a0af --- /dev/null +++ b/MongoEnvironmentalDataRepository.py @@ -0,0 +1,32 @@ +from app.EnvironmentalDataRepository import EnvironmentalDataRepository +from app.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) + 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[EnvironmentalData]: + filtro = { + "timestamp": { + "$gte": inicio, + "$lte": fim + } + } + cursor = self.collection.find(filtro) + documentos = await cursor.to_list() + return documentos + + async def get_by_instante(self, data: datetime) -> EnvironmentalData: + anterior = await self.collection.find_one( + {"timestamp": {"$lte": data}}, + sort=[("timestamp", -1)] + ) + return anterior \ No newline at end of file diff --git a/main.py b/main.py new file mode 100644 index 0000000..a162654 --- /dev/null +++ b/main.py @@ -0,0 +1,81 @@ +from app.MongoEnvironmentalDataRepository import MongoEnvironmentalDataRepository +from app.EnvironmentalData import EnvironmentalData +from datetime import datetime +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_SALA_ETS/service_topic/HMSoft") # subscribing mqtt topic + print("Connected: ", client, flags, rc, properties) + +@app.get("/root") +async def get_root(): + return "Server está funcionando" + +@app.get("/instante") +async def get_medicao_instante(data: datetime = datetime.now()) -> str: + env_data_dict = await repository.get_by_instante(data) + return dumps(env_data_dict) if env_data_dict is not None else HTTPException(404) + +@app.get("/intervalo") +async def get_medicao_intervalo(inicio: datetime, fim: datetime) -> str: + env_data_dict = await repository.get_by_intervalo(inicio, fim) + return dumps(env_data_dict) if env_data_dict is not None else HTTPException(404) + +@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", []) + fuso_brasil = pytz.timezone('America/Sao_Paulo') + + env_data = EnvironmentalData( + timestamp=datetime.now(fuso_brasil), + temperatura=service_values[0], + umidade=service_values[1], + gas=service_values[2] + ) + print("AAAAAAAAA {}".format(env_data.timestamp)) + await repository.insert_one(env_data) + +@fast_mqtt.on_disconnect() +def disconnect(client, packet, exc=None): + print("Disconnected") + +@app.post("/ffff") +async def func(): + fast_mqtt.publish("/HMSoft", "Hello from Fastapi") #publishing mqtt topic + + return {"result": True,"message":"Published" } \ No newline at end of file From 7cb65990ea3b30237a1354570f336a2c14ecdda9 Mon Sep 17 00:00:00 2001 From: Breno Vidigal <96669455+FlamingDev@users.noreply.github.com> Date: Fri, 13 Jun 2025 07:42:15 -0300 Subject: [PATCH 11/20] Add files via upload --- app/EnvironmentalDataRepository.py | 1 + app/MongoEnvironmentalDataRepository.py | 17 ++++++-------- app/main.py | 30 +++++++++---------------- 3 files changed, 19 insertions(+), 29 deletions(-) diff --git a/app/EnvironmentalDataRepository.py b/app/EnvironmentalDataRepository.py index 515ba66..6d814a7 100644 --- a/app/EnvironmentalDataRepository.py +++ b/app/EnvironmentalDataRepository.py @@ -1,4 +1,5 @@ from abc import ABC, abstractmethod +from dataclasses import dataclass from datetime import datetime from app.EnvironmentalData import EnvironmentalData # Classe abstrata de persistência e recuperação de dados do ambiente diff --git a/app/MongoEnvironmentalDataRepository.py b/app/MongoEnvironmentalDataRepository.py index eeb9165..3f3a0af 100644 --- a/app/MongoEnvironmentalDataRepository.py +++ b/app/MongoEnvironmentalDataRepository.py @@ -2,17 +2,15 @@ from app.EnvironmentalData import EnvironmentalData from datetime import datetime from pymongo import AsyncMongoClient -from bson.json_util import dumps - class MongoEnvironmentalDataRepository(EnvironmentalDataRepository): - def __init__(self, uri: str, db_name: str, collection_name: str): + def __init__(self, uri: str, db_name: str, collection_name: str) -> None: self.client = AsyncMongoClient(uri) self.db = self.client[db_name] self.collection = self.db.get_collection(collection_name) - async def insert_one(self, data: EnvironmentalData) -> any: - resp = await self.collection.insert_one(data.dict(exclude_none=True)) + 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[EnvironmentalData]: @@ -22,14 +20,13 @@ async def get_by_intervalo(self, inicio: datetime, fim: datetime) -> list[Enviro "$lte": fim } } - cursor = await self.collection.find(filtro) + cursor = self.collection.find(filtro) documentos = await cursor.to_list() - return dumps(documentos) + return documentos - async def get_by_instante(self, data) -> dict: + async def get_by_instante(self, data: datetime) -> EnvironmentalData: anterior = await self.collection.find_one( {"timestamp": {"$lte": data}}, sort=[("timestamp", -1)] ) - print(dumps(anterior)) - return dumps(anterior) \ No newline at end of file + return anterior \ No newline at end of file diff --git a/app/main.py b/app/main.py index a55ce4c..a162654 100644 --- a/app/main.py +++ b/app/main.py @@ -1,23 +1,18 @@ from app.MongoEnvironmentalDataRepository import MongoEnvironmentalDataRepository from app.EnvironmentalData import EnvironmentalData - from datetime import datetime +from bson.json_util import dumps import json import os -import pytz from dotenv import load_dotenv from contextlib import asynccontextmanager - -from fastapi import FastAPI +import pytz +from fastapi import FastAPI, HTTPException from fastapi_mqtt import FastMQTT, MQTTConfig load_dotenv() -print(os.getenv("DB_URI")) -print(os.getenv("DB_NAME")) -print(os.getenv("COLLECTION_NAME")) - uri = os.getenv("DB_URI") db_name = os.getenv("DB_NAME") collection_name = os.getenv("COLLECTION_NAME") @@ -37,7 +32,7 @@ async def _lifespan(_app: FastAPI): await fast_mqtt.mqtt_shutdown() app = FastAPI(lifespan=_lifespan) -repository = MongoEnvironmentalDataRepository(uri, db_name, collection_name); +repository = MongoEnvironmentalDataRepository(uri, db_name, collection_name) @fast_mqtt.on_connect() def connect(client, flags, rc, properties): @@ -49,18 +44,14 @@ async def get_root(): return "Server está funcionando" @app.get("/instante") -async def get_medicao_instante(data: datetime = datetime.now()): - resp = await repository.get_by_instante(data) - return resp +async def get_medicao_instante(data: datetime = datetime.now()) -> str: + env_data_dict = await repository.get_by_instante(data) + return dumps(env_data_dict) if env_data_dict is not None else HTTPException(404) @app.get("/intervalo") -async def get_medicao_intervalo(inicio: datetime, fim: datetime): - resp = await repository.get_by_intervalo(inicio, fim) - return resp - -@app.get("/teste") -async def teste(): - print(uri) +async def get_medicao_intervalo(inicio: datetime, fim: datetime) -> str: + env_data_dict = await repository.get_by_intervalo(inicio, fim) + return dumps(env_data_dict) if env_data_dict is not None else HTTPException(404) @fast_mqtt.on_message() async def message(client, topic, payload, qos, properties): @@ -69,6 +60,7 @@ async def message(client, topic, payload, qos, properties): data = json.loads(msg) # Transformando pra dicionario service_values = data.get("serviceValue", []) fuso_brasil = pytz.timezone('America/Sao_Paulo') + env_data = EnvironmentalData( timestamp=datetime.now(fuso_brasil), temperatura=service_values[0], From d8e40bf5cbe71b4226af46184862c0913854240c Mon Sep 17 00:00:00 2001 From: Breno Vidigal <96669455+FlamingDev@users.noreply.github.com> Date: Fri, 13 Jun 2025 12:55:37 -0300 Subject: [PATCH 12/20] Delete MongoEnvironmentalDataRepository.py --- MongoEnvironmentalDataRepository.py | 32 ----------------------------- 1 file changed, 32 deletions(-) delete mode 100644 MongoEnvironmentalDataRepository.py diff --git a/MongoEnvironmentalDataRepository.py b/MongoEnvironmentalDataRepository.py deleted file mode 100644 index 3f3a0af..0000000 --- a/MongoEnvironmentalDataRepository.py +++ /dev/null @@ -1,32 +0,0 @@ -from app.EnvironmentalDataRepository import EnvironmentalDataRepository -from app.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) - 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[EnvironmentalData]: - filtro = { - "timestamp": { - "$gte": inicio, - "$lte": fim - } - } - cursor = self.collection.find(filtro) - documentos = await cursor.to_list() - return documentos - - async def get_by_instante(self, data: datetime) -> EnvironmentalData: - anterior = await self.collection.find_one( - {"timestamp": {"$lte": data}}, - sort=[("timestamp", -1)] - ) - return anterior \ No newline at end of file From 114c0c4fa919931d4d66bda9ea3d2105452d3431 Mon Sep 17 00:00:00 2001 From: Breno Vidigal <96669455+FlamingDev@users.noreply.github.com> Date: Fri, 13 Jun 2025 12:55:50 -0300 Subject: [PATCH 13/20] Delete main.py --- main.py | 81 --------------------------------------------------------- 1 file changed, 81 deletions(-) delete mode 100644 main.py diff --git a/main.py b/main.py deleted file mode 100644 index a162654..0000000 --- a/main.py +++ /dev/null @@ -1,81 +0,0 @@ -from app.MongoEnvironmentalDataRepository import MongoEnvironmentalDataRepository -from app.EnvironmentalData import EnvironmentalData -from datetime import datetime -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_SALA_ETS/service_topic/HMSoft") # subscribing mqtt topic - print("Connected: ", client, flags, rc, properties) - -@app.get("/root") -async def get_root(): - return "Server está funcionando" - -@app.get("/instante") -async def get_medicao_instante(data: datetime = datetime.now()) -> str: - env_data_dict = await repository.get_by_instante(data) - return dumps(env_data_dict) if env_data_dict is not None else HTTPException(404) - -@app.get("/intervalo") -async def get_medicao_intervalo(inicio: datetime, fim: datetime) -> str: - env_data_dict = await repository.get_by_intervalo(inicio, fim) - return dumps(env_data_dict) if env_data_dict is not None else HTTPException(404) - -@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", []) - fuso_brasil = pytz.timezone('America/Sao_Paulo') - - env_data = EnvironmentalData( - timestamp=datetime.now(fuso_brasil), - temperatura=service_values[0], - umidade=service_values[1], - gas=service_values[2] - ) - print("AAAAAAAAA {}".format(env_data.timestamp)) - await repository.insert_one(env_data) - -@fast_mqtt.on_disconnect() -def disconnect(client, packet, exc=None): - print("Disconnected") - -@app.post("/ffff") -async def func(): - fast_mqtt.publish("/HMSoft", "Hello from Fastapi") #publishing mqtt topic - - return {"result": True,"message":"Published" } \ No newline at end of file From af92a5e2987e9162267d223602bec56102964b79 Mon Sep 17 00:00:00 2001 From: Breno Vidigal <96669455+FlamingDev@users.noreply.github.com> Date: Sat, 14 Jun 2025 18:18:47 -0300 Subject: [PATCH 14/20] Add files via upload --- REST-API-cliente-mqtt-consultas/Dockerfile | 9 ++ .../__pycache__/main.cpython-311.pyc | Bin 0 -> 6942 bytes .../docker-compose.yaml | 26 ++++ REST-API-cliente-mqtt-consultas/main.py | 115 ++++++++++++++++++ .../models/EnvironmentalData.py | 10 ++ .../models/__init__.py | 0 .../EnvironmentalData.cpython-311.pyc | Bin 0 -> 882 bytes .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 186 bytes .../EnvironmentalDataRepository.py | 17 +++ .../MongoEnvironmentalDataRepository.py | 32 +++++ .../repositories/__init__.py | 0 ...nvironmentalDataRepository.cpython-311.pyc | Bin 0 -> 1484 bytes ...nvironmentalDataRepository.cpython-311.pyc | Bin 0 -> 2768 bytes .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 192 bytes .../requirements.txt | Bin 0 -> 842 bytes 15 files changed, 209 insertions(+) create mode 100644 REST-API-cliente-mqtt-consultas/Dockerfile create mode 100644 REST-API-cliente-mqtt-consultas/__pycache__/main.cpython-311.pyc create mode 100644 REST-API-cliente-mqtt-consultas/docker-compose.yaml create mode 100644 REST-API-cliente-mqtt-consultas/main.py create mode 100644 REST-API-cliente-mqtt-consultas/models/EnvironmentalData.py create mode 100644 REST-API-cliente-mqtt-consultas/models/__init__.py create mode 100644 REST-API-cliente-mqtt-consultas/models/__pycache__/EnvironmentalData.cpython-311.pyc create mode 100644 REST-API-cliente-mqtt-consultas/models/__pycache__/__init__.cpython-311.pyc create mode 100644 REST-API-cliente-mqtt-consultas/repositories/EnvironmentalDataRepository.py create mode 100644 REST-API-cliente-mqtt-consultas/repositories/MongoEnvironmentalDataRepository.py create mode 100644 REST-API-cliente-mqtt-consultas/repositories/__init__.py create mode 100644 REST-API-cliente-mqtt-consultas/repositories/__pycache__/EnvironmentalDataRepository.cpython-311.pyc create mode 100644 REST-API-cliente-mqtt-consultas/repositories/__pycache__/MongoEnvironmentalDataRepository.cpython-311.pyc create mode 100644 REST-API-cliente-mqtt-consultas/repositories/__pycache__/__init__.cpython-311.pyc create mode 100644 REST-API-cliente-mqtt-consultas/requirements.txt diff --git a/REST-API-cliente-mqtt-consultas/Dockerfile b/REST-API-cliente-mqtt-consultas/Dockerfile new file mode 100644 index 0000000..e2b4959 --- /dev/null +++ b/REST-API-cliente-mqtt-consultas/Dockerfile @@ -0,0 +1,9 @@ +FROM python:3.11-slim +WORKDIR /app + +COPY app/ app/ +COPY requirements.txt app/requirements.txt + +RUN pip install -r app/requirements.txt + +EXPOSE 8000 \ No newline at end of file diff --git a/REST-API-cliente-mqtt-consultas/__pycache__/main.cpython-311.pyc b/REST-API-cliente-mqtt-consultas/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9ddd7ada9e37aff1f5b0e2b5d71b6fef9c778e01 GIT binary patch literal 6942 zcmd5=+i%;}87D>RM%^r1@w%RFyQ;-pPh+ihc~%hVJCEz%AhiBw1` zOV&T?K_y*Lm%+0q+(}Q= zQ#+ zEv0BP=+yFEb^Mk(zPpa!3j6@$VZ4m*Uc((2iLc--+inA16WeyrU#AmdJxn9pFk@kw z7D;n^qwS#6z_#BD)ai6UInFk-Eo^IDEj!pyuCr2S?bmFX2`*yhl4uv(kqg&qRPs!- zxpt;yi*EO}x~*niXg4|6Q?YDr!3@r{u_O~>duK?debH*>Mt5#oN5>25*j1_HU)9K3 z=XO`*?pR>9;4LLX>t${1sc4yPz>MyI{&bf6WMjIv^r;VKD^k&}{hIsEgtv@%KWOf) z)u`m_G<%rtMciB#-N#rbu}JSzq!PjP@VLOw3a9z2oG9=~mY3>h(&iWw9Lv}lGRB>LCngelPPHea;}6xGciVxS^g^gZK9>?d^|4jGJ8!<(mXxO zieSP18ZF5u-a4y$&P+|cb^2PIP05_VBio2G{`S(0w8 zo1zokRn%x3Gz%FgV{|GNuYv(+A$K5vJYRv#8vq}-F&T1|l&h7k6xJ=PPXPWtAl|`l z6Tc-9MEx3rJbbmZXCAb+@O3}Qy1B`Yc>oFjIgI^YVLN%>X;XD;qsUD5$ zQOFlO1=5*4UHYvf@$Nj;tx~-j)vJ)(KF^^FA?}KXd+MZ1Tj|iOKyi zmRGqr82ivIbM#C;CjX&>(-eB zJuB%JF|Jc7QAn|(%(0S$x)z2cqS4juFbT+>i0}qslXM737TX}HH8PMV14{7cDmkK& zBMLdPPCAzcR-1FdyOz7ZQpuwlc~q%9BHAE+#P`SHQ%%S-K7sc++T%;U&fw5p%S5^r zN+zL)tQck``P)B+XVQEemMP6M!k3uX4{XC^shOlG2(pN<2{9x$kdjYqxOOS7U54bm zb3ey}r-Fa!B%lbb+eB7Qi@a(1p^-P5bOaVisYw}Z4hl;t`+DuH%~cms{p>E_89Y}r zzZHE9{KM=AxmsVUipf>W7&ce+2D9b@#&?0Y{RDj(4OBVhkRNYJ^{uUigau2+BKtR0 z%;0g^=z-{$n>HmF3q#x^%{$h|;Ps5PttzxYWQcA0R5PC2kGy$|a>%o`By&qq{Rpo! zmYi#gC=@U@vrSmJo6Q9+GZ#S8J~8hTB1P75YMB$YM zYIiMuP{c@UWIfP&Yh39$tOkx~fg?-Kg0FSW*PZuu=XR>TJ(_RNn(vjo@0Eu`500t6 z5zRNUL@tpVzNVWW-uUoy`Lk=PuTS&!Es;+`JJ&)(`Owh)DK#{#g@%`cC2338v3(mH@f@Rx)0~O53f7i z%O0gUqB{CDNB=Xz(qsDp1M}aYsTu8UF&78S#ea(a%V2H>H)Es;bpap$E2vAH!rpsrfy|I5 z^tEQJ+w|^#g}zWfLf_@rGpI!^s6{V}!^^EEBqr*SSlkbWBOY-GKH_0Sjv#UrkzffvR_pbSmyhOw&8DC^Y`TaJ%1kh;+X2+r}_6mp`BWsM>h9tvFUAD^M>=@aIQ)9?$W%w z*1QMu-UAN<4_a04u;v|JB9@2^um2{0ga3T$vkR(sx8~iwL>Q2JI3GHEf9C7B8ak*{KA<(h;Eh7gXdg@^Ltp>=n|^0*QjP~C%?dk`?Vn*t2( zroN||ZbUxaySx`L*y&$sR~oK?{mXbeGH~;ba40l}PLMbdqCeh^>fOT8g+)h=oEeu?I<#bCSU8R^vbl z0<0{eZir}Bbb=S&FX6`~U{Da%z>z5ikypei_98K>aTL?-Df&7xqZ3yIN!)E1NJ_J% zD9T$ow!vnfW+m|quq8C`20(0rguUEP@gnf1k@4Cr#IXnxxTbN7 zC88^CokE8MxWh_t(;{*e!xeQqx`m-roQRG%rSRQdE;8Z=*fCEY`*ODBDdmDZEc#ZElU)rrlp?c$jVuj>eQ&tti90K zzS46mqI3+Xje}a_VAcoGfv;_8uHbAbI6Vb#L(xw9EYC0?KOmBI6)DUUTspJ*hT`s1 z-F=$7FYDaE14Rpg?_Awe#Ne|@o)MTOsFk^(Y4>JlSFS6zZq?SU*}9=co&m)(a5sMc z=+|$mo-xfcmZdguY7GzO@t}&gXn0G}V!@9UF(AlVYqi9IS**Wn`M71N>7$Otj-my} zcf($c??zJIN`b8+)UM*tkYM4!$bH8H_g}payhW@L4;v(R!T3Bnv{_{2kfml&Dq4_a zU&U01ibH90;n3*)W7?t7M`Mr9JRbXI;_-wsbwQiDs2+MxJM>=R!14PI?ZELz9gkWc zcYM?NxKnxiy!Q5Q)B{oNK(t7-qq>3Ibr_$*t^uR05S!lQ864CI7>4Ge1*wc+7MFQ& n+<1Qx1F|_dsHDS?Yt7@WDjw4C5E`Bk8lDnC!tGm&4WRlbZM5EQ literal 0 HcmV?d00001 diff --git a/REST-API-cliente-mqtt-consultas/docker-compose.yaml b/REST-API-cliente-mqtt-consultas/docker-compose.yaml new file mode 100644 index 0000000..75a1923 --- /dev/null +++ b/REST-API-cliente-mqtt-consultas/docker-compose.yaml @@ -0,0 +1,26 @@ +services: + mongodb: + image: mongo:latest + restart: always + ports: + - "27017:27017" + environment: + MONGO_INITDB_ROOT_USERNAME: admin + MONGO_INITDB_ROOT_PASSWORD: secret + volumes: + - mongo_data:/data/db + web: + build: + dockerfile: app/Dockerfile + ports: + - "8000:8000" + environment: + - DB_URI=mongodb://admin:secret@mongodb:27017 + - DB_NAME=meu_banco + - COLLECTION_NAME=minha_colecao + command: uvicorn app.main:app --host 0.0.0.0 --port 8000 + depends_on: + - mongodb + +volumes: + mongo_data: \ No newline at end of file diff --git a/REST-API-cliente-mqtt-consultas/main.py b/REST-API-cliente-mqtt-consultas/main.py new file mode 100644 index 0000000..877765c --- /dev/null +++ b/REST-API-cliente-mqtt-consultas/main.py @@ -0,0 +1,115 @@ +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("/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") \ No newline at end of file diff --git a/REST-API-cliente-mqtt-consultas/models/EnvironmentalData.py b/REST-API-cliente-mqtt-consultas/models/EnvironmentalData.py new file mode 100644 index 0000000..31e9aac --- /dev/null +++ b/REST-API-cliente-mqtt-consultas/models/EnvironmentalData.py @@ -0,0 +1,10 @@ +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 \ No newline at end of file diff --git a/REST-API-cliente-mqtt-consultas/models/__init__.py b/REST-API-cliente-mqtt-consultas/models/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/REST-API-cliente-mqtt-consultas/models/__pycache__/EnvironmentalData.cpython-311.pyc b/REST-API-cliente-mqtt-consultas/models/__pycache__/EnvironmentalData.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c43567d194df850cad489978720e664a76ea9735 GIT binary patch literal 882 zcmZuv&ubGw6n?WiNj6PN5mPD{ZO~fCA)fS7s!-by#I{I(cnB-YG&AbL{zzvhNg=~~zwetjyf?G+ZFY7BaMaDsclQavPc1G- zW{OBusBmfxxQ#kvPYlGwdbEuo`QfT;m|bpL70MavWhM@ni-Mh#>X50dgjE-O?h0FEjCGrt-2AuQ281#vb-Cc=R7|;H5IK&tw3~V3g-ppja;g7YN)N)&lLf7d7{0?fM!0yjzGCl3LPqvpt+BRM z-?2Bs4*{;_k-byj-K(v=d|qpLE^bTI{6nQ`Ev(Y<6pL)^N_dfdZRZc$M>4Am>7aXz zK4a)kJ;~fcOf`mdA*n2NU-ah(rIT_@mk>j`l$0yoMsL5rcWlSBf*8_Da;w~3@0I$c zW6aYS(sFWdxx3kaFnDxQi|I0ANSBk_i`{zfaew3ZNlX_J!%;*cOP5V;S7~ask2njI z+miYwjm~o1^-V2Dsq@G#tkv=9Ka~q8@#aJH8pD}M2ua{>d=&}YiLc^}W=Z7?u7^SX Mw|4*hXKGabFDs|xWdHyG literal 0 HcmV?d00001 diff --git a/REST-API-cliente-mqtt-consultas/models/__pycache__/__init__.cpython-311.pyc b/REST-API-cliente-mqtt-consultas/models/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1644fd195c5cf73e0325fd97372b1314e177f046 GIT binary patch literal 186 zcmZ3^%ge<81ig=aGeGoX5CH>>P{wCAAY(d13PUi1CZpd4BO~Jn1{hJq3={(Z D)A%l= literal 0 HcmV?d00001 diff --git a/REST-API-cliente-mqtt-consultas/repositories/EnvironmentalDataRepository.py b/REST-API-cliente-mqtt-consultas/repositories/EnvironmentalDataRepository.py new file mode 100644 index 0000000..4401c8d --- /dev/null +++ b/REST-API-cliente-mqtt-consultas/repositories/EnvironmentalDataRepository.py @@ -0,0 +1,17 @@ +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_by_instante(self, data: datetime) -> EnvironmentalData: + pass diff --git a/REST-API-cliente-mqtt-consultas/repositories/MongoEnvironmentalDataRepository.py b/REST-API-cliente-mqtt-consultas/repositories/MongoEnvironmentalDataRepository.py new file mode 100644 index 0000000..45c6187 --- /dev/null +++ b/REST-API-cliente-mqtt-consultas/repositories/MongoEnvironmentalDataRepository.py @@ -0,0 +1,32 @@ +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 + + async def get_by_instante(self, data: datetime) -> dict: + anterior = await self.collection.find_one( + {"timestamp": {"$lte": data}}, + sort=[("timestamp", -1)] + ) + return anterior \ No newline at end of file diff --git a/REST-API-cliente-mqtt-consultas/repositories/__init__.py b/REST-API-cliente-mqtt-consultas/repositories/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/REST-API-cliente-mqtt-consultas/repositories/__pycache__/EnvironmentalDataRepository.cpython-311.pyc b/REST-API-cliente-mqtt-consultas/repositories/__pycache__/EnvironmentalDataRepository.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b402a11afab9aeaf0f5c9ebb1c18e75ef0ecc093 GIT binary patch literal 1484 zcma)6&1(}u6rcUfCT;p*t5ijd6ojBD3gSUT=ohU>i!@bm2`=00#4hYdJF}^#2kD`p z|3R-kRZ1`Z3H}K=2!=fsdh(VMPd)kGY?=^LtCQI`zqjuwI*8uj2LmbH?zGO925f-8o53N zJUSn2xhxEP8br1?hpe_|u^4To^%1}xp~RFNV#-u;B&s?x)heo^?5YP~J!(@4F?F!3 zH05aU$kd?f^^UEgJ9-~KE&L%@1%IhNd&V&!$8>zNFW42j5pp*QSuIvE#aL%Fs5EiVZgTMw9$)U7-NDk##<>bA)x!hT0_DSg#r;L|Y3k%ar^DCvf@O|Kg zw!=#+^TpM|^vmakvgbm*Xu;o%qCzJSJLK3H{H(SBl2~^Gx9ovb}Ko{$(-#$sRCnr`t z7p~O=>Nike9Yum7RF*~+1(G>lhn>#vSQ~4~l9sLCe$XVael3cnD^3-nkMF(}q^1s7 zp#2XCdtEHw9@Q7$e4jPDy9D~n)QtY*UAhJgeXQl(D`~$ z&hT@V)MEk)NIgE)*AY>@q#nIBIy0UoMSsR7!3~~J{s}}=ktC@>ChHf?2Dwx3oegrU c-a8xQalLmo)jlgczr}*~Q1tw91-&qoHMgRZ+ literal 0 HcmV?d00001 diff --git a/REST-API-cliente-mqtt-consultas/repositories/__pycache__/MongoEnvironmentalDataRepository.cpython-311.pyc b/REST-API-cliente-mqtt-consultas/repositories/__pycache__/MongoEnvironmentalDataRepository.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..33789d744cbf796c20a1f6ccda7697660de26fe9 GIT binary patch literal 2768 zcma)8O>7fK6rTO{#&K{GuyLHy(8d9*$PikJ)Tp8gKcZDjgp#zPR@Bwv8K+CvyJ2<> zO=_g5pvs3HdO%H7AvLFz3Jy^(I@4dJCb4N!QL0Nlp>5G3vgr2a*W|208^)V3U5k{CZP=U*G9Fuv2F9=z|lLbR8 zh*{B-MMEmcS(!sTx`?oJ2Vt3TO9DanFdl~aY^)9D zN1)w~CAeCLd)Pb9j*~Yp<_blsyCHm4HMIh9qdChkNY2qM)9;Weaf;L&%>gVyVKOu0 z`duLN$l-z!RN^rAkYD1#&`|wSLTWIhgswGZzIhLrvt|CZKwb>s+SJB)Nmv3c51N{g z8k`R!xVbPo!O(GLRqdumNm`;ZEOX_Y2aL<(tM0xj;;7B*y5Xjr7G2RMMxM68BFbEo zwga)*9*3d4`10KFe{7W0U8to2FrD*q$7_Fg}qPx%^?q--~1l*BvL5 zvrM~aIGR04H=Rl+_T*mh9G{+X6;;(u-BH!q^q$i9>4~-i9E38K=8rBT!}03n7_yC+%4f1pxYL3x5SdTJD5wb#{;N-X@O2Ev7{u7 zx@|0D+KyJ3PV=*3YRVxm#FXI>u(k(}nAc70h8#;ZblXYGJ_dcDk{$-)%6Z*zs0HC% zq_#!fFt&0F{7-ihC%wCgT=F_!19@NTc*k&` zy}q@cldC-^>m7-O(~GATj#nb-dUt=NE7g!t@~vlpMEE%)fXRWEld{rKP-mhX^$ebl zunfz-eyZw*RTa`f(O_~!Rj(H{!yloqF$={QVd3NjK4n?Z6`7AhiqvxsO|zjBKz>1< zZa+z|Pd{aZ`KJ9lkh$P#@Pc%fTQ~;mI&!i`ACvizi+&|Vpz?L14y_EP@V;34tEAFwaAGG8D^Q%Ew zPI41oy0v#s^zG`IG&DU^V82n`N87U;eFxSyP5MH4&xh#@eHRAU*T((^NJHQ_u8uBO pTHiW4U1@#m=uoBgt)o<>^=*hrF3~_cN#*F-XRQ1AE@R#q{{yx(wmJX+ literal 0 HcmV?d00001 diff --git a/REST-API-cliente-mqtt-consultas/repositories/__pycache__/__init__.cpython-311.pyc b/REST-API-cliente-mqtt-consultas/repositories/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..37ee7f3786163a5c7d384b83ec91c90af945ac0a GIT binary patch literal 192 zcmZ3^%ge<81euS0GeGoX5CH>>P{wCAAY(d13PUi1CZpdaZG%CW?p7Ve7s&kDEX%uwus@4H#7Wh^4Mc!CD+O% zD#xoupY46n$jN@7!L?|BqsD#E>X*lq^9e>R5#sDl^n?zW*TzAvugSs`wmmn_4hO1)Yq+I7<1Kq zL0n`Pa#Aj-9%-#O8BOayW>1`aEk|?;>H18BZp_V!zr%ckA%?mp#}leA9hUC0z7F5L z(wZ7_)|FaTUE{zrY?AWa0oCo3xo`_gcBd&$J235#?`ci0icaaPohaF(92vGk`>W0I j4(2&~V!w=CnV#W0FTD5d^?q=N Date: Mon, 16 Jun 2025 23:01:48 -0300 Subject: [PATCH 15/20] Add files via upload --- REST-API-cliente-mqtt-consultas/main.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/REST-API-cliente-mqtt-consultas/main.py b/REST-API-cliente-mqtt-consultas/main.py index 877765c..231e2e4 100644 --- a/REST-API-cliente-mqtt-consultas/main.py +++ b/REST-API-cliente-mqtt-consultas/main.py @@ -64,6 +64,20 @@ async def get_medicao_instante(data: datetime = datetime.now()) -> str: 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: From fd8e1052db2d21339f52750626eab28cca916c26 Mon Sep 17 00:00:00 2001 From: Breno Vidigal <96669455+FlamingDev@users.noreply.github.com> Date: Mon, 16 Jun 2025 23:02:32 -0300 Subject: [PATCH 16/20] Add files via upload --- .../repositories/EnvironmentalDataRepository.py | 5 +++++ .../repositories/MongoEnvironmentalDataRepository.py | 8 ++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/REST-API-cliente-mqtt-consultas/repositories/EnvironmentalDataRepository.py b/REST-API-cliente-mqtt-consultas/repositories/EnvironmentalDataRepository.py index 4401c8d..b0fbc57 100644 --- a/REST-API-cliente-mqtt-consultas/repositories/EnvironmentalDataRepository.py +++ b/REST-API-cliente-mqtt-consultas/repositories/EnvironmentalDataRepository.py @@ -1,6 +1,7 @@ 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): @@ -12,6 +13,10 @@ def insert_one(self, data: EnvironmentalData) -> any: 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 diff --git a/REST-API-cliente-mqtt-consultas/repositories/MongoEnvironmentalDataRepository.py b/REST-API-cliente-mqtt-consultas/repositories/MongoEnvironmentalDataRepository.py index 45c6187..6a9f9e5 100644 --- a/REST-API-cliente-mqtt-consultas/repositories/MongoEnvironmentalDataRepository.py +++ b/REST-API-cliente-mqtt-consultas/repositories/MongoEnvironmentalDataRepository.py @@ -22,11 +22,15 @@ async def get_by_intervalo(self, inicio: datetime, fim: datetime) -> list[dict]: } cursor = self.collection.find(filtro) documentos = await cursor.to_list() - return documentos + 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 \ No newline at end of file + 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() From 06c0423a9e5634edbc69ed701341fa303ef2cf35 Mon Sep 17 00:00:00 2001 From: Breno Vidigal <96669455+FlamingDev@users.noreply.github.com> Date: Wed, 2 Jul 2025 11:15:38 -0300 Subject: [PATCH 17/20] Delete app directory --- app/Dockerfile | 10 --- app/EnvironmentalData.py | 10 --- app/EnvironmentalDataRepository.py | 18 ------ app/MongoEnvironmentalDataRepository.py | 32 ---------- app/__init__.py | 0 app/main.py | 81 ------------------------- 6 files changed, 151 deletions(-) delete mode 100644 app/Dockerfile delete mode 100644 app/EnvironmentalData.py delete mode 100644 app/EnvironmentalDataRepository.py delete mode 100644 app/MongoEnvironmentalDataRepository.py delete mode 100644 app/__init__.py delete mode 100644 app/main.py diff --git a/app/Dockerfile b/app/Dockerfile deleted file mode 100644 index 6f19b9c..0000000 --- a/app/Dockerfile +++ /dev/null @@ -1,10 +0,0 @@ -FROM python:3.11-slim -WORKDIR /app - -COPY app/ app/ -COPY requirements.txt app/requirements.txt - -RUN pip install -r app/requirements.txt -RUN apt-get update && apt-get install -y tzdata - -EXPOSE 8000 \ No newline at end of file diff --git a/app/EnvironmentalData.py b/app/EnvironmentalData.py deleted file mode 100644 index c7abd64..0000000 --- a/app/EnvironmentalData.py +++ /dev/null @@ -1,10 +0,0 @@ -from pydantic import BaseModel -from datetime import datetime - -class EnvironmentalData(BaseModel): - timestamp: datetime = datetime.now() - temperatura: float | None = None - umidade: float | None = None - gas: bool | None = None - luminosidade: float | None = None - ruido: float | None = None \ No newline at end of file diff --git a/app/EnvironmentalDataRepository.py b/app/EnvironmentalDataRepository.py deleted file mode 100644 index 6d814a7..0000000 --- a/app/EnvironmentalDataRepository.py +++ /dev/null @@ -1,18 +0,0 @@ -from abc import ABC, abstractmethod -from dataclasses import dataclass -from datetime import datetime -from app.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_by_instante(self, data: datetime) -> EnvironmentalData: - pass diff --git a/app/MongoEnvironmentalDataRepository.py b/app/MongoEnvironmentalDataRepository.py deleted file mode 100644 index 3f3a0af..0000000 --- a/app/MongoEnvironmentalDataRepository.py +++ /dev/null @@ -1,32 +0,0 @@ -from app.EnvironmentalDataRepository import EnvironmentalDataRepository -from app.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) - 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[EnvironmentalData]: - filtro = { - "timestamp": { - "$gte": inicio, - "$lte": fim - } - } - cursor = self.collection.find(filtro) - documentos = await cursor.to_list() - return documentos - - async def get_by_instante(self, data: datetime) -> EnvironmentalData: - anterior = await self.collection.find_one( - {"timestamp": {"$lte": data}}, - sort=[("timestamp", -1)] - ) - return anterior \ No newline at end of file diff --git a/app/__init__.py b/app/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/app/main.py b/app/main.py deleted file mode 100644 index a162654..0000000 --- a/app/main.py +++ /dev/null @@ -1,81 +0,0 @@ -from app.MongoEnvironmentalDataRepository import MongoEnvironmentalDataRepository -from app.EnvironmentalData import EnvironmentalData -from datetime import datetime -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_SALA_ETS/service_topic/HMSoft") # subscribing mqtt topic - print("Connected: ", client, flags, rc, properties) - -@app.get("/root") -async def get_root(): - return "Server está funcionando" - -@app.get("/instante") -async def get_medicao_instante(data: datetime = datetime.now()) -> str: - env_data_dict = await repository.get_by_instante(data) - return dumps(env_data_dict) if env_data_dict is not None else HTTPException(404) - -@app.get("/intervalo") -async def get_medicao_intervalo(inicio: datetime, fim: datetime) -> str: - env_data_dict = await repository.get_by_intervalo(inicio, fim) - return dumps(env_data_dict) if env_data_dict is not None else HTTPException(404) - -@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", []) - fuso_brasil = pytz.timezone('America/Sao_Paulo') - - env_data = EnvironmentalData( - timestamp=datetime.now(fuso_brasil), - temperatura=service_values[0], - umidade=service_values[1], - gas=service_values[2] - ) - print("AAAAAAAAA {}".format(env_data.timestamp)) - await repository.insert_one(env_data) - -@fast_mqtt.on_disconnect() -def disconnect(client, packet, exc=None): - print("Disconnected") - -@app.post("/ffff") -async def func(): - fast_mqtt.publish("/HMSoft", "Hello from Fastapi") #publishing mqtt topic - - return {"result": True,"message":"Published" } \ No newline at end of file From a4b95d38cd9fd0fe59a43b5523ba531c8ea4c2e7 Mon Sep 17 00:00:00 2001 From: Breno Vidigal <96669455+FlamingDev@users.noreply.github.com> Date: Wed, 2 Jul 2025 11:16:16 -0300 Subject: [PATCH 18/20] Delete docker-compose.yaml --- docker-compose.yaml | 28 ---------------------------- 1 file changed, 28 deletions(-) delete mode 100644 docker-compose.yaml diff --git a/docker-compose.yaml b/docker-compose.yaml deleted file mode 100644 index 9624438..0000000 --- a/docker-compose.yaml +++ /dev/null @@ -1,28 +0,0 @@ -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: app/Dockerfile - ports: - - "8000:8000" - environment: - - DB_URI=mongodb://admin:secret@mongodb:27017 - - DB_NAME=meu_banco - - COLLECTION_NAME=minha_colecao - command: uvicorn app.main:app --host 0.0.0.0 --port 8000 - depends_on: - - mongodb - -volumes: - mongo_data: \ No newline at end of file From 3aff4f8b58e6c75338ad54d39727bc5d27c1b0bd Mon Sep 17 00:00:00 2001 From: Breno Vidigal <96669455+FlamingDev@users.noreply.github.com> Date: Wed, 2 Jul 2025 11:16:45 -0300 Subject: [PATCH 19/20] Delete requirements.txt --- requirements.txt | Bin 842 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 requirements.txt diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index f823caadf4d6c5c2cec450dcc24ffb09269eec0b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 842 zcmZWn?M}l$4D)X!9;MT6g~5LCEK}8XUB!BgwIIgB19s9+rqiv{#jz77zdsow&l@^q zyd?@G{9bY9{}wMiYpn3ZyT(24h>DEX%uwus@4H#7Wh^4Mc!CD+O% zD#xoupY46n$jN@7!L?|BqsD#E>X*lq^9e>R5#sDl^n?zW*TzAvugSs`wmmn_4hO1)Yq+I7<1Kq zL0n`Pa#Aj-9%-#O8BOayW>1`aEk|?;>H18BZp_V!zr%ckA%?mp#}leA9hUC0z7F5L z(wZ7_)|FaTUE{zrY?AWa0oCo3xo`_gcBd&$J235#?`ci0icaaPohaF(92vGk`>W0I j4(2&~V!w=CnV#W0FTD5d^?q=N Date: Wed, 2 Jul 2025 11:50:08 -0300 Subject: [PATCH 20/20] Add files via upload --- REST-API-cliente-mqtt-consultas/Dockerfile | 9 +++++---- REST-API-cliente-mqtt-consultas/docker-compose.yaml | 5 +++-- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/REST-API-cliente-mqtt-consultas/Dockerfile b/REST-API-cliente-mqtt-consultas/Dockerfile index e2b4959..4048d0e 100644 --- a/REST-API-cliente-mqtt-consultas/Dockerfile +++ b/REST-API-cliente-mqtt-consultas/Dockerfile @@ -1,9 +1,10 @@ FROM python:3.11-slim -WORKDIR /app +WORKDIR / -COPY app/ app/ -COPY requirements.txt app/requirements.txt +COPY . . +COPY requirements.txt requirements.txt -RUN pip install -r app/requirements.txt +RUN pip install -r requirements.txt +RUN apt-get update && apt-get install -y tzdata EXPOSE 8000 \ No newline at end of file diff --git a/REST-API-cliente-mqtt-consultas/docker-compose.yaml b/REST-API-cliente-mqtt-consultas/docker-compose.yaml index 75a1923..e3a41ac 100644 --- a/REST-API-cliente-mqtt-consultas/docker-compose.yaml +++ b/REST-API-cliente-mqtt-consultas/docker-compose.yaml @@ -7,18 +7,19 @@ services: environment: MONGO_INITDB_ROOT_USERNAME: admin MONGO_INITDB_ROOT_PASSWORD: secret + TZ: America/Sao_Paulo volumes: - mongo_data:/data/db web: build: - dockerfile: app/Dockerfile + dockerfile: Dockerfile ports: - "8000:8000" environment: - DB_URI=mongodb://admin:secret@mongodb:27017 - DB_NAME=meu_banco - COLLECTION_NAME=minha_colecao - command: uvicorn app.main:app --host 0.0.0.0 --port 8000 + command: uvicorn main:app --host 0.0.0.0 --port 8000 depends_on: - mongodb