When my son wants to use the computer, we generally let him do so for a predetermined period of time (maybe a half hour or an hour). Trouble arises when he "forgets" when he logged in or "loses track of time".

So I wrote this script to remind him how long he has been logged in. It pops up a reminder in KDE after 30, 60, 90 and 120 minutes letting him know how long he has been using the computer.

As an added bonus, it sends a text to my phone at 2 hours, just incase the computer was left on.

#!/usr/local/bin/perl use strict; use warnings; use Carp; use User; use Sys::Lastlog; use Time::localtime; my $ll = Sys::Lastlog->new(); my $llent = $ll->getllnam( User->Login ); my $tm = localtime( $llent->ll_time() ); my $login_time = sprintf( "%02d:%02d:%02d on %04d/%02d/%02d", $tm->hour, $tm->min, $tm->sec, $tm->year + 1900, $tm->mon + 1, $tm->mday ); my %actions = ( 1800 => sub { passive_pop("Thirty minutes"); }, 3600 => sub { passive_pop("One hour"); }, 5400 => sub { passive_pop("One hour thirty minutes"); }, 7200 => sub { passive_pop("Two hours"); tattle_tail(); }, ); for my $duration ( sort { $a <=> $b } keys %actions ) { sleep 1 until time - $llent->ll_time >= $duration; $actions{$duration}->(); } sub passive_pop { my $m = shift @_; my @args = ( "kdialog", "--passivepopup", $m . " has passed since you logged in at:\n " . + $login_time, "120" ); system(@args) == 0 or croak "system @args failed: $?"; return; } sub tattle_tail { use MIME::Lite; my $msg = MIME::Lite->new( From => 'tattle_tail@domain.com', To => 'text@domain.com', Subject => 'The computer may have been left on', Data => 'Childname logged in at ' . $login_time, ); $msg->send; return; }

Improvements and comments welcome.

KennV

Updated to reflect blokheads suggestions.
Thanks blokhead!!

Replies are listed 'Best First'.
Re: Reminder for KDE Kid
by blokhead (Monsignor) on Sep 21, 2007 at 19:17 UTC
    In your main loop, you check that the time difference is exactly 1800, 3600, etc. seconds. This is a condition that is only true for one second. And since you are sleeping for a full second, it seems conceivable that if the system is very busy, your process may not get woken up from its sleep in that one-second window of opportunity.

    I might rewrite the loop in the following way to be sure that the action is triggered the first time the script is woken up after a target number of seconds.

    sleep 1 until time - $llent->ll_time >= 1800; passive_pop("Thirty minutes"); sleep 1 until time - $llent->ll_time >= 3600; passive_pop("One hour"); sleep 1 until time - $llent->ll_time >= 5400; passive_pop("Ninety minutes"); sleep 1 until time - $llent->ll_time >= 7200; passive_pop("Two hours"); tattle_tail();
    Or to be even fancier and extensible-er:
    my %actions = ( 1800 => sub { passive_pop("Thirty minutes"); }, 3600 => sub { passive_pop("Sixty minutes"); }, 5400 => sub { passive_pop("Ninety minutes"); }, 7200 => sub { passive_pop("Two hours"); tattle_tail(); }, # 8000 => sub { disable_network_interface(); }, # 9999 => sub { self_destruct(); } ); for my $duration (sort {$a <=> $b} keys %actions) { sleep 1 until time - $llent->ll_time >= $duration; $actions{$duration}->(); }
    Also, it appears that your code as written will loop forever. This may be fine if your KDE autostart things get automatically killed when he logs out, but is something to consider.

    blokhead

      Thanks blokhead!!

      KDE's autostart thing did kill the script on logout but there was no reason to keep it running after the last action. So thanks again.

      I think maybe next time I've got some free time I'll put the actions in a config file using YAML::Tiny or something. Then I can put the actions in a readable file in my home folder and not have to worry about being root and all that to alter the actions. However, I don't think I should put code in the config, so I'll have to figure that out. Time to start reading...

      KennV
      Why sleep 1 second at all? No use hogging up the CPU looping every second when you can simply sleep until the next event.
      my $last = 0; for my $duration (sort {$a <=> $b} keys %actions) { sleep($duration - $last); $last += $duration; $actions{$duration}->(); }
Re: Reminder for KDE Kid
by n8g (Sexton) on Sep 21, 2007 at 12:51 UTC

    My oldest son is just starting to use the computer to play his 'letter game' as he calls it. I can see this coming in handy soon. Just out of curiosity how do you kick this off and do you have it set up in such a way to prevent him from disabling it? I suppose it could turn into an arms race but he would certainly learn something in the process. It's not like an off the shelf solution that would have hacks posted for it all over the net.

    BTW, starfall is a nice educational site for young children.

      I just copied the script into ~/.kde/Autostart as alert_time.pl and
      chown root:root alert_time.pl chmod 755 alert_time.pl
      KennV
Re: Reminder for KDE Kid
by Zen (Deacon) on Oct 23, 2007 at 21:58 UTC
    If I was his age with a parent like that, I'd be using your 1 hour time given to defeat your attempts. Sounds like an interesting, educational arms race. :)
Re: Reminder for KDE Kid
by Incorporeal (Initiate) on Oct 31, 2007 at 10:21 UTC
    Really quite cool - how could this be made more compatible though? I guess use of Tk - what other solutions are viable to allow the dialog to function on other Linux desktop environments, or even other operating systems?