No net on this one?
import serial
import json
from datetime import datetime
from systemd.daemon import notify, Notification
import tkinter as tk
#constants
BAUD_RATE = 500000
RAW_INPUT_STRING_SLICE_START = 12
INITIAL_DOSER_STRING = "pH 0.00 EC 0.00 temp 0.00"
#UART port
ser = serial.Serial('/dev/ttyACM2', BAUD_RATE, timeout=5) #open the serial port
#figure out if the object is a valid json
def is_json(myjson):
try:
#leverage json.loads to tell us what's wrong with the json, if anything
json_object = json.loads(myjson)
except ValueError as e:
#useful error report
#print('ERROR is_json() :',e)
print(e)
return False
return True
#only pass valid json to this func
def flatten_json(nested_json):
"""
Flatten json object with nested keys into a single level.
Args:
nested_json: A nested json object.
Returns:
The flattened json object if successful, None otherwise.
"""
out = {}
def flatten(x, name=''):
if type(x) is dict:
for a in x:
flatten(x[a], name + a + '_')
elif type(x) is list:
i = 0
for a in x:
flatten(a, name + str(i) + '_')
i += 1
else:
out[name[:-1]] = x
flatten(nested_json)
return out
def main():
# Send READY=1
notify(Notification.READY)
#button_setup()
root = tk.Tk()
root.title("Doser Environmentals")
label = tk.Label(root, fg="dark green")
label.pack()
label.config(text=str(INITIAL_DOSER_STRING))
button = tk.Button(root, text='Stop', width=25, command=root.destroy)
button.pack()
var = 1
keys = []
values = []
doser_string = INITIAL_DOSER_STRING
while var == 1:
root.update()
line = ser.readline()
#remove byte type and carriage return
try:
line = line.decode('ascii')
line = line.rstrip()
#wrap object
line = '[' + line + ']'
#print(line)
except UnicodeDecodeError as e:
print('ERROR:',e)
except TypeError as e:
print('ERROR:',e)
#uncomment to view raw object
#print(line) #print 'line'
json_dict = {}
#test if json in 'line' is valid json
if is_json(line) == True:
try:
#print(line)
line = json.loads(line)
flat_json = flatten_json(line)
print(flat_json)
#get key:value pairs
for key, value in flat_json.items():
#slice the first 12 char off each column name (the controller version)
json_dict[str(key[RAW_INPUT_STRING_SLICE_START:])] = value
keys.append(str(key[RAW_INPUT_STRING_SLICE_START:]))
values.append(str(value))
#print(keys)
#print(values)
if "DOS_ENV_RES_PH" and "DOS_ENV_RES_EC" in json_dict:
#print(json_dict["DOS_ENV_RES_PH"])
#print(json_dict["DOS_ENV_RES_EC"])
doser_string = "pH {0} EC {1} temp {2}".format(json_dict["DOS_ENV_RES_PH"],json_dict["DOS_ENV_RES_EC"],json_dict["DOS_ENV_RES_TEMP"])
label.config(text=str(doser_string))
keys.clear()
values.clear()
except ValueError as e:
print('ERROR try: commit_json(line):',e)
main()
from time import sleep
from datetime import datetime,timedelta
import serial
import json
from datetime import datetime
from systemd.daemon import notify, Notification
import tkinter as tk
from tkinter import *
#constants
BAUD_RATE = 500000
RAW_INPUT_STRING_SLICE_START = 12
INITIAL_DOSER_STRING = "pH 0.00 EC 0.00 temp 0.00\n avg pH 0.00 avg EC 0.00 avg temp 0.00"
INITIAL_CONTROLLER_REPLY = "Sensor Response: "
SENSOR_LIST = ["COM_SENSOR_0_COMMAND","COM_SENSOR_1_COMMAND","COM_SENSOR_2_COMMAND","COM_SENSOR_3_COMMAND","COM_SENSOR_0_DATA","COM_SENSOR_1_DATA","COM_SENSOR_2_DATA","COM_SENSOR_3_DATA"]
#table list
table_list = [("pH","EC","temp"),
("","",""),
("avg pH","avg EC","avg temp"),
("","",""),
("Sensor:","Command:","Response:"),
("","",""),
("","",""),
("","",""),
("","",""),
("","",""),
("","",""),
("","",""),
("","","")]
print_dict_flag = 0
#UART port
ser = serial.Serial('/dev/ttyACM2', BAUD_RATE, timeout=5) #open the serial port
class Table:
def __init__(self,root):
# code for creating table
for i in range(total_rows):
for j in range(total_columns):
self.e = Entry(root, width=20, fg='black',bg='white',relief="sunken",font=('Arial',16,'bold'))
self.e.grid(row=i, column=j)
grid_label = tk.Label(root, fg="black", bg="white", relief = "sunken", borderwidth = 2,font=('Arial',16,'bold'))
grid_label.grid(row=i, column = j, sticky=N+S+E+W)
grid_label.config(text=str(table_list[i][j]))
class CreateToolTip(object):
"""
create a tooltip for a given widget
"""
def __init__(self, widget, text='widget info'):
self.waittime = 500 #miliseconds
self.wraplength = 180 #pixels
self.widget = widget
self.text = text
self.widget.bind("<Enter>", self.enter)
self.widget.bind("<Leave>", self.leave)
self.widget.bind("<ButtonPress>", self.leave)
self.id = None
self.tw = None
def enter(self, event=None):
self.schedule()
def leave(self, event=None):
self.unschedule()
self.hidetip()
def schedule(self):
self.unschedule()
self.id = self.widget.after(self.waittime, self.showtip)
def unschedule(self):
id = self.id
self.id = None
if id:
self.widget.after_cancel(id)
def showtip(self, event=None):
x = y = 0
x, y, cx, cy = self.widget.bbox("insert")
x += self.widget.winfo_rootx() + 25
y += self.widget.winfo_rooty() + self.widget.winfo_height() + 1
# creates a toplevel window
self.tw = tk.Toplevel(self.widget)
# Leaves only the label and removes the app window
self.tw.wm_overrideredirect(True)
self.tw.wm_geometry("+%d+%d" % (x, y))
label = tk.Label(self.tw, text=self.text, justify='left',
background="#ffffff", relief='solid', borderwidth=1,
wraplength = self.wraplength)
label.pack(ipadx=1)
def hidetip(self):
tw = self.tw
self.tw= None
if tw:
tw.destroy()
#figure out if the object is a valid json
def is_json(myjson):
try:
#leverage json.loads to tell us what's wrong with the json, if anything
json_object = json.loads(myjson)
except ValueError as e:
#useful error report
#print('ERROR is_json() :',e)
print(e)
return False
return True
#only pass valid json to this func
def flatten_json(nested_json):
"""
Flatten json object with nested keys into a single level.
Args:
nested_json: A nested json object.
Returns:
The flattened json object if successful, None otherwise.
"""
out = {}
def flatten(x, name=''):
if type(x) is dict:
for a in x:
flatten(x[a], name + a + '_')
elif type(x) is list:
i = 0
for a in x:
flatten(a, name + str(i) + '_')
i += 1
else:
out[name[:-1]] = x
flatten(nested_json)
return out
def dose_enable():
command_to_write = str('dose_enable\r\n')
for i in command_to_write:
ser.write(i.encode('utf8'))
def calibrate_ph():
#call write to serial sensor with calibration commands
print("calibrating pH")
def print_dict():
global print_dict_flag
if print_dict_flag == 1:
print_dict_flag = 0
print('disable print json dict to shell')
else:
print_dict_flag = 1
print('enable print json dict to shell')
#pass multiuart port and command string
def write_to_serial_sensor(port,command):
#assemble command into string literal
combined_command = str(port) + " " + str(command)
command_to_write = 'atc {0} {1}\r\n'.format(str(port),str(command))
#iterate through string literal, write to connected serial port in utf8 encoding
for i in command_to_write:
ser.write(i.encode('utf8'))
def update_grid_labels(json_dict):
try:
if "COM_SENSOR_0_COMMAND" in json_dict:
ts = str(datetime.now().strftime("%m/%d/%Y, %H:%M:%S"))
com = str(json_dict["COM_SENSOR_0_COMMAND"])
update = str(ts + "\n" + com)
grid_ph_command_label.config(text=update)
if "COM_SENSOR_0_DATA" in json_dict:
ts = str(datetime.now().strftime("%m/%d/%Y, %H:%M:%S"))
com = str(json_dict["COM_SENSOR_0_DATA"])
update = str(ts + "\n" + com)
grid_ph_data_label.config(text=update)
if 'pH' in json_dict["COM_SENSOR_0_DATA"]:
#print("got ph info")
ts = str(datetime.now().strftime("%m/%d/%Y, %H:%M:%S"))
string_start = json_dict["COM_SENSOR_0_DATA"].index("?")
com = str(json_dict["COM_SENSOR_0_DATA"][string_start:])
update = str(ts + "\n" + com)
grid_ph_sensor_info_response_label.config(text=update)
if "COM_SENSOR_1_COMMAND" in json_dict:
ts = str(datetime.now().strftime("%m/%d/%Y, %H:%M:%S"))
com = str(json_dict["COM_SENSOR_1_COMMAND"])
update = str(ts + "\n" + com)
grid_ec_command_label.config(text=update)
if "COM_SENSOR_1_DATA" in json_dict:
ts = str(datetime.now().strftime("%m/%d/%Y, %H:%M:%S"))
com = str(json_dict["COM_SENSOR_1_DATA"])
update = str(ts + "\n" + com)
grid_ec_data_label.config(text=update)
if 'EC' in json_dict["COM_SENSOR_1_DATA"]:
#print("got ec info")
ts = str(datetime.now().strftime("%m/%d/%Y, %H:%M:%S"))
string_start = json_dict["COM_SENSOR_1_DATA"].index("?")
com = str(json_dict["COM_SENSOR_1_DATA"][string_start:])
update = str(ts + "\n" + com)
grid_ec_sensor_info_response_label.config(text=update)
if "COM_SENSOR_2_COMMAND" in json_dict:
ts = str(datetime.now().strftime("%m/%d/%Y, %H:%M:%S"))
com = str(json_dict["COM_SENSOR_2_COMMAND"])
update = str(ts + "\n" + com)
grid_temp_command_label.config(text=update)
if "COM_SENSOR_2_DATA" in json_dict:
ts = str(datetime.now().strftime("%m/%d/%Y, %H:%M:%S"))
com = str(json_dict["COM_SENSOR_2_DATA"])
update = str(ts + "\n" + com)
grid_temp_data_label.config(text=update)
if 'RTD' in json_dict['COM_SENSOR_2_DATA']:
#print("got temp info")
ts = str(datetime.now().strftime("%m/%d/%Y, %H:%M:%S"))
string_start = json_dict["COM_SENSOR_2_DATA"].index("?")
com = str(json_dict["COM_SENSOR_2_DATA"][string_start:])
update = str(ts + "\n" + com)
grid_temp_sensor_info_response_label.config(text=update)
if "COM_SENSOR_3_COMMAND" in json_dict:
ts = str(datetime.now().strftime("%m/%d/%Y, %H:%M:%S"))
com = str(json_dict["COM_SENSOR_3_COMMAND"])
update = str(ts + "\n" + com)
grid_flow_command_label.config(text=update)
if "COM_SENSOR_3_DATA" in json_dict:
ts = str(datetime.now().strftime("%m/%d/%Y, %H:%M:%S"))
com = str(json_dict["COM_SENSOR_3_DATA"])
update = str(ts + "\n" + com)
grid_flow_data_label.config(text=update)
if 'FLO' in json_dict['COM_SENSOR_3_DATA']:
#print("got flow info")
ts = str(datetime.now().strftime("%m/%d/%Y, %H:%M:%S"))
string_start = json_dict["COM_SENSOR_3_DATA"].index("?")
com = str(json_dict["COM_SENSOR_3_DATA"][string_start:])
update = str(ts + "\n" + com)
grid_flow_sensor_info_response_label.config(text=update)
if "DOS_ENV_RES_PH" and "DOS_ENV_RES_EC" in json_dict:
grid_ph_label.config(text=str(json_dict["DOS_ENV_RES_PH"]))
grid_ec_label.config(text=str(json_dict["DOS_ENV_RES_EC"]))
grid_temp_label.config(text=str(json_dict["DOS_ENV_RES_TEMP"]))
grid_ph_avg_label.config(text=str(json_dict["DOS_ENV_RES_AVG_PH"]))
grid_ec_avg_label.config(text=str(json_dict["DOS_ENV_RES_AVG_EC"]))
grid_temp_avg_label.config(text=str(json_dict["DOS_ENV_RES_AVG_TEMP"]))
except KeyError as e:
print('ERROR keyerror',e)
def main():
global print_dict_flag,root
# Send READY=1
notify(Notification.READY)
var = 1
get_sensor_info_timer = datetime.now()
get_sensor_info_timer = get_sensor_info_timer + timedelta(seconds=5)
get_sensor_info = 1
doser_string = INITIAL_DOSER_STRING
while var == 1:
#get sensor info one time after boot
curr_time = datetime.now()
if get_sensor_info == 1 and curr_time >= get_sensor_info_timer:
write_to_serial_sensor(0,"i")
sleep(0.05)
write_to_serial_sensor(1,"i")
sleep(0.05)
write_to_serial_sensor(2,"i")
sleep(0.05)
write_to_serial_sensor(3,"i")
get_sensor_info = 0
root.update()
line = ser.readline()
try:
#remove byte type and carriage return
line = line.decode('ascii')
line = line.rstrip()
#wrap object
line = '[' + line + ']'
#print(line)
except UnicodeDecodeError as e:
print('ERROR:',e)
except TypeError as e:
print('ERROR:',e)
#uncomment to view raw object
#print(line) #print 'line'
json_dict = {}
#test if json in 'line' is valid json
if is_json(line) == True:
try:
line = json.loads(line)
flat_json = flatten_json(line)
#get key:value pairs
for key, value in flat_json.items():
#slice the first 12 char off each column name (the controller version)
json_dict[str(key[RAW_INPUT_STRING_SLICE_START:])] = value
if print_dict_flag == 1:
print(json_dict)
result_list = []
for i in SENSOR_LIST:
if i in json_dict:
#print(i,json_dict[i])
result_list.append(json_dict[i])
if '*OK' in str(result_list):
#print(result_list)
#print(i)
#print("affirmative")
result_list = []
update_grid_labels(json_dict)
except ValueError as e:
print('ERROR',e)
main()
#tkinter setup
#button_setup()
root = tk.Tk()
root.title("Doser Environmentals")
# find total number of rows and
# columns in list
total_rows = len(table_list)
total_columns = len(table_list[0])
t = Table(root)
grid_ph_sensor_label = tk.Label(root, fg="black", bg="white", relief = "sunken", borderwidth = 2,font=('Arial',12,'bold'))
grid_ph_sensor_label.grid(row=5, column = 0, rowspan=1, sticky=N+S+E+W)
grid_ph_sensor_label.config(text=str("0-pH"))
grid_ph_sensor_info_response_label = tk.Label(root, fg="black", bg="white", relief = "sunken", borderwidth = 2,font=('Arial',12))
grid_ph_sensor_info_response_label.grid(row=6, column = 0, rowspan=1, sticky=N+S+E+W)
grid_ph_sensor_info_response_label.config(text=str(" "))
grid_ph_sensor_info_response_label_ttp = CreateToolTip(grid_ph_sensor_info_response_label, \
"This field contains sensor type and sensor firmware version")
grid_ec_sensor_label = tk.Label(root, fg="black", bg="white", relief = "sunken", borderwidth = 2,font=('Arial',12,'bold'))
grid_ec_sensor_label.grid(row=7, column = 0, rowspan=1, sticky=N+S+E+W)
grid_ec_sensor_label.config(text=str("1-EC"))
grid_ec_sensor_info_response_label = tk.Label(root, fg="black", bg="white", relief = "sunken", borderwidth = 2,font=('Arial',12))
grid_ec_sensor_info_response_label.grid(row=8, column = 0, rowspan=1, sticky=N+S+E+W)
grid_ec_sensor_info_response_label.config(text=str(" "))
grid_ec_sensor_info_response_label_ttp = CreateToolTip(grid_ec_sensor_info_response_label, \
"This field contains sensor type and sensor firmware version")
grid_temp_sensor_label = tk.Label(root, fg="black", bg="white", relief = "sunken", borderwidth = 2,font=('Arial',12,'bold'))
grid_temp_sensor_label.grid(row=9, column = 0, rowspan=1, sticky=N+S+E+W)
grid_temp_sensor_label.config(text=str("2-temp"))
grid_temp_sensor_info_response_label = tk.Label(root, fg="black", bg="white", relief = "sunken", borderwidth = 2,font=('Arial',12))
grid_temp_sensor_info_response_label.grid(row=10, column = 0, rowspan=1, sticky=N+S+E+W)
grid_temp_sensor_info_response_label.config(text=str(" "))
grid_temp_sensor_info_response_label_ttp = CreateToolTip(grid_temp_sensor_info_response_label, \
"This field contains sensor type and sensor firmware version")
grid_flow_sensor_label = tk.Label(root, fg="black", bg="white", relief = "sunken", borderwidth = 2,font=('Arial',12,'bold'))
grid_flow_sensor_label.grid(row=11, column = 0, rowspan=1, sticky=N+S+E+W)
grid_flow_sensor_label.config(text=str("3-flow"))
grid_flow_sensor_info_response_label = tk.Label(root, fg="black", bg="white", relief = "sunken", borderwidth = 2,font=('Arial',12))
grid_flow_sensor_info_response_label.grid(row=12, column = 0, rowspan=1, sticky=N+S+E+W)
grid_flow_sensor_info_response_label.config(text=str(" "))
grid_flow_sensor_info_response_label_ttp = CreateToolTip(grid_flow_sensor_info_response_label, \
"This field contains sensor type and sensor firmware version")
grid_ph_label = tk.Label(root, fg="black", bg="white")
grid_ph_label.grid(row=1, column = 0)
grid_ph_label.config(text=str(0.00))
grid_ec_label = tk.Label(root, fg="black", bg="white")
grid_ec_label.grid(row=1, column = 1)
grid_ec_label.config(text=str(0.00))
grid_temp_label = tk.Label(root, fg="black", bg="white")
grid_temp_label.grid(row=1, column = 2)
grid_temp_label.config(text=str(0.00))
grid_ph_avg_label = tk.Label(root, fg="black", bg="white")
grid_ph_avg_label.grid(row=3, column = 0)
grid_ph_avg_label.config(text=str(0.00))
grid_ec_avg_label = tk.Label(root, fg="black", bg="white")
grid_ec_avg_label.grid(row=3, column = 1)
grid_ec_avg_label.config(text=str(0.00))
grid_temp_avg_label = tk.Label(root, fg="black", bg="white")
grid_temp_avg_label.grid(row=3, column = 2)
grid_temp_avg_label.config(text=str(0.00))
grid_ph_command_label = tk.Label(root, fg="black", bg="white", relief = "sunken", borderwidth = 2)
grid_ph_command_label.grid(row=5, column = 1, rowspan=2, sticky=N+S+E+W)
grid_ph_command_label.config(text=str("boot"))
grid_ph_command_label_ttp = CreateToolTip(grid_ph_command_label, \
"This was the last command sent, if it says boot here then no commands have been sent ")
grid_ph_data_label = tk.Label(root, fg="black", bg="white", relief = "sunken", borderwidth = 2)
grid_ph_data_label.grid(row=5, column = 2, rowspan=2, sticky=N+S+E+W)
grid_ph_data_label.config(text=str(" "))
grid_ph_data_label_ttp = CreateToolTip(grid_ph_data_label, \
"This was the last response received from the sensor, if this is blank there has been no response received ")
grid_ec_command_label = tk.Label(root, fg="black", bg="white", relief = "sunken", borderwidth = 2)
grid_ec_command_label.grid(row=7, column = 1, rowspan=2, sticky=N+S+E+W)
grid_ec_command_label.config(text=str("boot"))
grid_ec_command_label_ttp = CreateToolTip(grid_ec_command_label, \
"This was the last command sent, if it says boot here then no commands have been sent ")
grid_ec_data_label = tk.Label(root, fg="black", bg="white", relief = "sunken", borderwidth = 2)
grid_ec_data_label.grid(row=7, column = 2, rowspan=2, sticky=N+S+E+W)
grid_ec_data_label.config(text=str(" "))
grid_ec_data_label_ttp = CreateToolTip(grid_ec_data_label, \
"This was the last response received from the sensor, if this is blank there has been no response received ")
grid_temp_command_label = tk.Label(root, fg="black", bg="white", relief = "sunken", borderwidth = 2)
grid_temp_command_label.grid(row=9, column = 1, rowspan=2, sticky=N+S+E+W)
grid_temp_command_label.config(text=str("boot"))
grid_temp_command_label_ttp = CreateToolTip(grid_temp_command_label, \
"This was the last command sent, if it says boot here then no commands have been sent ")
grid_temp_data_label = tk.Label(root, fg="black", bg="white", relief = "sunken", borderwidth = 2)
grid_temp_data_label.grid(row=9, column = 2, rowspan=2, sticky=N+S+E+W)
grid_temp_data_label.config(text=str(" "))
grid_temp_data_label_ttp = CreateToolTip(grid_temp_data_label, \
"This was the last response received from the sensor, if this is blank there has been no response received ")
grid_flow_command_label = tk.Label(root, fg="black", bg="white", relief = "sunken", borderwidth = 2)
grid_flow_command_label.grid(row=11, column = 1, rowspan=2, sticky=N+S+E+W)
grid_flow_command_label.config(text=str("boot"))
grid_flow_command_label_ttp = CreateToolTip(grid_flow_command_label, \
"This was the last command sent, if it says boot here then no commands have been sent ")
grid_flow_data_label = tk.Label(root, fg="black", bg="white", relief = "sunken", borderwidth = 2)
grid_flow_data_label.grid(row=11, column = 2, rowspan=2, sticky=N+S+E+W)
grid_flow_data_label.config(text=str(" "))
grid_flow_data_label_ttp = CreateToolTip(grid_flow_data_label, \
"This was the last response received from the sensor, if this is blank there has been no response received ")
print_dict_button = tk.Button(root, text='Print dict', width=25, command=print_dict)
print_dict_button.grid(column=1)
dose_enable_button = tk.Button(root, text='Auto-dose enable/disable', width=25, command=dose_enable)
dose_enable_button.grid(column=1)
cal_button = tk.Button(root, text='Calibrate pH', width=25, command=calibrate_ph)
cal_button.grid(column=1)
stop_button = tk.Button(root, text='Stop', width=25, command=root.destroy)
stop_button.grid(column=1)