First major contributions in an interim state #1
@@ -1,6 +1,7 @@
|
||||
#general imports
|
||||
import datetime
|
||||
import sqlite3
|
||||
import base64
|
||||
|
||||
# imports from Project
|
||||
from RaspberryPie.logger import captScribe
|
||||
@@ -12,6 +13,7 @@ class BGenSecretary:
|
||||
self.database = database_path
|
||||
self.image_path = image_path
|
||||
|
||||
|
||||
def _record(self, data: dict):
|
||||
connection = None
|
||||
try:
|
||||
@@ -31,13 +33,65 @@ class BGenSecretary:
|
||||
if connection is sqlite3.Connection:
|
||||
connection.close()
|
||||
|
||||
def recordPicture(self, picture):
|
||||
def recordPicture(self, picture: bytes):
|
||||
with open("{}/{}.jpg".format(self.image_path, str(datetime.datetime.now())), "w") as f:
|
||||
f.write(picture)
|
||||
|
||||
self._record({"picture": {"picture": picture}})
|
||||
self._record({"picture": {"picture": base64.encodebytes(picture).decode('ascii').replace("\n", "")}})
|
||||
|
||||
def recordAir(self, data):
|
||||
self._record({"air": {"temperature": data[0], "humidity": data[1]}})
|
||||
|
||||
def _fetchSingle(self, table, time: datetime.datetime):
|
||||
unix_time = int(time.timestamp())
|
||||
command = "SELECT * FROM {} ORDER BY ABS(unix_time - {}) ASC LIMIT 1".format(table, unix_time)
|
||||
connection, entry = None
|
||||
try:
|
||||
connection = sqlite3.connect(self.database)
|
||||
cursor = connection.cursor()
|
||||
cursor.execute(command)
|
||||
entry = cursor.fetchone()
|
||||
captScribe.info("Fetched entry for {} from {}".format(str(unix_time), table), "BGenSecretary._fetchSingle")
|
||||
except sqlite3.Error as e:
|
||||
captScribe.error(str(e), "BGenSecretary._fetchSingle")
|
||||
finally:
|
||||
if connection is sqlite3.Connection:
|
||||
connection.close()
|
||||
return tuple(entry) if entry is sqlite3.Row else None
|
||||
|
||||
def _fetchMultiple(self, table, end:datetime.datetime, start: datetime.datetime):
|
||||
unix_time_end = int(end.timestamp())
|
||||
unix_time_start = int(start.timestamp())
|
||||
command = "SELECT * FROM {} WHERE unix_time BETWEEN {} AND {}".format(unix_time_start, unix_time_end)
|
||||
connection, entries = None
|
||||
try:
|
||||
connection = sqlite3.connect(self.database)
|
||||
cursor = connection.cursor()
|
||||
cursor.execute(command)
|
||||
entries = cursor.fetchall()
|
||||
captScribe.info("Fetched entries for {} from {}".format(str((unix_time_start, unix_time_end)), table), "BGenSecretary._fetchSingle")
|
||||
except sqlite3.Error as e:
|
||||
captScribe.error(str(e), "BGenSecretary._fetchSingle")
|
||||
finally:
|
||||
if connection is sqlite3.Connection:
|
||||
connection.close()
|
||||
return [tuple(entry) for entry in entries] if entries is not None else None
|
||||
|
||||
def fetchAir(self, time=datetime.datetime.now(), start_time=None): # time is either one point or the end point if start is given
|
||||
if not start_time:
|
||||
entry = self._fetchSingle("air", time)
|
||||
return {"unix_time": entry[0], "time_string": entry[1], "temperature": entry[2], "humidity": entry[3]}
|
||||
else:
|
||||
entries = self._fetchMultiple("air", time, start_time)
|
||||
return {"unix_time": [entry[0] for entry in entries], "time_string": [entry[1] for entry in entries], "temperature": [entry[2] for entry in entries], "humidity": [entry[3] for entry in entries]}
|
||||
|
||||
def fetchPicture(self, time=datetime.datetime.now(), start_time=None):
|
||||
if not start_time:
|
||||
entry = self._fetchSingle("picture", time)
|
||||
return {"unix_time": entry[0], "time_string": entry[1], "picture": entry[2]}
|
||||
else:
|
||||
entries = self._fetchMultiple("picture", time, start_time)
|
||||
return {"unix_time": [entry[0] for entry in entries], "time_string": [entry[1] for entry in entries], "picture": [entry[2] for entry in entries]}
|
||||
|
||||
|
||||
bGenSecretary = BGenSecretary(config["File Locations"]["database_file"], config["File Locations"],["image_path"])
|
||||
Binary file not shown.
@@ -0,0 +1,19 @@
|
||||
import datetime
|
||||
from RaspberryPie.config import config
|
||||
from RaspberryPie.dataHandling import bGenSecretary
|
||||
|
||||
def time(): return ""
|
||||
|
||||
def weatherUrls(): return [config["WeatherUrls"][i] for i in config["WeatherUrls"]]
|
||||
|
||||
def getLatestAirData(): return bGenSecretary.fetchAir()
|
||||
|
||||
def getLatestPicture(): return bGenSecretary.fetchAir()
|
||||
|
||||
def getDataRangeAir(start: int, end: int): return bGenSecretary.fetchAir(datetime.datetime.utcfromtimestamp(end), datetime.datetime.utcfromtimestamp(start))
|
||||
|
||||
def getDataRangePictures(start: int, end: int): return bGenSecretary.fetchPicture(datetime.datetime.utcfromtimestamp(end), datetime.datetime.utcfromtimestamp(start))
|
||||
|
||||
def getSingleAirData(time: int): return bGenSecretary.fetchAir(datetime.datetime.utcfromtimestamp(time))
|
||||
|
||||
def getSinglePicture(time: int): return bGenSecretary.fetchPicture(datetime.datetime.utcfromtimestamp(time))
|
||||
@@ -1,15 +1,56 @@
|
||||
from flask import Flask, render_template, make_response
|
||||
import json
|
||||
|
||||
import RaspberryPie.flaskAddons as fa
|
||||
|
||||
app = Flask(__name__)
|
||||
@app.route("/")
|
||||
def index():
|
||||
pass
|
||||
latestAirData = fa.getLatestAirData()
|
||||
latestPicture = fa.getLatestPicture()
|
||||
return render_template("index.html",
|
||||
WeatherTime = latestAirData["time_string"],
|
||||
temp = latestAirData["temperature"],
|
||||
humi = latestAirData["humidity"],
|
||||
weather_urls=fa.weatherUrls(),
|
||||
PictureTime = latestPicture["time_string"],
|
||||
picture = latestPicture["picture"])
|
||||
|
||||
|
||||
@app.route("/data/<start>/<end>/")
|
||||
def functionName(start, end):
|
||||
data = {}
|
||||
db_entries = getEnvironment(int(start), int(end))
|
||||
data["labels"] = db_entries["temperature"][0]
|
||||
data["temp"] = db_entries["temperature"][1]
|
||||
data["humi"] = db_entries["humidity"][1]
|
||||
return json.dumps(data)
|
||||
def airData(start, end):
|
||||
data = fa.getDataRangeAir(int(start), int(end))
|
||||
return json.dumps(data)
|
||||
|
||||
@app.route("/picture/<time>/")
|
||||
def picture(time):
|
||||
if time == "latest":
|
||||
return json.dumps(fa.getLatestPicture())
|
||||
else:
|
||||
return json.dumps(fa.getLatestPicture(int(time)))
|
||||
|
||||
@app.route("/initiate/picture/")
|
||||
def inititatePicture():
|
||||
pass
|
||||
|
||||
@app.route("/inititate/air/")
|
||||
def ininitiateAir():
|
||||
pass
|
||||
|
||||
@app.route("/initiate/gpio/<state>/")
|
||||
def ininitisteGPIO(state):
|
||||
try:
|
||||
state = int(state)
|
||||
except:
|
||||
state = state
|
||||
|
||||
if state == "open" or state == 0:
|
||||
return "Opened", 200
|
||||
elif state == "close" or state == 1:
|
||||
return "Closed", 200
|
||||
return "state not found", 404
|
||||
|
||||
|
||||
@app.route("/initiate/shutdown/")
|
||||
def initiateShutdown():
|
||||
pass
|
||||
@@ -58,7 +58,7 @@ class MajGenObserver:
|
||||
def write(self, text):
|
||||
self.captured = text
|
||||
def __str__(self):
|
||||
return str(self.captured)
|
||||
return self.captured
|
||||
|
||||
def __init__(self, schedule_timing):
|
||||
self.schedule_timing = schedule_timing
|
||||
|
||||
@@ -19,11 +19,11 @@
|
||||
<h2>Weather Forecast</h2>
|
||||
<canvas id="ForecastChart" width="400" height="200"></canvas>
|
||||
<h2>Third party weather providers</h2>
|
||||
{% for image in urls %}
|
||||
{% for image in weather_urls %}
|
||||
<img src="{{ image }}">
|
||||
<h2>Webcam</h2>
|
||||
<a id="PictureTime">{{ PictureTime }}</a><br>
|
||||
<img id="Webcam" src="/latest.jpg">
|
||||
<img id="Webcam" src="data:image/jpg;base64,{{ picture }}">
|
||||
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user