diff --git a/control/fixed_duty.py b/control/fixed_duty.py index 0b01341..e3c53ff 100644 --- a/control/fixed_duty.py +++ b/control/fixed_duty.py @@ -7,6 +7,13 @@ class FixedDutyCycle(controllers.Controller): self.start = kwargs.pop('start_time', perf_counter()) self.period = kwargs.pop('period') self.set_duty(kwargs.pop('duty_perc')) + operator = kwargs.pop('operator', '<') + functions = { + '<': lambda (a, b): a < b, + '>': lambda (a, b): a > b, + '==': lambda (a, b): a == b, + } + self.operator = functions[operator] super().__init__(*args, **kwargs) self.last_time = None self.total_failed_read = 0 @@ -42,7 +49,7 @@ class FixedDutyCycle(controllers.Controller): return False self.failed_read = 0 return (self.timepoint() < self.duty) if ( - self.input < self.target) else False + self.operator(self.input, self.target)) else False # 0. refractary_period is fixed (e.g. 30s, depends on the hardware) @@ -57,9 +64,10 @@ class FixedDutyCycle(controllers.Controller): # HOW LONG MUST BE THE HISTORY? def fixed_duty_wrapper(args): - name, duty, period = stringify(args.car, quote=False), args.cdr.car, args.cdr.cdr.car - print('name, duty, period', name, duty*100, period) + name, duty, period, op = stringify( + args.car, quote=False), args.cdr.car, args.cdr.cdr.car, args.cdr.cdr.cdr.car + print('name, duty, period, operation', name, duty*100, period, op) return (name, FixedDutyCycle( target=None, # reach_period_s=60*60, duty_perc=duty*100, period=period, - start_time=perf_counter())) + start_time=perf_counter(), operator=op)) diff --git a/phasectrl.py b/phasectrl.py index f2e8992..2e218a1 100644 --- a/phasectrl.py +++ b/phasectrl.py @@ -10,7 +10,7 @@ from actuators import actuators from utils import consumption_diff, consumption_to_string, stohms MY_GLOBAL_ENV = ( - _('make-duty-controller', 3, fixed_duty_wrapper, + _('make-duty-controller', 4, fixed_duty_wrapper, _('format-time', 1, lambda x: stohms(x.car), GLOBAL_ENV))) diff --git a/recipes.json b/recipes.json index cd90fa8..451a657 100644 --- a/recipes.json +++ b/recipes.json @@ -3,8 +3,8 @@ "name": "Koji Rice (MISO)", "description": "Tiene riso alla temperatura e umidità giuste per il koji", "controllers": [ - "(make-duty-controller \"heater\" 0.40 60)", - "(make-duty-controller \"humidifier\" 0.80 100)" + "(make-duty-controller \"heater\" 0.40 60 '<)", + "(make-duty-controller \"humidifier\" 0.10 100 '<)" ], "phases": [ { @@ -62,7 +62,7 @@ "name": "Tepache", "description": "Tiene il tepache a ~23 gradi", "controllers": [ - "(make-duty-controller \"heater\" 0.20 120)" + "(make-duty-controller \"heater\" 0.20 120 '<)" ], "phases": [ { @@ -78,7 +78,7 @@ "name": "Stracchino", "description": "Tiene lo stracchino a ~35 gradi per 24 ore", "controllers": [ - "(make-duty-controller \"heater\" 0.80 120)" + "(make-duty-controller \"heater\" 0.80 120 '<)" ], "phases": [ { @@ -90,48 +90,49 @@ } ] }, - { - "name": "Yogurt", - "description": "Pastorizza lo yogurt a 82 gradi, lascia raffreddare per fare l'inoculo, mantiene a 42 gradi fino a che è pronto.", - "controllers": [ - "(make-duty-controller \"heater\" 0.20 120)" - ], - "phases": [ - { - "name": "Riscalda", - "description": "Preheat yogurt to 82°C", - "exit_condition": "(and (>= (get-sensor \"T_food\") 81.5)\n(> (time-in-this-phase) (minutes 15)))", - "on_load": "(begin (set-controller \"heater\" \"T_food\")\n(set-target \"T_food\" 82.0))", - "on_exit": "#t" + { + "name": "Yogurt", + "description": "Lascia raffreddare lo yogurt per fare l'inoculo, mantiene a 42 gradi fino a che è pronto, e poi porta a 4 gradi.", + "controllers": [ + "(make-duty-controller \"heater\" 0.20 120 '<)" + "(make-duty-controller \"freezer\" 0.20 120 '>)" + ], + "phases": [ + { + "name": "Cool", + "description": "Cool to 46°C", + "exit_condition": "(and (< (get-sensor \"T_food\") 46.0)\n(> (get-sensor \"T_food\") 42.0))", + "on_load": "(begin (set-controller \"heater\" \"T_food\") (set-target \"T_food\" 46.0) (set-controller \"freezer\" \"T_ext\") (set-target \"T_ext\" 46.0))", + "on_exit": "#t" }, - { - "name": "Cool", - "description": "Cool to 46°C", - "exit_condition": "(and (< (get-sensor \"T_food\") 46.0)\n(> (get-sensor \"T_food\") 42.0))", - "on_load": "(set-target \"T_food\" 46.0)", - "on_exit": "#t" + { + "name": "Inoculate (backslopping)", + "description": "Add 50ml Yogurt", + "exit_condition": "(manual-intervention \"Inocula 50g di yogurt\" '((\"Fatto\" #t)))", + "on_load": "(notify \"Inoculate 50g of yogurt NOW!\")", + "on_exit": "(notify (concat \"Inoculated at \" (now)))" }, - { - "name": "Inoculate (backslopping)", - "description": "Add 50ml Yogurt", - "exit_condition": "(manual-intervention \"Inocula 50g di yogurt\" '((\"Fatto\" #t)))", - "on_load": "(notify \"Inoculate 50g of yogurt NOW!\")", - "on_exit": "(notify (concat \"Inoculated at \" (now)))" + { + "name": "Hold", + "description": "Keep at 42°C for 3h", + "exit_condition": "(> (time-in-this-phase) (hours 3))", + "on_load": "(begin (set-target \"T_food\" 41.0) (set-target \"T_ext\" 41.0))", + "on_exit": "(notify \"You can remove the yogurt from the heater\")" }, - { - "name": "Hold", - "description": "Keep at 42°C for 3h", - "exit_condition": "(> (time-in-this-phase) (hours 3))", - "on_load": "(set-target \"T_food\" 41.0)", - "on_exit": "(notify \"You can remove the yogurt from the heater\")" + { + "name": "Refrigerate", + "description": "Lower temperature to 4gradi", + "exit_condition": "#f", + "on_load": "(begin (set-target \"T_food\" 4.0) (set-target \"T_ext\" 4.0))", + "on_exit": "(notify \"You can remove the yogurt from the heater\")" } - ] + ] }, { "name": "Nattō", "description": "FIXME", "controllers": [ - "(make-duty-controller \"heater\" 0.20 120)" + "(make-duty-controller \"heater\" 0.20 120 '<)" ], "phases": [] }, @@ -139,7 +140,7 @@ "name": "Tempeh", "description": "FIXME", "controllers": [ - "(make-duty-controller \"heater\" 0.20 120)" + "(make-duty-controller \"heater\" 0.20 120 '<)" ], "phases": [] }, @@ -147,7 +148,7 @@ "name": "Gorgonzola", "description": "FIXME", "controllers": [ - "(make-duty-controller \"heater\" 0.20 120)" + "(make-duty-controller \"heater\" 0.20 120 '<)" ], "phases": [] }