diff --git a/content/post/smart-rice-cooker.md b/content/post/smart-rice-cooker.md index 37ad241..d4d8450 100644 --- a/content/post/smart-rice-cooker.md +++ b/content/post/smart-rice-cooker.md @@ -36,9 +36,20 @@ Many of my parts have arrived (rice cooker, thermistors, relay, and NodeMCU), so *** +# Terminology + +### Directive + +A directive is an instruction for the rice cooker. +User facing directives have, at most, a single input. + +Internally, directives chain each other with conditions to achieve their given goal. + +*** + # Thoughts -Having received shipment of the rice cooker, and beginning to use it, I realise there's nothing about it that makes it fit only for rice, if I can control the heating myself. +Having received shipment of the rice cooker, and beginning to use it, I realize there's nothing about it that makes it fit only for rice, if I can control the heating myself. Everything about it is like any other hot pot, it's just tuned for cooking rice. Thus, once I convert the thing to being smart, I will be able to use it for, say, ramen, or any number of other things. @@ -46,37 +57,18 @@ The possibility of steaming things only furthers this goal. ## Recipes -The question is raised, how should I deal with parametric recipes, and more specifically, internally governed parametric recipes. -That is, recipes that have no prior knowledge of the volume of rice and water added, but infer it from the time it takes to reach temperature. -This value, that is, the duration taken to reach temperature, only holds value when a set heating cycle is used, such as full heat, or constant PWM. -Typically however, no PWM is required during initial heat, only once at heat. +Recipes should be submitted as simple JSON structures. +These may be linted, and will contain no logic. +All calculations are to be done when producing the recipe. +This is done so as to ease the technical burden on the cooker. -As such, a value that any directive may rely upon should be the duration taken by some prior directive. -This then leads me to say that each and every step in a recipe must have a unique identity, so that later directives may rely on them. +## Heating / Cooling -This, then, immediately appears to be far more complicated than I should worry about, instead, this behaviour aught to be offloaded to Lua or some other scripting system. -As such, the NodeMCU should be ideal, as it supports a variation of Lua. -Ideally, this will allow branching logic also, and storing of values, simplifying my technical burden. +Active cooling is not something worth designing for, as it is not an issue to begin with. -Alternatively, it does not sound impossible to write a simple translator to emit both a Lua scripted version of a recipe, and a version that may be embedded directly into the compiled code (so that non-Lua boards may be used). +## Coding -## Heating - -The contents of the rice cooker should be considered when heating/cooling, as they will absorb the heat and thermal lag will be an issue. -If possible, look into either weighing the contents for a rough approximation (hard/complicated) or use recipe provided portion sizes to calculate the thermal capacity of the contents (water, mainly). - -Seeing as the dumb rice cooker still manages to kick itself off when needed, even given different serving sizes, there must be a simple way to find the time needed to cook the rice, even without predefines portion sizes. - -On the face of it, I would assume the time rice is kept at full heat will only slightly increase in duration as the volume of rice increases, if at all. -The time it takes to get up to heat shouln't be ignored, as some cooking must be done during that time. -The variety of rice should not be discounted either. - -Further research into the dynamics of rice cooking are meritted, once internet and more rice is available once again. - -## Cooling - -I am planning my setup in such a way as to allow actively cooling the cooking pot, but upon further consideration, it is likely not an issue worth worrying about. -As such, I'll continue my planning as I am, but not be too worried about the details for now. +Internally, a temperature kill switch should be enacted, which will kick in if the *** @@ -84,11 +76,10 @@ As such, I'll continue my planning as I am, but not be too worried about the det I tentatively (with no real experience designing them) plan on my API being something like the following. -- `/action/light/kill` - *Stops all light activity* +- `/action/light/kill` - *Kill all light activity* - `/action/light/set` - *Change lighting mode, with optional duration* -- `/action/temperature/kill` - *Stops all heating/cooling, lets the cooker cool to room temperature alone* -- `/action/temperature/set` - *Heat/cool to given temperature, then hold. Should allow setting a target heat/cool rate. Should allow setting a hold duration* -*(proxy to `/settings/cook/recipe/list`)* +- `/action/temperature/kill` - *Stops all heating* +- `/action/temperature/set` - *Heat/cool to given temperature.* - `/routine/cook/kill` - *Kill any current running routine* - `/routine/cook/list` - *List known cooking routines* - `/routine/cook/schedule/list` - *List any scheduled routines* @@ -97,47 +88,66 @@ I tentatively (with no real experience designing them) plan on my API being some - `/sensor/temperature` - *Returns temperature* - `/settings/cook/recipe/list` - *List known cooking routines* - `/settings/cook/recipe/set` - *Submit/modify/delete a cooking routine* -- `/settings/cook/warm/duration` - *Determine post-cook warming duration* -- `/settings/cook/warm/set` - *Turn post-cook warming on/off* -- `/settings/cook/warm/temperature` - *Set post-cook warming temperature* - `/settings/lighting/list` - *List lighting modes* - `/settings/lighting/set` - *Submit/modify/delete a lighting mode* - `/settings/time/set` - *Set/read date and time* -# Cooking schedule definition specifications +# Cooking recipe definition specifications -Directives are distinct actions to be taken. - -They may be catagorised as follows: +They may be categorized as follows: #### Primary Directives -* Sleep * Heat -* Cooling +* Sleep #### Secondary Directives -* Temperature +* Lighting Change +* Lighting Kill +* Temperature Change +* Temperature Hold +* Temperature Kill + +## Definitions These are defined as such: ### Sleep -Just wait for given duration, or until a given condition is met. +Wait for a given duration. +No need to expose to recipes directly, see `Kill`, `Temperature Change`, and `Temperature Hold` instead. +Will keep things like LED lights going still. ### Heat -Heat for a given duration, or until a given condition is met. +Takes a bool, turns the heating element on or off. +Non-blocking so that conditions may be checked without unnecessarily cycling the relay. +Dangerous to expose to recipes directly, see `Kill` -### Cool -Cool for a given duration, or until a given condition is met. -If I someday choose to use a fan, this should be an active feature. -Instead, it's the same as `Sleep` for now. +### Lighting Change +Change lighting mode. -### Temperature -Heat/cool to given temperature, optionally at a given rate of change (may be difficult for cooling if no fan is included), or percentage load (which will set a PWM rate, or if full, run constant). -This should just be a proxy directive to `Heat`, `Cool`, and `Sleep`. -For now that should work, but in due course, with tuning and benchmarks, this should run cooling at a variable rate (using a fan, I wouldn't want to cut on and off all the time). -Heating should be fine be fine with fairly large PWM, as the thermal lag I expect to be significant, and we want to try to hit our deadline as quickly as possible. +### Lighting Kill +Kill any running lighting mode. + +### Temperature Change +Heat/cool to given temperature. +This should just be a proxy directive to `Heat` and `Sleep`. +That is, `Heat` if under temp, `Sleep` if over temp. +As heating during cooking tends to be a matter of getting to temperature as quickly as possible, there is no need for a duration setting. + +### Temperature Hold +Hold at current temperature for given duration. +This should just be a proxy directive to `Heat` and `Sleep`. +That is, `Heat` if under temp, `Sleep` if over temp, until an internal clock has ticked over the time required. + +### Temperature Kill +Turns off heat, cancels any running recipe. +Takes no input. +Just a proxy to `Heat`, but only as a false bool. + +*Might* be used at the end of a recipe, unnecessary though. +Mostly to be used as a soft kill switch, invoked from a physical button or via API. +Examples might be canceling an infinite temperature holding cycle (e.g rice warming). # Dep Graph diff --git a/src/connections.dot b/src/connections.dot index f3c1b97..756f292 100644 --- a/src/connections.dot +++ b/src/connections.dot @@ -20,12 +20,14 @@ digraph { "Depend on value" "Proxy to value" "Depend on function" + "Proxy to function" } "Depend on value" -> "Node"[depend_value] "Proxy to value" -> "Node"[proxy_value] "Depend on function" -> "Node"[depend_function] + "Proxy to function" -> "Node"[proxy_function] label="Key" @@ -33,14 +35,33 @@ digraph { subgraph cluster_directives { - "Sleep" - "Heat" - "Cool" - "Temperature" + subgraph cluster_primary { + "Sleep" + "Heat" + label="Primary" + } + + subgraph cluster_secondary { + "Lighting Change" + "Lighting Kill" + "Temperature Kill" + "Temperature Change" + "Temperature Hold" + label="Secondary" + } + label="Directives" } + subgraph cluster_sensor { + + "Temperature" + + label="Sensors" + + } + subgraph cluster_api { subgraph cluster_action { @@ -66,7 +87,7 @@ digraph { label="action" } - subgraph cluster_sensor { + subgraph cluster_api_sensor { "/api/sensor/temperature"[label="temperature"] @@ -119,16 +140,6 @@ digraph { subgraph cluster_settings_cook { - subgraph cluster_warm { - - "/api/settings/cook/warm/temperature"[label="temperature"] - "/api/settings/cook/warm/set"[label="set"] - "/api/settings/cook/warm/duration"[label="duration"] - - label="warm" - - } - subgraph cluster_recipe { "/api/settings/cook/recipe/list"[label="list"] @@ -149,7 +160,14 @@ digraph { label="api" } - "Temperature" -> { "Heat" "Cool" "Sleep" }[depend_function] + "Temperature Change" -> { "Heat" "Sleep" }[depend_function] + "Temperature Hold" -> { "Heat" "Sleep" }[depend_function] + "Temperature Kill" -> "Heat"[proxy_function] + { "Temperature Change" "Temperature Hold" } -> "Temperature"[depend_value] + + "/api/action/temperature/set" -> "Temperature Change"[proxy_function] + "/api/action/temperature/kill" -> "Temperature Kill"[proxy_function] + "/api/action/temperature/kill" -> "Temperature"[proxy_value] "/api/routine/cook/list" -> "/api/settings/cook/recipe/list"[proxy_value] // Description checklist /////////////////////////////////////////////////////// @@ -166,17 +184,17 @@ digraph { "/api/sensor/temperature"[documented] "/api/settings/cook/recipe/list"[documented] "/api/settings/cook/recipe/set"[documented] -"/api/settings/cook/warm/duration"[documented] -"/api/settings/cook/warm/set"[documented] -"/api/settings/cook/warm/temperature"[documented] "/api/settings/lighting/list"[documented] "/api/settings/lighting/set"[documented] "/api/settings/time/set"[documented] -"Temperature"[documented] "Heat"[documented] -"Cool"[documented] +"Lighting Change"[documented] +"Lighting Kill"[documented] "Sleep"[documented] +"Temperature Change"[documented] +"Temperature Hold"[documented] +"Temperature Kill"[documented] //////////////////////////////////////////////////////////////////////////////// diff --git a/static/images/rice/connections.svg b/static/images/rice/connections.svg index baa4dc2..53de7d4 100644 --- a/static/images/rice/connections.svg +++ b/static/images/rice/connections.svg @@ -4,314 +4,384 @@ - - + + %3 - + cluster_key - -Key + +Key cluster_doc - + cluster_sub - + cluster_directives - -Directives + +Directives -cluster_api - -api +cluster_primary + +Primary -cluster_action - -action +cluster_secondary + +Secondary -cluster_light - -light +cluster_sensor + +Sensors -cluster_temperature - -temperature +cluster_api + +api -cluster_sensor - -sensor +cluster_action + +action -cluster_routine - -routine +cluster_light + +light -cluster_routine_cook - -cook +cluster_temperature + +temperature -cluster_schedule - -schedule +cluster_api_sensor + +sensor -cluster_settings - -settings +cluster_routine + +routine -cluster_time - -time +cluster_routine_cook + +cook -cluster_lighting - -lighting +cluster_schedule + +schedule -cluster_settings_cook - -cook +cluster_settings + +settings -cluster_warm - -warm +cluster_time + +time +cluster_lighting + +lighting + + +cluster_settings_cook + +cook + + cluster_recipe - -recipe + +recipe Done - -Done + +Done Documented - -Documented + +Documented Undocumented - -Undocumented + +Undocumented Depend on value - -Depend on value + +Depend on value - + Node - -Node + +Node Depend on value->Node - - + + Proxy to value - -Proxy to value + +Proxy to value Proxy to value->Node - - + + Depend on function - -Depend on function + +Depend on function Depend on function->Node - - + + + + + +Proxy to function + +Proxy to function + + + +Proxy to function->Node + + - + Sleep - -Sleep + +Sleep - -Heat - -Heat - - -Cool - -Cool +Heat + +Heat + + + +Lighting Change + +Lighting Change + + + +Lighting Kill + +Lighting Kill + + + +Temperature Kill + +Temperature Kill + + + +Temperature Kill->Heat + + + + + +Temperature Change + +Temperature Change + + + +Temperature Change->Sleep + + + + + +Temperature Change->Heat + + - + Temperature - -Temperature + +Temperature - - -Temperature->Sleep - - + + +Temperature Change->Temperature + + - - -Temperature->Heat - - + + +Temperature Hold + +Temperature Hold - - -Temperature->Cool - - + + +Temperature Hold->Sleep + + + + + +Temperature Hold->Heat + + + + + +Temperature Hold->Temperature + + - + /api/action/light/kill - -kill + +kill - + /api/action/light/set - -set + +set - + /api/action/temperature/kill - -kill + +kill + + + +/api/action/temperature/kill->Temperature Kill + + + + + +/api/action/temperature/kill->Temperature + + - + /api/action/temperature/set - -set + +set + + + +/api/action/temperature/set->Temperature Change + + - + /api/sensor/temperature - -temperature + +temperature - + /api/routine/cook/list - -list + +list - + /api/settings/cook/recipe/list - -list + +list - + /api/routine/cook/list->/api/settings/cook/recipe/list - - + + - + /api/routine/cook/start - -start + +start - + /api/routine/cook/kill - -kill + +kill - + /api/routine/cook/schedule/list - -list + +list - + /api/routine/cook/schedule/set - -set + +set - + /api/settings/time/set - -set + +set - + /api/settings/lighting/list - -list + +list - + /api/settings/lighting/set - -set - - - -/api/settings/cook/warm/temperature - -temperature - - - -/api/settings/cook/warm/set - -set - - - -/api/settings/cook/warm/duration - -duration + +set - + /api/settings/cook/recipe/set - -set + +set