@@ -0,0 +1,119 @@ | |||
""" | |||
created by caliskan at 19.04.2023 | |||
contains all constants for the backend architecture of the smart garden project | |||
""" | |||
MQTT_BROKER_LOCAL = "lorem ipsum" | |||
MQTT_BROKER_GLOBAL = "mqtt.eclipseprojects.io" | |||
RASPI_CLIENT_ID = "smart_farming_raspi" | |||
BACKEND_CLIENT_ID = "smart_farming_server" | |||
# Topics: | |||
Topics = { | |||
"ROBOT_ACTION_DRIVE": "ROBOT/ACTION/DRIVE", | |||
"ROBOT_ACTION_GETPOSITION": "ROBOT/ACTION/GETPOSITION", | |||
"ROBOT_ACTION_GETBATTERY": "ROBOT/ACTION/GETBATTERY", | |||
"ROBOT_DATA_SENSORDATA": "ROBOT/DATA/SENSORDATA", | |||
"ROBOT_DATA_BATTERY": "ROBOT/DATA/BATTERY", | |||
"ROBOT_DATA_POSITION": "ROBOT/DATA/POSITION", | |||
"ROBOT_DATA_PICTURE": "ROBOT/DATA/PICTURE", | |||
"BACKEND_ACTION_DRIVE": "BACKEND/ACTION/DRIVE", | |||
"BACKEND_ACTION_GETPOSITION": "BACKEND/ACTION/GETPOSITION", | |||
"BACKEND_ACTION_GETBATTERY": "BACKEND/ACTION/GETBATTERY", | |||
"BACKEND_ACTION_GETALLDATA": "BACKEND/ACTION/GETALLDATA", | |||
"BACKEND_DATA_SENSORDATA": "BACKEND/DATA/SENSORDATA", | |||
"BACKEND_DATA_SENSORDATAALL": "BACKEND/DATA/SENSORDATA_ALL", | |||
"BACKEND_DATA_POSITION": "BACKEND/DATA/POSITION", | |||
"BACKEND_DATA_BATTERY": "BACKEND/DATA/BATTERY", | |||
"BACKEND_DATA_PICTURE": "BACKEND/DATA/PICTURE" | |||
} | |||
# MQTT Messages: | |||
# region Robot -> Backend | |||
SENSORDATA = { | |||
"AirTemperature": 0.0, | |||
"AirHumidity" : 0.0, | |||
"SoilMoisture" : 0.0, | |||
"Brightness" : 0, | |||
"PlantID": 0, | |||
"ActionID": 0 | |||
} | |||
# TODO When sensor is available | |||
POSITION = { | |||
"Position": "" | |||
} | |||
BATTERY = { | |||
"Battery": 0.0 | |||
} | |||
# endregion | |||
# region Backend -> Robot | |||
DRIVE = { | |||
"PlantID": 0, | |||
"ActionID": 0 | |||
} | |||
# GETPOSITION -> no message needed | |||
# GETBATTERY -> no message needed | |||
# endregion | |||
# region Backend -> Frontend | |||
PLANTDATA = { | |||
"AirTemperature": 0.0, | |||
"AirHumidity" : 0.0, | |||
"SoilMoisture" : 0.0, | |||
"Brightness" : 0, | |||
"PlantID": 0, | |||
"Timestamp": "", | |||
"MeasurementID": 0 | |||
} | |||
ALLPLANTDATA = [ | |||
PLANTDATA, | |||
PLANTDATA, | |||
PLANTDATA, | |||
PLANTDATA, | |||
PLANTDATA, | |||
PLANTDATA | |||
] | |||
# TODO When sensor is available | |||
POSITION = { | |||
"Position": "", | |||
"Timestamp": "" | |||
} | |||
BATTERY = { | |||
"Battery": 0.0, | |||
"Timestamp": "" | |||
} | |||
# endregion | |||
# region Frontend -> Backend | |||
DRIVE = { | |||
"PlantID": 0 | |||
} | |||
# GETPOSITION -> no message needed | |||
# GETBATTERY -> no message needed | |||
# GETALLDATA -> no message needed | |||
# endregion |
@@ -0,0 +1,120 @@ | |||
import paho.mqtt.client as mqtt | |||
import json | |||
import threading | |||
import os | |||
import raspy_sensors as RaspySensors | |||
from defines import Topics | |||
def measure_send_data(plantID, actionID, client: mqtt.Client): | |||
""" | |||
Reads all sensors and publishes data via MQTT | |||
Args: | |||
plantID (_type_): plant to measure | |||
actionID (_type_): current ID of driving action | |||
client (mqtt.Client): current mqtt client for publishing | |||
""" | |||
sensor = RaspySensors() | |||
sensorData = sensor.readSensors() | |||
sensorData["PlantID"] = plantID | |||
sensorData["ActionID"] = actionID | |||
client.publish(Topics["ROBOT_DATA_SENSORDATA"], json.dumps(sensorData, indent=4)) | |||
def drive_plant_thread(plantID, actionID, client: mqtt.Client): | |||
""" | |||
Function to drive to plant according to number from MQTT message in thread | |||
Meassure and publish data via MQTT | |||
Drive home to starting point | |||
Args: | |||
plantID (_type_): plant to measure | |||
actionID (_type_): current ID of driving action | |||
client (mqtt.Client): current mqtt client for publishing | |||
""" | |||
os.system(f'sshpass -p maker ssh robot@ev3dev.local python3 /home/robot/Programme/plant_{plantID}.py') | |||
print("Measuring Sensors") | |||
#FIXME Sensor not working | |||
# measure_send_data(plantID, actionID, client) | |||
print("Robot driving home") | |||
if plantID % 2 == 0: | |||
leftRight = -50 #rotating left | |||
else: | |||
leftRight = 50 #rotating right | |||
os.system(f'sshpass -p maker ssh robot@ev3dev.local python3 /home/robot/Programme/drive_back.py {leftRight}') | |||
print("Robot home") | |||
#TODO decide about robot occupied message | |||
#client.publish("ROBOT/DATA/OCCUPIED", "false") | |||
#region MQTT callbacks | |||
#Testing | |||
def send_data_json(clients: mqtt.Client, userdata, message: mqtt.MQTTMessage): | |||
strIn = str(message.payload.decode("UTF-8")) | |||
dataDict = json.loads(strIn) | |||
print("Received data: ", json.dumps(dataDict)) | |||
def drive_plant(clients: mqtt.Client, userdata, message: mqtt.MQTTMessage): | |||
""" | |||
Function to drive to plant according to request | |||
Starting Drive in Thread | |||
Args: | |||
clients (mqtt.Client): current mqtt client | |||
userdata (_type_): _description_ | |||
message (mqtt.MQTTMessage): received message | |||
""" | |||
dictMessage = json.loads(str(message.payload.decode("UTF-8"))) | |||
plantID = dictMessage["PlantID"] | |||
actionID = dictMessage["ActionID"] | |||
print(f"received drive to plant {plantID}") | |||
thread = threading.Thread(target= drive_plant_thread, args=(plantID, actionID, clients), daemon=True) | |||
thread.start() | |||
def get_position(clients: mqtt.Client, userdata, message: mqtt.MQTTMessage): | |||
""" | |||
Callback function for GPS position request | |||
Function to send actual GPS position via MQTT | |||
Args: | |||
clients (mqtt.Client): current mqtt client | |||
userdata (_type_): _description_ | |||
message (mqtt.MQTTMessage): received message | |||
""" | |||
# TODO Write GPS Sensor Function | |||
position = { | |||
"Position": "" | |||
} | |||
clients.publish(Topics["ROBOT_DATA_POSITION"], json.dumps(position, indent=4)) | |||
def get_BatteryStatus(clients: mqtt.Client, userdata, message: mqtt.MQTTMessage): | |||
""" | |||
Callback function for battery status request | |||
Function to read battery status from ev3 and send via MQTT | |||
Args: | |||
clients (mqtt.Client): current mqtt client | |||
userdata (_type_): _description_ | |||
message (mqtt.MQTTMessage): received message | |||
""" | |||
battery = { | |||
"Battery": 0.0 | |||
} | |||
#TODO read Battery | |||
clients.publish(Topics["ROBOT_DATA_BATTERY"], json.dumps(battery, indent=4)) | |||
#endregion |
@@ -9,71 +9,10 @@ Interaction with the EV3 via SSH | |||
""" | |||
import paho.mqtt.client as mqtt | |||
import json | |||
import threading | |||
import os | |||
import time | |||
import functions | |||
from raspy_sensors import RaspySensors | |||
from defines import Topics, RASPI_CLIENT_ID, MQTT_BROKER_GLOBAL | |||
from software.defines import Topics, RASPI_CLIENT_ID, MQTT_BROKER_GLOBAL | |||
#region global Varaibles | |||
# FIXME Sensor not working | |||
#sensors: RaspySensors | |||
#endregion | |||
#region global functions | |||
# TODO auslagern | |||
def measure_send_data(plantID, actionID, client: mqtt.Client): | |||
""" | |||
Reads all sensors and publishes data via MQTT | |||
Args: | |||
plantID (_type_): plant to measure | |||
actionID (_type_): current ID of driving action | |||
client (mqtt.Client): current mqtt client for publishing | |||
""" | |||
sensorData = sensors.readSensors() | |||
sensorData["PlantID"] = plantID | |||
sensorData["ActionID"] = actionID | |||
client.publish(Topics["ROBOT_DATA_SENSORDATA"], json.dumps(sensorData, indent=4)) | |||
# TODO auslagern | |||
def drive_plant_thread(plantID, actionID, client: mqtt.Client): | |||
""" | |||
Function to drive to plant according to number from MQTT message in thread | |||
Meassure and publish data via MQTT | |||
Drive home to starting point | |||
Args: | |||
plantID (_type_): plant to measure | |||
actionID (_type_): current ID of driving action | |||
client (mqtt.Client): current mqtt client for publishing | |||
""" | |||
os.system(f'sshpass -p maker ssh robot@ev3dev.local python3 /home/robot/Programme/plant_{plantID}.py') | |||
#CHECK if working properly | |||
print("Measuring Sensors") | |||
#FIXME Sensor not working | |||
# measure_send_data(plantID, actionID, client) | |||
print("Robot driving home") | |||
if plantID % 2 == 0: | |||
leftRight = -50 #rotating left | |||
else: | |||
leftRight = 50 #rotating right | |||
os.system(f'sshpass -p maker ssh robot@ev3dev.local python3 /home/robot/Programme/drive_back.py {leftRight}') | |||
print("Robot home") | |||
#TODO decide about robot occupied message | |||
#client.publish("ROBOT/DATA/OCCUPIED", "false") | |||
def on_connect(client: mqtt.Client, userdata, flags, rc): | |||
""" | |||
@@ -88,10 +27,10 @@ def on_connect(client: mqtt.Client, userdata, flags, rc): | |||
""" | |||
if rc == 0: | |||
#Add callbacks | |||
client.message_callback_add("ROBOT/DATA", send_data_json) #Testing | |||
client.message_callback_add(Topics["ROBOT_ACTION_DRIVE"], drive_plant) | |||
client.message_callback_add(Topics["ROBOT_ACTION_GETPOSITION"], get_position) | |||
client.message_callback_add(Topics["ROBOT_ACTION_GETBATTERY"], get_BatteryStatus) | |||
client.message_callback_add("ROBOT/DATA", functions.send_data_json) #Testing | |||
client.message_callback_add(Topics["ROBOT_ACTION_DRIVE"], functions.drive_plant) | |||
client.message_callback_add(Topics["ROBOT_ACTION_GETPOSITION"], functions.get_position) | |||
client.message_callback_add(Topics["ROBOT_ACTION_GETBATTERY"], functions.get_BatteryStatus) | |||
#Subscribe to topics | |||
client.subscribe("ROBOT/DATA") #Testing | |||
@@ -102,89 +41,12 @@ def on_connect(client: mqtt.Client, userdata, flags, rc): | |||
print("MQTT initialized") | |||
#endregion | |||
# TODO auslagern | |||
#region MQTT callbacks | |||
#Testing | |||
def send_data_json(clients: mqtt.Client, userdata, message: mqtt.MQTTMessage): | |||
strIn = str(message.payload.decode("UTF-8")) | |||
dataDict = json.loads(strIn) | |||
print("Received data: ", json.dumps(dataDict)) | |||
# CHECK if working properly | |||
def drive_plant(clients: mqtt.Client, userdata, message: mqtt.MQTTMessage): | |||
""" | |||
Function to drive to plant according to request | |||
Starting Drive in Thread | |||
Args: | |||
clients (mqtt.Client): current mqtt client | |||
userdata (_type_): _description_ | |||
message (mqtt.MQTTMessage): received message | |||
""" | |||
dictMessage = json.loads(str(message.payload.decode("UTF-8"))) | |||
plantID = dictMessage["PlantID"] | |||
actionID = dictMessage["ActionID"] | |||
print(f"received drive to plant {plantID}") | |||
thread = threading.Thread(target= drive_plant_thread, args=(plantID, actionID, clients), daemon=True) | |||
thread.start() | |||
def get_position(clients: mqtt.Client, userdata, message: mqtt.MQTTMessage): | |||
""" | |||
Callback function for GPS position request | |||
Function to send actual GPS position via MQTT | |||
Args: | |||
clients (mqtt.Client): current mqtt client | |||
userdata (_type_): _description_ | |||
message (mqtt.MQTTMessage): received message | |||
""" | |||
# TODO Write Sensor Function | |||
position = { | |||
"Position": "" | |||
} | |||
clients.publish(Topics["ROBOT_DATA_POSITION"], json.dumps(position, indent=4)) | |||
def get_BatteryStatus(clients: mqtt.Client, userdata, message: mqtt.MQTTMessage): | |||
""" | |||
Callback function for battery status request | |||
Function to read battery status from ev3 and send via MQTT | |||
Args: | |||
clients (mqtt.Client): current mqtt client | |||
userdata (_type_): _description_ | |||
message (mqtt.MQTTMessage): received message | |||
""" | |||
battery = { | |||
"Battery": 0.0 | |||
} | |||
#TODO read Battery | |||
clients.publish(Topics["ROBOT_DATA_BATTERY"], json.dumps(battery, indent=4)) | |||
#endregion | |||
def main(): | |||
""" | |||
Initialises MQTT and Sensors | |||
Runs forever and controlls all robot functions | |||
""" | |||
# CHECK if global | |||
# FIXME Sensor not working | |||
# global sensors | |||
# sensors = RaspySensors() | |||
client = mqtt.Client(RASPI_CLIENT_ID) | |||
client.on_connect = on_connect | |||
client.connect(MQTT_BROKER_GLOBAL) |
@@ -57,6 +57,8 @@ class RaspySensors: | |||
#read TSL2561 | |||
self.sensorData["Brightness"] = round(self.tsl2561.lux, 2) | |||
#TODO SoilMoisture Sensor | |||
return self.sensorData | |||
#TODO - take picture function |