aboutsummaryrefslogtreecommitdiff
path: root/RPGH.py
diff options
context:
space:
mode:
authorerg_samowzbudnik <uinarf@autistici.org>2021-06-01 15:11:52 +0200
committererg_samowzbudnik <uinarf@autistici.org>2021-06-01 15:11:52 +0200
commita2a05d9e9d9245be4c6e4e9c70334b8ac5fc299b (patch)
treeb44a805bfcff41d82c8cfc19cb2e92cc4af1b56d /RPGH.py
downloadRPGH-a2a05d9e9d9245be4c6e4e9c70334b8ac5fc299b.tar.gz
RPGH-a2a05d9e9d9245be4c6e4e9c70334b8ac5fc299b.tar.bz2
RPGH-a2a05d9e9d9245be4c6e4e9c70334b8ac5fc299b.zip
Initial commit of a beta version.
Diffstat (limited to 'RPGH.py')
-rw-r--r--RPGH.py345
1 files changed, 345 insertions, 0 deletions
diff --git a/RPGH.py b/RPGH.py
new file mode 100644
index 0000000..bfbad39
--- /dev/null
+++ b/RPGH.py
@@ -0,0 +1,345 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+__author__ = "Franek Łazarewicz-Muradyan"
+__copyright__ = "Copyright 2021, Franek Łazarewicz-Muradyan"
+__version__ = "0.1"
+__status__ = "Beta"
+__email__ = "uinarf@autistici.org"
+
+"""
+This is the main program starting the GUI
+"""
+
+import sys, os
+from PyQt5 import QtWidgets
+import matplotlib
+matplotlib.use('qt5agg')
+from matplotlib.figure import Figure
+from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
+from matplotlib import dates
+from datetime import datetime, timedelta
+from time import sleep
+import configparser
+from RPGH_gui import Ui_MainWindow
+#from RPGH_main_gui import Ui_MainWindow
+import pandas as pd
+from pandas.plotting import register_matplotlib_converters
+register_matplotlib_converters()
+import mysql.connector
+
+__location__ = os.path.realpath(
+ os.path.join(os.getcwd(), os.path.dirname(__file__)))
+
+# read and extract/format configuration data
+config_f = 'settings_config_parser.cfg'
+config_cl = 'settings_client.cfg'
+config_abs = os.path.join(__location__, config_f)
+config_cl_abs = os.path.join(__location__, config_cl)
+cfg = configparser.ConfigParser(interpolation=None)
+cfg_cl = configparser.ConfigParser(interpolation=None)
+cfg.read(config_abs)
+cfg_cl.read(config_cl_abs)
+
+
+class Data:
+
+ def fetch_table(self, table, _min, _max):
+ self.table = table
+ # limits of data to fetch from-to:
+ self._min = _min
+ self._max = _max
+ try:
+ conn = mysql.connector.connect(**cfg_cl['mysql'])
+ except mysql.connector.Error as e:
+ try:
+ conn = mysql.connector.connect(
+ host=cfg_cl['mysql']['host'],
+ user=cfg_cl['mysql']['user'],
+ password=cfg_cl['mysql']['password'],
+ database=cfg_cl['mysql']['database']
+ )
+ except mysql.connector.Error as e:
+ print(f"Couldn't connect to a database: {e}")
+ sys.exit()
+ cur = conn.cursor()
+ sql = (
+ f"SELECT * FROM {self.table} WHERE timestamp BETWEEN %s AND %s"
+ )
+ #sql = (
+ # f"SELECT * FROM {self.table};"
+ #)
+ cur.execute(sql, (self._min, self._max))
+ #cur.execute(sql)
+ rows = cur.fetchall()
+ fields = [i[0] for i in cur.description]
+ df = pd.DataFrame([[x for x in i] for i in rows])
+
+ return fields, df
+
+class DesignerMainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
+ def __init__(self, parent = None):
+
+ super(DesignerMainWindow, self).__init__(parent)
+ self.setupUi(self)
+
+# setting up mplwidget
+ self.mplwidget()
+
+ def mplwidget(self):
+
+ timestamp_format = cfg.get('various', 'timestamp_format')
+ _now_p = datetime.now()
+ _past_p = _now_p - timedelta(hours=12)
+ # time limits formated for mysql:
+ _now = _now_p.strftime(timestamp_format)
+ _past = _past_p.strftime(timestamp_format)
+
+# unpacking data settings
+ temp_max = cfg.getint('temperature', 'temp_max')
+ temp_min = cfg.getint('temperature', 'temp_min')
+ light_max = cfg.getint('light', 'light_max')
+ light_min = cfg.getint('light', 'light_min')
+ humid_max = cfg.getint('humidity', 'humidity_max')
+ humid_min = cfg.getint('humidity', 'humidity_min')
+ soil_max = cfg.getint('water', 'soil_moisture_max')
+ soil_min = cfg.getint('water', 'soil_moisture_min')
+
+ # ax limits
+ now = _now_p.strftime("%H:%M:%S")
+ past = _past_p.strftime("%H:%M:%S")
+
+# unpacking temperature data
+ _temp_data = Data()
+ temp_fields, temp_data = _temp_data.fetch_table(
+ 'temperature', _past, _now
+ )
+ timestamp_temp = pd.to_datetime(
+ pd.Series(temp_data[0])
+ )
+ temp_01 = (
+ temp_data[1],
+ cfg['w1_mapping'][f'{temp_fields[1]}']
+ )
+ temp_02 = (
+ temp_data[2],
+ cfg['w1_mapping'][f'{temp_fields[2]}']
+ )
+ temp_03 = (
+ temp_data[3],
+ cfg['w1_mapping'][f'{temp_fields[3]}']
+ )
+ temp_04 = (
+ temp_data[4],
+ cfg['w1_mapping'][f'{temp_fields[4]}']
+ )
+
+# unpacking light data
+ self.light_data = Data()
+ light_fields, light_data = self.light_data.fetch_table(
+ 'light', _past, _now)
+ timestamp_1 = pd.to_datetime(
+ pd.Series(light_data[0]), format=timestamp_format
+ )
+ broadband = light_data[1]
+ infrared = light_data[2]
+ visible = light_data[3]
+
+# unpacking humidity data
+ self.hum_data = Data()
+ hum_fields, hum_data = self.hum_data.fetch_table(
+ 'humidity', _past, _now
+ )
+ timestamp_2 = pd.to_datetime(
+ pd.Series(hum_data[0]), format=timestamp_format
+ )
+ humid = hum_data[2]
+
+# unpacking rain data
+ self.rain_data = Data()
+ rain_fields, rain_data = self.hum_data.fetch_table(
+ 'rain', _past, _now
+ )
+ timestamp_3 = pd.to_datetime(
+ pd.Series(rain_data[0]), format=timestamp_format
+ )
+ rain = rain_data[1]
+
+ days = dates.DayLocator()
+ hours = dates.HourLocator()
+ minutes = dates.MinuteLocator()
+ seconds = dates.SecondLocator()
+ dfmt = dates.DateFormatter('%b %d')
+ tmfd = dates.DateFormatter('%H %M')
+
+# ploting temperature data
+ self.mpl.canvas.ax.set_ylabel('Temperature ($^\circ$C)')
+ self.mpl.canvas.ax.grid(True)
+ self.mpl.canvas.ax.plot(
+ timestamp_temp,
+ temp_01[0],
+ c='brown',
+ ls=':',
+ label=f'{temp_01[1]}'
+ )
+ self.mpl.canvas.ax.plot(
+ timestamp_temp,
+ temp_02[0],
+ c='orange',
+ ls='dotted',
+ label=f'{temp_02[1]}'
+ )
+ self.mpl.canvas.ax.fill_between(
+ timestamp_temp,
+ temp_01[0],
+ temp_02[0]
+ )
+ self.mpl.canvas.ax.fill_between(
+ timestamp_temp,
+ temp_01[0],
+ temp_max,
+ where=temp_01[0]>=temp_max,
+ edgecolor='red',
+ facecolor='none',
+ hatch='/',
+ interpolate=True
+ )
+ self.mpl.canvas.ax.fill_between(
+ timestamp_temp,
+ temp_02[0],
+ temp_min,
+ where=temp_02[0]<=temp_min,
+ edgecolor='red',
+ facecolor='none',
+ hatch='/',
+ interpolate=True
+ )
+ self.mpl.canvas.ax.legend(loc='upper left')
+ #self.mpl.canvas.ax.set_xlim([now, past])
+# adding light subplot
+ self.mpl.canvas.ax_1.set_ylabel('Light')
+ self.mpl.canvas.ax_1.grid(True)
+ self.mpl.canvas.ax_1.plot(
+ timestamp_1,
+ broadband,
+ c='cyan',
+ ls='-.',
+ label='broadband'
+ )
+ self.mpl.canvas.ax_1.plot(
+ timestamp_1,
+ infrared,
+ c='red',
+ ls='-.',
+ label='infrared'
+ )
+ self.mpl.canvas.ax_01 = self.mpl.canvas.ax_1.twinx()
+ self.mpl.canvas.ax_01.set_ylabel("light lm")
+ self.mpl.canvas.ax_01.plot(
+ timestamp_1,
+ visible,
+ c='orange',ls='-.',
+ label='visible'
+ )
+ self.mpl.canvas.ax_1.legend(loc='upper left')
+ self.mpl.canvas.ax_01.legend(loc='lower left')
+ self.mpl.canvas.ax_1.fill_between(
+ timestamp_1,
+ broadband,
+ light_max,
+ where=broadband>=light_max,
+ edgecolor='red',
+ facecolor='none',
+ hatch="/",
+ interpolate=True
+ )
+ self.mpl.canvas.ax_1.fill_between(
+ timestamp_1,
+ broadband,
+ light_min,
+ where=broadband<=light_min,
+ edgecolor='red',
+ facecolor='none',
+ hatch='/',
+ interpolate=True
+ )
+ #self.mpl.canvas.ax_1.set_xlim([now, past])
+# adding humidity subplot
+ self.mpl.canvas.ax_2.set_ylabel('Humidity %')
+ self.mpl.canvas.ax_2.set_xlabel('time')
+ self.mpl.canvas.ax_2.grid(True)
+ self.mpl.canvas.ax_2.plot(
+ timestamp_2,
+ humid,
+ c='blue',
+ ls='--',
+ label='humidity'
+ )
+ self.mpl.canvas.ax_2.legend(loc='upper left')
+ #self.mpl.canvas.ax_2.set_xlim([now, past])
+
+# setting up weather station tab:
+# adding temperature plot
+ self.mpl1.canvas.ax.set_ylabel('Temperature ($^\circ$C)')
+ self.mpl1.canvas.ax.grid(True)
+ self.mpl1.canvas.ax.plot(
+ timestamp_temp,
+ temp_03[0],
+ c='brown',
+ ls=':',
+ label=f'{temp_03[1]}'
+ )
+ self.mpl1.canvas.ax.plot(
+ timestamp_temp,
+ temp_04[0],
+ c='orange',
+ ls='dotted',
+ label=f'{temp_04[1]}'
+ )
+ self.mpl1.canvas.ax.legend(loc='upper left')
+ #self.mpl1.canvas.ax.set_xlim([now, past])
+# adding light plot
+ self.mpl1.canvas.ax_1.set_ylabel('Light lm')
+ self.mpl1.canvas.ax_1.grid(True)
+ self.mpl1.canvas.ax_1.plot(
+ timestamp_1,
+ visible,
+ c='yellow',
+ label='light'
+ )
+ self.mpl1.canvas.ax_1.legend(loc='upper left')
+ #self.mpl1.canvas.ax_1.set_xlim([now, past])
+# adding humidity/rainfall graph
+# mind you that hist() doesn't do what I'd like it to do. redo.
+ self.mpl1.canvas.ax_2.set_ylabel('Rainfall mm')
+ self.mpl1.canvas.ax_2.set_xlabel('time')
+ self.mpl1.canvas.ax_2.grid(True)
+# this is a hack: unit for bar width is days hence hum_data.shape[0] = numbers
+# of columns in dataframe allowing for dynamic sizing
+ self.mpl1.canvas.ax_2.bar(
+ timestamp_3,
+ rain,
+ width = .01*(1/rain_data.shape[0]),
+ edgecolor = 'black',
+ label='rainfall'
+ )
+ self.mpl1.canvas.ax_2.legend(loc='upper left')
+ #self.mpl1.canvas.ax_2.set_xlim([now, past])
+
+
+ def mpl_replot(self):
+ self.mpl.canvas.ax.clear()
+ self.mpl.canvas.ax_1.clear()
+ self.mpl.canvas.ax_2.clear()
+ self.mpl1.canvas.ax.clear()
+ self.mpl1.canvas.ax_1.clear()
+ self.mpl1.canvas.ax_2.clear()
+ self.mpl.canvas.draw_idle()
+ self.mpl1.canvas.draw_idle()
+ self.mplwidget()
+
+if __name__ == '__main__':
+ app = QtWidgets.QApplication([sys.argv])
+ gui = DesignerMainWindow()
+ gui.show()
+ sys.exit(app.exec_())