Thanks for sharing @hmw
One thing I noticed about this that I really like @cregini is your usage of the term ‘Sunrise’ - I think that’s much better than ‘day start’
Brilliant hack. That was an excellent choice to limit the scope of the project to only edit existing fields in a recipe. There are a few things that may end up not working (if I’m being honest) but that’s where I think we haven’t communicated all of the requirements (and frankly limitations) of the hardware clearly enough. I’d say 95% of the work we did on a GUI for building recipes was around adding/rearranging steps within a sequence - especially when they get complex trying to mimic a day cycle.
Good to know - for what it’s worth to anyone reading this, I’ve seen Chris build several cool apps using Adafruit IO - all of them looked better than the actual MARSfarm interface, lol. Adafruit is a super reputable/awesome company that manufactures open-source circuit boards in NYC. Their hardware and software (it would seem) are both great for creating quick prototypes that bring an idea into the real world. Strong recommendation to any maker/electrically inclined teachers to check out Adafruit!
Lastly, I pulled this chunk of code out of the Recipe Remixer we’re working on. You can use this as a test for the recipes you create - as well as instructions for if you did want to add to the functionality of the GUI what constraints you would need to consider.
datavalidation.py
# Author: Ryan Wu
# Created: July 2022
#
# (c) Copyright by MARSfarm
class DataValidator():
def __init__(self):
self.error = None
self.env_setting_checks = {0: self.check_fan, 1: self.check_temp, 2: self.check_pump, 3: self.check_light}
# ------------------------ Switch Statement Functions ------------------------ #
# take in list
def check_fan(self, setting_value):
try:
typecasted_setting = int(setting_value[0])
if int(typecasted_setting) != 0:
if int(typecasted_setting)!= 1:
self.error = "Circulation fan setting must either be 0 (for off) or 1 (for on). You entered {}.".format(setting_value)
return True
except ValueError:
self.error = "Setting must be either 0 (for off) or 1 (for on). You entered {}.".format(setting_value)
return True
return False
def check_temp(self, setting_value):
try:
typecasted_setting = int(setting_value[0])
if int(typecasted_setting) < 65 or int(typecasted_setting > 90):
self.error = "Temperature must either be between 65 or 90. You entered {}.".format(setting_value)
return True
except ValueError:
self.error = "Temperature must either be between 65 or 90. You entered {}.".format(setting_value)
return True
return False
def check_pump(self, setting_value):
try:
typecasted_setting = int(setting_value[0])
if int(typecasted_setting) < 0 or int(typecasted_setting > 2000):
self.error = "Pump volume (in ml) must either be above 0 ml or below 2000ml (2 liters). You entered {}.".format(setting_value)
return True
except ValueError:
self.error = "Pump volume (in ml) must either be number 0 ml or below 2000ml (2 liters). You entered {}.".format(setting_value)
return True
return False
def check_light(self, setting_value_list):
#TODO: check on second pass
for light_value in setting_value_list:
try:
typecasted_setting = int(light_value)
if (typecasted_setting < 0) or (typecasted_setting > 255):
self.error = "Setting values must be number between 0 and 255. You entered {}.".format(light_value)
return True
except ValueError:
self.error = "Setting values must be number between 0 and 255. You entered {}.".format(light_value)
return True
return False
# """
# function that validates the time block, hour and minute
# Parameters:
# -----------
# hour : var to be checked
# minute : var to be checked
# Return:
# True if invalid data, False if data is valid
# """
def validate_time(self, hour, minute):
try:
typecasted_hour = int(hour)
if typecasted_hour > 23 or typecasted_hour < 0:
self.error = "Hour must be a number between 0 and 23. You entered: {}".format(typecasted_hour)
return True
except ValueError:
self.error = "Hour must be a number between 0 and 23. You entered: {}".format(hour)
return True
# checking minute for number between 0 and 60
try:
typecasted_min = int(minute)
if typecasted_min > 60 or typecasted_min < 0:
self.error = "Minute must be a number between 0 and 60. You entered: {}".format(typecasted_min)
return True
except ValueError:
self.error = "Minute must be a number between 0 and 23. You entered: {}".format(minute)
return True
return False
def validate_setting(self, setting_input, env_index):
# TODO: parse setting_input
# 1. check for blank, not int, send typecasted here \/
return self.env_setting_checks.get(env_index)(setting_input)
def validate_all(self, hour, minute, setting_input, env_index):
error_in_time = self.validate_time(hour, minute)
error_in_setting = self.validate_setting(setting_input, env_index)
if error_in_time == True or error_in_setting == True:
return True
return False
def validate_new_file_name(self, new_name, file_list):
if len(new_name) == 0:
self.error = "You must enter a new file name. The file name was left blank."
return True
chars_not_allowed = set('!@#$%^&*()+=[];:."')
if any((char in chars_not_allowed) for char in new_name):
self.error = "Special Chars !@#$%^&*()+=[];:. not allowed."
return True
ascii_approved_name = ""
ascii_approved_name += new_name
ascii_approved_name += ".json"
for name in file_list:
if str(name) == str(ascii_approved_name):
self.error = "You've already named a file {}. Choose a different name!".format(new_name)
return True
return False