diff --git a/app.py b/app.py
index c05cbb7..dcea74f 100755
--- a/app.py
+++ b/app.py
@@ -6,12 +6,17 @@ from time import sleep
import time
import requests
import json
+import paho.mqtt.client as mqtt
# global last_indoor_data
global indoor_server_ip
global indoor_server_password
global outdoor_api_url
+global outdoor_data
global location
+global mqtt_enabled
+global mqtt_client
+global base_topic
# Load the config file "config.json"
config = json.loads(open("config.json", "r").read())
@@ -19,93 +24,44 @@ indoor_server_ip = config["indoor_server_ip"]
indoor_server_password = config["indoor_server_password"]
outdoor_api_url = config["outdoor_api_url"]
location = config["location"]
+mqtt_enabled = config["mqtt_enabled"]
-# Assume that the indoor unit is offline
-# The get_indoor_data() function will update this variable
-last_indoor_data = {
- "offline": True
-}
+# Initialize Variables
+outdoor_data = {}
-# def get_indoor_data() -> list:
-# global indoor_server_ip
-# global indoor_server_password
-# # SMB server details
-# server_name = indoor_server_ip
-# share_name = "airvisual"
-# username = "airvisual"
-# password = indoor_server_password
-
-# # File details, The file is a text file with name:
-# # _AirVisual_values.txt
-# # Get the prefix of the file name
-# prefix = time.strftime("%Y%m", time.localtime())
-# file_path = prefix + "_AirVisual_values.txt"
+def mqtt_reconnect():
+ global mqtt_client
+ global mqtt_server_ip
+ global mqtt_server_port
+ global mqtt_username
+ global mqtt_password
+ global mqtt_client_id
+ global base_topic
+ if not mqtt_client.is_connected():
+ # Connect to the MQTT server
+ mqtt_client.connect(mqtt_server_ip, mqtt_server_port)
+ # Start the MQTT client
+ mqtt_client.loop_start()
+ if mqtt_client.is_connected():
+ print("Connected to MQTT server!")
+ else:
+ print("Failed to connect to MQTT server!")
+ return False
+ return True
-# # Connect to the SMB server
-# conn = SMBConnection(username, password, "", "")
-# conn.connect(server_name, 139)
+if mqtt_enabled:
+ mqtt_server_ip = config["mqtt_server_ip"]
+ mqtt_server_port = config["mqtt_server_port"]
+ mqtt_username = config["mqtt_username"]
+ mqtt_password = config["mqtt_password"]
+ mqtt_client_id = config["mqtt_client_id"]
+ base_topic = config["base_topic"]
-# # Read the file contents
-# file_obj = open(file_path, "wb")
-# conn.retrieveFile(share_name, file_path, file_obj)
-# conn.close()
-
-# # Open the local cached file
-# file_obj = open(file_path, "r")
-
-# # The first line of the file contains the header
-# # The header contains the column names separated by a semicolon (;)
-# # The rest of the file contains the data separated by a semicolon (;)
-# # Extract the column names and the data from the file
-# file_obj.seek(0)
-# header = file_obj.readline().strip().split(";")
-# data = file_obj.readlines()
-# # Split all the data into a list of lists
-# data = [row.strip().split(";") for row in data]
-# file_obj.close()
-
-
-# # Remap the header names
-# headers_map = {
-# "PM2_5(ug/m3)": "pm25",
-# "PM10(ug/m3)": "pm10",
-# "PM1(ug/m3)": "pm1",
-# "CO2(ppm)": "co2",
-# "AQI(US)": "aqi",
-# "Temperature(C)": "temperature",
-# "Humidity(%RH)": "humidity",
-# "Timestamp": "time"
-# }
-
-# # Remove rows with header names that are not in the header map
-# # First, get the indices of the header names that are in the header map
-# headers_indices = []
-# for index, name in enumerate(header):
-# if name in headers_map:
-# headers_indices.append(index)
-
-# # Construct the new header with the header names that are in the header map
-# header = [header[index] for index in headers_indices]
-
-# # Construct the new data with only the columns indicated by the header indices
-# data = [[row[index] for index in headers_indices] for row in data]
-
-# # Remap the header names
-# headers = [headers_map[name] for name in header]
-
-# # Convert unix timestamp to human readable time
-# for row in data:
-# row[headers.index("time")] = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(int(row[headers.index("time")])))
-
-# # Create a list of dictionaries representing the data
-# # Each dictionary represents a row of data
-# data_list = []
-# for row in data:
-# data_dict = {}
-# for header in headers:
-# data_dict[header] = row[headers.index(header)]
-# data_list.append(data_dict)
-# return data_list
+ # Create an MQTT client
+ mqtt_client = mqtt.Client(client_id=mqtt_client_id)
+ # Set the username and password
+ mqtt_client.username_pw_set(mqtt_username, mqtt_password)
+ mqtt_reconnect()
def get_outdoor_data_current() -> dict:
# Fetch the data from the AirVisual API
@@ -142,6 +98,7 @@ def get_outdoor_data_current() -> dict:
response = requests.get(url)
try:
print("Fetching data from API!" )
+ print(response)
data = response.json()
# Create a dictionary of the data
data = {
@@ -167,7 +124,8 @@ def get_outdoor_data_current() -> dict:
# Remove the last_updated key
# TODO store the data in a database
return data
- except:
+ except Exception as e:
+ print(e)
# Oops, we got rate limited
# Return the cached data
print("Rate limited!")
@@ -196,7 +154,7 @@ app = Flask(__name__)
# Refresh the indoor data every 30 seconds
def refresh_data():
while True:
-
+ global outdoor_data
# print("Fetching indoor data!")
# indoor_data = get_indoor_data()
# global last_indoor_data
@@ -204,9 +162,17 @@ def refresh_data():
# last_indoor_data = indoor_data[-1]
# Fetch the outdoor data
- print("Fetching outdoor data!")
+ print("Fetching outdoor data!")
outdoor_data = get_outdoor_data_current()
-
+ # Reconnect the MQTT client
+ mqtt_reconnect()
+ mqtt_client.publish(base_topic+"/temperature", outdoor_data["temperature"], retain=True)
+ mqtt_client.publish(base_topic+"/humidity", outdoor_data["humidity"], retain=True)
+ mqtt_client.publish(base_topic+"/pressure", outdoor_data["pressure"], retain=True)
+ mqtt_client.publish(base_topic+"/pm25", outdoor_data["pm25"], retain=True)
+ mqtt_client.publish(base_topic+"/pm10", outdoor_data["pm10"], retain=True)
+ mqtt_client.publish(base_topic+"/pm1", outdoor_data["pm1"], retain=True)
+ mqtt_client.publish(base_topic+"/aqi", outdoor_data["aqi"], retain=True)
sleep(30)
# Start the thread to refresh the data
diff --git a/nginx.json b/nginx.json
index 8ee4ce4..2b3d3f7 100644
--- a/nginx.json
+++ b/nginx.json
@@ -1,6 +1,6 @@
{
"listeners": {
- "*:80": {
+ "*:8080": {
"pass": "routes"
}
},
@@ -40,7 +40,7 @@
],
"applications": {
"iqair-apiserver-satitm": {
- "type": "python 3.10",
+ "type": "python 3.8",
"path": "/app/iqair-apiserver",
"home": "/app/venv",
"module": "app",
@@ -48,7 +48,7 @@
"working_directory": "/app/env-satitm"
},
"iqair-apiserver-satite": {
- "type": "python 3.10",
+ "type": "python 3.8",
"path": "/app/iqair-apiserver",
"home": "/app/venv",
"module": "app",
@@ -57,4 +57,4 @@
}
}
-}
\ No newline at end of file
+}
diff --git a/static/card.html b/static/card.html
index 9ca394e..e7b245a 100644
--- a/static/card.html
+++ b/static/card.html
@@ -52,7 +52,7 @@
.top_element {
display: grid;
grid-template-columns: 1fr 2fr 2fr;
- background-color: #97FF55;
+ background-color: #767676;
height: 190px;
}
@@ -104,7 +104,7 @@
justify-content: center;
justify-items: center;
align-items: center;
- background-color: #7bdb3f;
+ background-color: #474747;
font-size: 100px;
color: #fff;
@@ -161,8 +161,8 @@
Loading . . .
N/A
@@ -173,7 +173,7 @@
N/A
-
PM2.5 (μg/m3)
+
PM2.5 (μg/m³)
@@ -216,15 +216,21 @@
console.log(data);
// Set Title Location String
- $("#title").text(data.location);
+ // The location is the location key in the JSON response
+ // It must also be appended with the timestamp
+ var update_time = data.time_outdoor
+ // Data is in format YYYY-MM-DD hh:mm:ss
+ // We only want hh:mm
+ var update_time = update_time.substring(11, 16);
+ $("#title").text(data.location+" @ "+update_time);
// Update outdoor AQI and PM2.5 values
$("#outdoor-aqi").text(data.aqi_outdoor);
- $("#outdoor-pm25").text(data.pm25_outdoor);
+ $("#outdoor-pm25").text(data.pm25_outdoor.toFixed(1));
// Update outdoor temperature and humidity values
- $("#outdoor-temp").text("Temperature: " + data.temperature_outdoor + "°C");
- $("#outdoor-humid").text("Humidity: " + data.humidity_outdoor + "%");
+ $("#outdoor-temp").text("Temperature: " + data.temperature_outdoor.toFixed(1) + "°C");
+ $("#outdoor-humid").text("Humidity: " + data.humidity_outdoor.toFixed(1) + "%");
// Is outdoor AQI healthy?
// If AQI is less than 50, it is healthy
diff --git a/static/index.html b/static/index.html
index e8ff6e5..82af7cf 100644
--- a/static/index.html
+++ b/static/index.html
@@ -53,8 +53,12 @@
Air Quality Monitoring System
Chulalongkorn University Demonstation School
Where are you?
-
Primary School
-
Secondary School
+
Primary School
+
Card
+
Compact
+
Secondary School
+
Card
+
Compact
diff --git a/static/square.html b/static/square.html
new file mode 100644
index 0000000..5191121
--- /dev/null
+++ b/static/square.html
@@ -0,0 +1,176 @@
+
+
+
+