File Coverage

blib/lib/Acme/FishFarm.pm
Criterion Covered Total %
statement 130 150 86.6
branch 15 32 46.8
condition 1 3 33.3
subroutine 22 22 100.0
pod 12 12 100.0
total 180 219 82.1


line stmt bran cond sub pod time code
1             package Acme::FishFarm;
2              
3 2     2   183324 use 5.008;
  2         18  
4 2     2   14 use strict;
  2         5  
  2         76  
5 2     2   11 use warnings;
  2         4  
  2         69  
6 2     2   11 use Carp "croak";
  2         5  
  2         135  
7              
8 2     2   913 use Acme::FishFarm::Feeder;
  2         6  
  2         76  
9 2     2   1032 use Acme::FishFarm::OxygenMaintainer;
  2         6  
  2         64  
10 2     2   1019 use Acme::FishFarm::WaterConditionMonitor;
  2         6  
  2         100  
11 2     2   1133 use Acme::FishFarm::WaterLevelMaintainer;
  2         5  
  2         68  
12 2     2   972 use Acme::FishFarm::WaterFiltration;
  2         6  
  2         129  
13              
14             =head1 NAME
15              
16             Acme::FishFarm - A Fish Farm with Automated Systems
17              
18             =head1 VERSION
19              
20             Version 1.01
21              
22             =cut
23              
24             our $VERSION = '1.01';
25              
26              
27             =head1 SYNOPSIS
28              
29             use 5.010;
30              
31             use Acme::FishFarm ":all";
32              
33             my $water_monitor = Acme::FishFarm::WaterConditionMonitor->install;
34             my $oxygen = Acme::FishFarm::OxygenMaintainer->install( DO_generation_volume => 1.92 );
35              
36             $water_monitor->add_oxygen_maintainer( $oxygen );
37              
38             say "Water condition monitor installed...";
39             say "Oxygen maintainer installed and connected to water condition monitor...";
40             say "Water condition monitor switched on!";
41             say "";
42              
43             while ( "fish are swimming happily" ) {
44             ### DO
45             check_DO( $oxygen, reduce_precision( rand(8) ) );
46             say "";
47            
48             ### pH
49             check_pH( $water_monitor, 6.912 );
50             #check_pH( $water_monitor, 5.9 );
51             say "" ;
52            
53             ## temperature
54             #check_temperature( $water_monitor, 23 );
55             check_temperature( $water_monitor, 26 );
56             say "";
57            
58             ## turbidity
59             check_turbidity( $water_monitor, 120 );
60             #check_turbidity( $water_monitor, 190 );
61             say "";
62            
63             # all LEDs
64             render_leds( $water_monitor );
65             say "";
66            
67             # buzzers
68             render_buzzer( $water_monitor );
69            
70             sleep(3);
71             say "-----------------------------";
72             }
73            
74             =head1 EXPORT
75              
76             The C<:all> tag can be used to import all the subroutines available in this module.
77              
78             =cut
79              
80 2     2   18 use Exporter qw( import );
  2         4  
  2         3166  
81             our @EXPORT_OK = qw(
82             install_all_systems
83             reduce_precision consume_oxygen
84             check_DO check_pH check_temperature check_turbidity check_water_filter check_water_level check_feeder
85             render_leds render_buzzer
86             );
87             our %EXPORT_TAGS = (
88             all => [ qw( install_all_systems reduce_precision consume_oxygen check_DO check_pH check_temperature
89             check_turbidity check_water_filter check_water_level check_feeder render_leds
90             render_buzzer ) ],
91             );
92              
93             =head1 NOTES
94              
95             Almost all the subroutines in this module will give output. The unit measurements used will be according to the ones mentioned in C.
96              
97             =head1 SYSTEM INSTALLATION RELATED SUBROUTINES
98              
99             =head2 install_all_systems
100              
101             Installs all the available systems the default way and returns them as a list of C objects in the following sequence:
102              
103             (Feeder, OxygenMaintainer, WaterConditionMonitor, WaterLevelMaintainer, WaterFiltration)
104              
105             =cut
106              
107             sub install_all_systems {
108 1     1 1 106 my $feeder = Acme::FishFarm::Feeder->install;
109 1         10 my $oxygen_maintainer = Acme::FishFarm::OxygenMaintainer->install;
110 1         10 my $water_monitor = Acme::FishFarm::WaterConditionMonitor->install;
111 1         9 my $water_level = Acme::FishFarm::WaterLevelMaintainer->install;
112 1         10 my $water_filter = Acme::FishFarm::WaterFiltration->install;
113            
114             # remember to connect water oxygem maintainer to water condition monitoring :)
115 1         7 $water_monitor->add_oxygen_maintainer( $oxygen_maintainer );
116            
117 1         7 ( $feeder, $oxygen_maintainer, $water_monitor, $water_level, $water_filter );
118             }
119              
120              
121             =head1 SENSOR READING RELATED SUBROUTINES
122              
123             =head2 reduce_precision ( $decimal )
124              
125             Reduces positive or negative C<$decimal> to a 3-decimal value. Make sure to pass in a decimal with more than 3 decimal points.
126              
127             Returns the reduced precision value.
128              
129             This subroutine is useful if you are trying to set the current sensor readings randomly using the built-in C function as you do not want to end up with too many decimals on the screen.
130              
131             =cut
132              
133             sub reduce_precision {
134 3     3 1 3844 my $sensor_reading = shift;
135 3 100       230 croak "Please pass in a decimal value" if not $sensor_reading =~ /\./;
136            
137 2         15 $sensor_reading =~ /(-?\d+\.\d{3})/;
138 2         13 return $1;
139             }
140              
141             =head1 AUTOMATED SYSTEMS RELATED SUBROUTINES
142              
143             All of the subroutines here will give output.
144              
145             Take note that there are some systems that can't be connected to the water monitoring system and therefore will not effect the LEDs or buzzers. These systems are:
146              
147             =over 4
148              
149             =item * Acme::FishFarm::Feeder
150              
151             =item * Acme::FishFarm::WaterFiltration
152              
153             =item * Acme::FishFarm::WaterLevelMaintainer
154              
155             =back
156              
157             =head2 consume_oxygen ( $oxygen_maintainer, $consumed_oxygen )
158              
159             This will cause the oxygen level (DO level) of the C to reduce by C<$consumed_oxygen mg/L>
160              
161             Returns 1 upon success.
162             =cut
163              
164             sub consume_oxygen {
165 2     2 1 5 my $o2_maintainer = shift;
166 2         4 my $consumed_oxygen = shift;
167 2         36 print "$consumed_oxygen mg/L of oxygen consumed...\n";
168 2         13 my $o2_remaining = $o2_maintainer->current_DO - $consumed_oxygen;
169 2         13 $o2_maintainer->current_DO( $o2_remaining );
170 2         10 1;
171             }
172              
173             =head2 check_DO ( $oxygen_maintainer, $current_DO_reading )
174              
175             This checks and outputs the condition of the current DO level.
176              
177             Take note that this process will trigger the LED and buzzer if abnormal condition is present.
178              
179             Returns 1 upon success.
180             =cut
181              
182             sub check_DO {
183 1     1 1 4 my ( $oxygen, $current_reading ) = @_;
184 1         5 my $DO_threshold = $oxygen->DO_threshold;
185              
186 1         4 $oxygen->current_DO( $current_reading );
187 1         5 $oxygen->is_low_DO;
188            
189 1         16 print "Current Oxygen Level: ", $current_reading, " mg/L",
190             " (low: < ", $DO_threshold, ")\n";
191              
192 1 50       5 if ( $oxygen->is_low_DO ) {
193 0         0 print " !! Low oxygen level!\n";
194             } else {
195 1         8 print " Oxygen level is normal.\n";
196             }
197 1         7 1;
198             }
199              
200             =head2 check_pH ( $water_monitor, $current_ph_reading )
201              
202             This checks and outputs the condition of the current pH value.
203              
204             Take note that this process will trigger the LED and buzzer if abnormal condition is present.
205              
206             Returns 1 upon success.
207              
208             =cut
209              
210             sub check_pH {
211 1     1 1 4 my ( $water_monitor, $current_reading ) = @_;
212 1         8 my $ph_range = $water_monitor->ph_threshold;
213            
214 1         6 $water_monitor->current_ph( $current_reading );
215 1         7 $water_monitor->ph_is_normal;
216            
217 1         3 print "Current pH: ", $water_monitor->current_ph,
218             " (normal range: ", $ph_range->[0], "~", $ph_range->[1], ")\n";
219              
220 1 50       7 if ( !$water_monitor->ph_is_normal ) {
221 1         9 print " !! Abnormal pH!\n";
222             } else {
223 0         0 print " pH is normal.\n";
224             }
225 1         6 1;
226             }
227              
228             =head2 check_temperature ( $water_monitor, $current_temperature_reading )
229              
230             This checks and outputs the condition of the current temperature.
231              
232             Take note that this process will trigger the LED and buzzer if abnormal condition is present.
233              
234             Returns 1 upon success.
235              
236             =cut
237              
238             sub check_temperature {
239 1     1 1 4 my ( $water_monitor, $current_reading ) = @_;
240 1         5 my $temperature_range = $water_monitor->temperature_threshold;
241              
242 1         16 $water_monitor->current_temperature( $current_reading );
243 1         5 $water_monitor->temperature_is_normal;
244            
245 1         5 print "Current temperature: ", $water_monitor->current_temperature, " C",
246             " (normal range: ", $temperature_range->[0], " C ~ ", $temperature_range->[1], " C)\n";
247              
248 1 50       8 if ( !$water_monitor->temperature_is_normal ) {
249 0         0 print " !! Abnormal temperature!\n";
250             } else {
251 1         10 print " Temperature is normal.\n";
252             }
253 1         7 1;
254             }
255              
256             =head2 check_turbidity ( $water_monitor, $current_turbidity_reading )
257              
258             This checks and outputs the condition of the current temperature.
259              
260             Take note that this process will trigger the LED and buzzer if abnormal condition is present.
261              
262             Returns 1 upon success.
263              
264             =cut
265              
266             sub check_turbidity {
267 1     1 1 3 my ( $water_monitor, $current_reading ) = @_;
268 1         5 my $turbidity_threshold = $water_monitor->turbidity_threshold;
269              
270 1         6 $water_monitor->current_turbidity( $current_reading );
271            
272 1         3 print "Current Turbidity: ", $water_monitor->current_turbidity, " ntu",
273             " (dirty: > ", $turbidity_threshold, ")\n";
274              
275 1 50       6 if ( $water_monitor->water_dirty ) {
276 1         8 print " !! Water is dirty!\n";
277             } else {
278 0         0 print " Water is still clean.\n";
279             }
280 1         8 1;
281             }
282              
283              
284             =head2 check_water_filter ( $water_filter, $current_waste_count, $reduce_waste_by )
285              
286             This checks, performs necessary actions and outputs the condition of the current waste count in the filtering cylinder.
287              
288             Take note that this process B trigger the LED and buzzer if abnormal condition is present.
289              
290             Returns 1 upon success.
291              
292             =cut
293              
294             sub check_water_filter {
295 1     1 1 3 my $water_filter = shift;
296 1         2 my $current_reading = shift;
297 1   33     18 my $reduce_waste_by = shift || $water_filter->reduce_waste_count_by;
298 1         5 my $waste_threshold = $water_filter->waste_count_threshold;
299            
300 1         5 $water_filter->current_waste_count( $current_reading );
301 1         13 print "Waste Count to Reduce: ", $water_filter->reduce_waste_count_by, "\n";
302 1         11 print "Current Waste Count: ", $current_reading, " (high: >= ", $waste_threshold, ")\n";
303              
304 1 50       6 if ( $water_filter->is_cylinder_dirty ) {
305 1         68 print " !! Filtering cylinder is dirty!\n";
306 1         10 $water_filter->turn_on_spatulas;
307 1         7 print " Cleaning spatulas turned on.\n";
308 1         7 $water_filter->clean_cylinder( $reduce_waste_by );
309 1         8 print " Cleaning the cylinder...Done!\n";
310 1         6 print "Current waste count: ", $water_filter->current_waste_count, "\n";
311             } else {
312 0         0 print " Filtering cylinder is still clean.\n";
313             }
314 1         6 1;
315             }
316              
317             =head2 check_water_level ( $water_level_maintainer, $current_water_level )
318              
319             This checks, performs necessary actions and outputs the condition of the current waste count in the filtering cylinder.
320              
321             Take note that this process B trigger the LED and buzzer if abnormal condition is present.
322              
323             Returns 1 upon success.
324              
325             =cut
326              
327             sub check_water_level {
328 1     1 1 3 my $water_level = shift;
329 1         2 my $current_reading = shift;
330 1         7 my $height_increase = $water_level->water_level_increase_height; # for output
331 1         5 my $water_level_threshold = $water_level->low_water_level_threshold;
332            
333 1         6 $water_level->current_water_level( $current_reading ); # input by user
334 1         12 print "Current Water Level: ", $current_reading, " m (low: < ", $water_level_threshold, " m)\n";
335              
336 1 50       6 if ( $water_level->is_low_water_level ) {
337 1         8 print " !! Water level is low!\n";
338 1         7 $water_level->pump_water_in;
339 1         14 print " Pumping in ", $height_increase, " m of water...\n";
340 1         6 print "Current Water Level: ", $water_level->current_water_level, " m\n";
341             } else {
342 0         0 print " Water level is still normal.\n";
343             }
344 1         7 1;
345             }
346              
347             =head2 check_feeder ( $feeder, $verbose )
348              
349             This checks, performs necessary actions and outputs the condition of the feeder. Each call will tick the clock inside the feeder. See C for more info.
350              
351             If the food tank is empty, it will be filled to the default. So if you want to fill a different amount, please set the amount before hand. See C.
352              
353             Setting C<$verbose> to 1 will give more output about the empty food tank.
354              
355             Take note that this process B trigger the LED and buzzer if abnormal condition is present.
356              
357             Returns 1 upon success.
358              
359             =cut
360              
361             sub check_feeder {
362 2     2 1 5 my ( $feeder, $verbose ) = @_;
363 2 50       10 if ( $feeder->timer_is_up ) {
364 0         0 print "Timer is up, time to feed the fish!\n";
365            
366 0 0       0 if ( $verbose) {
367 0         0 $feeder->feed_fish( verbose => 1 );
368             } else {
369 0         0 $feeder->feed_fish;
370             }
371 0         0 print " Feeding ", $feeder->feeding_volume, " cm^3 of fish food to the fish...\n";
372            
373             } else {
374 2         7 print $feeder->time_remaining, " hours left until it's time to feed the fish.\n";
375             }
376            
377 2 50       11 if ( $feeder->food_remaining <= 0 ) {
378 0         0 print " !! Food tank empty!\n";
379 0         0 $feeder->refill; # default back to 500 cm^3
380 0         0 print " Refilled food tank back to ", $feeder->food_tank_capacity, " cm^3.\n";
381             }
382              
383 2         7 print " Food Remaining: ", $feeder->food_remaining, "cm^3.\n";
384            
385 2         11 $feeder->tick_clock;
386 2         8 1;
387             }
388              
389             =head2 render_leds ( $water_monitor )
390              
391             Outputs which LEDs are lighted up. Returns 1 upon success.
392              
393             Currently this subroutine only shows the LEDs present in the C object. See that module for more details about the available LEDs.
394              
395             More LEDs will be available in the future.
396              
397             =cut
398              
399             sub render_leds {
400 1     1 1 4 my $water_monitor = shift;
401              
402             # must check condition first! If not it won't work
403             # this process will update the LEDs status
404 1         7 $water_monitor->ph_is_normal;
405 1         5 $water_monitor->temperature_is_normal;
406 1         5 $water_monitor->lacking_oxygen;
407 1         5 $water_monitor->water_dirty;
408            
409 1         3 print "Total LEDs up: ", $water_monitor->lighted_LED_count, "\n";
410              
411 1 50       8 if ( $water_monitor->is_on_LED_pH ) {
412 1         8 print " pH LED: on\n";
413             } else {
414 0         0 print " pH LED: off\n";
415             }
416            
417 1 50       6 if ( $water_monitor->is_on_LED_temperature ) {
418 0         0 print " Temperature LED: on\n";
419             } else {
420 1         8 print " Temperature LED: off\n";
421             }
422            
423 1 50       7 if ( $water_monitor->is_on_LED_DO ) {
424 0         0 print " Low DO LED: on\n";
425             } else {
426 1         8 print " Low DO LED: off\n";
427             }
428            
429 1 50       6 if ( $water_monitor->is_on_LED_turbidity ) {
430 1         7 print " Turbidity LED: on\n";
431             } else {
432 0         0 print " Turbidity LED: off\n";
433             }
434 1         7 1;
435             }
436              
437             =head2 render_buzzer ( $water_monitor )
438              
439             Outputs which buzzer is buzzing. Returns 1 upon success.
440              
441             See C for details on how the short and long buzzers are switched on and off.
442              
443             =cut
444              
445             sub render_buzzer {
446 1     1 1 2 my $water_monitor = shift;
447            
448             #$water_monitor->_tweak_buzzers;
449 1 50       6 if ( $water_monitor->is_on_buzzer_long ) {
    0          
450 1         10 print "Long buzzer is on, water condition very critical!\n";
451             } elsif ( $water_monitor->is_on_buzzer_short ) {
452 0         0 print "Short buzzer is on, water condition is a bit worrying :|\n";
453             } else {
454 0         0 print "No buzzers on, what a peaceful moment.\n";
455             }
456 1         6 1;
457             }
458              
459              
460             =head1 AUTHOR
461              
462             Raphael Jong Jun Jie, C<< >>
463              
464             =head1 BUGS
465              
466             Please report any bugs or feature requests to C, or through
467             the web interface at L. I will be notified, and then you'll
468             automatically be notified of progress on your bug as I make changes.
469              
470              
471              
472              
473             =head1 SUPPORT
474              
475             You can find documentation for this module with the perldoc command.
476              
477             perldoc Acme::FishFarm
478              
479              
480             You can also look for information at:
481              
482             =over 4
483              
484             =item * RT: CPAN's request tracker (report bugs here)
485              
486             L
487              
488             =item * CPAN Ratings
489              
490             L
491              
492             =item * Search CPAN
493              
494             L
495              
496             =back
497              
498              
499             =head1 ACKNOWLEDGEMENTS
500              
501             Besiyata d'shmaya
502              
503             =head1 SEE ALSO
504              
505             Acme::FishFarm::Feeder
506              
507             Acme::FishFarm::OxygenMaintainer
508              
509             Acme::FishFarm::WaterConditionMonitor
510              
511             Acme::FishFarm::WaterFiltration
512              
513             Acme::FishFarm::::WaterLevelMaintainer
514              
515             =head1 LICENSE AND COPYRIGHT
516              
517             This software is Copyright (c) 2021 by Raphael Jong Jun Jie.
518              
519             This is free software, licensed under:
520              
521             The Artistic License 2.0 (GPL Compatible)
522              
523              
524             =cut
525              
526             1; # End of Acme::FishFarm