Skip to content
Snippets Groups Projects
Commit 6a57cfdc authored by Ewan Crowle's avatar Ewan Crowle
Browse files

Update 12 files

- /monday24.tar
- /static/script.js
- /static/Final_LT_HD_Horizontal.png
- /static/css/style.css
- /templates/index.html
- /local.db
- /flasktest.py
- /thingsboard.py
- /main.py
- /models.py
- /emails.py
- /.gitignore
parent a40ed47f
No related branches found
No related tags found
No related merge requests found
__pycache__
\ No newline at end of file
......@@ -24,4 +24,4 @@ def send(to_email, name, points, total_points):
print(response.text)
# Test
send("CrowleE@cardiff.ac.uk", "Ewan", 20, 200)
\ No newline at end of file
# send("@cardiff.ac.uk", "", 20, 200)
\ No newline at end of file
from flask import Flask, render_template
import sqlalchemy as db
from sqlalchemy.orm import sessionmaker
import models
app = Flask(__name__)
# Initialise the database engine
engine = db.create_engine('sqlite:///local.db', echo=True)
Session = sessionmaker(bind=engine)
@app.route('/')
def index():
session = Session()
returns = session.query(models.Return).all() #Queries the returns
session.close()
return render_template('index.html', returns=returns)
if __name__ == '__main__':
app.run(debug=True, host='0.0.0.0', port=5055)
local.db 0 → 100644
File added
......@@ -11,6 +11,7 @@ from pyzbar.pyzbar import decode
from PIL import Image
import sqlalchemy as db
from sqlalchemy.orm import sessionmaker
import uuid
# All in seconds
POLL_INTERVAL = 1
......@@ -67,6 +68,21 @@ def lookup_product(engine, product_id):
return product
def create_return(engine, return_obj):
print('Creating return')
Session = sessionmaker(bind=engine)
session = Session()
try:
session.add(return_obj)
session.commit()
session.refresh(return_obj)
print('Successfully created return',return_obj.id)
except Exception as e:
session.rollback()
print(e)
finally:
session.close()
def main():
print('Initialising...')
......@@ -75,6 +91,7 @@ def main():
init_lcd()
i2c.init_pins()
customer = None
# Store the customer ID here to prevent double scanning.
......@@ -171,7 +188,14 @@ def main():
i2c.setText(messages.STATE_PRODUCT_DEPOSITED)
i2c.buzz()
time.sleep(5)
emails.send(customer.email, customer.first_name, 20, 200)
new_return = models.Return(customer_id=customer.id,product_id=product.id,reward_value=product.reward_value)
create_return(engine, new_return)
time.sleep(5)
emails.send(customer.email, customer.first_name, product.reward_value, 200)
print(f"Succesful return. ID: {new_return.id}")
customer = None
customer_id = None
product = None
......
......@@ -2,7 +2,7 @@ from datetime import datetime
from sqlalchemy import Integer, String, DateTime
from sqlalchemy.orm import DeclarativeBase
from sqlalchemy.orm import mapped_column
from uuid import uuid4
class Base(DeclarativeBase):
pass
......@@ -28,7 +28,7 @@ class Product(Base):
class Return(Base):
__tablename__ = "returns"
id = mapped_column(String, primary_key=True)
id = mapped_column(String, primary_key=True, default=lambda: str(uuid4()))
customer_id = mapped_column(String, nullable=False)
product_id = mapped_column(String, nullable=False)
return_date = mapped_column(DateTime, nullable=False, default=datetime.utcnow)
......
File deleted
static/Final_LT_HD_Horizontal.png

42.2 KiB

/* /static/css/style.css */
.page {
margin-left: 10%;
margin-right: 10%;
}
.section {
font-family: system-ui, sans-serif;
text-align: center;
color: #1E1C59;
display: flex;
flex-direction: column;
margin-top: 20px;
}
#points {
font-size: 64px;
font-weight: bold;
}
.left {
text-align: left;
}
.footer {
margin-top: 100px;
font-size: 14px;
}
.navbar {
background-color: #1E1C59;
padding: 10px;
display: flex;
align-items: center;
}
.navbar img{
height: 45px;
margin-left: 20px;
}
document.addEventListener("DOMContentLoaded", function() {
let countdown = 5; // Needs to be updated if fetch time changes
let countdownElement = document.getElementById("countdown");
function fetchReturns() {
fetch('/returns')
.then(response => response.json())
.then(data => {
let container = document.getElementById("returns-container");
container.innerHTML = "";
data.returns.forEach(ret => {
let p = document.createElement("p");
p.textContent = `${ret.id} - ${ret.timestamp}`;
container.appendChild(p);
});
countdown = 5;
})
.catch(error => console.error("Error fetching returns:", error));
}
// Function to update countdown timer
function updateCountdown() {
countdownElement.textContent = countdown;
countdown--;
if (countdown < 0) {
countdown = 5; // Reset
}
}
// 5000ms > 5 seconds
setInterval(fetchReturns, 5000);
setInterval(updateCountdown, 1000);
// Initial fetch
fetchReturns();
});
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Return Dashboard</title>
<!-- css style sheet -->
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
</head>
<body>
<div class="navbar">
<a href="#">
<img src="{{ url_for('static', filename='Final_LT_HD_Horizontal.png') }}" alt="Logo">
</a>
</div>
<div class="page section">
<h1>Returns List</h1>
<p>Here are the latest returns:<br>
This page will reset in <span id="countdown">5</span> seconds</p>
<ul>
{% for return in returns | reverse %}
<p><strong>ID:</strong> {{ return.id }}</p>
<p><strong>Customer ID:</strong> {{ return.customer_id }}</p>
<p><strong>Product ID:</strong> {{ return.product_id }}</p>
<p><strong>Reward Value:</strong> {{ return.reward_value }}</p>
<p><strong>Return Date:</strong> {{ return.return_date }}</p>
<!-- hr splits -->
<hr>
{% endfor %}
</ul>
</div>
<div class="footer">
This page will reset in <span id="countdown">5</span> seconds
</div>
<script src="{{ url_for('static', filename='script.js') }}"></script>
</body>
</html>
import paho.mqtt.client as mqtt
import json
# -----------------------------------------------------------------------------
# 2. ThingsBoard Configuration
# -----------------------------------------------------------------------------
# - We connect to a ThingsBoard server for storing and visualizing sensor data.
# - 'thingsboard.cs.cf.ac.uk' is the server address for your institution.
# - ACCESS_TOKEN is a unique string that authenticates this device to ThingsBoard.
# Ensure you use your own token to post data to your own ThingsBoard dashboard.
# -----------------------------------------------------------------------------
THINGSBOARD_HOST = 'thingsboard.cs.cf.ac.uk'
ACCESS_TOKEN = 'zHObHAhH5uTIwRrT8GF7' # Replace with your actual token as needed
# -----------------------------------------------------------------------------
# 3. MQTT Callbacks
# -----------------------------------------------------------------------------
# - These callback functions are automatically called by the paho-mqtt library
# in response to various MQTT events (publishing, receiving messages, connecting).
# -----------------------------------------------------------------------------
def on_publish(client, userdata, result):
"""
Called whenever a message is successfully published to the MQTT broker.
Prints 'Success' to confirm the publish event, helping you verify
that data actually reached the server.
"""
print("Success")
def on_message(client, userdata, msg):
"""
Called when the client receives a message on a subscribed topic.
For this script, we listen for RPC requests that instruct the device
to toggle the buzzer. The message payload is in JSON format, which we decode.
"""
print('Topic: ' + msg.topic + '\nMessage: ' + str(msg.payload))
data = json.loads(msg.payload)
# If the method is "setValue", we interpret "params" to be either True or False,
# which determines the buzzer's ON/OFF state.
if data['method'] == 'setValue':
print(data['params'])
buzzer_state['State'] = data['params']
# The grovepi.digitalWrite function sends a digital HIGH or LOW to the buzzer pin
# depending on whether we pass True (HIGH) or False (LOW).
grovepi.digitalWrite(buzzer, data['params'])
def on_connect(client, userdata, flags, rc, *extra_params):
"""
Called after the client attempts to connect to the MQTT broker.
rc (result code) = 0 means a successful connection.
This is a good place to log or print a message indicating the connection status.
"""
print('Connected with result code ' + str(rc))
# -----------------------------------------------------------------------------
# 5. MQTT Client Creation and Configuration
# -----------------------------------------------------------------------------
# - The paho.mqtt library needs a client instance to manage connections and
# message events. We'll attach our callback functions and connect to the
# ThingsBoard server using our access token.
# -----------------------------------------------------------------------------
client = mqtt.Client()
def init_mqtt():
# Provide the ACCESS_TOKEN for device authentication to ThingsBoard.
client.username_pw_set(ACCESS_TOKEN)
# Bind our callbacks for connect, publish, and message events.
client.on_connect = on_connect
client.on_publish = on_publish
client.on_message = on_message
# Connect to the ThingsBoard server on port 1883 (standard MQTT).
# The third parameter (60) is the keepalive interval in seconds.
client.connect(THINGSBOARD_HOST, 1883, 60)
# Subscribe to RPC commands from ThingsBoard to let remote users
# toggle the buzzer by sending "setValue" method calls.
client.subscribe('v1/devices/me/rpc/request/+')
# Start the MQTT network loop in a separate thread, so the script can continue
# running and processing sensor data while maintaining an MQTT connection.
client.loop_start()
def publish_return(new_return):
payload = {
event_type: "return",
data: new_return,
}
client.publish('v1/devices/me/telemetry', json.dumps(payload), qos=1)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment