view release on metacpan or search on metacpan
Changes history for App::RPi::EnvUI
0.30 2017-12-21
- this will be the last beta release. The next release will be 1.00,
will be stable, and will have proper documentation
- the env_to_db() Event will now restart itself if it crashes
- significant modifications to the API action_light() infrastructure...
we use DateTime objects now, per stevieb9/scripts/perl/light_timer
- code cleanup
- fix void assignment of hash in API
- DateTime objects are now properly set in the class scope for
action_light()
- updated t/50 with newer tests; we now perform tests to ensure that if
the on/off cycle completes within the same 24 hour period, the next
"on" time will be pushed to the following day
- updated the timezone in the src config file and db to
America/Vancouver
- fix issue where in test mode, Events aren't created and stored into
can be used external to the web app itself.
***NOTE*** This distribution is still in heavy development. It will
unit test on any *nix PC, but at this time, it will only run correctly
on a Raspberry Pi with wiringPi <http://wiringpi.com> installed. We
also require sudo to run the webapp, due to limitations in other
software I rely upon, but I've got fixes in the works to eliminate the
sudo requirement.
This distribution reads environmental sensors, turns on/off devices
based on specific thresholds, contains an adjustable grow light timer,
as well as feeding timers.
The software connects to Raspberry Pi GPIO pins for each "auxillary",
and at specific times or thresholds, turns on and or off the 120/240v
devices that you've relayed to that voltage (if you choose to use this
functionality).
Whether or not you connect/use the automation functionality, the web UI
is a one-page app that relies on jQuery/Javascript to pull updates from
the server, push changes to the server, and display up-to-date live
information relating to all functionality.
browsers open to the app's UI page will render updates at the same
time, regardless if another browser or the automation makes any
changes.
WHAT IT DOES
Reads temperature and humidity data via a hygrometer sensor through the
RPi::DHT11 distribution.
It then allows, through a one-page asynchronous web UI to turn on and
off 120/240v devices through buttons, timers and reached threshold
limits.
For example. We have a max temperature limit of 80F. We assign an
auxillary (GPIO pin) that is connected to a relay to a 120v exhaust
fan. Through the configuration file, we load the temp limit, and if the
temp goes above it, we enable the fan via the GPIO pin.
To prevent the fan from going on/off repeatedly if the temp hovers at
the limit, a minimum "on time" is also set, so by default, if the fan
turns on, it'll stay on for 30 minutes, no matter if the temp drops
lib/App/RPi/EnvUI.pm view on Meta::CPAN
*** Note that my focus hasn't been one about detailed security, so please, if
you desire to test this software, ensure it is not Internet facing, and you have
adequate protection from undesired access ***
A self-contained, one-page web application that runs on a Raspberry Pi and
monitors and manages an indoor grow room environment, with an API that can be
used external to the web app itself.
This distribution reads environmental sensors, turns on/off devices based on
specific thresholds, contains an adjustable grow light timer, and five extra
auxillary channels that you can configure for your own use.
The software connects to Raspberry Pi GPIO pins for each C<"auxillary">, and at
specific times or thresholds, turns on and or off the 120/240v devices that
you've relayed to that voltage (if you choose to use this functionality).
=head1 WHAT IT DOES
Reads temperature and humidity data via a hygrometer sensor through the
L<RPi::DHT11> distribution.
It then allows, through a one-page asynchronous web UI to turn on and off
120/240v devices through buttons, timers and reached threshold limits.
For example. We have a max temperature limit of 80F. We assign an auxillary
(GPIO pin) that is connected to a relay to a 120v exhaust fan. Through the
configuration file, we load the temp limit, and if the temp goes above it, we
enable the fan via the GPIO pin.
To prevent the fan from going on/off repeatedly if the temp hovers at the limit,
a minimum "on time" is also set, so by default, if the fan turns on, it'll stay
on for 30 minutes, no matter if the temp drops back below the limit.
lib/App/RPi/EnvUI/API.pm view on Meta::CPAN
$state
Optional, Bool. C<0> to turn the pin off (C<LOW>), or C<1> to turn it on
(C<HIGH>).
Return: Bool. Returns the current state of the aux pin.
=head2 aux_time($aux_id, $time)
Sets/gets the length of time an auxillary channel's GPIO pin has been C<HIGH>
(on). Mainly used to determine timers.
Parameters:
$aux_id
Mandatory, String. The string name of an auxillary channel (eg: C<aux1>).
$time
Optional, output from C<time()>. If sent in, we'll set the start time of a pin
on event to this.
Return, Integer (seconds). Returns the elapsed time in seconds since the last
timestamp was sent in with the C<$time> parameter, after being subtracted with
a current C<time()> call. If C<$time> has not been sent in, or an internal timer
has reset this value, the return will be zero (C<0>).
=head2 config($conf_file)
Sets/gets the currently loaded configuration file.
Parameters:
$conf_file
lib/App/RPi/EnvUI/Configuration.pod view on Meta::CPAN
=head1 CONFIGURATIIION OPTIONS
Configure options are separated into separate sections based on their purpose.
=head2 CORE CONFIGURATION SECTION
The C<core> configuration section contains the following configuration
directives, which pertain to the core operation of the system.
=head3 event_fetch_timer
Value: Integer, the number of seconds we'll poll the environment sensors and
update the database with the new information.
Default: C<15>
=head3 event_action_timer
Value: Integer, representing the interval (seconds) that the server will read
the current state of the system, and will enable/disable any functional GPIO
pins.
Default: C<3>
=head3 event_display_timer
Value: Integer, representing the interval (seconds) that the client UI will
automatically refresh the page (asynchronously).
Default: C<4>
=head3 time_zone
Value: A time zone as accepted by L<DateTime>'s C<new()> method's C<time_zone>
parameter.
lib/App/RPi/EnvUI/Event.pm view on Meta::CPAN
my $api = App::RPi::EnvUI::API->new(
testing => $self->{testing},
test_mock => 0
);
$api->{db} = $db;
$self->{db} = $db;
$self->{timeout} = $api->_config_control('event_timeout');
my $event = Async::Event::Interval->new(
$api->_config_core('event_fetch_timer'),
sub {
local $SIG{ALRM} = sub { kill 9, $$; };
alarm $self->{timeout};
my ($temp, $hum) = $api->read_sensor;
alarm 0;
$api->env($temp, $hum);
},
);
return $event;
lib/App/RPi/EnvUI/Event.pm view on Meta::CPAN
my $db = App::RPi::EnvUI::DB->new(testing => $self->{testing});
my $api = App::RPi::EnvUI::API->new(
testing => $self->{testing},
test_mock => 0
);
$api->{db} = $db;
$self->{db} = $db;
my $event = Async::Event::Interval->new(
$api->_config_core('event_action_timer'),
sub {
my $t_aux = $api->env_temp_aux;
my $h_aux = $api->env_humidity_aux;
$api->action_temp($t_aux, $api->temp);
$api->action_humidity($h_aux, $api->humidity);
$api->action_light
if $api->_config_light('enable');
}
public/js/core.js view on Meta::CPAN
"use strict";
var temp_limit = -1;
var humidity_limit = -1;
var logged_in;
var graph_event = null; // graph interval timer
$(document).on('pageshow', '#home', function(){
// authentication
$.ajax({
async: false,
type: 'GET',
url: '/logged_in',
success: function(data){
public/js/core.js view on Meta::CPAN
$(document).on('pagebeforehide', '#stats', function(){
clearInterval(graph_event);
});
// external functions
// events
function event_interval(){
$.get('/get_config/event_display_timer', function(interval){
interval = interval * 1000;
setInterval(display_env, interval);
});
}
// core functions
function aux_update(){
display_time();
public/js/core.js view on Meta::CPAN
$('div.ui-page-active #humidity').text(humidity +' %');
$('div.ui-page-active #humidity_limit').text('Limit: ' + humidity_limit);
}
// statistics page JS
// events
function graph_interval(){
$.get('/get_config/event_display_timer', function(interval){
interval = interval * 1000;
graph_event = setInterval(display_graphs, interval);
});
}
function display_graphs(){
$.get('/graph_data', function(data){
var graph_data = $.parseJSON(data);
create_graphs(graph_data);
});
INSERT INTO control VALUES ('event_timeout', '60');
DROP TABLE IF EXISTS core;
CREATE TABLE core (
id VARCHAR(20),
value VARCHAR(50)
);
INSERT INTO core VALUES ('event_fetch_timer', 15);
INSERT INTO core VALUES ('event_action_timer', 3);
INSERT INTO core VALUES ('event_display_timer', 4);
INSERT INTO core VALUES ('time_zone', 'America/Vancouver');
INSERT INTO core VALUES ('sensor_pin', -1);
INSERT INTO core VALUES ('testing', 0);
INSERT INTO core VALUES ('debug_sensor', 0);
INSERT INTO core VALUES ('log_file', "");
INSERT INTO core VALUES ('debug_level', -1);
INSERT INTO core VALUES ('devel', 0);
DROP TABLE IF EXISTS light;
src/envui-dist.json view on Meta::CPAN
{
"core": {
"event_fetch_timer": "15",
"event_action_timer": "3",
"event_display_timer": "4",
"time_zone": "America/Vancouver",
"sensor_pin": "-1",
"testing": "0",
"debug_sensor": "0",
"log_file": "",
"debug_level": "-1",
"devel": "0"
},
"control": {
"temp_limit": "80",
for (@directives){
my $value = $db->config_control($_);
is $value, $values[$i], "control $_ has value $values[$i] by default";
$i++;
}
}
{ # config_core()
my @directives = qw(
event_fetch_timer event_action_timer event_display_timer
sensor_pin testing time_zone
);
my @values = qw(
15 3 4 -1 0 America/Vancouver
);
my $i = 0;
for (@directives){
t/100-events.t view on Meta::CPAN
return_value => 20
);
is ref $evt, 'App::RPi::EnvUI::Event', "new() returns a proper object";
is $api->testing, 1, "testing param to new() ok";
#FIXME: add tests to test overrides for hum and temp
# mock out some subs that rely on external C libraries
# set the event timers
$db->update('core', 'value', 1, 'id', 'event_fetch_timer');
my $f = $api->_config_core('event_fetch_timer');
is $f, 1, "event_fetch_timer set ok for testing";
$db->update('core', 'value', 1, 'id', 'event_action_timer');
my $a = $api->_config_core('event_action_timer');
is $a, 1, "event_action_timer set ok for testing";
# configure pins
my $taux = $api->env_temp_aux;
my $tpin = $api->aux_pin($taux, 0);
is $tpin, 0, "set temp aux to pin for testing ok";
my $haux = $api->env_humidity_aux;
my $hpin = $api->aux_pin($haux, 0);
is $hpin, 0, "set humidity aux to pin for testing ok";
t/210-route_get_config.t view on Meta::CPAN
use lib "$FindBin::Bin/../lib";
use HTTP::Request::Common;
use Plack::Test;
use App::RPi::EnvUI;
my $test = Plack::Test->create(App::RPi::EnvUI->to_app);
{
my @directives = qw(
event_fetch_timer event_action_timer event_display_timer
sensor_pin testing time_zone
);
my @values = qw(
15 3 4 -1 0 America/Vancouver
);
is @directives, @values, "test configuration ok";
my $i = 0;
t/30-api_config.t view on Meta::CPAN
for (@directives){
my $value = $api->_config_control($_);
is $value, $values[$i], "control $_ has value $values[$i] by default";
$i++;
}
}
{ # config_core()
my @directives = qw(
event_fetch_timer event_action_timer event_display_timer
sensor_pin testing time_zone
);
my @values = qw(
15 3 4 -1 0 America/Vancouver
);
my $i = 0;
for (@directives){