Poor man's remote start/stop from phone

If you've made a patch to quick fix a bug or to add a new feature not yet in the main tree then post it here so others can try it out.
Post Reply
montagdude
Posts: 88
Joined: Fri Nov 10, 2017 6:05 pm

Poor man's remote start/stop from phone

Post by montagdude »

Here is the situation. In order for my wife to actually start ZoneMinder when she leaves home, she needs a minimal amount of navigating and waiting. And honestly, waiting on web pages to load, logging in, clicking a few links, etc. is a bit tedious for me too. So I did some brainstorming, and this is the best I could come up with, outside of some sort of X10 solution (which I may still look into). Here is what I have done:
  1. Set up my ZoneMinder server to be an SSH server as well. (Actually, it was that anyway, because I normally manage it remotely.)
  2. Download SFTP client apps for my phone and my wife's phone.
  3. Create empty files called start and stop on both phones in a location where they can be quickly accessed through the app.
  4. Set up profiles to transfer those files to a specified location on the server via the SFTP app.
  5. Run the following script on the server. All it does is periodically check for the existence of the start or stop file, and if one exists, it will send the appropriate start or stop command to ZoneMinder and delete the file.
Then, to start or stop ZoneMinder, all one needs to do is to upload the appropriate file through the SFTP app.

Code: Select all

#!/usr/bin/perl -w
#
# Checks if some files are present to automatically start or stop ZoneMinder.
#

use strict;
use warnings;
use ZoneMinder;

$| = 1;

# Interval between file checking cycles
my $timeout = 15;

# Start/stop files
my $startfile = "/home/backup/start";
my $stopfile = "/home/backup/stop";

# Delete if they exist to start
if ( fileExists( $startfile ) ) {
    unlink( $startfile );
}
if ( fileExists( $stopfile ) ) {
    unlink( $stopfile );
}

# Check if files exist and take appropriate action
while (1) {

    if ( fileExists( $startfile ) ) {
        my $runstate = runCommand( "zmdc.pl check" );
        if ( $runstate ne "running" ) {
            Info( "Starting ZoneMinder" );
            runCommand( "zmpkg.pl start" );
        }
        unlink( $startfile );
    }
    elsif ( fileExists( $stopfile ) ) {
        my $runstate = runCommand( "zmdc.pl check" );
        if ( $runstate eq "running" ) {
            Info( "Stopping ZoneMinder" );
            runCommand( "zmpkg.pl stop" );
        }
        unlink( $stopfile );
    }
    sleep $timeout;
}

sub fileExists {
    my $fname = shift;

    open( my $fh, "<", $fname ) or return( 0 );
    close( $fh );

    return( 1 );
}
It's definitely not perfect. It still requires several clicks to send the file, but there is no waiting for webpages to load and no logging in. If you leave the SFTP app open to the right location, it actually only requires a couple clicks to do the job. I think it might be quick enough that my wife will do it.

I am also open to other ideas. I know there is the zmNinja, which is probably more convenient to use on a mobile device than the website is, but I haven't tried it.It would be nice to be able to implement this solution through a bash script that can be launched with just a single click, but I don't think that's possible on my wife's iPhone without at least jailbreaking it, and we're not going to do that.
alabamatoy
Posts: 349
Joined: Sun Jun 05, 2016 2:53 pm

Re: Poor man's remote start/stop from phone

Post by alabamatoy »

I wrote* a php page which is login/pw protected by the webserver....but once you authenticate, your browser can cache the credentials so you dont have to do anything but click on the URL and then click login. The PHP page uses curl to display the runstate of ZM and let you change it to another saved runstate. Its in the form https:/ / yourdomain/zmrunstate.php?runstate=record_all or something like that.

It works pretty well from an android using Firefox, once you have authenticated the first time: Click on bookmark (I have different bookmarks for different runstates). Wait for a bit for ZM to change runstate. Swerve back onto the road to avoid hitting a stop sign. :-)

php can fire a system command, so you could use this same approach to start or stop zoneminder. I leave mine running all the time and just change the state. There are other posts on her that detail how to do this from your phone using the GPS of the phone to make a change when you arrive or leave, but I haven't tried that.

* - actually, I stole it from somewhere, but I forget where, probably on this forum somewhere.
alabamatoy
Posts: 349
Joined: Sun Jun 05, 2016 2:53 pm

Re: Poor man's remote start/stop from phone

Post by alabamatoy »

Code:
===============================================

Code: Select all

<!DOCTYPE html>
<html>
<body>

<h1>Changing runstate</h1>

<?php
try {
//variables
$tmpfname = tempnam ("/tmp", 'cookiename');
$runstate = htmlspecialchars($_GET["runstate"]);
$url1 = "https://your_zoneminder_domain_name/zm/index.php";
$url2 = "https://your_zoneminder_domain_name/zm/api/states/change/" . $runstate . ".json";
$url3 = "https://your_zoneminder_domain_name/zm/api/states.json";
$post = "username=SPECIAL_ACCOUNT&password=SPECIAL_ACCOUNT_PASSWORD&action=login&view=console";

//echo "url1 equals " . $url1 . "<br>";
//echo "url2 equals " . $url2 . "<br>";
//echo "post equals " . $post . "<br>";

//
//Authenticate
//

//open connection
$ch = curl_init();
    if (FALSE === $ch)
        throw new Exception('failed to initialize1');

//set the url, number of POST vars, POST data
curl_setopt($ch, CURLOPT_URL, $url1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
curl_setopt($ch, CURLOPT_COOKIEJAR,  $tmpfname );
curl_setopt($ch, CURLOPT_COOKIEFILE, $tmpfname );
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYSTATUS, false);
  
//execute post
$result = curl_exec($ch);
    if (FALSE === $result)
        throw new Exception(curl_error($ch), curl_errno($ch));

//close connection
curl_close($ch);

//
//Change Run State
//

//open connection
$ch = curl_init();
    if (FALSE === $ch)
        throw new Exception('failed to initialize2');

//set the url, number of POST vars, POST data
curl_setopt($ch, CURLOPT_URL, $url2);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_COOKIEJAR,  $tmpfname );
curl_setopt($ch, CURLOPT_COOKIEFILE, $tmpfname );
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYSTATUS, false);

//echo "CH equals " . $ch . "<br>";

//execute post
$result = curl_exec($ch);
    if (FALSE === $result) {
        throw new Exception(curl_error($ch), curl_errno($ch));
        echo "Appears to have failed, see system error log for details.<br>";
    }
    else {
        echo "Appears to have been successful, runstate should now be set to " . $runstate . "<br>"; 
//        echo "results are: <br><br>" . $result . "<br>";
//        $json = json_decode($result, true);
//        echo "json results are: <br><br>" . $json['success'] . "<br>";
    }
  
//close connection
curl_close($ch);
}

catch(Exception $e) {

    trigger_error(sprintf(
        'Curl failed with error #%d: %s',
        $e->getCode(), $e->getMessage()),
        E_USER_ERROR);
    }

?>

</body>
</html>
====================================

There are some commented debug writes still in there. Create a ZM user SPECIAL_ACCOUNT and enter that in the code. Set that account to have "system edit" and no other rights. YOu will need to have curl installed for this to work.
Post Reply