motioneye-project / motioneye

A web frontend for the motion daemon.
GNU General Public License v3.0
4.01k stars 662 forks source link

Feature requests/ideas: MotionEye activation by leaving home (using smartphone detection) #203

Open 4eversr opened 8 years ago

4eversr commented 8 years ago

Hello from germany, some ideas/features i would like to see in a future motioneye release.

1.) I would like to have the possibility, that the cameras/motion detection are only active, when i am not at home. So perhaps it is possible to detect, if my smartphone is on the local wifi network or bluetooth area by e.g. send a ping to the local ip address of my smartphone or use some kind of gps fencing ? So when i am at home, motioneye is completely deactivated and when i (and my smartphone) are not in the local wireless network, motioneye starts with motion detection and mail notification. That would be the best feature ever... :) 2.) I am planning to add a real, physical "camera lens cover" to my raspberry which is activated by a little carson servo engine to make 100% sure, that no one can observe me, when i am at home and the camera should be deactivated. This automated lens cover can also be triggered by "smartphone is in home area"-detection via the GPIO pins.. (See http://tutorials-raspberrypi.de/raspberry-pi-servo-motor-steuerung/ for details) 3.) I am also planning to add some "camera is active" status light/LED some meters away from the camera, which notifies me without attracting attention, that the camera is activated, but do not show some burglars the direct way to the place where the raspberry camera is hidden. Therefore it would be perfect, if motioneye is able to put a GPIO pin of the respberry on, when the camera is active (and off, when it is not)-

elliopitas commented 8 years ago

i like the first idea you can put your phone a static ip address and ping ever x amount of time to that ip address which both time and ip will be specified in the web gui

best feature ever!!!

4eversr commented 8 years ago

...and of course, when the "smartphone ping"-thing is integrated, ít can do a "ping to the smartphone" first, whenever it detects a motion, so when the ping-request gets an response from the smartphone motioneye can ignore the previous motion and have not to send a "false positive" mail notification.

influenced commented 8 years ago

I do exactly this, with a few extra bells and whistles. Well OK, one extra bell and/or whistle - I also control some of the lights. I have the following script running as a cronjob under root on my Raspberry Pi, which activates/deactivates the service (and hence the entire website) and also turns on/off lights at certain hours of the day if the service is running (i.e. nobody is home).

I've set 192.168.1.20 and .30 as the static IPs for the two phones that control it on my router; you can add as many as you like into the array. It's a tiny bit hard-coded (the lights for cameras 2 and 3) but it shouldn't be particularly hard to change or remove that functionality, which is directly calling the same scripts that motioneye uses for action buttons - see https://github.com/ccrisan/motioneye/wiki/Action-Buttons

Also note that the test for whether the service is running is systemd specific; shouldn't be too hard to rewrite it for the older service styles.

#!/bin/bash

#if this is reachable the LAN is working (there are probably better ways of checking but I am v. lazy)
router_ip="192.168.1.1"

#if any of these IPs are reachable, someone is home
phone_ips=("192.168.1.20" "192.168.1.30")

function lights_off
{
  /etc/motioneye/light_off_2
  /etc/motioneye/light_off_3
}

function lights_on
{
  /etc/motioneye/light_on_2
  /etc/motioneye/light_on_3
}

function lights_check
{
    hr=`date +%H`
    case $hr in
      0[1-7,0]|1[7-9]|2*)
        lights_on
        ;;
      *)
        lights_off
        ;;
    esac
}

#only run if LAN is up
ping -c 1 $router_ip &>/dev/null || exit 0

#check for phones
phones_present=0
for phone in "${phone_ips[@]}"
do
  ping -c 1 $phone &>/dev/null && phones_present=1
done

if systemctl -q is-active motioneye.service ; then
  # service is up
  if [[ $phones_present -eq 1 ]] ; then
    # someone is home, stop service
    systemctl stop motioneye.service
    lights_off
  else
    lights_check
  fi

else
  # service is down
  if [[ $phones_present -eq 0 ]] ; then
    # nobody home, start service
    systemctl start motioneye.service
    lights_check
  fi
fi

Just save the script in /etc/motioneye as autoactivate.sh, set the executable flag (sudo chmod a+x autoactivate.sh) and use sudo crontab -e to run it every 5 minutes with this expression:

*/5 * * * * /etc/motioneye/autoactivate.sh

You can (e.g.) easily change /5 to /15 to run it every 15 minutes, or read up on cron expressions to do something more sophisticated (such as run Mon-Fri).

influenced commented 8 years ago

Oh right, and the expression 0[1-7,0]|1[7-9]|2*) in check_lights is checking for any hour between 00 and 07, then 17-19, then any hour from 20 onwards - if that's the time, the lights are turned on, otherwise they're turned off. Easily changed.

One last thing: that first comment - #!/bin/bash - is important and has to be the very first line, as it tells the script to run under bash; that script likely won't run under sh (or possibly other shells). For one thing, I'm using bash-syntax tests and loops; for another, the &> redirection won't work under sh.

influenced commented 8 years ago

If you don't want the extra light functionality, here's a simplified version that just turns motioneye on or off:

#!/bin/bash

#if this is reachable the LAN is working (there are probably better ways of checking but I am v. lazy)
router_ip="192.168.1.1"

#if any of these IPs are reachable, someone is home
phone_ips=("192.168.1.20" "192.168.1.30")

#only run if LAN is up
ping -c 1 $router_ip &>/dev/null || exit 0

#check for phones
phones_present=0
for phone in "${phone_ips[@]}"
do
  ping -c 1 $phone &>/dev/null && phones_present=1
done

if systemctl -q is-active motioneye.service ; then
  # service is up
  if [[ $phones_present -eq 1 ]] ; then
    # someone is home, stop service
    systemctl stop motioneye.service
  fi
else
  # service is down
  if [[ $phones_present -eq 0 ]] ; then
    # nobody home, start service
    systemctl start motioneye.service
  fi
fi
elliopitas commented 8 years ago

nice i hope this feature gets aded to the web gui @ccrisan

petermolnar commented 8 years ago

I'd add a few notes here: pinging the device is a good way, there is an altenative one, if you happen to run dd-wrt or openwrt on your router:

From here you have the list of connected MAC addresses which might be just as good as the IP addresses, in case the IPs float for some reason.

Squal78 commented 8 years ago

Hello, I've improved Influenced's script for my usage with this one. It aims to start/stop detection by updating the thread-x.conf file. It stops motioneye / update motion_detection param / start motioneye

Then I will try to create an rest api with node-red to call this script from an url

#!/bin/bash
# Status should received on/off
status=$1

TARGET_KEY="# @motion_detection"
CamConfFile="/etc/motioneye/thread-3.conf"

if [[ $status = "off" ]] ; then
   systemctl stop motioneye.service
   sed -i "s/\($TARGET_KEY * *\).*/\1$status/" $CamConfFile
   systemctl start motioneye.service
elif [[ $status = "on" ]] ; then
   systemctl stop motioneye.service
   sed -i "s/\($TARGET_KEY * *\).*/\1$status/" $CamConfFile
   systemctl start motioneye.service
fi
influenced commented 8 years ago

Neat! Slight improvements: the if test serves no purpose there (other than perhaps validating that status is "on" or "off") - you do the same thing in both cases. And the regex can be improved slightly so that it handles whitespace better (note that I also changed TARGET_KEY to not include the start of comment, moving that to the regex):

#!/bin/bash
# Status should received on/off
status=$1

TARGET_KEY="@motion_detection"
CamConfFile="/etc/motioneye/thread-3.conf"

systemctl stop motioneye.service
sed -i "s/\(#\s*$TARGET_KEY\s\s*\).*/\1$status/" $CamConfFile
systemctl start motioneye.service

(the odd "\s\s*" there is the equivalent of "\s+" - at least one character of whitespace - but sed defaults to using only basic regex expressions, and the extended ones aren't necessarily portable)

elliopitas commented 8 years ago

can you add this @ccrisan as a feature in update in the web gui

ccrisan commented 8 years ago

I don't have too much time these days to take care of such a feature. I'll see what I can do in the future.

elliopitas commented 8 years ago

it is ok

petermolnar commented 8 years ago

Here is my solution, currently under testing, running from cron on motioneyeos. This one requires an ssh login to the router, so either an openwrt, a dd-wrt or something similar on the router side for the access.

#!/bin/bash

function debug () {
    if [ ${debug} -eq 1 ]; then
        echo "$1"
    fi
}

# switch to IP mode by disabling it
# some phones do not respond to ping, so instead we're testing for
# arp table presence on the router
# this requires initial setup of ssh keys
# on motionpieos do:
# - mount -o remount,rw /
# - mkdir ~/.ssh
# - ssh-keygen -f ~/.ssh/key -b 4096 -t rsa
# - press Enter when prompted for password
# - on the router add the contents of ~/.ssh/key.pub to the authorized keys
#   this varies router by router how to

debug=0

# if you decide to use the ip addresses I highly recommend using static IPs on
# your devices instead of DHCP
arp_enabled=1

# prevent activation on, for example a device reboot, or when it's not present for
# only a little while, in seconds
timeout=600

# instead of hardcoded values, we can rely on the routing table to find our router
router=$(/sbin/route -n | awk '/^0.0.0.0/ { print $2}')

# this needs filling in by hand unfortunately
declare -A phones
phones=(["first.phone.ip.address"]="mac:address:of:the:first:phone" ["second.phone.ip.address"]="mac:address:of:the:second:phone")

# phone detection value
phones_status="/tmp/phonedetector.status"

if [ ! -f "${phones_status}" ]; then
    touch "${phones_status}"
    status_previous=0
else
    status_previous=$(cat "${phones_status}")
fi

status_current=0

if [ ${arp_enabled} -eq 1 ]; then
    # in case of relying on arp, we need to be able to connect to the router
    if ! ping -c 1 ${router} &>/dev/null; then
        debug "router unreachable"
        exit 1
    fi

    # associative array, the values are the mac addresses
    arp=$(ssh -i ~/.ssh/key root@${router} -- 'arp' 2>&1)
    for mac in "${phones[@]}"; do
        if grep -sqi "${mac}" <<< "${arp}"; then
            status_current=1
        fi
    done
else
    # associative array, the keys are the ip addresses; if it can be pinged,
    # it's present
    for ip in "${!phones[@]}"; do
        if ping -c 1 "${ip}" &>/dev/null; then
            status_current=1
        fi
    done
fi

# in case it's a transition from present to not present, wait for the timeout
# to prevent flapping
if [ ${status_current} -eq 0 ] && [ ${status_previous} -eq 1 ]; then
    status_epoch=$(stat -c %Y "${phones_status}")
    min_epoch=$(($(date +%s)-${timeout}))

    if [ ${status_epoch} -gt ${min_epoch} ]; then
        debug "status change was less then ${timeout} seconds ago, waiting a bit more"
        exit 0
    fi
fi

# store the status if we hadn't left the script earlier
echo "${status_current}" > "${phones_status}"
touch "${phones_status}"

# in case this is a transition turn the motion detection on or off
# depending on the status
motion_key="@motion_detection"
config_file="/data/etc/thread-1.conf"

if [ ${status_current} -eq 1 ]; then
    motion_detected="off"
else
    motion_detected="on"
fi

motion_current="$(cat $config_file | grep $motion_key | awk '{print $NF}')"

if [ "${motion_current}" != "${motion_detected}" ]; then
    /etc/init.d/S85motioneye stop
    sed -i "s/\(#\s*$motion_key\s\s*\).*/\1$motion_detected/" $config_file
    /etc/init.d/S85motioneye start
fi
influenced commented 8 years ago

In bash, you can simply declare an array with phones=() although if you prefer the declare for stylistic reasons I won't judge you (openly). I love that your script can use both IP and MAC addresses, and also the automatic obtaining of the router address - I am totally stealing both of those bits, and you can't stop me!

Anyway, parts of your solution almost exactly duplicate some of the changes I've made to my own, but yours is probably clearer for general use (I've got some extra stuff to do with 'locking' and 'unlocking' the both the service and the lighting to prevent the script from acting). I might split the lighting off into a separate cronjob anyway - it's getting close to the point where the logic needs to be differentiated, and I'm thinking about future changes (e.g. specific lights that come on when motion is detected).

If you want some suggestions for improvements:

  1. The config_files that get modified could be an array, for multiple cameras. Or you could even search for files that match the generic pattern /etc/motioneye/thread-#.conf.
  2. Perhaps a flag for whether you're using init.d or systemd service styles.
4eversr commented 8 years ago

Hi, as announced in my first post i wanted to enable motioneye motion-detection only when i am not at home, and i also want to add a servo engine which physicaly covers the camera lens when i am at home. I have found a very good solution, which nearly works perfectly, but at the moment i have problems to start/stop motioneye with minimal user rights.

So, from the beginning: I use a raspberry pi 2 with latest Raspbian OS, where motioneye and the smarthome software "fhem" is installed. - For FHEM there is a simple module available which enables Geofencing with your smartphone (android or apple ios). This module is called GEOFANCY, on android you need the app "EgiGeoZone". This app triggers the fhem module when you leave or arrive in your defined geo fencing area. This works like a charm and is a very accu friendly way of presence detection, perhaps a thing which can be easily integrated in future motioneye releaes (?) :) - But back to topic: FHEM now is able to recognize if i am at home or not by using the geofancy module. - This presence information now start a script which triggers a gpio pin of the raspberry pi, which is connected to a carson servo engine which physically open/close the camera lens. - This works like a charm. - But now i have the problem to start/stop motioneye as the "fhem"-user, which have only minimal user rights. (I already added this user to "/etc/group" in the "gpio" group, so this user was able to activate the gpio pin for the servo engine without "sudo" rights. - I tried to add the user "fhem" to the "video" group also, but at the moment i was not able to stop motioneye or disable motion detection with this "fhem" user. So i think I need a little help at this point, or i have to figure this out myself...

influenced commented 8 years ago

What you can do is add /bin/systemctl start motioneye.service and /bin/systemctl stop motioneye.service to the sudoers list with visudo, which allows a user to sudo exact command lines (including the path is always a good idea) without opening up greater access. There's a ton of documentation out there on how to do this properly, so I won't try to duplicate that here - just google "visudo" (do not attempt to edit the sudoers file any other way, and note that despite the name modern versions of visudo let you use alternate editors such as nano).

4eversr commented 8 years ago

@influenced Thank you very much, your "visudo"-tip worked like a charm and was very easy to integrate. Now the user fhem is able to start and stop the motioneye service and control the servo engine for the camera lens cover, which all is controled by the gps position of my smartphone. ;) - As from now the fhem software is in charge of the motioneye service, i disabled the motioneye service to run automatically on startup of the raspberry pi (sudo systemctl disable motioneye.service).

Hard2findaNameHere commented 8 years ago

@influenced I have been reading your work here and it is very interesting and something I may like to pursue later on, but I have another hurdle I cannot get around. From reading Crisan's information on Action Buttons and how to create them to appear in the top of the video window for user selection to simply write to the GPIO I am at a loss of how to achieve this. Crisan has given me some advice of placing the executable script file (mine is ledon_1 which is a virtual copy of his lights_on_1) into the /data directory, rebooting and it all should work, but sadly nothing. Could you please offer any advice of how I can implement several Action Buttons which are visible on the webview video window? I am using a raspberry Pi 3 and installed the latest motioneye image. In this image many of the files are in different directories to the examples given at this site ie; motioneye.conf is in the /data/etc folder and I cannot find a motioneye folder anywhere or a light_on_1 file anywhere either. Can you possibly assist?

influenced commented 8 years ago

AFAIK the script has to have the specific names expected for an action - so for camera 1, the only scripts it will find must be called one of:

light_on_1 light_off_1 unlock_1 lock_1 alarm_on_1 alarm_off_1

I don't use motioneyeos so I don't know what directories it expects things in, sorry.

influenced commented 8 years ago

These pages are helpful for motioneye/motioneyeos actions:

https://github.com/ccrisan/motioneyeos/wiki/Action-Buttons https://github.com/ccrisan/motioneye/wiki/Action-Buttons

Hard2findaNameHere commented 8 years ago

@influenced You did it!!! I can now see the icons (action buttons) thank you so very much sir! I am in your debt :-) But now when I select the action button my light does not turn on...actually I am using GPIO5 and a logic 1 or 0 is not being asserted to the pin (except for the pull up voltage presence. here's the scripts...

light_on_1:

!/bin/bash

GPIO=5 test -e /sys/class/gpio/gpio$GPIO || echo $GPIO > /sys/class/gpio/export echo out > /sys/class/gpio/gpio$GPIO/direction echo 1 > /sys/class/gpio/gpio%GPIO/value

light_off_1:

!/bin/bash

GPIO=5 test -e /sys/class/gpio/gpio$GPIO || echo $GPIO > /sys/class/gpio/export echo out > /sys/class/gpio/gpio$GPIO/direction echo 0 > /sys/class/gpio/gpio%GPIO/value

Hard2findaNameHere commented 8 years ago

@influenced .....this script file "AFAIK" where does that normally reside in your motion os? I definitely cannot find it here in motioneye.

ccrisan commented 8 years ago

The script must must have one of the names described in the wiki articles above and must be placed in /data/etc. In your case, the file must be at /data/etc/light_on_1 (and probably /data/etc/light_off_1). The "%" in your script must be replaced with a "$".

Hard2findaNameHere commented 8 years ago

Calin how can I add more to the script rather than the six listed? David

----- Reply message ----- From: "Calin Crisan" notifications@github.com To: "ccrisan/motioneye" motioneye@noreply.github.com Cc: "Hard2findaNameHere" dsm73953@bigpond.net.au, "Comment" comment@noreply.github.com Subject: [ccrisan/motioneye] Feature requests/ideas: MotionEye activation by leaving home (using smartphone detection) (#203) Date: Fri, Jun 3, 2016 18:09

The script must must have one of the names described in the wiki articles above and must be placed in /data/etc. In your case, the file must be at /data/etc/light_on_1 (and probably /data/etc/light_off_1). The "%" in your script must be replaced with a "$".


You are receiving this because you commented. Reply to this email directly or view it on GitHub: https://github.com/ccrisan/motioneye/issues/203#issuecomment-223517252

ccrisan commented 8 years ago

You can't.

Hard2findaNameHere commented 8 years ago

can you Crisan? :-)

Hard2findaNameHere commented 8 years ago

sorry Calin, can you add more action buttons or is it too much work?

Hard2findaNameHere commented 8 years ago

Hi again Calin, I don't know if you seen my last message, and previously you advised that I cannot add any more action buttons. But Calin is it possible that you could in your next release? For example in addition to the present could you include pan left and right, tilt up and down and rotate left and right? I have fully utilised your existing buttons as toggle features but desperately need a few more. Again any help with this will be sincerely appreciated.

David

----- Reply message ----- From: "Calin Crisan" notifications@github.com To: "ccrisan/motioneye" motioneye@noreply.github.com Cc: "Hard2findaNameHere" dsm73953@bigpond.net.au, "Comment" comment@noreply.github.com Subject: [ccrisan/motioneye] Feature requests/ideas: MotionEye activation by leaving home (using smartphone detection) (#203) Date: Sun, Jun 5, 2016 22:32

You can't.


You are receiving this because you commented. Reply to this email directly or view it on GitHub: https://github.com/ccrisan/motioneye/issues/203#issuecomment-223810666

ccrisan commented 8 years ago

@Hard2findaNameHere I currently have other priorities when it comes to motionEye.

ozett commented 8 years ago

as the internet still lives from ideas of others, this here is very interesting to me. but i will provide another idea, how i check the presence of our phones at home. i have the wifi-router logging into syslog on my linux. there the rsyslog can be scripted to do action on wlan events. this is an improvement, as the iphones are not constantly logged into wlan/wifi, but still at home. i give my snippet from my rsylog.conf , it is not complete, but shows the idea how to check presence in another fashion... :smile:

/etc/rsyslog.conf snippet:

#alive iphone3 /check for away with other AP-messages...

if $msg contains 'a4:c3:61:d0:19:c0 WPA: group key handshake completed' then {
        #or $msg contains '8c:3a:e3:6d:d6:70 WPA: group key handshake completed' then
        action(type="omfile" file="/var/log/wlan-vucic-alive.log")
        action(type="omfwd" target="192.168.14.253" port="4720" protocol="udp" template="vucicaliveeg")
        }
flipy commented 8 years ago

following @petermolnar script, and taking @influenced suggestions, I set up a new revision with the following changes:

Tested with motioneyeos on a Raspberry Pi 3.

Find more information on petermolnar site: https://petermolnar.net/motioneyeos-mobile-phone-presence-detection-for-auto-onoff-based-on-network-ip-or-mac-address/

#!/bin/bash

declare -a debugmsgs

function debug () {
        if [ -t 0 ]; then
                echo "$1"
        else
                debugmsgs+=("$1")
#               logger -t 'phonedetector' "${1}"
        fi
}

sshcmd="/usr/bin/ssh -i /data/etc/ssh_host_rsa_key"
routeruser="root"
dhcpleasefile="/tmp/var/lib/misc/dnsmasq.leases"

# some phones do not respond to ping, so instead we're first trying to ssh to
# the router; this requires initial setup of ssh keys
# on motionEyeOS do:
# - ssh-keygen -f /data/etc/ssh_key -b 4096 -t rsa
# - press Enter when prompted for password, so no password is set
# - on the router add the contents of /data/etc/ssh_key.pub to the authorized keys list
#   this varies router by router how to

# prevent activation on, for example, a device reboot, or when it's not present for
# only a little while, in seconds
timeout=240

# instead of hardcoded values, we can rely on the routing table to find our router
router=$(/sbin/route -n | awk '/^0.0.0.0/ { print $2}')
debug "router IP: ${router}"

# this needs filling in by hand unfortunately
declare -A phones
phones=(["192.168.2.100"]="AC:CF:85:01:72:56" ["192.168.2.78"]="64:BC:0C:65:CC:B3")

# get configuration files for all cameras connected to this system
cameras=(/data/etc/thread-*.conf)

# phone detection value
status_file="/tmp/phonedetector.status"
if [ ! -f "${status_file}" ]; then
        touch "${status_file}"
        echo 0 > "${status_file}"
fi

status_current=0
status_previous=$(cat "${status_file}")
debug "previous status in ${status_file} is: ${status_previous}"

# check if it's possible to ssh to the router
use_arp="no"
if ping -W1 -c 1 ${router} &>/dev/null; then
        use_arp="$(${sshcmd} ${routeruser}@${router} -- 'hostname' &>/dev/null && echo 'yes' || echo 'no')"
fi

# ping all active leases in DHCP table
# this is to ensure they are still here and alive
# otherwise some wireless devices just disappear long enough to make us
# flap
if [ "${use_arp}" == "yes" ]; then
        leases=$(${sshcmd} ${routeruser}@${router} -- "cat ${dhcpleasefile} | awk '{print \$3}'")
        for ip in $leases; do
                ping -W1 -c1 $ip 2>&1 >/dev/null;
        done
fi

# use IP or MAC in the arp table
use_ip=0

if [ "${use_arp}" == "yes" ]; then
        debug "router arp table available"
        arp=$(${sshcmd} ${routeruser}@${router} -- "`which arp`" 2>&1)
        debug "arp table: ${arp}"

        # rely on IP addresses in the ARP table; since the MAC addresses can be flaky
        # due to power saving wifi settings, this is usually more stable
        if [ ${use_ip} -eq 1 ]; then
                debug "trying to detect presence based on IP from router arp table"
                for ip in "${!phones[@]}"; do
                        if grep -sqi "${ip}" <<< "${arp}"; then
                                debug "found valid IP: ${ip}"
                                status_current=1
                        fi
                done
        else
                debug "trying to detect presence based on MAC from router arp table"
                for mac in "${phones[@]}"; do
                        if grep -sqi "${mac}" <<< "${arp}"; then
                                debug "found valid MAC: ${mac}"
                                status_current=1
                        fi
                done
        fi
else
        debug "router arp table is not available, trying to ping IPs directly for presence detection"
        for ip in "${!phones[@]}"; do
                if ping -W 1 -c 1 "${ip}" &>/dev/null; then
                        status_current=1
                fi
        done
fi

# to prevent flapping we will rely on the status file's last modification
# time and have a window for status change
echo "${status_current}" > "${status_file}"
debug "detected status: ${status_current}"

if [ ${status_current} -ne ${status_previous} ]; then
        status_epoch=$(stat -c %Y "${status_file}")
        min_epoch=$(($(date +%s)-${timeout}))

        if [ ${status_epoch} -gt ${min_epoch} ]; then
                debug "status change was less then ${timeout} seconds ago, waiting a bit more"
                exit 0
        fi
fi

touch "${status_file}"

# in case this is a transition turn the motion detection on or off
# depending on the status
motion_key="@motion_detection"
motion_current="$(cat ${cameras[0]} | grep $motion_key | awk '{print $NF}')"
debug "motion current: ${motion_current}"

if [ ${status_current} -eq 1 ]; then
        motion_detected="off"
else
        motion_detected="on"
fi
debug "motion detected: ${motion_detected}"

# foolproofing
if [ "${motion_current}" != "on" ] && [ "${motion_current}" != "off" ]; then
        motion_current="off"
fi

if [ "${motion_current}" != "${motion_detected}" ]; then
        debug "statuses differ, restarting service"
        /etc/init.d/S85motioneye stop
        for camera in "${cameras[@]}"; do
                sed -i "s/\(#\s*$motion_key\s\s*\).*/\1$motion_detected/" ${camera}
                debug "setting ${camera} motion detection to ${motion_detected}"
        done
        /etc/init.d/S85motioneye start
fi

exit 0
wokawoka commented 6 years ago

Sorry to revive this issue after so much time but I'm experiencing a problem with the script that @flipy posted (after having modified @petermolnar one) and it seems that in the meanwhile no new ways of achieving the result came out.

I believe that my problem relies on the fact that I'm not using a dd-wrt or openwrt but instead I'm running tomato. Tomato correctly optputs the arp table by issuing the "arp" command while connected on ssh, but I suppose that the format might be different from the output of dd-wrt because the script get executed without errors but it outputs: router arp table is not available, trying to pin IPs directly for presence detection but unfortunately my phone (android) doesn't answer to pings.

The SSH key is properly set up and motioneye connects regularly to my router. The output of the "arp" command on my tomato router is:

meye-08676fXX (192.168.1.13) at B8:27:EB:32:XX:XX [ether]  on br0
android-d14d2da26f12XXXX (192.168.1.3) at CC:61:E5:1D:XX:XX [ether] PERM on br0
DESKTOP-OVUXXXX (192.168.1.24) at 00:13:EF:F3:XX:XX [ether]  on br0

Any idea about how I could modify the script to correctly read the output of the arp command of my router running tomato? Many thanks

flipy commented 6 years ago

@wokawoka based on the information provided, it looks like the script is only trying to PING devices and not fetching an ARP table from the router.

There are two main variables that you can modify to use an ARP table for detection instead of PING'ing devices.

One is use_arp, if you set it up to user_arp="yes", it will try to fetch the ARP table from the main router.

The other one is use_ip, which by default it will use MACs for detecting presence from the ARP table. If you switch it to use_ip=1, it will use IPs instead.

wokawoka commented 6 years ago

@flipy Many thanks for answering. After reading your suggestion I did try the script after having modified user_arp= to yes at first, and then use_ip= to 1 on a second time, but in both cases unfortunately the script outputs

router IP: 192.168.1.1
previous status in /tmp/phonedetector.status is: 0
router arp table is not available, trying to ping IPs directly for presence detection
detected status: 0
motion current: on
motion detected: on

so that I thought that the formatting of the arp command output was not correctly interpreted from the script because of differencies in the arp command output between tomato and openwrt. If I connect via ssh from motioneye to the router I can access it without problems by using the ssh key and without requiring any password.

The output of the arp command on my router is

meye-08676fXX (192.168.1.13) at B8:27:EB:32:XX:XX [ether]  on br0
android-d14d2da26f12XXXX (192.168.1.3) at CC:61:E5:1D:XX:XX [ether] PERM on br0
DESKTOP-OVUXXXX (192.168.1.24) at 00:13:EF:F3:XX:XX [ether]  on br0

could it be possible that the script was written to read the output formatted in a different way? Many thanks again!

evripidis commented 6 years ago

I've just followed the instructions here that is good for me but unfortunately I think I have a mistake.

If I execute manually the script (sudo bash -x) works like a charm, but cron doesn't seem to work. I've edited the crontab in /etc/crontab and added to run every minute...no luck...

/1 * /home/pi/Scripts/autoactivate.sh

Any ideas?

influenced commented 6 years ago

Hi evripidis - did you include the very first line of the script (the "#!/bin/bash" comment)? That tells it to run with bash instead of just sh (or whatever the default is). That would explain why manually running it with bash would work, but cron does not.

evripidis commented 6 years ago

Yes, my script is exactly the same. I've only changed my IPs.

evripidis commented 6 years ago

As far as I can understand from syslog, cron executes the script but I get no results. Probably a path issue? (This is the correct path)

Aug 31 00:42:02 raspberrypi CRON[1085]: (pi) CMD (/home/pi/autoactivate.sh) Aug 31 00:43:01 raspberrypi CRON[1098]: (pi) CMD (/home/pi/autoactivate.sh) Aug 31 00:44:01 raspberrypi CRON[1110]: (pi) CMD (/home/pi/autoactivate.sh) Aug 31 00:45:01 raspberrypi CRON[1122]: (pi) CMD (/home/pi/autoactivate.sh) Aug 31 00:46:01 raspberrypi CRON[1139]: (pi) CMD (/home/pi/autoactivate.sh) Aug 31 00:47:01 raspberrypi CRON[1154]: (pi) CMD (/home/pi/autoactivate.sh) Aug 31 00:48:01 raspberrypi CRON[1166]: (pi) CMD (/home/pi/autoactivate.sh) Aug 31 00:49:01 raspberrypi CRON[1179]: (pi) CMD (/home/pi/autoactivate.sh) Aug 31 00:49:01 raspberrypi CRON[1175]: (CRON) info (No MTA installed, discarding output) Aug 31 00:50:01 raspberrypi CRON[1192]: (pi) CMD (/home/pi/autoactivate.sh)

evripidis commented 6 years ago

Just an update if anyone else has the same issue. I've redone all the process that @influenced mentioned on the previous post but this time as root with sudo -i. Now the system works perfectly!

tokenwizard commented 5 years ago

I came up with a possible more "hacky" way to do this, but it seems to be working for me.

In the /etc/motioneye folder, I copied each of my thread-#.conf files to create "thread-#.conf.disarmed" and "thread-#.conf.armed".

Then in each of those files, I modified the parameters for the on_picture_save command, so the "armed" one includes the pushover.py script offered up by petakcore in https://github.com/ccrisan/motioneye/issues/869

and in the "disarmed" file I removed the reference to the pushover script.

thread-1.conf.armed (all one line for the on_picture_save parameter): ..... on_picture_save /usr/local/lib/python2.7/dist-packages/motioneye/scripts/relayevent.sh "/etc/motioneye/motioneye.conf" picture_save %t %f; _**python /usr/bin/pushover/push-bar.py %f**_ .....

thread-1.conf.disarmed (all one line for the on_picture_save parameter): .... on_picture_save /usr/local/lib/python2.7/dist-packages/motioneye/scripts/relayevent.sh "/etc/motioneye/motioneye.conf" picture_save %t %f ....

Then.... In my "alarm_on_1" script in /etc/motioneye, I just tell it to copy the "armed" conf file, overwriting thread-1.conf:

!/bin/bash

sudo cp /etc/motioneye/thread-1.conf.armed /etc/motioneye/thread-1.conf sudo systemctl restart motioneye.service

and in my alarm_off_1 script, I copy the "disarmed" conf file over the thread-1.conf file:

!/bin/bash

sudo cp /etc/motioneye/thread-1.conf.disarmed /etc/motioneye/thread-1.conf sudo systemctl restart motioneye.service

Of course, I had to allow my "{server}" user the ability to "sudo cp" without password.

I would think you could include any number of "armed" parameters in your armed versions of the conf files and use this method to quickly toggle. You could probably even create a "combined" toggle script to swap all the conf files to the armed version or disarmed version in one fell swoop.

I was having issues with sed command properly locating and modifying the correct parameters in the conf files, so I went this more hacky route.

dimgod59 commented 5 years ago

excuse me for the question but how to save a script in ssh at the right place on motioneyeOS?

jasaw commented 5 years ago

@dimgod59 /data partition is writable. /data/etc directory seems like a sensible place to put your scripts.

hoFFy84 commented 5 years ago

I'm really new to scripting, RegExp, and so on. Most things I've done so far are based on copy, edit, paste. Now I copied and edited the script examples from @influenced and @Squal78 to have a script that edits the camera-1.conf file only when the motion_detection value is not correct when someone is / is not at home and only restarts the motioneye when necessary. I believe there is a lot potential to optimize the code, but for my little scripting skills and in my tests this works so far ;) When one of the phone_ips is reachable and the value in camera-1.conf don't match, then the motion_detection value will be changed, and the service restarted.

#!/bin/bash

#if this is reachable the LAN is working (there are probably better ways of checking but I am v. lazy)
router_ip="192.168.178.1"

#if any of these IPs are reachable, someone is home
phone_ips=("192.168.178.100")

CamConfFile="/etc/motioneye/camera-1.conf"

#only run if LAN is up
ping -c 1 $router_ip  &>/dev/null || exit 0

#check for phones
phones_present=0
for phone in "${phone_ips[@]}"
do
 ping -c 1 $phone  &>/dev/null && phones_present=1
done

if [ $phones_present -eq 1 ] && grep -q '@motion_detection on' $CamConfFile ; then
                systemctl stop motioneye.service
                sed -i 's/@motion_detection on/@motion_detection off/g' $CamConfFile
                systemctl start motioneye.service
        elif  [ $phones_present -eq 1 ] && grep -q '@motion_detection off' $CamConfFile ; then
                exit 1
        elif   [ $phones_present -eq 0 ] && grep -q '@motion_detection off' $CamConfFile ; then
                systemctl stop motioneye.service
                sed -i 's/@motion_detection off/@motion_detection on/g' $CamConfFile
                systemctl start motioneye.service
        elif [ $phones_present -eq 0 ] && grep -q '@motion_detection on' $CamConfFile ; then
                exit 1
fi

One question is actually unsolved until I found enough time to google it: The ping to the phone is only sent once. But what if my phone left the wifi for whatever reason for a short time. Also I have a huge garden, and not every part is covered with wifi. I would like to have sent lets say 30 pings, or try it for thirty seconds. If the IP is not reached once during that time, then it should be treated as unreachable... Any ideas?

As far as I've tried ping -w30 $router_ip || exit 0 might be a solution

dranelixx commented 3 years ago

Hej i have some problems with the script im trying to use arp because after some time my phones dont respond in pings anymore, but my problem is that it says there is no arp table, on my router i have openwrt running when i type arp in the shell i get this:

192.168.1.114    0x1         0x2         f0:d5:bf:b8:58:80     *        br-lan
192.168.1.11      0x1         0x2         ec:71:db:23:30:a6    *        br-lan
192.168.1.83      0x1         0x2         dc:a6:32:f6:f9:e0      *        br-lan
192.168.1.144    0x1         0x2         cc:f7:35:94:2d:17     *        br-lan
192.168.1.191    0x1         0x2         8a:50:0c:c6:26:0d    *        br-lan
                   0x1         0x2         00:17:10:9a:6b:26   *        eth0.2
192.168.1.10      0x1         0x2         ec:71:db:3b:e6:51    *        br-lan

my script look like this;

#!/bin/bash

declare -a debugmsgs

function debug () {
        if [ -t 0 ]; then
                echo "$1"
        else
                debugmsgs+=("$1")
#               logger -t 'phonedetector' "${1}"
        fi
}

sshcmd="/usr/bin/ssh -i ~/.ssh/id_rsa/ root@openwrt.lan"
routeruser="root"
dhcpleasefile="/tmp/dhcp.leases"

# some phones do not respond to ping, so instead we're first trying to ssh to
# the router; this requires initial setup of ssh keys
# on motionEyeOS do:
# - ssh-keygen -f /data/etc/ssh_key -b 4096 -t rsa
# - press Enter when prompted for password, so no password is set
# - on the router add the contents of /data/etc/ssh_key.pub to the authorized keys list
#   this varies router by router how to

# prevent activation on, for example, a device reboot, or when it's not present for
# only a little while, in seconds
timeout=240

# instead of hardcoded values, we can rely on the routing table to find our router
router=$(/sbin/route -n | awk '/^0.0.0.0/ { print $2}')
debug "router IP: ${router}"

# this needs filling in by hand unfortunately
declare -A phones
phones=(["192.168.1.171"]="8C:1A:BF:01:85:68" ["192.168.1.181"]="B0:72:BF:3C:6B:07" ["192.168.1.191"]="8A:50:0C:C6:26:0D")

# get configuration files for all cameras connected to this system
cameras=(/etc/motioneye/camera-*.conf)

# phone detection value
status_file="/tmp/phonedetector.status"
if [ ! -f "${status_file}" ]; then
        touch "${status_file}"
        echo 0 > "${status_file}"
fi

status_current=0
status_previous=$(cat "${status_file}")
debug "previous status in ${status_file} is: ${status_previous}"

# check if it's possible to ssh to the router
use_arp="yes"
if ping -W1 -c 1 ${router} &>/dev/null; then
        use_arp="$(${sshcmd} ${routeruser}@${router} -- 'hostname' &>/dev/null && echo 'yes' || echo 'no')"
fi

# ping all active leases in DHCP table
# this is to ensure they are still here and alive
# otherwise some wireless devices just disappear long enough to make us
# flap
if [ "${use_arp}" == "yes" ]; then
        leases=$(${sshcmd} ${routeruser}@${router} -- "cat ${dhcpleasefile} | awk '{print \$3}'")
        for ip in $leases; do
                ping -W1 -c1 $ip 2>&1 >/dev/null;
        done
fi

# use IP or MAC in the arp table
use_ip=1

if [ "${use_arp}" == "yes" ]; then
        debug "router arp table available"
        arp=$(${sshcmd} ${routeruser}@${router} -- "`which arp`" 2>&1)
        debug "arp table: ${arp}"

        # rely on IP addresses in the ARP table; since the MAC addresses can be flaky
        # due to power saving wifi settings, this is usually more stable
        if [ ${use_ip} -eq 1 ]; then
                debug "trying to detect presence based on IP from router arp table"
                for ip in "${!phones[@]}"; do
                        if grep -sqi "${ip}" <<< "${arp}"; then
                                debug "found valid IP: ${ip}"
                                status_current=1
                        fi
                done
        else
                debug "trying to detect presence based on MAC from router arp table"
                for mac in "${phones[@]}"; do
                        if grep -sqi "${mac}" <<< "${arp}"; then
                                debug "found valid MAC: ${mac}"
                                status_current=1
                        fi
                done
        fi
else
        debug "router arp table is not available, trying to ping IPs directly for presence detection"
        for ip in "${!phones[@]}"; do
                if ping -W 1 -c 1 "${ip}" &>/dev/null; then
                        status_current=1
                fi
        done
fi

# to prevent flapping we will rely on the status file's last modification
# time and have a window for status change
echo "${status_current}" > "${status_file}"
debug "detected status: ${status_current}"

if [ ${status_current} -ne ${status_previous} ]; then
        status_epoch=$(stat -c %Y "${status_file}")
        min_epoch=$(($(date +%s)-${timeout}))

        if [ ${status_epoch} -gt ${min_epoch} ]; then
                debug "status change was less then ${timeout} seconds ago, waiting a bit more"
                exit 0
        fi
fi

touch "${status_file}"

# in case this is a transition turn the motion detection on or off
# depending on the status
motion_key="@motion_detection"
motion_current="$(cat ${cameras[0]} | grep $motion_key | awk '{print $NF}')"
debug "motion current: ${motion_current}"

if [ ${status_current} -eq 1 ]; then
        motion_detected="off"
else
        motion_detected="on"
fi
debug "motion detected: ${motion_detected}"

# foolproofing
if [ "${motion_current}" != "on" ] && [ "${motion_current}" != "off" ]; then
        motion_current="off"
fi

if [ "${motion_current}" != "${motion_detected}" ]; then
        debug "statuses differ, restarting service"
        /etc/init.d/S85motioneye stop
        for camera in "${cameras[@]}"; do
                sed -i "s/\(#\s*$motion_key\s\s*\).*/\1$motion_detected/" ${camera}
                debug "setting ${camera} motion detection to ${motion_detected}"
        done
        /etc/init.d/S85motioneye start
fi

exit 0

the ssh key is inserted onto my router and when i try to ssh into my router thro the motioneye server i can login fine without password, so what could go wrong here? Hu

brummbrum commented 3 years ago

adding another twist to the collection of scripts.... this snippet is unrelated to phone detection but changes what gets enabled/disabled. Background: Rather than just enabling/disabling motion detection the script enables/disables individual cameras. This is often more useful, e.g. if you want to save CPU on a weaker hardware like the Raspberry Pi. Even without motion detection the constant reception of video stream data can consume a lot of CPU. If you have network cameras those will also clog your network all the time, which can be significant especially with network cameras connected over wifi.

#!/bin/bash
# First command line argument is camera ID: integer (1....) defining which camera shall be switched on/off
# Second comand line argument can be "on" or "off"
camera=$1
status=$2

# For motioneyeOS: Config_dir='/data/etc/motioneye/'
Config_dir='/etc/motioneye/'
Cam_filename="camera-${camera}.conf"

MotionConf_filepath=$Config_dir"motion.conf"
CamConf_filepath=$Config_dir${Cam_filename}
echo "Checking ${CamConf_filepath} and ${MotionConf_filepath}..."

if ( grep -q '@enabled on' $CamConf_filepath ) && [ "$status" = "off" ] ; then
        echo "Switching OFF camera ${camera}"
        systemctl stop motioneye.service
        sed -i "s/camera ${Cam_filename}//g" $MotionConf_filepath
        sed -i 's/@enabled on/@enabled off/g' $CamConf_filepath
        systemctl start motioneye.service
        exit 0
fi

if ( grep -q '@enabled off' $CamConf_filepath ) && [ "$status" = "on" ] ; then
        echo "Switching ON camera ${camera}"
        systemctl stop motioneye.service
        if ! ( grep -q "camera ${Cam_filename}" $MotionConf_filepath ) ; then
                sed -i -e '$a'"camera ${Cam_filename}" $MotionConf_filepath
        fi
        sed -i 's/@enabled off/@enabled on/g' $CamConf_filepath
        systemctl start motioneye.service
        exit 0
fi

echo "Camera status not changed"
exit 1
lukquz commented 1 year ago

hey, sorry to bother you guys, but are there any news on the topic?

Has the feature been added or is there a easy kind of tutorial or documentation on the matter? I'm rather new here/in working with the raspberry pi and therefore a little unsure if I'm able to do this.

I have Raspi 3B and a simple raspi came that works already. My connection is quite fast but that's it, not special router setup an so on. I know a little about coding and the basics commands and stuff about linux and the terminal. Do you have any advise or something like that?

Best regards and thanks in advance.