improving my python controlled wifi presence detector for Rpi light switch

倖福魔咒の 提交于 2019-12-13 03:38:14

问题


Hi I have made an automatic light switch program destined for my pi, it tracks if my phone is on wifi network it works but its not very fast. If i speed it up I either receive lots of false positives or doesnt work I have found and only changed a tiny bit of code from other examples online. I'm still learning.

so I've got two lots of code one bash and one python. python uses arp-scan and bash uses ip neighbor and ping with seem to be more reliable so can someone help me mash the bash code into python and make it use {arp-scan, ip neighbor, ping and maybe bluetooth as well

I would like to add some settings like

  • ensure the lights dont get turned on in day time hours
  • somehow track the gpio high low toggle in a better way
  • adding bluetooth scan that actually work when android dev is sleeping (screen off)

at the moment i have it running on the pi as a web site for testing here is a screenshot of my pi site

at the moment i have it running on the pi as a web site for testing here is a screenshot of my pi site

python code example

#!/usr/bin/python3
import RPi.GPIO as GPIO
import subprocess
from time import sleep
is_home = False
home_run_count = 0
out_run_count = 0
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)
GPIO.setup(17, GPIO.OUT)

if __name__ == '__main__':
    while True:
        p = subprocess.Popen("arp-scan -l -r 6 | grep MAC:MAC:MAC",stdout=subprocess.PIPE, shell=True)
    (output, err) = p.communicate()
    p_status = p.wait()
    if output:
        #print("Android device is connected to your network!")
        is_home = True
    if p.returncode != 0:
            #print("The device is not present!")
            is_home = False
            #home_run_count = 0
            #out_run_count -= 1
    if is_home is True and home_run_count < 1:
        #print("lights on!")
        #GPIO.setmode(GPIO.BCM)
        #GPIO.setup(17, GPIO.OUT)
        GPIO.output(17, True)
        sleep(0.5);
        GPIO.output(17, False)
        home_run_count += 1
        out_run_count = 0
        is_home = True
    if is_home is False and out_run_count < 1:
        #print("lights off!")
        #GPIO.setmode(GPIO.BCM)
        #GPIO.setup(17, GPIO.OUT)
        GPIO.output(17, True)
        sleep(0.5);
        GPIO.output(17, False)
        out_run_count += 1
        home_run_count = 0
        is_home = False
enter code here

Bash script code

#!/bin/bash
# A script to do something when Phone returns Home.

mac="some mac addy"     # Your phone mac address
ip_addr=""                              # Leave blank or ip for test
network="some ip addy"          # Your network (Class C only)
range="90 100"                      # ip address possible range
pgm() {
    echo "switching lights "
    echo "1" > /sys/class/gpio/gpio17/value
    sleep 0.5s
    echo "0" > /sys/class/gpio/gpio17/value 
}

#-----Rpi-Mod----
echo "17" > /sys/class/gpio/export                  
echo "out" > /sys/class/gpio/gpio17/direction
#-----End of Rpi mod first section-------

start=$(echo "$range" | cut -d " " -f1)
stop=$(echo "$range" | cut -d " " -f2)
network=$(echo "$network" | cut -d. -f1-3)

echo "Start  $(date)"
while [ 1 ]; do
    cnt=0
    fail=0
    [ "$ip_addr" ] || while [ ! "$ip_addr" ]; do
        for x in $(seq "$start" "$stop"); do
            (junk=$(ping -c1 -W1 "$network"."$x") & )
            wait
        done
        sleep 8
        ip_addr=$(ip neighbor | grep "$mac" | cut -d " " -f1)
        ((cnt++))
        if (( $cnt > 15 )); then
            cnt=0
            echo "--- Phone not Home  $(date)"
            #sleep 300      # 5 minutes
        fi
        if [ "$ip_addr" ]; then
            echo "--- Phone is Home, Count = $cnt, Date = $(date)"
            echo "Phone ip = $ip_addr  mac = $mac"
        fi
    done

    while [ "$ip_addr" ]; do
        junk="$(ping -c1 -W1 $ip_addr)"
        sleep 8
        home_nw="$(ip neighbor | grep $ip_addr | cut -d ' ' -f 1,5,6)"
        echo "$home_nw - $(date)"
        is_home=$(echo "$home_nw" | cut -d " " -f3)
        if [ "$is_home" == "REACHABLE" ] && (( "$fail" >= 3 )); then
            echo "--- Phone returned Home - $(date)"
            pgm
        fi
        [ "$is_home" == "REACHABLE" ] && fail=0
        mac_stat=$(echo "$home_nw" | cut -d " " -f2)
        if [ "$mac_stat" == "FAILED" ]; then
            (( "$fail" < 10 )) && ((fail++))
            ip_test="$(ip neighbor | grep $mac | cut -d ' ' -f1)"
            if [ "$ip_test" ]; then
                [ "$ip_test" == "$ip_addr" ] || ip_addr=""
            fi
            if (( "$fail" == 3 )); then
                echo "--- Phone not at Home  $(date)"
                pgm
            fi
        else
            if [ "$mac_stat" != "$mac" ]; then
                ip_addr=""
            fi
        fi
        #sleep 300          # 5 minutes
    done
done

I don't know enough to implement my changes but still learning so would appreciate some woking cot to try and in the process learn.

------------------------------------------------------ update -------------------------------------------------------------------

I tried to put code in the comment but it didn't work. I've sort of managed to get what I wanted. I modified the python script to call a new script (see below) because I was unable to get popen to run my function maybe it needs to be a class or clash, I'm open to suggestions.

def present():
    with urllib.request.urlopen("http://blah.ip.blah/some.json") as url:
        sleep(0.5);
        data = json.loads(url.read().decode())
        #print(data)
        'MAC:MAC:MAC:' in data

So because I could not make the rest of the logic work i just stuck it in a new file like this

#!/usr/bin/python3
import urllib.request, json
from time import sleep
import os
try:
   with urllib.request.urlopen("http://blah.ip.blah/some.json") as url:
       sleep(0.5);
       data = json.loads(url.read().decode())
       #print(data)
       'MAC:MAC:MAC:' in data
except KeyboardInterrupt:
    os._exit(1)

but would love to combine it with the main light script as a function. why does this not work ?

    (output, err) = (  present() )
    p_status = (  present() )

----------------------------------------------------------- end of update one -----------------------------------------------
I had some trouble getting the python loop to keep running when called from the site but it was an silly incorrect path issue, that's why I want to have it all on one file
----------------------------------------------------------- end of update two ---------------------------------------------

I've asked a similar question if anyone is interested

|improve this question

回答1:


I wrote a bash script that uses fping that detects devices entering/exiting a LAN It could easily be adapted to turn lights on and off. The code is here https://grymoire.wordpress.com/2019/12/09/using-bash-to-monitor-devices-entering-exiting-a-lan/



来源:https://stackoverflow.com/questions/59106852/improving-my-python-controlled-wifi-presence-detector-for-rpi-light-switch

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!