User avatar
paddyg
Posts: 2003
Joined: Sat Jan 28, 2012 11:57 am
Location: UK

Re: Door and Window Alert too slow

Wed Oct 18, 2017 8:15 pm

OK you can do something like

Code: Select all

with open('pipins.conf', 'r') as f:
  conf = f.readlines()
for c in conf:
  c = c.split()
  actpins.append(c[0])
  sensor.append(' '.join(c[1:])) # assuming you have multi-word descriptions, otherwise just append(c[1])
But python being generally so readable there's no advantage (imho) to putting info like this in config files - just enter it as a list at the start of your program (pretty much as per earlier code)!

Later on in your code you use the list actpins oddly. You would have to do something like

Code: Select all

NOTIFY_CMD = {pin: Template("""echo "$date $sensor $state" | mail -s "Pi: $sensor $state" $email""") for pin in actpins}
...
    for i, id in enumerate(actpins):
        STATE[id]['prior'] = STATE[id]['current']
        STATE[id]['current'] = 'opened' if io.input(id) else 'closed'
        if STATE[id]['current'] != STATE[id]['prior']: # only need to do anything on change
            notification_list.append((id, STATE[id]['current'], sensor[i]))
(I've not checked the logic of the code otherwise)

HOWEVER I would urge you to switch to the gpiozero version as in my last post on 25th Sep which has the emailing happening in a callback function in a different thread so won't ever miss signals as your first code did. (Or the visual programming event driven system used by code red, though I can understand you wanting to get to grips with 'proper' programming)

Paddy

P.S. I've not tried it but the following is a collection of the various suggestions over this thread

Code: Select all

#!/usr/bin/env python
from gpiozero import Button
from signal import pause
import time
from datetime import datetime
import subprocess
from string import Template

SLEEP_TIME  = 0.01
NOTIFY_LIST = ['*******@*******.com', '*********@**********.com'] 
ACTPINS = {8:'Door',
           9:'East Window',
           10:'West Window',
           11:'Motion Diningroom'}

def current_date (fmt="%a %d-%m-%Y @ %H:%M:%S"):
    return datetime.strftime(datetime.now(), fmt)

NOTIFY_CMD = {pin: Template("""echo "$date $sensor $state" | mail -s "Pi: $sensor $state" $email""") for pin in ACTPINS}
 
def notify (id, state, sensor_name):
    """Send each of the email addresses in NOTIFY_LIST a message"""
    for email in NOTIFY_LIST:
        shell_cmd = NOTIFY_CMD[id].substitute(date=current_date(),
                                  state=state, sensor=sensor_name, email=email)
        proc = subprocess.Popen(shell_cmd, shell=True,
                                stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        stdout_value, stderr_value = proc.communicate()
        with open('log.txt', 'a') as f:
          f.write('{}\n'.format(shell_cmd))
 
def do_action(button):
  # function to send email etc will only run when opened or closed
  state = 'closed' if button.is_pressed else 'opened'
  notify(button.pin, state, ACTPINS[button.pin])

buttons = {}
for id in ACTPINS:
  buttons[id] = Button(id)
  buttons[id].when_pressed = do_action
  buttons[id].when_released = do_action

pause()
also https://groups.google.com/forum/?hl=en-GB&fromgroups=#!forum/pi3d

mccalleyt
Posts: 22
Joined: Sun Sep 24, 2017 10:18 pm

Re: Door and Window Alert too slow

Wed Oct 18, 2017 9:06 pm

But python being generally so readable there's no advantage (imho) to putting info like this in config files - just enter it as a list at the start of your program (pretty much as per earlier code)!
I am using that way to make it easy to add or remove pins as needed by the user. I am aiming to make this a little more user friendly. I have so many ideas to add to it, but the more I do this the easier it is getting for me.

Edit: I need to find a way to add or remove email addresses as needed as well.
Edit: I actually find doing the "proper" programming to be a little easier to do what I want how I want it done. Node-RED is awesome, but I'm making this configurable by text a lot like most of linux (a proper OS).

asandford
Posts: 1717
Joined: Mon Dec 31, 2012 12:54 pm
Location: Ealing

Re: Door and Window Alert too slow

Thu Oct 19, 2017 12:16 am

mccalleyt wrote:
Wed Oct 18, 2017 3:23 pm
After alot of reading and research I have found the best way to accomplish what I am after is to write the program in python and then use Cython to translate to C so I can speed up the pin polling frequency.
Polling should be the last resort, devices should interrupt if they want a fast response.

mccalleyt
Posts: 22
Joined: Sun Sep 24, 2017 10:18 pm

Re: Door and Window Alert too slow

Thu Oct 19, 2017 1:11 am

That is what I am after. I'm very new to all of this so I commonly mis-speak words in relation to Python or other languages. Node-RED would definitely work for what I am doing, but I want to make implementation to be fast and easy. Just put in the pins you want, emails to send it to and the program does the rest.

mccalleyt
Posts: 22
Joined: Sun Sep 24, 2017 10:18 pm

Re: Door and Window Alert too slow

Thu Oct 19, 2017 9:03 pm

Ok I looked it over and this is what I came up with......

Code: Select all

#!/usr/bin/env python
from gpiozero import Button
from signal import pause
import time
from datetime import datetime
import subprocess
from string import Template

aSLEEP_TIME  = 0.01
NOTIFY_LIST = ['*******@*******.com', '*********@**********.com'] 
#ACTPINS = {8:'Door',
#           9:'East Window',
#           10:'West Window',
#           11:'Motion Diningroom'}

ACTPINS = []
SENSOR = []
PINS = []

with open('pipins.conf') as my_file:
    for line in my_file:
        PINS.append(line)

ACTPINS = [i[0] for i in PINS]
SENSOR  = [i[1] for i in PINS]

def current_date (fmt="%a %d-%m-%Y @ %H:%M:%S"):
    return datetime.strftime(datetime.now(), fmt)

NOTIFY_CMD = {pin: Template("""echo "$date $sensor $state" | mail -s "Pi: $sensor $state" $email""") for pin in ACTPINS}
 
def notify (id, state, sensor_name):
    """Send each of the email addresses in NOTIFY_LIST a message"""
    for email in NOTIFY_LIST:
        shell_cmd = NOTIFY_CMD[id].substitute(date=current_date(),
                                  state=state, sensor=sensor_name, email=email)
        proc = subprocess.Popen(shell_cmd, shell=True,
                                stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        stdout_value, stderr_value = proc.communicate()
        with open('log.txt', 'a') as f:
          f.write('{}\n'.format(shell_cmd))
 
def do_action(button):
  # function to send email etc will only run when opened or closed
  state = 'closed' if button.is_pressed else 'opened'
  notify(button.pin, state, SENSOR[button.pin])

buttons = {}
for id in ACTPINS:
  buttons[id] = Button(id)
  buttons[id].when_pressed = do_action
  buttons[id].when_released = do_action

pause()
I hope this is correct. I like to use the config file because it makes the program more modular for expansion. I won't want a huge block of code to sort through to find certain aspects of the program.

User avatar
paddyg
Posts: 2003
Joined: Sat Jan 28, 2012 11:57 am
Location: UK

Re: Door and Window Alert too slow

Thu Oct 19, 2017 9:45 pm

Well the quickest way to find what's wrong is to run it and work your way through the errors. But after a quick look I can suggest the following: Your listing now doesn't use the variable SENSOR, instead ACTPINS is a dict with key equal to the pin number and the value equal to the description.

Your code to iterate through the lines in your file isn't quite right as 'line' will be a string i.e. '8 Front_door' so i[0] will be '8' and i[1] will be ' '. You need to split the line into words, and convert the first word into an integer. Something along the lines of

Code: Select all

 ACTPINS = {}
 with open('pipins.conf','r') as my_file:
   for line in my_file:
     l_split = line.split()
     ACTPINS[int(l_split[0])] = l_split[1]
and get rid of SENSOR and PINS
also https://groups.google.com/forum/?hl=en-GB&fromgroups=#!forum/pi3d

mccalleyt
Posts: 22
Joined: Sun Sep 24, 2017 10:18 pm

Re: Door and Window Alert too slow

Thu Oct 19, 2017 9:55 pm

Thanks, so can I use single or double quotes for using names with a space between them?

asandford
Posts: 1717
Joined: Mon Dec 31, 2012 12:54 pm
Location: Ealing

Re: Door and Window Alert too slow

Thu Oct 19, 2017 11:09 pm

mccalleyt wrote:
Thu Oct 19, 2017 1:11 am
That is what I am after. I'm very new to all of this so I commonly mis-speak words in relation to Python or other languages. Node-RED would definitely work for what I am doing, but I want to make implementation to be fast and easy. Just put in the pins you want, emails to send it to and the program does the rest.
For the gpio stuff, have a look here

For email, have a look here

(none of these videos are mine and google solves many problems).

mccalleyt
Posts: 22
Joined: Sun Sep 24, 2017 10:18 pm

Re: Door and Window Alert too slow

Fri Oct 20, 2017 12:32 am

Code: Select all

NOTIFY_LIST = {} 
with open("email.conf") as notify:
    for word in notify.read().split():
    NOTIFY_LIST[word]
Does this jive with the rest of the code for what I am after?

User avatar
paddyg
Posts: 2003
Joined: Sat Jan 28, 2012 11:57 am
Location: UK

Re: Door and Window Alert too slow

Fri Oct 20, 2017 7:08 am

Nearly. You are using a dict as a set (as @asanford suggests worth spending a bit of time looking at the docs for these things, as well as list). The normal approach would use a simple list.
dict version

Code: Select all

NOTIFY_LIST = {}
 with open('pipins.conf') as notify:
   for word in notify.read().split():
     z[word] = ''
list version

Code: Select all

NOTIFY_LIST = []
with open('pipins.conf') as notify:
  for word in notify.read().split():
    NOTIFY_LIST.append(word)
Or just

Code: Select all

with open('pipins.conf') as notify:
 NOTIFY_LIST = notify.read().split():
   
also https://groups.google.com/forum/?hl=en-GB&fromgroups=#!forum/pi3d

mccalleyt
Posts: 22
Joined: Sun Sep 24, 2017 10:18 pm

Re: Door and Window Alert too slow

Fri Oct 20, 2017 3:12 pm

I forgot that detail(about dict, list and tuple). I have been learning on the go with SoloLearn and Programming Hub. I think I have caught the "programming bug" and I find myself day dreaming in code. Programming used to be my kryptonite and is slowing becoming my Lois Lane. Plus learning python has some irony to it for me. When I was in grade school I loved (still do) to watch Monty Python anything.

mccalleyt
Posts: 22
Joined: Sun Sep 24, 2017 10:18 pm

Re: Door and Window Alert too slow

Tue Oct 24, 2017 10:56 pm

Ok this should look better. I have changed a few things.

Code: Select all

#!/usr/bin/env python
from gpiozero import Button
from signal import pause
from datetime import datetime
import subprocess
from string import Template

emails = open('email.conf', 'r')
pipins = open('pipins.conf', 'r')

notifylist = []
for word in emails.read().split():
    notifylist.append(word)

actpins = {}
for line in pipins:
    l_split = line.split()
    actpins[int(l_split[0])] = l_split[1]


def current_date(fmt="%a %d-%m-%Y @ %H:%M:%S"):
    return datetime.strftime(datetime.now(), fmt)


notifycmd = {pin: Template("""echo "$date $sensor $state" | mail -s "Pi: $sensor $state" $email""") for pin in ACTPINS}


def notify(id, state, sensor_name):
    """Send each of the email addresses in NOTIFY_LIST a message"""
    for email in notifylist:
        shell_cmd = notifycmd[id].substitute(date=current_date(), state=state, sensor=sensor_name, email=email)
        proc = subprocess.Popen(shell_cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        stdout_value, stderr_value = proc.communicate()
        # This is where the sensor state changes are written to a file called sensor.log
        with open('sensor.log', 'a') as f:
            f.write('{}\n'.format(shell_cmd))


def dostate(button):
    # function to send email etc will only run when opened or closed
    state = 'closed' if button.is_pressed else 'opened'
    notify(button.pin, state, actpins[button.pin])
    print(state)


buttons = {}
for id in actpins:
    buttons[id] = Button(id)
    buttons[id].when_pressed = dostate
    buttons[id].when_released = dostate
    print(id)
    print(buttons)
    print(actpins)
    print(notifylist)

pause()

Return to “Python”

Who is online

Users browsing this forum: RogerW and 26 guests