add: edge template

This commit is contained in:
Toolf
2024-02-12 18:21:08 +02:00
parent 173a61d117
commit 9a179e09e9
12 changed files with 398 additions and 0 deletions

View File

@@ -0,0 +1,76 @@
import logging
import paho.mqtt.client as mqtt
from app.interfaces.agent_gateway import AgentGateway
from app.entities.agent_data import AgentData, GpsData
from app.usecases.data_processing import process_agent_data
from app.interfaces.hub_gateway import HubGateway
class AgentMQTTAdapter(AgentGateway):
def __init__(
self,
broker_host,
broker_port,
topic,
hub_gateway: HubGateway,
batch_size=10,
):
self.batch_size = batch_size
# MQTT
self.broker_host = broker_host
self.broker_port = broker_port
self.topic = topic
self.client = mqtt.Client()
# Hub
self.hub_gateway = hub_gateway
def on_connect(self, client, userdata, flags, rc):
if rc == 0:
logging.info("Connected to MQTT broker")
self.client.subscribe(self.topic)
else:
logging.info(f"Failed to connect to MQTT broker with code: {rc}")
def on_message(self, client, userdata, msg):
"""Processing agent data and sent it to hub gateway"""
try:
payload: str = msg.payload.decode("utf-8")
# Create AgentData instance with the received data
agent_data = AgentData.model_validate_json(payload, strict=True)
# Process the received data (you can call a use case here if needed)
processed_data = process_agent_data(agent_data)
# Store the agent_data in the database (you can send it to the data processing module)
if not self.hub_gateway.save_data(processed_data):
logging.error("Hub is not available")
except Exception as e:
logging.info(f"Error processing MQTT message: {e}")
def connect(self):
self.client.on_connect = self.on_connect
self.client.on_message = self.on_message
self.client.connect(self.broker_host, self.broker_port, 60)
def start(self):
self.client.loop_start()
def stop(self):
self.client.loop_stop()
# Usage example:
if __name__ == "__main__":
broker_host = "localhost"
broker_port = 1883
topic = "agent_data_topic"
# Assuming you have implemented the StoreGateway and passed it to the adapter
store_gateway = HubGateway()
adapter = AgentMQTTAdapter(broker_host, broker_port, topic, store_gateway)
adapter.connect()
adapter.start()
try:
# Keep the adapter running in the background
while True:
pass
except KeyboardInterrupt:
adapter.stop()
logging.info("Adapter stopped.")

View File

@@ -0,0 +1,29 @@
import logging
import requests as requests
from app.entities.processed_agent_data import ProcessedAgentData
from app.interfaces.hub_gateway import HubGateway
class HubHttpAdapter(HubGateway):
def __init__(self, api_base_url):
self.api_base_url = api_base_url
def save_data(self, processed_data: ProcessedAgentData):
"""
Save the processed road data to the Hub.
Parameters:
processed_data (ProcessedAgentData): Processed road data to be saved.
Returns:
bool: True if the data is successfully saved, False otherwise.
"""
url = f"{self.api_base_url}/processed_agent_data/"
response = requests.post(url, data=processed_data.model_dump_json())
if response.status_code != 200:
logging.info(
f"Invalid Hub response\nData: {processed_data.model_dump_json()}\nResponse: {response}"
)
return False
return True

View File

@@ -0,0 +1,50 @@
import logging
import requests as requests
from paho.mqtt import client as mqtt_client
from app.entities.processed_agent_data import ProcessedAgentData
from app.interfaces.hub_gateway import HubGateway
class HubMqttAdapter(HubGateway):
def __init__(self, broker, port, topic):
self.broker = broker
self.port = port
self.topic = topic
self.mqtt_client = self._connect_mqtt(broker, port)
def save_data(self, processed_data: ProcessedAgentData):
"""
Save the processed road data to the Hub.
Parameters:
processed_data (ProcessedAgentData): Processed road data to be saved.
Returns:
bool: True if the data is successfully saved, False otherwise.
"""
msg = processed_data.model_dump_json()
result = self.mqtt_client.publish(self.topic, msg)
status = result[0]
if status == 0:
return True
else:
print(f"Failed to send message to topic {self.topic}")
return False
@staticmethod
def _connect_mqtt(broker, port):
"""Create MQTT client"""
print(f"CONNECT TO {broker}:{port}")
def on_connect(client, userdata, flags, rc):
if rc == 0:
print(f"Connected to MQTT Broker ({broker}:{port})!")
else:
print("Failed to connect {broker}:{port}, return code %d\n", rc)
exit(rc) # Stop execution
client = mqtt_client.Client()
client.on_connect = on_connect
client.connect(broker, port)
client.loop_start()
return client

View File

@@ -0,0 +1,32 @@
from datetime import datetime
from pydantic import BaseModel, field_validator
class AccelerometerData(BaseModel):
x: float
y: float
z: float
class GpsData(BaseModel):
latitude: float
longitude: float
class AgentData(BaseModel):
accelerometer: AccelerometerData
gps: GpsData
timestamp: datetime
@classmethod
@field_validator("timestamp", mode="before")
def parse_timestamp(cls, value):
# Convert the timestamp to a datetime object
if isinstance(value, datetime):
return value
try:
return datetime.fromisoformat(value)
except (TypeError, ValueError):
raise ValueError(
"Invalid timestamp format. Expected ISO 8601 format (YYYY-MM-DDTHH:MM:SSZ)."
)

View File

@@ -0,0 +1,7 @@
from pydantic import BaseModel
from app.entities.agent_data import AgentData
class ProcessedAgentData(BaseModel):
road_state: str
agent_data: AgentData

View File

@@ -0,0 +1,40 @@
from abc import ABC, abstractmethod
class AgentGateway(ABC):
"""
Abstract class representing the Agent Gateway interface.
All agent gateway adapters must implement these methods.
"""
@abstractmethod
def on_message(self, client, userdata, msg):
"""
Method to handle incoming messages from the agent.
Parameters:
client: MQTT client instance.
userdata: Any additional user data passed to the MQTT client.
msg: The MQTT message received from the agent.
"""
pass
@abstractmethod
def connect(self):
"""
Method to establish a connection to the agent.
"""
pass
@abstractmethod
def start(self):
"""
Method to start listening for messages from the agent.
"""
pass
@abstractmethod
def stop(self):
"""
Method to stop the agent gateway and clean up resources.
"""
pass

View File

@@ -0,0 +1,20 @@
from abc import ABC, abstractmethod
from app.entities.processed_agent_data import ProcessedAgentData
class HubGateway(ABC):
"""
Abstract class representing the Store Gateway interface.
All store gateway adapters must implement these methods.
"""
@abstractmethod
def save_data(self, processed_data: ProcessedAgentData) -> bool:
"""
Method to save the processed agent data in the database.
Parameters:
processed_data (ProcessedAgentData): The processed agent data to be saved.
Returns:
bool: True if the data is successfully saved, False otherwise.
"""
pass

View File

@@ -0,0 +1,15 @@
from app.entities.agent_data import AgentData
from app.entities.processed_agent_data import ProcessedAgentData
def process_agent_data(
agent_data: AgentData,
) -> ProcessedAgentData:
"""
Process agent data and classify the state of the road surface.
Parameters:
agent_data (AgentData): Agent data that containing accelerometer, GPS, and timestamp.
Returns:
processed_data_batch (ProcessedAgentData): Processed data containing the classified state of the road surface and agent data.
"""
# Implement it