App-RPi-EnvUI

 view release on metacpan or  search on metacpan

Changes  view on Meta::CPAN

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

README  view on Meta::CPAN

    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.

README  view on Meta::CPAN

    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);
    });

src/db.sql  view on Meta::CPAN


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",

t/10-db.t  view on Meta::CPAN

    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){



( run in 1.619 second using v1.01-cache-2.11-cpan-49f99fa48dc )