191 |
193 |
192 |
194 |
193 |
195 |
194 void *my_simulator_loop(void *threadid) |
196 void *my_simulator_loop(void *threadid) |
195 { |
197 { |
|
198 my_simulator_state = 1; |
|
199 syslog(LOG_NOTICE, "Thread my_simulator_loop started"); |
|
200 |
|
201 /* |
|
202 * Run the state machine |
|
203 */ |
|
204 simulate(); |
|
205 |
|
206 syslog(LOG_NOTICE, "Thread my_simulator_loop stopped"); |
|
207 my_simulator_state = 0; |
|
208 return 0; |
|
209 } |
|
210 |
|
211 |
|
212 SM_DECL(simulate, (char *)"simulator") |
|
213 SM_STATES |
|
214 Init, |
|
215 Waiting, |
|
216 Run, |
|
217 Websocket |
|
218 SM_NAMES |
|
219 (char *)"Init", |
|
220 (char *)"Waiting", |
|
221 (char *)"run", |
|
222 (char *)"Websocket" |
|
223 SM_EDECL |
196 simulator_list *simulator; |
224 simulator_list *simulator; |
197 time_t now, last = (time_t)0; |
225 time_t now, last = (time_t)0; |
198 int seconds = 0; |
226 int seconds = 0; |
199 double k_room_air, sqm_room_air, thick_room_air, air_heat_transfer; |
227 double k_room_air, sqm_room_air, thick_room_air, air_heat_transfer; |
200 double air_change, vhc_air = 0.00121; |
228 double air_change, vhc_air = 0.00121; |
201 |
229 double air_temp, beer_temp, chiller_temp; |
202 my_simulator_state = 1; |
230 bool changed = false; |
203 syslog(LOG_NOTICE, "Thread my_simulator_loop started"); |
231 |
|
232 SM_START(Init) |
|
233 |
|
234 SM_STATE(Init) |
204 |
235 |
205 for (simulator = Config.simulators; simulator; simulator = simulator->next) { |
236 for (simulator = Config.simulators; simulator; simulator = simulator->next) { |
206 /* |
237 /* |
207 * Heater and cooler have the air temperature |
238 * Heater and cooler have the air temperature |
208 */ |
239 */ |
209 simulator->s_heat_temp = simulator->s_cool_temp = simulator->room_temperature; |
240 simulator->s_heat_temp = simulator->s_cool_temp = simulator->room_temperature; |
210 } |
241 } |
211 |
242 SM_PROCEED(Waiting); |
212 for (;;) { |
243 |
213 if (my_simulator_shutdown) |
244 SM_STATE(Waiting) |
214 break; |
245 |
215 |
246 if (my_simulator_shutdown) { |
216 now = time(NULL); |
247 SM_SUCCESS; |
217 if (now != last) { |
248 } |
218 last = now; |
249 now = time(NULL); |
|
250 if (now != last) { |
|
251 last = now; |
|
252 seconds++; |
|
253 SM_PROCEED(Run); |
|
254 } |
|
255 mDelay(50L); |
|
256 |
|
257 SM_STATE(Run) |
|
258 |
|
259 changed = false; |
|
260 for (simulator = Config.simulators; simulator; simulator = simulator->next) { |
|
261 if (my_simulator_shutdown) { |
|
262 SM_SUCCESS; |
|
263 } |
|
264 |
|
265 /* |
|
266 * Copy to duplicates |
|
267 */ |
|
268 air_temp = simulator->air_temperature; |
|
269 beer_temp = simulator->beer_temperature; |
|
270 chiller_temp = simulator->chiller_temperature; |
|
271 |
|
272 /* |
|
273 * First, calculate temperature difference between the room and the air in the |
|
274 * fridge. We use the volume air to roughly calculate the total area between |
|
275 * the in and outside. Calculate the effect and shift the air temperature towards |
|
276 * the room temperature. |
|
277 */ |
|
278 sqm_room_air = (cbrtl(simulator->volume_air) * cbrtl(simulator->volume_air) * 6) / 100; /* square meters all fridge sides */ |
|
279 thick_room_air = 0.04; /* 4 cm walls */ |
|
280 k_room_air = 0.03; /* Polystrene */ |
|
281 air_heat_transfer=(k_room_air * sqm_room_air * (simulator->room_temperature - air_temp)) / thick_room_air; |
|
282 air_change = (air_heat_transfer / (vhc_air * ((simulator->volume_air - simulator->volume_beer) * 1000))) / 60.0; |
|
283 air_temp += air_change; |
|
284 |
|
285 /* |
|
286 * If heating, calculate temperature of the heating plate. If heating is off but |
|
287 * the plate is warmer then the air, calculate the cooling down temperature. |
|
288 * Finally, calculate the new air and plate temperature. |
|
289 */ |
|
290 if (simulator->heater_present == DEVPRESENT_YES && simulator->heater_power >= 50) { |
|
291 if (simulator->s_heat_temp < simulator->heater_temp) { |
|
292 simulator->s_heat_temp += 0.05; |
|
293 if (simulator->s_heat_temp > simulator->air_temperature) |
|
294 air_temp += ((simulator->s_heat_temp - air_temp) / 100.0); |
|
295 } |
|
296 } else { |
219 /* |
297 /* |
220 * Each second |
298 * Follow the air temperature |
221 */ |
299 */ |
222 seconds++; |
300 simulator->s_heat_temp -= (simulator->s_heat_temp - air_temp) / 25.0; |
223 |
301 } |
224 for (simulator = Config.simulators; simulator; simulator = simulator->next) { |
302 |
225 if (my_simulator_shutdown) |
303 /* |
226 break; |
304 * If cooling, calculate temperature of the cooling plate. If cooling is off but |
227 |
305 * the plate is colder then the air, calculate the warming up temperature. |
228 /* |
306 * Finsally, calculate the new air and plate temperature. |
229 * First, calculate temperature difference between the room and the air in the |
307 */ |
230 * fridge. We use the volume air to roughly calculate the total area between |
308 if (simulator->cooler_present == DEVPRESENT_YES && simulator->cooler_power >= 50) { |
231 * the in and outside. Calculate the effect and shift the air temperature towards |
309 if (simulator->s_cool_temp > simulator->cooler_temp) { |
232 * the room temperature. |
310 simulator->s_cool_temp -= 0.05; |
233 */ |
311 if (simulator->s_cool_temp < air_temp) |
234 sqm_room_air = (cbrtl(simulator->volume_air) * cbrtl(simulator->volume_air) * 6) / 100; /* square meters all fridge sides */ |
312 air_temp -= ((air_temp - simulator->s_cool_temp) / 100.0); |
235 thick_room_air = 0.04; /* 4 cm walls */ |
|
236 k_room_air = 0.03; /* Polystrene */ |
|
237 air_heat_transfer=(k_room_air * sqm_room_air * (simulator->room_temperature - simulator->air_temperature)) / thick_room_air; |
|
238 air_change = (air_heat_transfer / (vhc_air * ((simulator->volume_air - simulator->volume_beer) * 1000))) / 60.0; |
|
239 simulator->air_temperature += air_change; |
|
240 |
|
241 /* |
|
242 * If heating, calculate temperature of the heating plate. If heating is off but |
|
243 * the plate is warmer then the air, calculate the cooling down temperature. |
|
244 * Finally, calculate the new air and plate temperature. |
|
245 */ |
|
246 if (SIMheating) { |
|
247 if (simulator->s_heat_temp < simulator->heater_temp) { |
|
248 simulator->s_heat_temp += 0.05; |
|
249 if (simulator->s_heat_temp > simulator->air_temperature) |
|
250 simulator->air_temperature += ((simulator->s_heat_temp - simulator->air_temperature) / 100.0); |
|
251 } |
|
252 } else { |
|
253 /* |
|
254 * Follow the air temperature |
|
255 */ |
|
256 simulator->s_heat_temp -= (simulator->s_heat_temp - simulator->air_temperature) / 25.0; |
|
257 } |
|
258 |
|
259 /* |
|
260 * If cooling, calculate temperature of the cooling plate. If cooling is off but |
|
261 * the plate is colder then the air, calculate the warming up temperature. |
|
262 * Finsally, calculate the new air and plate temperature. |
|
263 */ |
|
264 if (SIMcooling) { |
|
265 if (simulator->s_cool_temp > simulator->cooler_temp) { |
|
266 simulator->s_cool_temp -= 0.05; |
|
267 if (simulator->s_cool_temp < simulator->air_temperature) |
|
268 simulator->air_temperature -= ((simulator->air_temperature - simulator->s_cool_temp) / 100.0); |
|
269 } |
|
270 } else { |
|
271 simulator->s_cool_temp -= (simulator->s_cool_temp - simulator->air_temperature) / 25.0; |
|
272 } |
|
273 |
|
274 /* |
|
275 * Calculate final temperature of the beer and the air. |
|
276 */ |
|
277 // Cheap trick, just follow slowly the air temp. |
|
278 simulator->beer_temperature += ((simulator->air_temperature - simulator->beer_temperature) / 500.0); |
|
279 simulator->air_temperature += ((simulator->beer_temperature - simulator->air_temperature) / 2500.0); |
|
280 simulator->chiller_temperature = simulator->cooler_temp; // Libk these |
|
281 } |
313 } |
282 mDelay(100L); |
314 } else { |
283 } |
315 simulator->s_cool_temp -= (simulator->s_cool_temp - air_temp) / 25.0; |
284 mDelay(50L); |
316 } |
285 } |
317 |
286 |
318 /* |
287 syslog(LOG_NOTICE, "Thread my_simulator_loop stopped"); |
319 * Calculate final temperature of the beer and the air. |
288 my_simulator_state = 0; |
320 */ |
289 return 0; |
321 // Cheap trick, just follow slowly the air temp. |
290 } |
322 beer_temp += ((air_temp - beer_temp) / 500.0); |
|
323 air_temp += ((beer_temp - air_temp) / 2500.0); |
|
324 chiller_temp = simulator->cooler_temp; // Link these |
|
325 |
|
326 /* |
|
327 * Finally update simulated sensors with the new values. |
|
328 * The devices_loop will pickup the values and sets the resolution. |
|
329 */ |
|
330 if (air_temp != simulator->air_temperature) { |
|
331 // syslog(LOG_NOTICE, "SIM %d: air %f to %f", simulator->simno, simulator->air_temperature, air_temp); |
|
332 simulator->air_temperature = air_temp; |
|
333 changed = true; |
|
334 } |
|
335 if (beer_temp != simulator->beer_temperature) { |
|
336 // syslog(LOG_NOTICE, "SIM %d: beer %f to %f", simulator->simno, simulator->beer_temperature, beer_temp); |
|
337 simulator->beer_temperature = beer_temp; |
|
338 changed = true; |
|
339 } |
|
340 if (chiller_temp != simulator->chiller_temperature) { |
|
341 // syslog(LOG_NOTICE, "SIM %d: chiller %f to %f", simulator->simno, simulator->chiller_temperature, chiller_temp); |
|
342 simulator->chiller_temperature = chiller_temp; |
|
343 changed = true; |
|
344 } |
|
345 } |
|
346 SM_PROCEED(Websocket); |
|
347 |
|
348 SM_STATE(Websocket) |
|
349 |
|
350 if (my_simulator_shutdown) { |
|
351 SM_SUCCESS; |
|
352 } |
|
353 if (changed) { |
|
354 simulator_ws(); |
|
355 changed = false; |
|
356 } |
|
357 SM_PROCEED(Waiting); |
|
358 |
|
359 SM_END |
|
360 SM_RETURN |
291 |
361 |
292 |
362 |
293 #endif |
363 #endif |