diff --git a/additional_files/html_template_readings1.html b/additional_files/html_template_readings1.html new file mode 100644 index 0000000..50b4930 --- /dev/null +++ b/additional_files/html_template_readings1.html @@ -0,0 +1,29 @@ + + + + + Sensors System Details + + +

+ + + + diff --git a/additional_files/html_template_readings2.html b/additional_files/html_template_readings2.html new file mode 100644 index 0000000..cffe9a8 --- /dev/null +++ b/additional_files/html_template_readings2.html @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/additional_files/html_template_readings3.html b/additional_files/html_template_readings3.html new file mode 100644 index 0000000..1c7c43e --- /dev/null +++ b/additional_files/html_template_readings3.html @@ -0,0 +1,5 @@ +
Sensor Interval ReadingsSensor Trigger Readings
_{{IntervalTypes}}__{{TriggerTypes}}_
_{{IntervalReadings}}__{{TriggerReadings}}_
+

Sensor Readings File +
+

+

diff --git a/app_config.py b/app_config.py index b17e0b1..9e02ea2 100644 --- a/app_config.py +++ b/app_config.py @@ -17,17 +17,21 @@ along with this program. If not, see . """ import os -import sys import logging from logging.handlers import RotatingFileHandler from datetime import datetime +script_directory = str(os.path.dirname(os.path.realpath(__file__))).replace("\\", "/") + +if not os.path.exists(os.path.dirname(script_directory + "/logs/")): + os.makedirs(os.path.dirname(script_directory + "/logs/")) + logger = logging.getLogger(__name__) logger.setLevel(logging.INFO) formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(funcName)s: %(message)s', '%Y-%m-%d %H:%M:%S') -file_handler = RotatingFileHandler('logs/KootNet_log.txt', maxBytes=256000, backupCount=5) +file_handler = RotatingFileHandler(script_directory + '/logs/KootNet_log.txt', maxBytes=256000, backupCount=5) file_handler.setFormatter(formatter) stream_handler = logging.StreamHandler() stream_handler.setFormatter(formatter) @@ -35,57 +39,74 @@ logger.addHandler(file_handler) logger.addHandler(stream_handler) -app_location_directory = str(os.path.dirname(sys.argv[0])) + "/" -config_file = app_location_directory + "config.txt" - -class CreateConfigSettings: +class CreateDefaultConfigSettings: + """ Creates a object holding all the Control Centers default configuration options. """ def __init__(self): - save_to = str(os.path.join(os.path.join(os.environ['USERPROFILE']), 'Desktop\\')) - self.save_to = save_to.replace('\\', '/') + self.script_directory = str(os.path.dirname(os.path.realpath(__file__))).replace("\\", "/") + self.logs_directory = script_directory + "/logs" + self.additional_files_directory = self.script_directory + "/additional_files" + self.config_file = self.script_directory + "/config.txt" + self.about_text = self.additional_files_directory + "/about_text.txt" + self.app_version = "Tested on Python 3.7 / KootNet Sensors - PC Control Center / Ver. Alpha.19.2" + + # Start of user configurable options + self.save_to = str(os.path.expanduser('~/Desktop/')).replace('\\', '/') self.graph_start = "2018-09-12 00:00:01" self.graph_end = "2200-01-01 00:00:01" - self.time_offset = "-7" - self.sql_queries_skip = "3" - self.temperature_offset = "-4" - self.network_check_timeout = "2" - self.network_details_timeout = "5" - self.allow_power_controls = 0 - self.allow_reset_config = 0 + self.datetime_offset = -7.0 + self.sql_queries_skip = 3 + self.temperature_offset = -4.0 + self.live_refresh = 5 + self.network_timeout_sensor_check = 2 + self.network_timeout_data = 5 + self.allow_advanced_controls = 0 self.ip_list = ["192.168.10.11", "192.168.10.12", "192.168.10.13", "192.168.10.14", "192.168.10.15", "192.168.10.16", "192.168.10.17", "192.168.10.18", "192.168.10.19", "192.168.10.20", "192.168.10.21", "192.168.10.22", "192.168.10.23", "192.168.10.24", "192.168.10.25", "192.168.10.26"] + def reset_to_defaults(self): + default_config = CreateDefaultConfigSettings() + + self.save_to = default_config.save_to + self.graph_start = default_config.graph_start + self.graph_end = default_config.graph_end + self.datetime_offset = default_config.datetime_offset + self.sql_queries_skip = default_config.sql_queries_skip + self.temperature_offset = default_config.temperature_offset + self.live_refresh = default_config.live_refresh + self.network_timeout_sensor_check = default_config.network_timeout_sensor_check + self.network_timeout_data = default_config.network_timeout_data + self.allow_advanced_controls = default_config.allow_advanced_controls + self.ip_list = default_config.ip_list + -def load_file(): - config_settings = CreateConfigSettings() +def get_from_file(): + """ Loads the Control Center configurations from file and returns the Verified settings. """ + config_settings = CreateDefaultConfigSettings() try: - os.path.isfile(config_file) - local_file = open(config_file, 'r') + os.path.isfile(config_settings.config_file) + local_file = open(config_settings.config_file, 'r') tmp_config_settings = local_file.read().split(',') local_file.close() config_settings.save_to = tmp_config_settings[0] config_settings.graph_start = tmp_config_settings[1] config_settings.graph_end = tmp_config_settings[2] - config_settings.time_offset = tmp_config_settings[3] + config_settings.datetime_offset = tmp_config_settings[3] config_settings.sql_queries_skip = tmp_config_settings[4] config_settings.temperature_offset = tmp_config_settings[5] - config_settings.network_check_timeout = tmp_config_settings[6] - config_settings.network_details_timeout = tmp_config_settings[7] + config_settings.live_refresh = tmp_config_settings[6] + config_settings.network_timeout_sensor_check = tmp_config_settings[7] + config_settings.network_timeout_data = tmp_config_settings[8] - if int(tmp_config_settings[8]) >= 0: - config_settings.allow_power_controls = int(tmp_config_settings[8]) - else: - logger.error("Setting Enable Sensor Shutdown/Reboot - BAD - Using Default") - - if int(tmp_config_settings[9]) >= 0: - config_settings.allow_reset_config = int(tmp_config_settings[9]) - else: - logger.error("Setting Enable Config Reset - BAD - Using Default") + try: + config_settings.allow_advanced_controls = int(tmp_config_settings[9]) + except Exception as error: + logger.error("Setting Enable Sensor Shutdown/Reboot - Using Default: " + str(error)) count = 0 while count < 16: @@ -98,16 +119,22 @@ def load_file(): count = count + 1 logger.debug("Configuration File Load - OK") - return config_settings except Exception as error: logger.warning("Configuration File Load Failed - Using All or Some Defaults: " + str(error)) - return config_settings + + check_config(config_settings) + return config_settings def check_config(config_settings): + """ + Checks the provided Control Center configuration for validity and returns it. + + Invalid options are replaced with defaults. + """ logger.debug("Checking Configuration Settings") - default_settings = CreateConfigSettings() + default_settings = CreateDefaultConfigSettings() if os.path.isdir(config_settings.save_to): logger.debug("Setting Save to Folder - OK") @@ -130,53 +157,54 @@ def check_config(config_settings): config_settings.graph_end = default_settings.graph_end try: - float(config_settings.time_offset) + config_settings.datetime_offset = float(config_settings.datetime_offset) logger.debug("Setting DataBase Hours Offset - OK") except Exception as error: logger.error("Setting DataBase Hours Offset - BAD - Using Default: " + str(error)) - config_settings.time_offset = default_settings.time_offset + config_settings.datetime_offset = default_settings.datetime_offset try: - int(config_settings.sql_queries_skip) + config_settings.sql_queries_skip = int(config_settings.sql_queries_skip) logger.debug("Setting Skip SQL Queries - OK") except Exception as error: logger.error("Setting Skip SQL Queries - BAD - Using Default: " + str(error)) config_settings.sql_queries_skip = default_settings.sql_queries_skip try: - float(config_settings.temperature_offset) + config_settings.temperature_offset = float(config_settings.temperature_offset) logger.debug("Setting Temperature Offset - OK") except Exception as error: logger.error("Setting Temperature Offset - BAD - Using Default: " + str(error)) config_settings.temperature_offset = default_settings.temperature_offset try: - int(config_settings.network_check_timeout) + config_settings.live_refresh = int(config_settings.live_refresh) + logger.debug("Setting Live Refresh - OK") + except Exception as error: + logger.error("Setting Live Refresh - BAD - Using Default: " + str(error)) + config_settings.live_refresh = default_settings.live_refresh + + try: + config_settings.network_timeout_sensor_check = int(config_settings.network_timeout_sensor_check) logger.debug("Setting Sensor Check Timeout - OK") except Exception as error: logger.error("Setting Sensor Check Timeout - BAD - Using Default: " + str(error)) - config_settings.network_check_timeout = default_settings.network_check_timeout + config_settings.network_timeout_sensor_check = default_settings.network_timeout_sensor_check try: - int(config_settings.network_details_timeout) + config_settings.network_timeout_data = int(config_settings.network_timeout_data) logger.debug("Setting Get Details Timeout - OK") except Exception as error: logger.error("Setting Get Details Timeout - BAD - Using Default: " + str(error)) - config_settings.network_details_timeout = default_settings.network_details_timeout + config_settings.network_timeout_data = default_settings.network_timeout_data try: - if config_settings.allow_power_controls >= 0: + config_settings.allow_advanced_controls = int(config_settings.allow_advanced_controls) + if 2 > config_settings.allow_advanced_controls >= 0: logger.debug("Setting Enable Sensor Shutdown/Reboot - OK") except Exception as error: logger.error("Setting Enable Sensor Shutdown/Reboot - BAD - Using Default: " + str(error)) - config_settings.allow_power_controls = default_settings.allow_power_controls - - try: - if config_settings.allow_reset_config >= 0: - logger.debug("Setting Enable Config Reset - OK") - except Exception as error: - logger.error("Setting Enable Config Reset - BAD - Using Default: " + str(error)) - config_settings.allow_reset_config = default_settings.allow_reset_config + config_settings.allow_advanced_controls = default_settings.allow_advanced_controls count = 0 while count < 16: @@ -187,27 +215,26 @@ def check_config(config_settings): config_settings.ip_list[count] = default_settings.ip_list[count] count = count + 1 - return config_settings - -def save_config_to_file(temp_config_settings): - config_settings = check_config(temp_config_settings) +def save_config_to_file(config_settings): + """ Saves provided Control Center configuration to file. """ + check_config(config_settings) var_final_write = str(config_settings.save_to) var_final_write = var_final_write + ',' + str(config_settings.graph_start) var_final_write = var_final_write + ',' + str(config_settings.graph_end) - var_final_write = var_final_write + ',' + str(config_settings.time_offset) + var_final_write = var_final_write + ',' + str(config_settings.datetime_offset) var_final_write = var_final_write + ',' + str(config_settings.sql_queries_skip) var_final_write = var_final_write + ',' + str(config_settings.temperature_offset) - var_final_write = var_final_write + ',' + str(config_settings.network_check_timeout) - var_final_write = var_final_write + ',' + str(config_settings.network_details_timeout) - var_final_write = var_final_write + ',' + str(config_settings.allow_power_controls) - var_final_write = var_final_write + ',' + str(config_settings.allow_reset_config) + var_final_write = var_final_write + ',' + str(config_settings.live_refresh) + var_final_write = var_final_write + ',' + str(config_settings.network_timeout_sensor_check) + var_final_write = var_final_write + ',' + str(config_settings.network_timeout_data) + var_final_write = var_final_write + ',' + str(config_settings.allow_advanced_controls) for ip in config_settings.ip_list: var_final_write = var_final_write + ',' + str(ip) try: - local_file = open(config_file, 'w') + local_file = open(config_settings.config_file, 'w') local_file.write(var_final_write) local_file.close() logger.debug("Configuration Settings Save to File - OK") diff --git a/app_graph.py b/app_graph.py index 9745203..7ae93ca 100644 --- a/app_graph.py +++ b/app_graph.py @@ -16,21 +16,25 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . """ +import sensor_commands import plotly import sqlite3 -import plotly.graph_objs as go +import os import logging from logging.handlers import RotatingFileHandler from datetime import datetime, timedelta -from plotly import tools +from plotly import tools, graph_objs as go +from matplotlib import pyplot, animation, style from guizero import warn +script_directory = str(os.path.dirname(os.path.realpath(__file__))) + logger = logging.getLogger(__name__) logger.setLevel(logging.INFO) formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(funcName)s: %(message)s', '%Y-%m-%d %H:%M:%S') -file_handler = RotatingFileHandler('logs/KootNet_log.txt', maxBytes=256000, backupCount=5) +file_handler = RotatingFileHandler(script_directory + '/logs/KootNet_log.txt', maxBytes=256000, backupCount=5) file_handler.setFormatter(formatter) stream_handler = logging.StreamHandler() @@ -39,6 +43,8 @@ logger.addHandler(file_handler) logger.addHandler(stream_handler) +style.use("dark_background") + class CreateGraphData: """ Creates an object to hold all the data needed for a graph. """ @@ -52,8 +58,6 @@ def __init__(self): self.time_offset = 0.0 self.graph_start = "1111-08-21 00:00:01" self.graph_end = "9999-01-01 00:00:01" - self.graph_type = "" - self.graph_table = "IntervalData" self.graph_columns = ["DateTime", "SensorName", "SensorUpTime", "IP", "SystemTemp", "EnvironmentTemp", "Pressure", "Humidity", "Lumen", "Red", "Green", "Blue"] self.max_sql_queries = 200000 @@ -84,131 +88,273 @@ def __init__(self): self.sql_data_gyro_z = [] -def start_graph(graph_data): +class CreateLiveGraph: + def __init__(self, sensor_type, ip, current_config): + self.current_config = current_config + self.sensor_type = sensor_type + self.ip = ip + self.first_datetime = str(datetime.time(datetime.now()))[:8] + + self.fig = pyplot.figure() + self.fig.canvas.set_window_title('Live Sensor Graph') + self.ax1 = self.fig.add_subplot(1, 1, 1) + self.x = [] + self.y = [] + + self.ani = animation.FuncAnimation(self.fig, + self._update_graph, + interval=float(self.current_config.live_refresh) * 1000) + pyplot.show() + + def _update_graph(self, x_frame): + current_time = str(datetime.time(datetime.now()))[:8] + sensor_name = sensor_commands.get_sensor_hostname(self.ip, + self.current_config.network_timeout_data) + try: + if self.sensor_type is "SensorUpTime": + sensor_reading = sensor_commands.get_sensor_uptime(self.ip, + self.current_config.network_timeout_data) + sensor_type_name = "Sensor Uptime" + measurement_type = "" + elif self.sensor_type is "SystemTemp": + sensor_reading = sensor_commands.get_sensor_cpu_temperature(self.ip, + self.current_config.network_timeout_data) + + try: + sensor_reading = round(float(sensor_reading), 3) + except Exception as error: + logger.warning(str(error)) + + sensor_type_name = "CPU Temperature" + measurement_type = " °C" + elif self.sensor_type is "EnvironmentTemp": + sensor_reading = sensor_commands.get_sensor_temperature(self.ip, + self.current_config.network_timeout_data) + + try: + sensor_reading = round(float(sensor_reading) + + float(self.current_config.temperature_offset), 3) + except Exception as error: + logger.warning(str(error)) + + sensor_type_name = "Environmental Temperature" + measurement_type = " °C" + elif self.sensor_type is "Pressure": + sensor_reading = sensor_commands.get_sensor_pressure(self.ip, + self.current_config.network_timeout_data) + sensor_type_name = "Pressure" + measurement_type = " hPa" + elif self.sensor_type is "Humidity": + sensor_reading = sensor_commands.get_sensor_humidity(self.ip, + self.current_config.network_timeout_data) + + try: + sensor_reading = int(round(float(sensor_reading), 0)) + except Exception as error: + logger.warning(str(error)) + + sensor_type_name = "Humidity" + measurement_type = " %RH" + elif self.sensor_type is "Lumen": + sensor_reading = sensor_commands.get_sensor_lumen(self.ip, + self.current_config.network_timeout_data) + sensor_type_name = "Lumen" + measurement_type = " Lumen" + elif self.sensor_type[0] == "Red": + sensor_reading = sensor_commands.get_sensor_rgb(self.ip, + self.current_config.network_timeout_data) + sensor_type_name = "RGB" + measurement_type = "" + elif self.sensor_type[0] == "Acc_X": + sensor_reading = 0 + sensor_type_name = "Accelerometer XYZ" + measurement_type = "" + elif self.sensor_type[0] == "Mag_X": + sensor_reading = 0 + sensor_type_name = "Magnetometer XYZ" + measurement_type = "" + elif self.sensor_type[0] == "Gyro_X": + sensor_reading = 0 + sensor_type_name = "Gyroscope XYZ" + measurement_type = "" + else: + sensor_reading = 0 + sensor_type_name = "Invalid Sensor" + measurement_type = "" + + self.ax1.clear() + self.y.append(sensor_reading) + self.x.append(x_frame) + self.ax1.plot(self.x, self.y) + + if self.sensor_type is "SensorUpTime": + try: + uptime_days = int(float(sensor_reading) // 1440) + uptime_hours = int((float(sensor_reading) % 1440) // 60) + uptime_min = int(float(sensor_reading) % 60) + sensor_reading = str(uptime_days) + " Days / " + \ + str(uptime_hours) + "." + \ + str(uptime_min) + " Hours" + except Exception as error: + logger.warning(str(error)) + + pyplot.title("Sensor: " + sensor_name + " || IP: " + self.ip) + pyplot.xlabel("Start Time: " + self.first_datetime + + " || Last Updated: " + current_time + + " || Reading: " + str(sensor_reading) + measurement_type) + + if self.sensor_type is "SensorUpTime": + measurement_type = " in Minutes" + elif self.sensor_type is "Lumen": + measurement_type = "" + + pyplot.ylabel(sensor_type_name + measurement_type) + pyplot.xticks([]) + except Exception as error: + logger.error("Live Graph - Invalid Sensor Data: " + str(error)) + + +def start_graph_interval(graph_data): + graph_data.graph_table = "IntervalData" logger.debug("SQL Columns: " + str(graph_data.graph_columns)) logger.debug("SQL Table(s): " + str(graph_data.graph_table)) logger.debug("SQL Start DateTime: " + str(graph_data.graph_start)) logger.debug("SQL End DateTime: " + str(graph_data.graph_end)) logger.debug("SQL DataBase Location: " + str(graph_data.db_location)) + # Adjust dates to Database timezone in UTC 0 new_time_offset = int(graph_data.time_offset) * -1 - get_sql_graph_start = adjust_interval_datetime(graph_data.graph_start, new_time_offset) - get_sql_graph_end = adjust_interval_datetime(graph_data.graph_end, new_time_offset) - if graph_data.graph_table == "IntervalData": - for var_column in graph_data.graph_columns: - var_sql_query = "SELECT " + \ - str(var_column) + \ - " FROM " + \ - str(graph_data.graph_table) + \ - " WHERE " + \ - var_column + \ - " IS NOT NULL AND DateTime BETWEEN datetime('" + \ - str(get_sql_graph_start) + \ - "') AND datetime('" + \ - str(get_sql_graph_end) + \ - "') LIMIT " + \ - str(graph_data.max_sql_queries) - - sql_column_data = get_sql_data(graph_data, var_sql_query) - - if str(var_column) == "DateTime": - count = 0 - for data in sql_column_data: - sql_column_data[count] = adjust_interval_datetime(data, int(graph_data.time_offset)) + get_sql_graph_start = _adjust_interval_datetime(graph_data.graph_start, new_time_offset) + get_sql_graph_end = _adjust_interval_datetime(graph_data.graph_end, new_time_offset) + for var_column in graph_data.graph_columns: + var_sql_query = "SELECT " + \ + str(var_column) + \ + " FROM " + \ + str(graph_data.graph_table) + \ + " WHERE " + \ + var_column + \ + " IS NOT NULL AND DateTime BETWEEN datetime('" + \ + str(get_sql_graph_start) + \ + "') AND datetime('" + \ + str(get_sql_graph_end) + \ + "') LIMIT " + \ + str(graph_data.max_sql_queries) + + sql_column_data = _get_sql_data(graph_data, var_sql_query) + + # Adjust SQL data from its UTC time, to user set timezone (Hour Offset) + if str(var_column) == "DateTime": + count = 0 + for data in sql_column_data: + sql_column_data[count] = _adjust_interval_datetime(data, int(graph_data.time_offset)) + count = count + 1 + + graph_data.sql_data_time = sql_column_data + + elif str(var_column) == "SensorName": + graph_data.sql_data_host_name = sql_column_data + elif str(var_column) == "SensorUpTime": + graph_data.sql_data_up_time = sql_column_data + elif str(var_column) == "IP": + graph_data.sql_data_ip = sql_column_data + elif str(var_column) == "SystemTemp": + graph_data.sql_data_cpu_temp = sql_column_data + elif str(var_column) == "EnvironmentTemp": + count = 0 + for data in sql_column_data: + try: + sql_column_data[count] = str(float(data) + float(graph_data.temperature_offset)) count = count + 1 - - graph_data.sql_data_time = sql_column_data - - elif str(var_column) == "SensorName": - graph_data.sql_data_host_name = sql_column_data - elif str(var_column) == "SensorUpTime": - graph_data.sql_data_up_time = sql_column_data - elif str(var_column) == "IP": - graph_data.sql_data_ip = sql_column_data - elif str(var_column) == "SystemTemp": - graph_data.sql_data_cpu_temp = sql_column_data - elif str(var_column) == "EnvironmentTemp": - count = 0 - for data in sql_column_data: - try: - sql_column_data[count] = str(float(data) + float(graph_data.temperature_offset)) - count = count + 1 - except Exception as error: - count = count + 1 - logger.error("Bad SQL entry from Column 'EnvironmentTemp' - " + str(error)) - - graph_data.sql_data_hat_temp = sql_column_data - - elif str(var_column) == "Pressure": - graph_data.sql_data_pressure = sql_column_data - elif str(var_column) == "Humidity": - graph_data.sql_data_humidity = sql_column_data - elif str(var_column) == "Lumen": - graph_data.sql_data_lumen = sql_column_data - elif str(var_column) == "Red": - graph_data.sql_data_red = sql_column_data - elif str(var_column) == "Green": - graph_data.sql_data_green = sql_column_data - elif str(var_column) == "Blue": - graph_data.sql_data_blue = sql_column_data - else: - logger.error(var_column + " - Does Not Exist") - - elif graph_data.graph_table == "TriggerData": - for var_column in graph_data.graph_columns: - var_sql_query = "SELECT " + \ - str(var_column) + \ - " FROM " + \ - str(graph_data.graph_table) + \ - " WHERE " + \ - var_column + \ - " IS NOT NULL AND DateTime BETWEEN datetime('" + \ - str(get_sql_graph_start) + \ - ".000') AND datetime('" + \ - str(get_sql_graph_end) + \ - ".000') LIMIT " + \ - str(graph_data.max_sql_queries) - - sql_column_data = get_sql_data(graph_data, var_sql_query) - - if str(var_column) == "DateTime": - count = 0 - for data in sql_column_data: - sql_column_data[count] = adjust_trigger_datetime(data, int(graph_data.time_offset)) + except Exception as error: count = count + 1 - - graph_data.sql_data_time = sql_column_data - - elif str(var_column) == "SensorName": - graph_data.sql_data_host_name = sql_column_data - elif str(var_column) == "IP": - graph_data.sql_data_ip = sql_column_data - elif str(var_column) == "Acc_X": - graph_data.sql_data_acc_x = sql_column_data - elif str(var_column) == "Acc_Y": - graph_data.sql_data_acc_y = sql_column_data - elif str(var_column) == "Acc_Z": - graph_data.sql_data_acc_z = sql_column_data - elif str(var_column) == "Mag_X": - graph_data.sql_data_mg_x = sql_column_data - elif str(var_column) == "Mag_Y": - graph_data.sql_data_mg_y = sql_column_data - elif str(var_column) == "Mag_Z": - graph_data.sql_data_mg_z = sql_column_data - elif str(var_column) == "Gyro_X": - graph_data.sql_data_gyro_x = sql_column_data - elif str(var_column) == "Gyro_Y": - graph_data.sql_data_gyro_y = sql_column_data - elif str(var_column) == "Gyro_Z": - graph_data.sql_data_gyro_z = sql_column_data - else: - logger.error(var_column + " - Does Not Exist") - - trace_graph(graph_data) + logger.error("Bad SQL entry from Column 'EnvironmentTemp' - " + str(error)) + + graph_data.sql_data_hat_temp = sql_column_data + + elif str(var_column) == "Pressure": + graph_data.sql_data_pressure = sql_column_data + elif str(var_column) == "Humidity": + graph_data.sql_data_humidity = sql_column_data + elif str(var_column) == "Lumen": + graph_data.sql_data_lumen = sql_column_data + elif str(var_column) == "Red": + graph_data.sql_data_red = sql_column_data + elif str(var_column) == "Green": + graph_data.sql_data_green = sql_column_data + elif str(var_column) == "Blue": + graph_data.sql_data_blue = sql_column_data + else: + logger.error(var_column + " - Does Not Exist") + _plotly_graph(graph_data) logger.debug("Interval DB Graph Complete") -def adjust_interval_datetime(var_datetime, time_offset): +def start_graph_trigger(graph_data): + graph_data.graph_table = "TriggerData" + logger.debug("SQL Columns: " + str(graph_data.graph_columns)) + logger.debug("SQL Table(s): " + str(graph_data.graph_table)) + logger.debug("SQL Start DateTime: " + str(graph_data.graph_start)) + logger.debug("SQL End DateTime: " + str(graph_data.graph_end)) + logger.debug("SQL DataBase Location: " + str(graph_data.db_location)) + + # Adjust dates to Database timezone in UTC 0 + new_time_offset = int(graph_data.time_offset) * -1 + get_sql_graph_start = _adjust_interval_datetime(graph_data.graph_start, new_time_offset) + get_sql_graph_end = _adjust_interval_datetime(graph_data.graph_end, new_time_offset) + + for var_column in graph_data.graph_columns: + var_sql_query = "SELECT " + \ + str(var_column) + \ + " FROM " + \ + str(graph_data.graph_table) + \ + " WHERE " + \ + var_column + \ + " IS NOT NULL AND DateTime BETWEEN datetime('" + \ + str(get_sql_graph_start) + \ + ".000') AND datetime('" + \ + str(get_sql_graph_end) + \ + ".000') LIMIT " + \ + str(graph_data.max_sql_queries) + + sql_column_data = _get_sql_data(graph_data, var_sql_query) + + if str(var_column) == "DateTime": + count = 0 + for data in sql_column_data: + sql_column_data[count] = _adjust_trigger_datetime(data, int(graph_data.time_offset)) + count = count + 1 + + graph_data.sql_data_time = sql_column_data + + elif str(var_column) == "SensorName": + graph_data.sql_data_host_name = sql_column_data + elif str(var_column) == "IP": + graph_data.sql_data_ip = sql_column_data + elif str(var_column) == "Acc_X": + graph_data.sql_data_acc_x = sql_column_data + elif str(var_column) == "Acc_Y": + graph_data.sql_data_acc_y = sql_column_data + elif str(var_column) == "Acc_Z": + graph_data.sql_data_acc_z = sql_column_data + elif str(var_column) == "Mag_X": + graph_data.sql_data_mg_x = sql_column_data + elif str(var_column) == "Mag_Y": + graph_data.sql_data_mg_y = sql_column_data + elif str(var_column) == "Mag_Z": + graph_data.sql_data_mg_z = sql_column_data + elif str(var_column) == "Gyro_X": + graph_data.sql_data_gyro_x = sql_column_data + elif str(var_column) == "Gyro_Y": + graph_data.sql_data_gyro_y = sql_column_data + elif str(var_column) == "Gyro_Z": + graph_data.sql_data_gyro_z = sql_column_data + else: + logger.error(var_column + " - Does Not Exist") + _plotly_graph(graph_data) + logger.debug("Trigger DB Graph Complete") + + +def _adjust_interval_datetime(var_datetime, time_offset): """ Adjusts the provided datetime by the provided hour offset and returns the result. @@ -229,7 +375,7 @@ def adjust_interval_datetime(var_datetime, time_offset): return str(new_time) -def adjust_trigger_datetime(var_datetime, time_offset): +def _adjust_trigger_datetime(var_datetime, time_offset): """ Adjusts the provided datetime by the provided hour offset and returns the result. @@ -258,7 +404,7 @@ def adjust_trigger_datetime(var_datetime, time_offset): return str(new_time) + tmp_ms -def get_sql_data(graph_interval_data, sql_command): +def _get_sql_data(graph_interval_data, sql_command): """ Execute SQLite3 command and return the results. """ return_data = [] @@ -288,7 +434,7 @@ def get_sql_data(graph_interval_data, sql_command): return return_data -def trace_graph(graph_interval_data): +def _plotly_graph(graph_interval_data): """ Create and open a HTML offline Plotly graph with the data provided. """ sub_plots = [] row_count = 0 @@ -336,7 +482,7 @@ def trace_graph(graph_interval_data): sub_plots.append('Sensor Uptime') logger.debug("Graph Sensor Uptime Added") - if len(graph_interval_data.sql_data_cpu_temp) > 1: + if len(graph_interval_data.sql_data_cpu_temp) > 1 or len(graph_interval_data.sql_data_hat_temp) > 1: row_count = row_count + 1 trace_cpu_temp = go.Scatter(x=graph_interval_data.sql_data_time, @@ -495,7 +641,7 @@ def trace_graph(graph_interval_data): fig['layout'].update(height=2048) try: - plotly.offline.plot(fig, filename=graph_interval_data.save_file_to + 'PlotSensors.html', auto_open=True) + plotly.offline.plot(fig, filename=graph_interval_data.save_file_to + 'SensorGraph.html', auto_open=True) logger.debug("Graph Creation - OK") except Exception as error: logger.error("Graph Creation - Failed - " + str(error)) diff --git a/app_reports.py b/app_reports.py index a3bd6ea..b318d77 100644 --- a/app_reports.py +++ b/app_reports.py @@ -16,20 +16,21 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . """ +import sensor_commands import webbrowser -import sys import os import logging -from sensor_commands import get_system_info, get_sensor_config -from app_config import load_file as load_config +import app_config from logging.handlers import RotatingFileHandler +script_directory = str(os.path.dirname(os.path.realpath(__file__))).replace("\\", "/") + logger = logging.getLogger(__name__) logger.setLevel(logging.INFO) formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(funcName)s: %(message)s', '%Y-%m-%d %H:%M:%S') -file_handler = RotatingFileHandler('logs/KootNet_log.txt', maxBytes=256000, backupCount=5) +file_handler = RotatingFileHandler(script_directory + '/logs/KootNet_log.txt', maxBytes=256000, backupCount=5) file_handler.setFormatter(formatter) stream_handler = logging.StreamHandler() stream_handler.setFormatter(formatter) @@ -37,176 +38,164 @@ logger.addHandler(file_handler) logger.addHandler(stream_handler) -app_location_directory = str(os.path.dirname(sys.argv[0])) + "/" -html_template_system1 = "additional_files/html_template_system1.html" -html_template_system2 = "additional_files/html_template_system2.html" -html_template_system3 = "additional_files/html_template_system3.html" -html_template_config1 = "additional_files/html_template_config1.html" -html_template_config2 = "additional_files/html_template_config2.html" -html_template_config3 = "additional_files/html_template_config3.html" - - -def html_system_codes(): - logger.debug("Getting Sensor Details HTML replacement Codes") - - html_replacement_vars = ["{{HostName}}", - "{{IP}}", - "{{DateTime}}", - "{{UpTime}}", - "{{CPUTemp}}", - "{{FreeDisk}}", - "{{IntervalSize}}", - "{{TriggerSize}}", - "{{SQLWriteEnabled}}", - "{{CustomEnabled}}"] - - return html_replacement_vars +class HTMLSystem: + def __init__(self): + self.config_settings = app_config.get_from_file() + self.template1 = script_directory + "/additional_files/html_template_system1.html" + self.template2 = script_directory + "/additional_files/html_template_system2.html" + self.template3 = script_directory + "/additional_files/html_template_system3.html" + self.file_output_name = "SensorsSystem.html" + + self.replacement_codes = ["{{HostName}}", + "{{IP}}", + "{{DateTime}}", + "{{UpTime}}", + "{{CPUTemp}}", + "{{FreeDisk}}", + "{{IntervalSize}}", + "{{TriggerSize}}", + "{{SQLWriteEnabled}}", + "{{CustomEnabled}}"] + + def get_sensor_data(self, ip): + sensor_data = sensor_commands.get_sensor_system(ip, self.config_settings.network_timeout_data) + # Convert the sensor's system uptime of minutes to human readable day/hour.min + sensor_data[3] = _convert_minutes_string(sensor_data[3]) + + return sensor_data + + +class HTMLReadings: + def __init__(self): + self.config_settings = app_config.get_from_file() + self.template1 = script_directory + "/additional_files/html_template_readings1.html" + self.template2 = script_directory + "/additional_files/html_template_readings2.html" + self.template3 = script_directory + "/additional_files/html_template_readings3.html" + self.file_output_name = "SensorsSystem.html" + + self.replacement_codes = ["{{IntervalTypes}}", + "{{IntervalReadings}}", + "{{TriggerTypes}}", + "{{TriggerReadings}}"] + + def get_sensor_data(self, ip): + sensor_data = sensor_commands.get_sensor_readings(ip, self.config_settings.network_timeout_data) + + return sensor_data + + +class HTMLConfig: + def __init__(self): + self.config_settings = app_config.get_from_file() + self.template1 = script_directory + "/additional_files/html_template_config1.html" + self.template2 = script_directory + "/additional_files/html_template_config2.html" + self.template3 = script_directory + "/additional_files/html_template_config3.html" + self.file_output_name = "SensorsConfig.html" + + self.replacement_codes = ["{{HostName}}", + "{{IP}}", + "{{DateTime}}", + "{{IntervalDuration}}", + "{{TriggerDuration}}", + "{{SQLWriteEnabled}}", + "{{CustomEnabled}}", + "{{CustomAcc}}", + "{{CustomMag}}", + "{{CustomGyro}}"] + + def get_sensor_data(self, ip): + sensor_data = sensor_commands.get_sensor_config(ip, self.config_settings.network_timeout_data) + + return sensor_data + + +def sensor_html_report(report_configuration, ip_list): + """ Creates and opens a HTML Report based on provided IP's and report configurations data. """ + final_file = _get_file_content(report_configuration.template1) + sensor_html_template = _get_file_content(report_configuration.template2) + + # Add first HTML Template file to final HTML output file + # Insert each sensors data into final HTML output file through the 2nd template & replacement codes + for ip in ip_list: + try: + current_sensor_html = sensor_html_template + sensor_data = report_configuration.get_sensor_data(ip) -def html_config_codes(): - logger.debug("Getting Sensor Config HTML replacement Codes") - - html_replacement_vars = ["{{HostName}}", - "{{IP}}", - "{{DateTime}}", - "{{IntervalDuration}}", - "{{TriggerDuration}}", - "{{SQLWriteEnabled}}", - "{{CustomEnabled}}", - "{{CustomAcc}}", - "{{CustomMag}}", - "{{CustomGyro}}"] + current_sensor_html = _replace_with_codes(sensor_data, + report_configuration.replacement_codes, + current_sensor_html) - return html_replacement_vars + final_file = final_file + current_sensor_html + except Exception as error: + logger.error("Report Failure: " + str(error)) + # Merge the result with the Final HTML Template file. + template3 = _get_file_content(report_configuration.template3) + final_file = final_file + template3 -def open_html(outfile): try: - file_var = "file:///" + outfile - webbrowser.open(file_var, new=2) - logger.debug("Graph HTML File Opened - OK") + save_to_location = str(report_configuration.config_settings.save_to + report_configuration.file_output_name) + _save_data_to_file(final_file, save_to_location) + _open_html(save_to_location) + logger.debug("Sensor Report - HTML Save File - OK") except Exception as error: - logger.error("Graph HTML File Opened - Failed - " + str(error)) - - -def open_url(url): - webbrowser.open(url) + logger.error("Sensor Report - HTML Save File - Failed: " + str(error)) -def sensor_system_report(ip_list): - final_file = '' - sensor_html = '' - temp_config = load_config() - net_timeout = int(temp_config.network_details_timeout) - +def _get_file_content(file_location): try: - html_file_part = open(str(app_location_directory + html_template_system1), 'r') - final_file = html_file_part.read() - html_file_part.close() - html_file_part = open(str(app_location_directory + html_template_system2), 'r') - sensor_html = html_file_part.read() - html_file_part.close() - logger.debug("Open First 2 System Report Templates - OK") + tmp_file = open(file_location, "r") + file_content = tmp_file.read() + tmp_file.close() except Exception as error: - logger.error("Open First 2 System Report Templates - Failed: " + str(error)) + logger.error("Unable to get file contents: " + str(error)) + file_content = "Unable to get file contents: " + str(error) - # For each IP in the list, Get its data per Report "Type" - # Inserting them into a final HTML file, based on a 3 part template - replacement_codes = html_system_codes() - for ip in ip_list: - try: - current_sensor_html = sensor_html - sensor_data = get_system_info(ip, net_timeout) - - uptime_days = int(float(sensor_data[3]) // 1440) - uptime_hours = int((float(sensor_data[3]) % 1440) // 60) - uptime_min = int(float(sensor_data[3]) % 60) - sensor_data[3] = str(uptime_days) + " Days / " + str(uptime_hours) + "." + str(uptime_min) + " Hours" - - count = 0 - for code in replacement_codes: - try: - replace_word = str(sensor_data[count]) - except Exception as error: - replace_word = "Failed" - logger.error("Invalid Sensor Data: " + str(error)) - - print(code + " / " + replace_word) - current_sensor_html = current_sensor_html.replace(code, replace_word) - count = count + 1 - final_file = final_file + current_sensor_html - except Exception as error: - logger.error("System Report Failure: " + str(error)) + return file_content - try: - html_file_part = open(str(app_location_directory + html_template_system3), 'r') - html_end = html_file_part.read() - html_file_part.close() - final_file = final_file + html_end - logger.debug("Created System Report - HTML File - OK") - except Exception as error: - logger.error("Open 3rd System Report Template File Failed: " + str(error)) +def _convert_minutes_string(var_minutes): try: - save_to_location = str(temp_config.save_to + "SensorsSystem.html") - file_out = open(save_to_location, 'w') - file_out.write(final_file) - file_out.close() - open_html(save_to_location) - logger.debug("Sensor System Report - HTML Save File - OK") + uptime_days = int(float(var_minutes) // 1440) + uptime_hours = int((float(var_minutes) % 1440) // 60) + uptime_min = int(float(var_minutes) % 60) + str_day_hour_min = str(uptime_days) + " Days / " + str(uptime_hours) + "." + str(uptime_min) + " Hours" except Exception as error: - logger.error("Sensor System Report - HTML Save File - Failed: " + str(error)) + logger.error("Unable to convert Minutes to days/hours.min: " + str(error)) + str_day_hour_min = var_minutes + return str_day_hour_min -def sensor_config_report(ip_list): - final_file = '' - sensor_html = '' - temp_config = load_config() - net_timeout = int(temp_config.network_details_timeout) - try: - html_file_part = open(str(app_location_directory + html_template_config1), 'r') - final_file = html_file_part.read() - html_file_part.close() - html_file_part = open(str(app_location_directory + html_template_config2), 'r') - sensor_html = html_file_part.read() - html_file_part.close() - logger.debug("Open First 2 Config Report Templates - OK") - except Exception as error: - logger.error("Open First 2 Config Report Templates - Failed: " + str(error)) - - # For each IP in the list, Get its data per Report "Type" - # Inserting them into a final HTML file, based on a 3 part template - replacement_codes = html_config_codes() - for ip in ip_list: +def _replace_with_codes(data, codes, template): + count = 0 + for code in codes: try: - current_sensor_html = sensor_html - sensor_data = get_sensor_config(ip, net_timeout) - - count = 0 - for code in replacement_codes: - current_sensor_html = current_sensor_html.replace(code, str(sensor_data[count])) - count = count + 1 - final_file = final_file + current_sensor_html + replace_word = str(data[count]) except Exception as error: - logger.error("Config Report Failure: " + str(error)) + replace_word = "No Data" + logger.error("Invalid Sensor Data: " + str(error)) + + template = template.replace(code, replace_word) + count = count + 1 + + return template + +def _save_data_to_file(data, file_location): try: - html_file_part = open(str(app_location_directory + html_template_config3), 'r') - html_end = html_file_part.read() - html_file_part.close() - final_file = final_file + html_end - logger.debug("Created Sensor Config Report - HTML File - OK") + file_out = open(file_location, "w") + file_out.write(data) + file_out.close() except Exception as error: - logger.error("Open 3rd Template File Failed: " + str(error)) + logger.error("Unable to save file: " + str(error)) - # Write to a HTML file + +def _open_html(outfile): + """ Opens a HTML file in the default web browser. """ try: - save_to_location = str(temp_config.save_to + "SensorsConfig.html") - file_out = open(save_to_location, 'w') - file_out.write(final_file) - file_out.close() - open_html(save_to_location) - logger.debug("Sensor Config Report - HTML Save File - OK") + webbrowser.open_new_tab("file:///" + outfile) + logger.debug("Graph HTML File Opened - OK") except Exception as error: - logger.error("Sensor Config Report - HTML Save File - Failed: " + str(error)) + logger.error("Graph HTML File Opened - Failed - " + str(error)) diff --git a/main_guizero.py b/main_guizero.py index ff210ee..ec02a6c 100644 --- a/main_guizero.py +++ b/main_guizero.py @@ -20,7 +20,6 @@ DEBUG - Detailed information, typically of interest only when diagnosing problems. test INFO - Confirmation that things are working as expected. WARNING - An indication that something unexpected happened, or indicative of some problem in the near future - (e.g. ‘disk space low’). The software is still working as expected. ERROR - Due to a more serious problem, the software has not been able to perform some function. CRITICAL - A serious error, indicating that the program itself may be unable to continue running. """ @@ -29,43 +28,112 @@ import app_reports import app_graph import os -import sys import platform import subprocess -from guizero import App, Window, CheckBox, PushButton, Text, TextBox, MenuBar, info, ButtonGroup +import webbrowser +from guizero import App, Window, CheckBox, PushButton, Text, TextBox, MenuBar, info, warn, ButtonGroup from tkinter import filedialog +from matplotlib import pyplot from threading import Thread from queue import Queue import logging from logging.handlers import RotatingFileHandler -logger = logging.getLogger(__name__) +script_directory = str(os.path.dirname(os.path.realpath(__file__))).replace("\\", "/") +logger = logging.getLogger(__name__) logger.setLevel(logging.INFO) -formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s', '%Y-%m-%d %H:%M:%S') -file_handler = RotatingFileHandler('logs/KootNet_log.txt', maxBytes=256000, backupCount=5) +file_handler = RotatingFileHandler(script_directory + '/logs/KootNet_log.txt', + maxBytes=256000, + backupCount=5) +formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s', + '%Y-%m-%d %H:%M:%S') file_handler.setFormatter(formatter) stream_handler = logging.StreamHandler() stream_handler.setFormatter(formatter) - logger.addHandler(file_handler) logger.addHandler(stream_handler) -app_location_directory = str(os.path.dirname(sys.argv[0])) + "/" -config_file = app_location_directory + "/config.txt" -app_version = "Tested on Python 3.7 / KootNet Sensors - PC Control Center / Ver. Alpha.19.1" -app_about_location = app_location_directory + "/additional_files/about_text.txt" - -sensor_ip_queue = Queue() -sensor_data_queue = Queue() - - -def set_about_text(): +current_config = app_config.get_from_file() +data_queue = Queue() + + +def _app_custom_configurations(): + """ Apply system & user specific settings to application. Used just before application start. """ + # Add extra tk options to guizero windows + app.on_close(_app_exit) + app.tk.resizable(False, False) + window_graph.tk.resizable(False, False) + window_sensor_commands.tk.resizable(False, False) + window_sensor_config.tk.resizable(False, False) + window_sensor_reports.tk.resizable(False, False) + window_app_about.tk.resizable(False, False) + window_config.tk.resizable(False, False) + + # Add custom selections and GUI settings + app_checkbox_all_column1.value = 0 + app_checkbox_all_column2.value = 0 + graph_checkbox_up_time.value = 1 + graph_checkbox_temperature.value = 1 + graph_checkbox_pressure.value = 0 + graph_checkbox_humidity.value = 0 + graph_checkbox_lumen.value = 0 + graph_checkbox_colour.value = 0 + sensor_config_checkbox_db_record.value = 1 + sensor_config_checkbox_custom.value = 0 + + _set_about_text() + app_check_all_ip_checkboxes(1) + app_check_all_ip_checkboxes(2) + _graph_radio_selection() + sensor_config_enable_recording() + sensor_config_enable_custom() + + about_textbox.disable() + config_textbox_save_to.disable() + sensor_config_button_set_config.disable() + commands_button_os_Upgrade.disable() + + # Platform specific adjustments + if platform.system() == "Windows": + app.tk.iconbitmap(current_config.additional_files_directory + "/icon.ico") + elif platform.system() == "Linux": + app.width = 490 + app.height = 250 + window_config.width = 675 + window_config.height = 275 + window_graph.width = 325 + window_graph.height = 440 + window_sensor_config.width = 365 + window_sensor_config.height = 240 + window_sensor_commands.width = 300 + window_sensor_commands.height = 260 + window_app_about.width = 555 + window_app_about.height = 290 + + set_config() + if not os.path.isfile(current_config.config_file): + logger.info('No Configuration File Found - Saving Default') + app_config.save_config_to_file(current_config) + + +def _app_exit(): + """ Clean ups before application closes. """ + log_handlers = logger.handlers[:] + for handler in log_handlers: + handler.close() + logger.removeHandler(handler) + + pyplot.close() + app.destroy() + + +def _set_about_text(): """ Loads and sets the about text from file. """ try: - local_file = open(app_about_location, 'r') + local_file = open(current_config.about_text, 'r') new_text = local_file.read() local_file.close() about_textbox.value = new_text @@ -74,94 +142,82 @@ def set_about_text(): logger.error("About Text Load - Failed: " + str(error)) -def app_menu_open_log(): +def app_menu_open_logs(): """ Opens the folder where the logs are kept. """ logger.debug("Open Logs Folder") - log_path = app_location_directory + "logs/" if platform.system() == "Windows": - os.startfile(log_path) + os.startfile(current_config.logs_directory) elif platform.system() == "Darwin": - subprocess.Popen(["open", log_path]) + subprocess.Popen(["open", current_config.logs_directory]) else: - subprocess.Popen(["xdg-open", log_path]) - - -def app_menu_open_config(): - """ Open's the Configuration window. """ - window_config.show() - - -def app_menu_open_commands(): - """ Open's the Sensor Commands window. """ - window_sensor_commands.show() - - -def app_menu_open_sensor_config(): - """ Open's the Sensor Configuration window. """ - window_sensor_config.show() + subprocess.Popen(["xdg-open", current_config.logs_directory]) def app_menu_download_interval_db(): """ Downloads the Interval SQLite3 database to the chosen location, from the selected sensors. """ - ip_list = check_sensors() - threads = [] - download_to_location = filedialog.askdirectory() + ip_list = get_verified_ip_list() + if len(ip_list) >= 1: + threads = [] + download_to_location = filedialog.askdirectory() - for ip in ip_list: - threads.append(Thread(target=sensor_commands.download_interval_db, args=[ip, download_to_location])) + if download_to_location is not "" and download_to_location is not None: + for ip in ip_list: + threads.append(Thread(target=sensor_commands.download_interval_db, + args=[ip, download_to_location])) - for thread in threads: - thread.start() + for thread in threads: + thread.start() - for thread in threads: - thread.join() + for thread in threads: + thread.join() - info("Downloads", "Interval Database Downloads Complete") + info("Downloads", "Interval Database Downloads Complete") + else: + warn("Warning", "User Cancelled Download Operation") + else: + warn("No IP Selected", "Please Select at least 1 Sensor IP") def app_menu_download_trigger_db(): """ Downloads the Trigger SQLite3 database to the chosen location, from the selected sensors. """ - ip_list = check_sensors() - threads = [] - download_to_location = filedialog.askdirectory() + ip_list = get_verified_ip_list() + if len(ip_list) >= 1: + threads = [] + download_to_location = filedialog.askdirectory() - for ip in ip_list: - threads.append(Thread(target=sensor_commands.download_trigger_db, args=[ip, download_to_location])) - - for thread in threads: - thread.start() - - for thread in threads: - thread.join() + if download_to_location is not "" and download_to_location is not None: + for ip in ip_list: + threads.append(Thread(target=sensor_commands.download_trigger_db, + args=[ip, download_to_location])) - info("Downloads", "Trigger Database Downloads Complete") + for thread in threads: + thread.start() + for thread in threads: + thread.join() -def app_menu_open_graph(): - """ Open the graphing window. """ - window_graph_interval.show() + info("Downloads", "Trigger Database Downloads Complete") + else: + warn("Warning", "User Cancelled Download Operation") + else: + warn("No IP Selected", "Please Select at least 1 Sensor IP") def app_menu_open_website(): """ Open the program's Website. """ - app_reports.open_url("http://kootenay-networks.com/?page_id=170") - - -def app_menu_open_about(): - """ Open the About window. """ - window_app_about.show() + webbrowser.open_new_tab("http://kootenay-networks.com/?page_id=170") def app_menu_open_build_sensor(): """ Open the help file for building a Sensor Unit. """ - help_file_location = app_location_directory + "additional_files/BuildSensors.html" - app_reports.open_html(help_file_location) + help_file_location = current_config.additional_files_directory + "/BuildSensors.html" + webbrowser.open_new_tab(help_file_location) def app_menu_open_sensor_help(): """ Open the help file for Sensor Units. """ - help_file_location = app_location_directory + "additional_files/SensorUnitHelp.html" - app_reports.open_html(help_file_location) + help_file_location = current_config.additional_files_directory + "/SensorUnitHelp.html" + webbrowser.open_new_tab(help_file_location) def app_check_all_ip_checkboxes(var_column): @@ -207,31 +263,25 @@ def app_check_all_ip_checkboxes(var_column): app_checkbox_ip16.value = 0 -def worker_sensor_check(net_timeout): +def _worker_sensor_check(ip): """ Used in Threads. Socket connects to sensor by IP's in queue. Puts results in a data queue. """ - while not sensor_ip_queue.empty(): - ip = sensor_ip_queue.get() - data = [ip, sensor_commands.check_online_status(ip, net_timeout)] + data = [ip, sensor_commands.check_sensor_status(ip, current_config.network_timeout_sensor_check)] + data_queue.put(data) - sensor_data_queue.put(data) - sensor_ip_queue.task_done() - -def check_sensors(): +def get_verified_ip_list(): """ Checks sensor online status and changes the programs IP textbox depending on the returned results. The sensor checks are Threaded by the IP's provided in the IP list. """ - ip_list = get_checked_ip() + ip_list = _make_ip_list() ip_list_final = [] - net_timeout = int(config_textbox_network_check.value) sensor_data_pool = [] threads = [] for ip in ip_list: - threads.append(Thread(target=worker_sensor_check, args=[net_timeout])) - sensor_ip_queue.put(ip) + threads.append(Thread(target=_worker_sensor_check, args=[ip])) for thread in threads: thread.start() @@ -239,9 +289,9 @@ def check_sensors(): for thread in threads: thread.join() - while not sensor_data_queue.empty(): - sensor_data_pool.append(sensor_data_queue.get()) - sensor_data_queue.task_done() + while not data_queue.empty(): + sensor_data_pool.append(data_queue.get()) + data_queue.task_done() sensor_data_pool.sort() @@ -330,7 +380,7 @@ def check_sensors(): # Returns selected IP's from Main App Window & Re-Sets unselected IP background to white -def get_checked_ip(): +def _make_ip_list(): """ Returns a list of all checked IP's, skipping duplicates """ checkbox_ip_list = [] @@ -418,94 +468,100 @@ def get_checked_ip(): return checkbox_ip_list +def app_sensor_readings_report(): + """ Create a HTML sensor Readings Report containing each IP selected and online. """ + var_ip_list = get_verified_ip_list() + readings_config = app_reports.HTMLReadings() + app_reports.sensor_html_report(readings_config, var_ip_list) + + def app_sensor_system_report(): """ Create a HTML sensor System Report containing each IP selected and online. """ - var_ip_list = check_sensors() - app_reports.sensor_system_report(var_ip_list) + var_ip_list = get_verified_ip_list() + system_config = app_reports.HTMLSystem() + app_reports.sensor_html_report(system_config, var_ip_list) def app_sensor_config_report(): """ Create a HTML sensor Configuration Report containing each IP selected and online. """ - var_ip_list = check_sensors() - app_reports.sensor_config_report(var_ip_list) + var_ip_list = get_verified_ip_list() + sensor_config_config = app_reports.HTMLConfig() + app_reports.sensor_html_report(sensor_config_config, var_ip_list) def config_button_save(): """ Save the programs Configuration and IP list to file """ logger.debug("Applying Configuration & Saving to File") - config_settings = app_config.CreateConfigSettings() - - config_settings.save_to = config_textbox_save_to.value - config_settings.graph_start = config_textbox_start.value - config_settings.graph_end = config_textbox_end.value - config_settings.time_offset = config_textbox_time_offset.value - config_settings.sql_queries_skip = config_textbox_sql_skip.value - config_settings.temperature_offset = config_textbox_temperature_offset.value - config_settings.network_check_timeout = config_textbox_network_check.value - config_settings.network_details_timeout = config_textbox_network_details.value - config_settings.allow_power_controls = config_checkbox_power_controls.value - config_settings.allow_reset_config = config_checkbox_reset.value - config_settings.ip_list[0] = app_textbox_ip1.value - config_settings.ip_list[1] = app_textbox_ip2.value - config_settings.ip_list[2] = app_textbox_ip3.value - config_settings.ip_list[3] = app_textbox_ip4.value - config_settings.ip_list[4] = app_textbox_ip5.value - config_settings.ip_list[5] = app_textbox_ip6.value - config_settings.ip_list[6] = app_textbox_ip7.value - config_settings.ip_list[7] = app_textbox_ip8.value - config_settings.ip_list[8] = app_textbox_ip9.value - config_settings.ip_list[9] = app_textbox_ip10.value - config_settings.ip_list[10] = app_textbox_ip11.value - config_settings.ip_list[11] = app_textbox_ip12.value - config_settings.ip_list[12] = app_textbox_ip13.value - config_settings.ip_list[13] = app_textbox_ip14.value - config_settings.ip_list[14] = app_textbox_ip15.value - config_settings.ip_list[15] = app_textbox_ip16.value - - config_settings = app_config.check_config(config_settings) - - app_config.save_config_to_file(config_settings) - set_config(config_settings) - - -def set_config(config_settings): + current_config.save_to = config_textbox_save_to.value + current_config.graph_start = config_textbox_start.value + current_config.graph_end = config_textbox_end.value + current_config.datetime_offset = config_textbox_time_offset.value + current_config.sql_queries_skip = config_textbox_sql_skip.value + current_config.temperature_offset = config_textbox_temperature_offset.value + current_config.live_refresh = graph_textbox_refresh_time.value + current_config.network_timeout_sensor_check = config_textbox_network_check.value + current_config.network_timeout_data = config_textbox_network_details.value + current_config.allow_advanced_controls = config_checkbox_power_controls.value + current_config.ip_list[0] = app_textbox_ip1.value + current_config.ip_list[1] = app_textbox_ip2.value + current_config.ip_list[2] = app_textbox_ip3.value + current_config.ip_list[3] = app_textbox_ip4.value + current_config.ip_list[4] = app_textbox_ip5.value + current_config.ip_list[5] = app_textbox_ip6.value + current_config.ip_list[6] = app_textbox_ip7.value + current_config.ip_list[7] = app_textbox_ip8.value + current_config.ip_list[8] = app_textbox_ip9.value + current_config.ip_list[9] = app_textbox_ip10.value + current_config.ip_list[10] = app_textbox_ip11.value + current_config.ip_list[11] = app_textbox_ip12.value + current_config.ip_list[12] = app_textbox_ip13.value + current_config.ip_list[13] = app_textbox_ip14.value + current_config.ip_list[14] = app_textbox_ip15.value + current_config.ip_list[15] = app_textbox_ip16.value + + app_config.save_config_to_file(current_config) + set_config() + + +def set_config(): """ Sets the programs Configuration to the provided settings. """ - final_config_settings = app_config.check_config(config_settings) - try: - config_textbox_save_to.value = final_config_settings.save_to - config_textbox_start.value = final_config_settings.graph_start - graph_textbox_start.value = final_config_settings.graph_start - config_textbox_end.value = final_config_settings.graph_end - graph_textbox_end.value = final_config_settings.graph_end - config_textbox_time_offset.value = final_config_settings.time_offset - config_textbox_sql_skip.value = final_config_settings.sql_queries_skip - graph_textbox_sql_skip.value = final_config_settings.sql_queries_skip - config_textbox_temperature_offset.value = final_config_settings.temperature_offset - graph_textbox_temperature_offset.value = final_config_settings.temperature_offset - config_textbox_network_check.value = final_config_settings.network_check_timeout - config_textbox_network_details.value = final_config_settings.network_details_timeout - config_checkbox_power_controls.value = final_config_settings.allow_power_controls - config_checkbox_reset.value = final_config_settings.allow_reset_config - app_textbox_ip1.value = config_settings.ip_list[0] - app_textbox_ip2.value = config_settings.ip_list[1] - app_textbox_ip3.value = config_settings.ip_list[2] - app_textbox_ip4.value = config_settings.ip_list[3] - app_textbox_ip5.value = config_settings.ip_list[4] - app_textbox_ip6.value = config_settings.ip_list[5] - app_textbox_ip7.value = config_settings.ip_list[6] - app_textbox_ip8.value = config_settings.ip_list[7] - app_textbox_ip9.value = config_settings.ip_list[8] - app_textbox_ip10.value = config_settings.ip_list[9] - app_textbox_ip11.value = config_settings.ip_list[10] - app_textbox_ip12.value = config_settings.ip_list[11] - app_textbox_ip13.value = config_settings.ip_list[12] - app_textbox_ip14.value = config_settings.ip_list[13] - app_textbox_ip15.value = config_settings.ip_list[14] - app_textbox_ip16.value = config_settings.ip_list[15] - config_checkbox_enable_reset() - config_checkbox_enable_shutdown() + config_textbox_save_to.value = current_config.save_to + config_textbox_start.value = current_config.graph_start + config_textbox_end.value = current_config.graph_end + config_textbox_time_offset.value = current_config.datetime_offset + config_textbox_sql_skip.value = current_config.sql_queries_skip + config_textbox_temperature_offset.value = current_config.temperature_offset + config_textbox_network_check.value = current_config.network_timeout_sensor_check + config_textbox_network_details.value = current_config.network_timeout_data + config_checkbox_power_controls.value = current_config.allow_advanced_controls + + graph_textbox_start.value = current_config.graph_start + graph_textbox_end.value = current_config.graph_end + graph_textbox_sql_skip.value = current_config.sql_queries_skip + graph_textbox_temperature_offset.value = current_config.temperature_offset + graph_textbox_refresh_time.value = current_config.live_refresh + + app_textbox_ip1.value = current_config.ip_list[0] + app_textbox_ip2.value = current_config.ip_list[1] + app_textbox_ip3.value = current_config.ip_list[2] + app_textbox_ip4.value = current_config.ip_list[3] + app_textbox_ip5.value = current_config.ip_list[4] + app_textbox_ip6.value = current_config.ip_list[5] + app_textbox_ip7.value = current_config.ip_list[6] + app_textbox_ip8.value = current_config.ip_list[7] + app_textbox_ip9.value = current_config.ip_list[8] + app_textbox_ip10.value = current_config.ip_list[9] + app_textbox_ip11.value = current_config.ip_list[10] + app_textbox_ip12.value = current_config.ip_list[11] + app_textbox_ip13.value = current_config.ip_list[12] + app_textbox_ip14.value = current_config.ip_list[13] + app_textbox_ip15.value = current_config.ip_list[14] + app_textbox_ip16.value = current_config.ip_list[15] + + config_checkbox_enable_advanced() + logger.debug("Configuration Set - OK") except Exception as error: logger.error("Configuration Set - One or More Items Failed - " + str(error)) @@ -523,114 +579,119 @@ def config_button_save_directory(): def config_button_reset_defaults(): + """ Resets all Control Center Configurations to default. """ logger.info("Resetting Configuration to Defaults") - default_settings = app_config.CreateConfigSettings() - set_config(default_settings) + current_config.reset_to_defaults() + set_config() -def config_checkbox_enable_reset(): - if config_checkbox_reset.value == 1: - config_button_reset.enable() - else: - config_button_reset.disable() - - -def config_checkbox_enable_shutdown(): +def config_checkbox_enable_advanced(): + """ Enables disabled buttons in the Control Center application. """ if config_checkbox_power_controls.value == 1: - commands_button_reboot.enable() + config_button_reset.enable() commands_button_shutdown.enable() commands_button_os_Upgrade.enable() + sensor_config_button_update_datetime.enable() sensor_config_button_set_config.enable() else: - commands_button_reboot.disable() + config_button_reset.disable() commands_button_shutdown.disable() commands_button_os_Upgrade.disable() + sensor_config_button_update_datetime.disable() sensor_config_button_set_config.disable() def commands_upgrade_smb(): + """ Sends the upgrade by SMB command to the Sensor Units IP. """ logger.debug("Sensor Upgrade - SMB") - ip_list = check_sensors() + ip_list = get_verified_ip_list() for ip in ip_list: sensor_commands.upgrade_program_smb(ip) - info("Information", "Sensor(s) Upgrading\n" - "Please Wait up to 30 seconds for the Services to restart") + info("Sensors Upgrading SMB", "Please Wait up to 30 seconds for the Services to restart") def commands_upgrade_http(): + """ Sends the upgrade by HTTP command to the Sensor Units IP. """ logger.debug("Sensor Upgrade - HTTP") - ip_list = check_sensors() + ip_list = get_verified_ip_list() for ip in ip_list: sensor_commands.upgrade_program_online(ip) - info("Information", "Sensor(s) Upgrading\n" - "Please Wait up to 30 seconds for the Services to restart") + info("Sensors Upgrading HTTP", "Please Wait up to 30 seconds for the Services to restart") def commands_os_upgrade(): + """ Sends the upgrade Operating System command to the Sensor Units IP. """ logger.debug("Sensor OS Upgrade") - ip_list = check_sensors() + ip_list = get_verified_ip_list() for ip in ip_list: sensor_commands.upgrade_os_linux(ip) - info("Information", "Sensor Operating System Upgrade Started\n" - "Once complete, the Sensor(s) will automatically reboot\n" - "This may take awhile ...") + info("Sensors Operating System Upgrade Started", + "Once complete, the Sensors will automatically reboot\n" + "Sensor should continue to Operate with minor interruptions\n\n" + "This process can take anywhere from 5 Min to 1 Hour") def commands_sensor_reboot(): + """ Sends the reboot system command to the Sensor Units IP. """ logger.debug("Sensor Reboot") - ip_list = check_sensors() + ip_list = get_verified_ip_list() for ip in ip_list: sensor_commands.reboot_sensor(ip) - info("Information", "Sensor(s) Rebooting") + info("Sensors Rebooting", "Allow up to 3 Min to reboot") def commands_sensor_shutdown(): - logger.debug("Sensor Reboot") - ip_list = check_sensors() + """ Sends the shutdown system command to the Sensor Units IP. """ + logger.debug("Sensor Shutdown") + ip_list = get_verified_ip_list() for ip in ip_list: sensor_commands.shutdown_sensor(ip) - info("Information", "Sensor(s) Shutting Down") + info("Sensors Shutting Down", "Allow up to 15 seconds to fully shutdown") def commands_restart_services(): + """ Sends the restart services command to the Sensor Units IP. """ logger.info("Sensor(s) Services Restarting - Please allow up to 20 Seconds to restart") - ip_list = check_sensors() + ip_list = get_verified_ip_list() for ip in ip_list: sensor_commands.restart_services(ip) - info("Information", "Sensor(s) Programs Restarting\nPlease allow up to 20 Seconds to restart") + info("Sensors Services Restarting", "Please allow up to 20 Seconds to restart") def commands_hostname_change(): + """ Sends the host name change command to the Sensor Units IP, along with the new host name. """ logger.debug("Change Sensor Hostname") - ip_list = check_sensors() + ip_list = get_verified_ip_list() for ip in ip_list: sensor_commands.set_hostname(ip) def commands_datetime_update(): + """ Sends the Date & Time update command to the Sensor Units IP, along with the computers Date & Time. """ logger.debug("Updating Sensors DateTime") - ip_list = check_sensors() + ip_list = get_verified_ip_list() for ip in ip_list: sensor_commands.set_datetime(ip) - info("DateTime Set", "Sensors Date & Time Synchronized with local Computer's") + info("Sensors DateTime Set", "Sensors Date & Time Synchronized with local Computer's") def sensor_config_enable_recording(): + """ Enables or disables the timing Sensor Configuration Window text boxes. """ if sensor_config_checkbox_db_record.value: sensor_config_textbox_interval.enable() sensor_config_textbox_trigger.enable() @@ -640,6 +701,7 @@ def sensor_config_enable_recording(): def sensor_config_enable_custom(): + """ Enables or disables the custom Sensor Configuration Window text boxes. """ if sensor_config_checkbox_custom.value: sensor_config_textbox_custom_acc.enable() sensor_config_textbox_custom_mag.enable() @@ -651,8 +713,9 @@ def sensor_config_enable_custom(): def sensor_config_set(): + """ Sends the update configuration command to the Sensor Units IP, along with the new configuration. """ logger.debug("Setting Sensor Config") - ip_list = check_sensors() + ip_list = get_verified_ip_list() config_settings_str = "," + str(sensor_config_checkbox_db_record.value) + "," + \ str(sensor_config_textbox_interval.value) + "," + \ str(sensor_config_textbox_trigger.value) + "," + \ @@ -664,76 +727,142 @@ def sensor_config_set(): for ip in ip_list: sensor_commands.set_sensor_config(ip, config_settings_str) - info("Information", "Sensor(s) Configuration Set") + info("Sensors Configuration Set", "Configurations Set") -def graph_radio_selection(): - if graph_radio_sensor_type.get() == "Interval": +def _graph_radio_selection(): + """ Enables or disables the Graph Window selections, based on graph type selected. """ + _graph_enable_all_checkboxes() + if graph_radio_sensor_type.get() == "Interval SQL": graph_checkbox_acc.disable() graph_checkbox_mag.disable() graph_checkbox_gyro.disable() + graph_button_live.disable() + graph_textbox_refresh_time.disable() + graph_checkbox_cpu_temp.enable() + graph_textbox_temperature_offset.enable() graph_checkbox_temperature.enable() graph_checkbox_pressure.enable() graph_checkbox_humidity.enable() graph_checkbox_lumen.enable() graph_checkbox_colour.enable() graph_checkbox_up_time.enable() - - if graph_radio_sensor_type.get() == "Trigger": + graph_textbox_start.enable() + graph_textbox_end.enable() + graph_textbox_sql_skip.enable() + graph_button_database.enable() + + if graph_radio_sensor_type.get() == "Trigger SQL": + graph_textbox_sql_skip.disable() + graph_textbox_temperature_offset.disable() + graph_checkbox_cpu_temp.disable() graph_checkbox_temperature.disable() graph_checkbox_pressure.disable() graph_checkbox_humidity.disable() graph_checkbox_lumen.disable() graph_checkbox_colour.disable() graph_checkbox_up_time.disable() + graph_button_live.disable() + graph_textbox_refresh_time.disable() graph_checkbox_acc.enable() graph_checkbox_mag.enable() graph_checkbox_gyro.enable() + graph_textbox_start.enable() + graph_textbox_end.enable() + graph_textbox_sql_skip.disable() + graph_button_database.enable() + + if graph_radio_sensor_type.get() == "Live": + graph_button_database.disable() + graph_textbox_sql_skip.disable() + graph_textbox_start.disable() + graph_textbox_end.disable() + graph_textbox_temperature_offset.enable() + graph_textbox_refresh_time.enable() + + graph_checkbox_up_time.enable() + graph_checkbox_up_time.value = 0 + graph_checkbox_cpu_temp.enable() + graph_checkbox_cpu_temp.value = 0 + graph_checkbox_temperature.enable() + graph_checkbox_temperature.value = 0 + graph_checkbox_pressure.enable() + graph_checkbox_pressure.value = 0 + graph_checkbox_humidity.enable() + graph_checkbox_humidity.value = 0 + graph_checkbox_lumen.enable() + graph_checkbox_lumen.value = 0 + graph_checkbox_colour.disable() + graph_checkbox_colour.value = 0 + graph_checkbox_acc.disable() + graph_checkbox_acc.value = 0 + graph_checkbox_mag.disable() + graph_checkbox_mag.value = 0 + graph_checkbox_gyro.disable() + graph_checkbox_gyro.value = 0 -def graph_button_interval(): - new_interval_graph = app_graph.CreateGraphData() - new_interval_graph.db_location = filedialog.askopenfilename() - if graph_radio_sensor_type.get() == "Trigger": - new_interval_graph.graph_table = "TriggerData" + graph_button_live.enable() - config_settings_check = app_config.CreateConfigSettings() - config_settings_check.save_to = config_textbox_save_to.value - config_settings_check.graph_start = graph_textbox_start.value - config_settings_check.graph_end = graph_textbox_end.value - config_settings_check.time_offset = config_textbox_time_offset.value - config_settings_check.sql_queries_skip = graph_textbox_sql_skip.value - config_settings_check.temperature_offset = graph_textbox_temperature_offset.value - config_settings_good = app_config.check_config(config_settings_check) +def graph_plotly_button(): + """ Create Plotly offline HTML Graph, based on user selections in the Graph Window. """ + new_graph_data = app_graph.CreateGraphData() + new_graph_data.db_location = filedialog.askopenfilename() - graph_textbox_start.value = str(config_settings_good.graph_start) - graph_textbox_end.value = str(config_settings_good.graph_end) - graph_textbox_sql_skip.value = str(config_settings_good.sql_queries_skip) - graph_textbox_temperature_offset.value = str(config_settings_good.temperature_offset) + current_config.graph_start = graph_textbox_start.value + current_config.graph_end = graph_textbox_end.value + current_config.sql_queries_skip = graph_textbox_sql_skip.value + current_config.temperature_offset = graph_textbox_temperature_offset.value - new_interval_graph.save_file_to = config_settings_good.save_to - new_interval_graph.graph_start = config_settings_good.graph_start - new_interval_graph.graph_end = config_settings_good.graph_end - new_interval_graph.time_offset = config_settings_good.time_offset - new_interval_graph.skip_sql = config_settings_good.sql_queries_skip - new_interval_graph.temperature_offset = config_settings_good.temperature_offset - # new_interval_graph.graph_type = "" - new_interval_graph.graph_columns = get_graph_column_checkboxes() - # new_interval_graph.get_sql_entries = ReplaceMe + app_config.check_config(current_config) + set_config() - app_graph.start_graph(new_interval_graph) + new_graph_data.save_file_to = current_config.save_to + new_graph_data.graph_start = current_config.graph_start + new_graph_data.graph_end = current_config.graph_end + new_graph_data.time_offset = current_config.datetime_offset + new_graph_data.skip_sql = current_config.sql_queries_skip + new_graph_data.temperature_offset = current_config.temperature_offset + new_graph_data.graph_columns = _graph_get_column_checkboxes() + if graph_radio_sensor_type.get() == "Interval SQL": + app_graph.start_graph_interval(new_graph_data) + elif graph_radio_sensor_type.get() == "Trigger SQL": + app_graph.start_graph_trigger(new_graph_data) -def get_graph_column_checkboxes(): + +def graph_live_button(): + pyplot.close() + try: + graph_checkbox = _graph_get_column_checkboxes()[3] + ip_list = get_verified_ip_list() + + current_config.live_refresh = graph_textbox_refresh_time.value + current_config.temperature_offset = graph_textbox_temperature_offset.value + app_config.check_config(current_config) + set_config() + + app_graph.CreateLiveGraph(graph_checkbox, ip_list[0], current_config) + except Exception as error: + logger.warning("No sensors selected in the main window - " + str(error)) + warn("Select Sensor", "Please Select a Sensor IP from the Main window\n" + "& Sensor Type from the Graph window") + + +def _graph_get_column_checkboxes(): + """ Returns selected SQL Columns from the Graph Window, depending on the Data Source Selected. """ column_checkboxes = ["DateTime", "SensorName", "IP"] - if graph_radio_sensor_type.get() == "Interval": + + data_source_radio = graph_radio_sensor_type.get() + if data_source_radio == "Interval SQL" or data_source_radio == "Live": if graph_checkbox_up_time.value: column_checkboxes.append("SensorUpTime") - if graph_checkbox_temperature.value: + if graph_checkbox_cpu_temp.value: column_checkboxes.append("SystemTemp") + if graph_checkbox_temperature.value: column_checkboxes.append("EnvironmentTemp") if graph_checkbox_pressure.value: column_checkboxes.append("Pressure") @@ -745,7 +874,7 @@ def get_graph_column_checkboxes(): column_checkboxes.append("Red") column_checkboxes.append("Green") column_checkboxes.append("Blue") - elif graph_radio_sensor_type.get() == "Trigger": + if data_source_radio == "Trigger SQL" or data_source_radio == "Live": if graph_checkbox_acc.value: column_checkboxes.append("Acc_X") column_checkboxes.append("Acc_Y") @@ -763,10 +892,158 @@ def get_graph_column_checkboxes(): return column_checkboxes -# GUI Window Configurations +def _graph_enable_all_checkboxes(): + graph_checkbox_up_time.enable() + graph_checkbox_up_time.value = 0 + graph_checkbox_cpu_temp.enable() + graph_checkbox_cpu_temp.value = 0 + graph_checkbox_temperature.enable() + graph_checkbox_temperature.value = 0 + graph_checkbox_pressure.enable() + graph_checkbox_pressure.value = 0 + graph_checkbox_humidity.enable() + graph_checkbox_humidity.value = 0 + graph_checkbox_lumen.enable() + graph_checkbox_lumen.value = 0 + graph_checkbox_colour.enable() + graph_checkbox_colour.value = 0 + graph_checkbox_acc.enable() + graph_checkbox_acc.value = 0 + graph_checkbox_mag.enable() + graph_checkbox_mag.value = 0 + graph_checkbox_gyro.enable() + graph_checkbox_gyro.value = 0 + + +def _graph_disable_other_checkboxes(var_checkbox): + if graph_radio_sensor_type.value == "Live": + if var_checkbox is "Uptime": + pass + else: + graph_checkbox_up_time.disable() + graph_checkbox_up_time.value = 0 + if var_checkbox is "Temperature": + pass + else: + graph_checkbox_temperature.disable() + graph_checkbox_temperature.value = 0 + if var_checkbox is "CPUTemperature": + pass + else: + graph_checkbox_cpu_temp.disable() + graph_checkbox_cpu_temp.value = 0 + if var_checkbox is "Pressure": + pass + else: + graph_checkbox_pressure.disable() + graph_checkbox_pressure.value = 0 + if var_checkbox is "Humidity": + pass + else: + graph_checkbox_humidity.disable() + graph_checkbox_humidity.value = 0 + if var_checkbox is "Lumen": + pass + else: + graph_checkbox_lumen.disable() + graph_checkbox_lumen.value = 0 + # if var_checkbox is "RGB": + # pass + # else: + # graph_checkbox_colour.disable() + # graph_checkbox_colour.value = 0 + # if var_checkbox is "Accelerometer": + # pass + # else: + # graph_checkbox_acc.disable() + # graph_checkbox_acc.value = 0 + # if var_checkbox is "Magnetometer": + # pass + # else: + # graph_checkbox_mag.disable() + # graph_checkbox_mag.value = 0 + # if var_checkbox is "Gyroscopic": + # pass + # else: + # graph_checkbox_gyro.disable() + # graph_checkbox_gyro.value = 0 + + if var_checkbox is "Uptime": + if graph_checkbox_up_time.value == 0: + _graph_enable_all_checkboxes() + else: + graph_checkbox_up_time.enable() + graph_checkbox_up_time.value = 1 + elif var_checkbox is "Temperature": + if graph_checkbox_temperature.value == 0: + _graph_enable_all_checkboxes() + else: + graph_checkbox_temperature.enable() + graph_checkbox_temperature.value = 1 + elif var_checkbox is "CPUTemperature": + if graph_checkbox_cpu_temp.value == 0: + _graph_enable_all_checkboxes() + else: + graph_checkbox_cpu_temp.enable() + graph_checkbox_cpu_temp.value = 1 + elif var_checkbox is "Pressure": + if graph_checkbox_pressure.value == 0: + _graph_enable_all_checkboxes() + else: + graph_checkbox_pressure.enable() + graph_checkbox_pressure.value = 1 + elif var_checkbox is "Humidity": + if graph_checkbox_humidity.value == 0: + _graph_enable_all_checkboxes() + else: + graph_checkbox_humidity.enable() + graph_checkbox_humidity.value = 1 + elif var_checkbox is "Lumen": + if graph_checkbox_lumen.value == 0: + _graph_enable_all_checkboxes() + else: + graph_checkbox_lumen.enable() + graph_checkbox_lumen.value = 1 + # elif var_checkbox is "RGB": + # if graph_checkbox_colour.value == 0: + # _graph_enable_all_checkboxes() + # else: + # graph_checkbox_colour.enable() + # graph_checkbox_colour.value = 1 + # elif var_checkbox is "Accelerometer": + # if graph_checkbox_acc.value == 0: + # _graph_enable_all_checkboxes() + # else: + # graph_checkbox_acc.enable() + # graph_checkbox_acc.value = 1 + # elif var_checkbox is "Magnetometer": + # if graph_checkbox_mag.value == 0: + # _graph_enable_all_checkboxes() + # else: + # graph_checkbox_mag.enable() + # graph_checkbox_mag.value = 1 + # elif var_checkbox is "Gyroscopic": + # if graph_checkbox_gyro.value == 0: + # _graph_enable_all_checkboxes() + # else: + # graph_checkbox_gyro.enable() + # graph_checkbox_gyro.value = 1 + + graph_checkbox_colour.disable() + graph_checkbox_colour.value = 0 + graph_checkbox_acc.disable() + graph_checkbox_acc.value = 0 + graph_checkbox_mag.disable() + graph_checkbox_mag.value = 0 + graph_checkbox_gyro.disable() + graph_checkbox_gyro.value = 0 + + +# GUI Window Setup app = App(title="KootNet Sensors - PC Control Center", width=405, height=295, + layout="grid") window_app_about = Window(app, @@ -777,19 +1054,12 @@ def get_graph_column_checkboxes(): visible=False) window_config = Window(app, - title="Configuration", + title="Control Center Configuration", width=580, height=300, layout="grid", visible=False) -window_graph_interval = Window(app, - title="Plotly Graphing", - width=270, - height=410, - layout="grid", - visible=False) - window_sensor_commands = Window(app, title="Sensor Commands", width=290, @@ -798,35 +1068,49 @@ def get_graph_column_checkboxes(): visible=False) window_sensor_config = Window(app, - title="Update Sensors Configuration", + title="Sensors Configuration Updater", width=340, height=265, layout="grid", visible=False) +window_sensor_reports = Window(app, + title="Sensor Reports", + width=475, + height=100, + layout="grid", + visible=False) + +window_graph = Window(app, + title="Graphing", + width=275, + height=505, + layout="grid", + visible=False) + app_menubar = MenuBar(app, toplevel=[["File"], - ["Download"], + ["Sensors"], ["Graphing"], ["Help"]], - options=[[["Control Center Configuration", - app_menu_open_config], - ["Open Logs", - app_menu_open_log], - ["Save IP List", + options=[[["Open Logs", + app_menu_open_logs], + ["Save ALL Configurations & IP's", config_button_save], - ["Sensors Configuration", - app_menu_open_sensor_config], - ["Sensor Commands", - app_menu_open_commands]], - [["Download Interval Database(s)", - app_menu_download_interval_db], - ["Download Trigger Database(s)", - app_menu_download_trigger_db]], - [["Plotly Offline Graphing", - app_menu_open_graph]], + ["Control Center Configuration", + window_config.show], + ["Quit", + _app_exit]], + [["Send Commands", + window_sensor_commands.show], + ["Update Configurations", + window_sensor_config.show], + ["Create Reports", + window_sensor_reports.show]], + [["Open Graph Window", + window_graph.show]], [["KootNet Sensors - About", - app_menu_open_about], + window_app_about.show], ["KootNet Sensors - Website", app_menu_open_website], ["Sensor Units - DIY", @@ -834,23 +1118,23 @@ def get_graph_column_checkboxes(): ["Sensor Units - Help", app_menu_open_sensor_help], ["PC Control Center - Help *WIP", - app_menu_open_about]]]) + window_app_about.show]]]) app_button_check_sensor = PushButton(app, text="Check Sensors\nStatus", - command=check_sensors, + command=get_verified_ip_list, grid=[1, 15, 2, 1], align="left") app_button_sensor_detail = PushButton(app, - text="View Sensors\nSystem Report", - command=app_sensor_system_report, + text="Download Sensor\nInterval Databases", + command=app_menu_download_interval_db, grid=[2, 15, 2, 1], align="right") app_button_sensor_config = PushButton(app, - text="View Sensors\nConfiguration Report", - command=app_sensor_config_report, + text="Download Sensor\nTrigger Databases", + command=app_menu_download_trigger_db, grid=[4, 15], align="right") @@ -1048,7 +1332,7 @@ def get_graph_column_checkboxes(): # About Window Section about_text1 = Text(window_app_about, - text=app_version, + text=current_config.app_version, grid=[1, 1], align="right") @@ -1067,18 +1351,11 @@ def get_graph_column_checkboxes(): grid=[1, 1], align="right") -config_checkbox_power_controls = \ - CheckBox(window_config, - text="Enable Advanced\nSensor Commands &\nConfiguration Options", - command=config_checkbox_enable_shutdown, - grid=[1, 1], - align="top") - -config_checkbox_reset = CheckBox(window_config, - text="Enable Configuration Reset button", - command=config_checkbox_enable_reset, - grid=[1, 2], - align="top") +config_checkbox_power_controls = CheckBox(window_config, + text="Enable Advanced\nSensor Commands &\nConfiguration Options", + command=config_checkbox_enable_advanced, + grid=[1, 1], + align="top") config_button_save_apply = PushButton(window_config, text="Save &\nApply", @@ -1217,150 +1494,247 @@ def get_graph_column_checkboxes(): grid=[2, 10], align="top") +# Sensor Reports Window Section +reports_text_select = Text(window_sensor_reports, + text="Check Sensor IPs from The Main Window", + grid=[1, 1, 3, 1], + color='#CB0000', + align="top") + +reports_text1 = Text(window_sensor_reports, + text="Live Readings Report |", + color='blue', + grid=[1, 6], + align="top") + +reports_button_check_sensor = PushButton(window_sensor_reports, + text="Create", + command=app_sensor_readings_report, + grid=[1, 7], + align="top") + +reports_text2 = Text(window_sensor_reports, + text="| System Report |", + color='blue', + grid=[2, 6], + align="top") + +reports_button_sensor_detail = PushButton(window_sensor_reports, + text="Create", + command=app_sensor_system_report, + grid=[2, 7], + align="top") + +reports_text3 = Text(window_sensor_reports, + text="| Configuration Report", + color='blue', + grid=[3, 6], + align="top") + +reports_button_sensor_config = PushButton(window_sensor_reports, + text="Create", + command=app_sensor_config_report, + grid=[3, 7], + align="top") + # Graph Window Section -graph_text_start = Text(window_graph_interval, +graph_text_sensor_type_name = Text(window_graph, + text="Data Source", + color='blue', + grid=[1, 1, 2, 1], + align="top") + +graph_radio_sensor_type = ButtonGroup(window_graph, + options=["Live", "Interval SQL", "Trigger SQL"], + horizontal="True", + command=_graph_radio_selection, + grid=[1, 2, 2, 1], + align="top") + +graph_text_space1 = Text(window_graph, + text=" ", + grid=[1, 3], + align="right") + +graph_text_start = Text(window_graph, text="Start DateTime: ", color='green', - grid=[1, 2], + grid=[1, 6], align="left") -graph_textbox_start = TextBox(window_graph_interval, +graph_textbox_start = TextBox(window_graph, text="", width=20, - grid=[2, 2], + grid=[2, 6], align="left") -graph_text_end = Text(window_graph_interval, +graph_text_end = Text(window_graph, text="End DateTime:", color='green', - grid=[1, 3], + grid=[1, 7], align="left") -graph_textbox_end = TextBox(window_graph_interval, +graph_textbox_end = TextBox(window_graph, text="", width=20, - grid=[2, 3], + grid=[2, 7], align="left") -graph_text_sql_skip = Text(window_graph_interval, +graph_text_sql_skip = Text(window_graph, text="Add row every:", color='green', - grid=[1, 4], + grid=[1, 8], align="left") -graph_textbox_sql_skip = TextBox(window_graph_interval, +graph_textbox_sql_skip = TextBox(window_graph, text="", width=10, - grid=[2, 4], + grid=[2, 8], align="left") -graph_text_sql_skip2 = Text(window_graph_interval, +graph_text_sql_skip2 = Text(window_graph, text="rows ", color='green', - grid=[2, 4], + grid=[2, 8], align="right") -graph_text_temperature_offset = Text(window_graph_interval, +graph_text_temperature_offset = Text(window_graph, text="Environmental:", color='green', - grid=[1, 5], + grid=[1, 9], align="left") -graph_textbox_temperature_offset = TextBox(window_graph_interval, +graph_textbox_temperature_offset = TextBox(window_graph, text="", - width=4, - grid=[2, 5], + width=5, + grid=[2, 9], align="left") -graph_text_temperature_offset2 = Text(window_graph_interval, +graph_text_temperature_offset2 = Text(window_graph, text="Temp Offset", color='green', - grid=[2, 5], + grid=[2, 9], align="right") -graph_text_sensor_type_space = Text(window_graph_interval, - text=" ", - grid=[1, 6], - align="right") +graph_text_refresh_time = Text(window_graph, + text="Live refresh (Sec):", + color='green', + grid=[1, 10], + align="left") -graph_text_sensor_type_name = Text(window_graph_interval, - text="Database Type", - color='blue', - grid=[1, 7, 2, 1], - align="top") +graph_textbox_refresh_time = TextBox(window_graph, + text="2", + width=5, + grid=[2, 10], + align="left") -graph_radio_sensor_type = ButtonGroup(window_graph_interval, - options=["Interval", "Trigger"], - horizontal="True", - command=graph_radio_selection, - grid=[1, 8, 2, 1], - align="top") +graph_text_space2 = Text(window_graph, + text=" ", + grid=[1, 11], + align="right") -graph_text_column_selection = Text(window_graph_interval, +graph_text_column_selection = Text(window_graph, text="Interval Sensors", color='blue', - grid=[1, 10, 2, 1], + grid=[1, 15, 2, 1], align="top") -graph_checkbox_up_time = CheckBox(window_graph_interval, +graph_checkbox_up_time = CheckBox(window_graph, text="System Uptime", - grid=[1, 11], + command=_graph_disable_other_checkboxes, + args=["Uptime"], + grid=[1, 16], align="left") -graph_checkbox_temperature = CheckBox(window_graph_interval, - text="Temperature", - grid=[1, 12], +graph_checkbox_cpu_temp = CheckBox(window_graph, + text="CPU Temperature", + command=_graph_disable_other_checkboxes, + args=["CPUTemperature"], + grid=[1, 17], + align="left") + +graph_checkbox_temperature = CheckBox(window_graph, + text="Env Temperature", + command=_graph_disable_other_checkboxes, + args=["Temperature"], + grid=[1, 18], align="left") -graph_checkbox_pressure = CheckBox(window_graph_interval, +graph_checkbox_pressure = CheckBox(window_graph, text="Pressure", - grid=[1, 13], + command=_graph_disable_other_checkboxes, + args=["Pressure"], + grid=[1, 19], align="left") -graph_checkbox_humidity = CheckBox(window_graph_interval, +graph_checkbox_humidity = CheckBox(window_graph, text="Humidity", - grid=[2, 11], + command=_graph_disable_other_checkboxes, + args=["Humidity"], + grid=[2, 16], align="left") -graph_checkbox_lumen = CheckBox(window_graph_interval, +graph_checkbox_lumen = CheckBox(window_graph, text="Lumen", - grid=[2, 12], + command=_graph_disable_other_checkboxes, + args=["Lumen"], + grid=[2, 17], align="left") -graph_checkbox_colour = CheckBox(window_graph_interval, +graph_checkbox_colour = CheckBox(window_graph, text="Colour RGB", - grid=[2, 13], + command=_graph_disable_other_checkboxes, + args=["RGB"], + grid=[2, 18], align="left") -graph_text_column_selection2 = Text(window_graph_interval, +graph_text_column_selection2 = Text(window_graph, text="Trigger Sensors", color='blue', - grid=[1, 14, 2, 1], + grid=[1, 24, 2, 1], align="bottom") -graph_checkbox_acc = CheckBox(window_graph_interval, +graph_checkbox_acc = CheckBox(window_graph, text="Accelerometer XYZ", - grid=[1, 15], + command=_graph_disable_other_checkboxes, + args=["Accelerometer"], + grid=[1, 25], align="left") -graph_checkbox_mag = CheckBox(window_graph_interval, +graph_checkbox_mag = CheckBox(window_graph, text="Magnetometer XYZ", - grid=[2, 15], + command=_graph_disable_other_checkboxes, + args=["Magnetometer"], + grid=[2, 25], align="left") -graph_checkbox_gyro = CheckBox(window_graph_interval, +graph_checkbox_gyro = CheckBox(window_graph, text="Gyroscopic XYZ", - grid=[1, 16], + command=_graph_disable_other_checkboxes, + args=["Gyroscopic"], + grid=[1, 26], align="left") -graph_button_sensors = PushButton(window_graph_interval, - text="Open Database &\nGraph Sensors", - command=graph_button_interval, - grid=[1, 18, 2, 1], - align="bottom") +graph_text_space3 = Text(window_graph, + text=" ", + grid=[1, 35], + align="right") + +graph_button_database = PushButton(window_graph, + text="Open & Graph\nDatabase", + command=graph_plotly_button, + grid=[1, 36, 2, 1], + align="left") + +graph_button_live = PushButton(window_graph, + text="Start Live Graph", + command=graph_live_button, + grid=[2, 36], + align="left") +# Sensor Commands Window commands_text_select = Text(window_sensor_commands, - text="Select Sensors from the Main Window", + text="Check Sensor IPs from the Main Window", grid=[1, 1, 3, 1], color='#CB0000', align="left") @@ -1433,7 +1807,7 @@ def get_graph_column_checkboxes(): # Update Sensor Configuration Section sensor_config_text_select = Text(window_sensor_config, - text="Select Sensors from the Main Window", + text="Check Sensor IPs from the Main Window", grid=[1, 1, 3, 1], color='#CB0000', align="left") @@ -1516,40 +1890,8 @@ def get_graph_column_checkboxes(): grid=[2, 14], align="right") -# Add extra tk options to windows -app.tk.iconbitmap(default="additional_files/icon.ico") -app.tk.resizable(False, False) -window_graph_interval.tk.resizable(False, False) -window_sensor_commands.tk.resizable(False, False) -window_sensor_config.tk.resizable(False, False) -window_app_about.tk.resizable(False, False) -window_config.tk.resizable(False, False) - -# Change other options before loading app -app_checkbox_all_column1.value = 0 -app_checkbox_all_column2.value = 0 -app_check_all_ip_checkboxes(1) -app_check_all_ip_checkboxes(2) -commands_button_os_Upgrade.disable() -graph_checkbox_up_time.value = 1 -graph_checkbox_temperature.value = 1 -graph_checkbox_pressure.value = 0 -graph_checkbox_humidity.value = 0 -graph_checkbox_lumen.value = 0 -graph_checkbox_colour.value = 0 -graph_radio_selection() -sensor_config_checkbox_db_record.value = 1 -sensor_config_checkbox_custom.value = 0 -sensor_config_enable_recording() -sensor_config_enable_custom() -sensor_config_button_set_config.disable() - -set_about_text() -about_textbox.disable() -config_textbox_save_to.disable() - -loaded_config_settings = app_config.load_file() -set_config(loaded_config_settings) +# Set custom app configurations +_app_custom_configurations() # Start the App logger.info('KootNet Sensors - PC Control Center - Started') diff --git a/miscTest.py b/miscTest.py new file mode 100644 index 0000000..bd1f702 --- /dev/null +++ b/miscTest.py @@ -0,0 +1,48 @@ +class Test1: + def __init__(self): + self.var1 = "test1: var1" + self.var2 = "test1: var2" + + +class Test2: + def __init__(self): + self.var1 = "test2: var1" + self.var2 = "test2: var2" + + +class Test3: + def __init__(self): + self.var1 = "test3: var1" + self.var2 = "test3: var2" + + +def print_test(test): + print(test.var1) + print(test.var2) + + +def mod_var1(test): + test.var1 = "Changed" + + +def mod_var2(test): + test.var2 = "Changed2" + + +test_1 = Test1() +test_2 = Test2() +test_3 = Test3() + +print_test(test_1) +print_test(test_2) +print_test(test_3) + +mod_var1(test_1) +print_test(test_1) +print_test(test_2) +print_test(test_3) +mod_var2(test_3) + +print_test(test_1) +print_test(test_2) +print_test(test_3) diff --git a/sensor_commands.py b/sensor_commands.py index ea50168..2b0c924 100644 --- a/sensor_commands.py +++ b/sensor_commands.py @@ -18,21 +18,22 @@ """ import socket import pickle -import os -import sys import re +import os import logging from logging.handlers import RotatingFileHandler from tkinter import simpledialog from datetime import datetime from urllib.request import urlopen +script_directory = str(os.path.dirname(os.path.realpath(__file__))) + logger = logging.getLogger(__name__) logger.setLevel(logging.INFO) formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(funcName)s: %(message)s', '%Y-%m-%d %H:%M:%S') -file_handler = RotatingFileHandler('logs/Sensor_Commands_log.txt', maxBytes=256000, backupCount=5) +file_handler = RotatingFileHandler(script_directory + '/logs/Sensor_Commands_log.txt', maxBytes=256000, backupCount=5) file_handler.setFormatter(formatter) stream_handler = logging.StreamHandler() stream_handler.setFormatter(formatter) @@ -40,11 +41,8 @@ logger.addHandler(file_handler) logger.addHandler(stream_handler) -app_location_directory = str(os.path.dirname(sys.argv[0])) + "/" -config_file = app_location_directory + "config.txt" - -def check_online_status(ip, net_timeout): +def check_sensor_status(ip, net_timeout): """ Socket connection to sensor IP. Return sensor status. """ socket.setdefaulttimeout(net_timeout) sock_g = socket.socket(socket.AF_INET, socket.SOCK_STREAM) @@ -59,10 +57,11 @@ def check_online_status(ip, net_timeout): sensor_status = "Offline" sock_g.close() + return sensor_status -def get_system_info(ip, net_timeout): +def get_sensor_system(ip, net_timeout): """ Socket connection to sensor IP. Return sensor system information. """ socket.setdefaulttimeout(net_timeout) sock_g = socket.socket(socket.AF_INET, socket.SOCK_STREAM) @@ -82,6 +81,174 @@ def get_system_info(ip, net_timeout): return final_data +def get_sensor_readings(ip, net_timeout): + """ + Socket connection to sensor IP. Return sensor's readings. + + Returned data is a list of 2 comma separated strings. + + The first string is the Interval readings, the second, Trigger readings. + """ + socket.setdefaulttimeout(net_timeout) + sock_g = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + + try: + sock_g.connect((ip, 10065)) + sock_g.send(b'GetSensorReadings') + var_data = pickle.loads(sock_g.recv(4096)) + sock_g.close() + logger.debug("Getting Sensor Readings from " + str(ip) + " - OK") + except Exception as error: + var_data = ["Readings Failed on " + ip, str(error), "Readings Failed on " + ip, str(error)] + logger.warning("Getting Sensor Readings from " + ip + " - Failed: " + str(error)) + + return var_data + + +def get_sensor_hostname(ip, net_timeout): + """ Socket connection to sensor IP. Return sensor's hostname. """ + socket.setdefaulttimeout(net_timeout) + sock_g = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + + try: + sock_g.connect((ip, 10065)) + sock_g.send(b'GetHostName') + var_data = pickle.loads(sock_g.recv(4096)) + sock_g.close() + logger.debug("Getting Sensor Readings from " + str(ip) + " - OK") + except Exception as error: + var_data = 0 + logger.warning("Getting Sensor Readings from " + ip + " - Failed: " + str(error)) + + return var_data + + +def get_sensor_uptime(ip, net_timeout): + """ Socket connection to sensor IP. Return sensor's System Uptime. """ + socket.setdefaulttimeout(net_timeout) + sock_g = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + + try: + sock_g.connect((ip, 10065)) + sock_g.send(b'GetSystemUptime') + var_data = pickle.loads(sock_g.recv(4096)) + sock_g.close() + logger.debug("Getting Sensor Readings from " + str(ip) + " - OK") + except Exception as error: + var_data = 0 + logger.warning("Getting Sensor Readings from " + ip + " - Failed: " + str(error)) + + return var_data + + +def get_sensor_cpu_temperature(ip, net_timeout): + """ Socket connection to sensor IP. Return sensor's System CPU Temperature. """ + socket.setdefaulttimeout(net_timeout) + sock_g = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + + try: + sock_g.connect((ip, 10065)) + sock_g.send(b'GetCPUTemperature') + var_data = pickle.loads(sock_g.recv(4096)) + sock_g.close() + logger.debug("Getting Sensor Readings from " + str(ip) + " - OK") + except Exception as error: + var_data = 0 + logger.warning("Getting Sensor Readings from " + ip + " - Failed: " + str(error)) + + return var_data + + +def get_sensor_temperature(ip, net_timeout): + """ Socket connection to sensor IP. Return sensor's temperature. """ + socket.setdefaulttimeout(net_timeout) + sock_g = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + + try: + sock_g.connect((ip, 10065)) + sock_g.send(b'GetEnvTemperature') + var_data = pickle.loads(sock_g.recv(4096)) + sock_g.close() + logger.debug("Getting Sensor Readings from " + str(ip) + " - OK") + except Exception as error: + var_data = 0 + logger.warning("Getting Sensor Readings from " + ip + " - Failed: " + str(error)) + + return var_data + + +def get_sensor_pressure(ip, net_timeout): + """ Socket connection to sensor IP. Return sensor's Pressure in hPa. """ + socket.setdefaulttimeout(net_timeout) + sock_g = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + + try: + sock_g.connect((ip, 10065)) + sock_g.send(b'GetPressure') + var_data = pickle.loads(sock_g.recv(4096)) + sock_g.close() + logger.debug("Getting Sensor Readings from " + str(ip) + " - OK") + except Exception as error: + var_data = 0 + logger.warning("Getting Sensor Readings from " + ip + " - Failed: " + str(error)) + + return var_data + + +def get_sensor_humidity(ip, net_timeout): + """ Socket connection to sensor IP. Return sensor's Humidity in %RH. """ + socket.setdefaulttimeout(net_timeout) + sock_g = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + + try: + sock_g.connect((ip, 10065)) + sock_g.send(b'GetHumidity') + var_data = pickle.loads(sock_g.recv(4096)) + sock_g.close() + logger.debug("Getting Sensor Readings from " + str(ip) + " - OK") + except Exception as error: + var_data = 0 + logger.warning("Getting Sensor Readings from " + ip + " - Failed: " + str(error)) + + return var_data + + +def get_sensor_lumen(ip, net_timeout): + """ Socket connection to sensor IP. Return sensor's Lumen. """ + socket.setdefaulttimeout(net_timeout) + sock_g = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + + try: + sock_g.connect((ip, 10065)) + sock_g.send(b'GetLumen') + var_data = pickle.loads(sock_g.recv(4096)) + sock_g.close() + logger.debug("Getting Sensor Readings from " + str(ip) + " - OK") + except Exception as error: + var_data = 0 + logger.warning("Getting Sensor Readings from " + ip + " - Failed: " + str(error)) + + return var_data + + +def get_sensor_rgb(ip, net_timeout): + """ Socket connection to sensor IP. Return sensor's Red, Green, Blue readings. """ + socket.setdefaulttimeout(net_timeout) + sock_g = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + + try: + sock_g.connect((ip, 10065)) + sock_g.send(b'GetRGB') + var_data = pickle.loads(sock_g.recv(4096)) + sock_g.close() + logger.debug("Getting Sensor Readings from " + str(ip) + " - OK") + except Exception as error: + var_data = 0 + logger.warning("Getting Sensor Readings from " + ip + " - Failed: " + str(error)) + + return var_data + + def get_sensor_config(ip, net_timeout): """ Socket connection to sensor IP. Return sensor configuration. """ socket.setdefaulttimeout(net_timeout) @@ -98,7 +265,7 @@ def get_sensor_config(ip, net_timeout): logger.warning("Configuration Received from " + ip + " - Failed: " + str(error)) sock_g.close() - sensor_system = get_system_info(ip, net_timeout) + sensor_system = get_sensor_system(ip, net_timeout) final_sensor_config = [str(sensor_system[0]), str(sensor_system[1]),