printing to stdout

2018-08-16 Thread richard lucassen
I can run a shell script from the commandline as root in which I start
a python script as user "ha". The output to stdout and stderr
generated by the python script is visible in an xterm:

#!/bin/dash
exec 2>&1
chpst -u ha:ha:i2c -U ha /usr/local/ha/init.sh
exec chpst -u ha:ha:i2c:gpio /usr/local/ha/wait4int.py

So far so good. But when I run the script supervised by runit, I can
see the output generated by the shell script "init.sh", but the output
of the python script is not transferred to the supervised logging. The
python script itself works, it reads out some I/O expanders on a
Raspberry Pi. But the output of the "print" commands seems to disappear:

[..]
while True:
  if GPIO.input(23) == 1: # if still 0, another event has occurred
GPIO.wait_for_edge(23, GPIO.FALLING)
  print ('---')
  while GPIO.input(23) == 0:
for pcf in pcf_present:
  output = bus.read_byte(pcf)
  print ("%x: %x" % (pcf, output))
  if GPIO.input(23) == 1:
loopcntr = 0
break
  else:
loopcntr += 1
if loopcntr >=20:
  print ('[ALERT] possible INT loop, disable 10 seconds')
  sleep (10)
GPIO.cleanup()

Anyone a hint? Note: I'm a newbie to python.

-- 
richard lucassen
http://contact.xaq.nl/
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: printing to stdout

2018-08-17 Thread richard lucassen
On Fri, 17 Aug 2018 08:31:22 +1000
Cameron Simpson  wrote:

> This isn't specific to Python, you'll find it with most programmes.
> (The shell's builtin "echo" command is an exception.)

[buffer explanation]

I already suspectec a buffered output and to check if it was the
buffer, I created a lot of output by pressing the button that generates
an INT quite a lot of times. But apparently this wasn't enough. After
all, the output is small:

---
38: ff
39: ff
3a: ff
3b: fb


I fear I generated 4095 bytes instead of 4096. Some wise human being
once said "Murphy was an optimist" :)

> So let's look at your script:
> 
> >  print ("%x: %x" % (pcf, output))
> [...]
> >  print ('[ALERT] possible INT loop, disable 10 seconds')
> 
> Your programme will be writing into a buffer. Your messages only go
> out when enough have accrued to fill the buffer.
> 
> To force te messages to go out in a timely manner you need to flush
> the buffer. You have two choices here: call sys.stdout.flush() or
> pass "flush=True" with the print call, eg:
> 
>   print(, flush=True)
> 
> Just looking at your loop I would be inclined to just call flush once
> at the bottom, _before_ the sleep() call:
> 
>   sys.stdout.flush()
> 
> Your call; the performance difference will be small, so it tends to
> come down to keeping your code readable and maintainable.

Yep, the "sys.stdout.flush()" did the job :) I had already been mucking
about with file=sys.stderr, but without result, just because of the
fact that stderr is never buffered AFAIK (the supervised script "run"
has an "exec 2>&1")

Anyroad, it works :)

Thnx!

-- 
richard lucassen
http://contact.xaq.nl/
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: printing to stdout

2018-08-19 Thread richard lucassen
On Fri, 17 Aug 2018 08:31:22 +1000
Cameron Simpson  wrote:

> Just looking at your loop I would be inclined to just call flush once
> at the bottom, _before_ the sleep() call:
> 
>   sys.stdout.flush()
> 
> Your call; the performance difference will be small, so it tends to
> come down to keeping your code readable and maintainable.

This is a working script I made. It initializes the I/O expanders, then
it waits for an INT from these I/O expanders on GPIO23, reads the
contents and sends which bit on which chip went up or down to a fifo
(and stdout for logging)

As I'm new to Python, just this question: are there any unPythony
things in this code?

##

#!/usr/bin/env python3

list_pcf = [0x38, 0x39, 0x3a, 0x3b]
list_pcf_value = []

import sys
from smbus import SMBus
from time import sleep
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BCM)
bus = SMBus(1)

# initialisation of the input devices:
print ("[INFO] initialisation input devices")
for i in range(len(list_pcf)):
  try:
bus.write_byte(list_pcf[i], 0xff) # set device to 0xff
output = bus.read_byte(list_pcf[i])
list_pcf_value.append(output) # append value to list
print ("found: %d, input value: 0x%x" % (list_pcf[i], output))
  except IOError:
print ("[ALERT] I/O problem device 0x%x (init)" % pcf)
  sys.stdout.flush()

# GPIO 23 set up as input. It is pulled up to stop false signals
GPIO.setup(23, GPIO.IN, pull_up_down=GPIO.PUD_UP)
loopcntr = 0 # detects if INT is kept low

while True:
  if GPIO.input(23) == 1: # if still 0, another event has occurred
GPIO.wait_for_edge(23, GPIO.FALLING)
  print ('---')
  while GPIO.input(23) == 0:
for i in range(len(list_pcf)):
  try:
output = bus.read_byte(list_pcf[i])
if output != list_pcf_value[i]:
  xor = list_pcf_value[i] ^ output
  for l in range(8):
if xor & 0x1:
  updown = (output >> l) & 0x1
  print ("%d bit %d: to %d" % (list_pcf[i],l,updown))
  print("%d %d %d" % (list_pcf[i],l,updown), 
file=open('/mnt/ramdisk/var/lib/ha/events.fifo', 'w'))
xor = xor >> 1
  list_pcf_value[i] = output
  except IOError:
print ("[ALERT] I/O problem device 0x%x" % list_pcf[i])

  if GPIO.input(23) == 1:
loopcntr = 0
break
  else:
loopcntr += 1
if loopcntr >=20:
      print ('[ALERT] possible INT loop, disable 10 seconds')
  sleep (10)
sys.stdout.flush()
GPIO.cleanup()

-- 
richard lucassen
http://contact.xaq.nl/
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: printing to stdout

2018-08-19 Thread richard lucassen
On Sun, 19 Aug 2018 19:53:04 +1000
Cameron Simpson  wrote:

[Oops, apparently you set the Reply-To to python-list@python.org,
normally that's no problem, but I did something wrong somewhere]

> There are always unPythonic bits. Even after you've cleaned them all
> up, since people will disagree about the finer points of Pythonicism
> there will be bits both over and under cleaned.

Although I do not understand exactly what zip is doing here (I presume
I switch to use pointers instead of the values), I like the
"enumerate" function, very handy :-) The code is now as
follows:

#!/usr/bin/env python3

import sys
from smbus import SMBus
from time import sleep
import RPi.GPIO as GPIO

list_pcf = [0x38, 0x39, 0x3a, 0x3b]
list_pcf_value = []
GPIO.setmode(GPIO.BCM)
bus = SMBus(1)

# initialisation of the input devices:
print ("[INFO] initialisation input devices")
for pcf in list_pcf:
  try:
bus.write_byte(pcf, 0xff) # set device to 0xff
  except IOError as e:
print ("[ALERT] I/O problem device 0x%x (init): %s" % (pcf, e))
  output = bus.read_byte(pcf)
  list_pcf_value.append(output) # append value to list
  print ("found pcf8574 at 0x%x, input value: 0x%x" % (pcf, output))
  sys.stdout.flush()

# GPIO 23 set up as input. It is pulled up to stop false signals
GPIO.setup(23, GPIO.IN, pull_up_down=GPIO.PUD_UP)
loopcntr = 0 # detects if INT is kept low

while True:
  if GPIO.input(23) == 1: # if still 0, another event has occurred
GPIO.wait_for_edge(23, GPIO.FALLING)

  while GPIO.input(23) == 0:
for device_nr, (pcf, pcf_value) in enumerate(zip(list_pcf, list_pcf_value)):
  try:
output = bus.read_byte(pcf)
  except IOError as e:
print ("[ALERT] I/O problem device 0x%x: %s" % (pcf, e))

  if output != pcf_value:
xor = pcf_value ^ output
for bit_pos in range(8):
  if xor & 0x1:
up_down = (output >> bit_pos) & 0x1
print ("pcf8574 0x%x bit %d: to %d" % (pcf,bit_pos,up_down))
# send decimal values to event script:
with open('/mnt/ramdisk/var/lib/ha/events.fifo', 'w') as fifo:
  print("%d %d %d" % (pcf,bit_pos,up_down), file=fifo)
  xor >>= 1
list_pcf_value[device_nr] = output

  if GPIO.input(23) == 1:
loopcntr = 0
break
  loopcntr += 1
  if loopcntr >=20:
print ('[ALERT] possible INT loop, disabling 10 seconds')
sys.stdout.flush()
sleep (10)

sys.stdout.flush()
GPIO.cleanup()

And it still works :-)

Thnx!

R.


-- 
richard lucassen
http://contact.xaq.nl/
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: printing to stdout

2018-08-19 Thread richard lucassen
On Sun, 19 Aug 2018 12:02:51 +0300
Marko Rauhamaa  wrote:

> richard lucassen :
> > As I'm new to Python, just this question: are there any unPythony
> > things in this code?
> 
> Your code looks neat.

Well, apparently there were quite a lot of things that makes the code
more readable I'd say. And even better. But it was indeed not very
unPythony. OTOH, I'm not a programmer, otherwise I would have written
this in C ;-)

R.

-- 
richard lucassen
http://contact.xaq.nl/
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: printing to stdout

2018-08-19 Thread richard lucassen
On Sun, 19 Aug 2018 19:53:04 +1000
Cameron Simpson  wrote:

> There are always unPythonic bits. Even after you've cleaned them all
> up, since people will disagree about the finer points of Pythonicism
> there will be bits both over and under cleaned.

Although I do not understand what zip is doing exactly here (I presume
I switch to use pointers instead of the values), I like the
"enumerate" function, very handy :-) The code is now as
follows:

#!/usr/bin/env python3

import sys
from smbus import SMBus
from time import sleep
import RPi.GPIO as GPIO

list_pcf = [0x38, 0x39, 0x3a, 0x3b]
list_pcf_value = []
GPIO.setmode(GPIO.BCM)
bus = SMBus(1)

# initialisation of the input devices:
print ("[INFO] initialisation input devices")
for pcf in list_pcf:
  try:
bus.write_byte(pcf, 0xff) # set device to 0xff
  except IOError as e:
print ("[ALERT] I/O problem device 0x%x (init): %s" % (pcf, e))
  output = bus.read_byte(pcf)
  list_pcf_value.append(output) # append value to list
  print ("found pcf8574 at 0x%x, input value: 0x%x" % (pcf, output))
  sys.stdout.flush()

# GPIO 23 set up as input. It is pulled up to stop false signals
GPIO.setup(23, GPIO.IN, pull_up_down=GPIO.PUD_UP)
loopcntr = 0 # detects if INT is kept low

while True:
  if GPIO.input(23) == 1: # if still 0, another event has occurred
GPIO.wait_for_edge(23, GPIO.FALLING)

  while GPIO.input(23) == 0:
for device_nr, (pcf, pcf_value) in enumerate(zip(list_pcf, list_pcf_value)):
  try:
output = bus.read_byte(pcf)
  except IOError as e:
print ("[ALERT] I/O problem device 0x%x: %s" % (pcf, e))

  if output != pcf_value:
xor = pcf_value ^ output
for bit_pos in range(8):
  if xor & 0x1:
up_down = (output >> bit_pos) & 0x1
print ("pcf8574 0x%x bit %d: to %d" % (pcf,bit_pos,up_down))
# send decimal values to event script:
with open('/mnt/ramdisk/var/lib/ha/events.fifo', 'w') as fifo:
  print("%d %d %d" % (pcf,bit_pos,up_down), file=fifo)
  xor >>= 1
list_pcf_value[device_nr] = output

  if GPIO.input(23) == 1:
loopcntr = 0
break
  loopcntr += 1
  if loopcntr >=20:
print ('[ALERT] possible INT loop, disabling 10 seconds')
sys.stdout.flush()
sleep (10)

sys.stdout.flush()
GPIO.cleanup()

And it still works :-)

Thnx!

R.

-- 
richard lucassen
http://contact.xaq.nl/
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: printing to stdout

2018-08-19 Thread Richard Lucassen
On Sun, 19 Aug 2018 10:11:08 -0400
Joel Goldstick  wrote:

> > Well, apparently there were quite a lot of things that makes the
> > code more readable I'd say. And even better. But it was indeed not
> > very unPythony. OTOH, I'm not a programmer, otherwise I would have
> > written this in C ;-)
> 
> This strikes me as an odd conclusion.  Raspberry Pi places a strong
> emphasis on python.  It certainly doesn't execute as fast as C can,
> but it provides a conceptually higher level programming model.  There
> is extremely good community support for python with Pi (a huge plus),
> and the code is much more understandable.  It is faster to write code
> with python, you can come back to it and understand it more readily at
> some later time, as can others.  And it runs 'fast enough' .  So, no,
> I don't think if you were a 'programmer' you would have used C to do
> this project.  But others may be of a different persuation.

You've got absolutely a point that Python seems to be largely supported
for Rpi. But I'll tell you something else: I just started to use a
Rpi ;-) I agree that python code is much more understandable than C.
 
> You seemed to have snipped your question about zip function.  It takes
> iterables (things like lists, tuples, dictionaries) as arguments and
> pairs them together to form tuples.  Look it up.  Very useful.  As and
> example, if you have list1 = (1,2,3), and list2 = (4,5,6,7) and zip
> them you will get ((1,4), (2,5),(3,6)).  (It stops when the shortest
> iterable is exhausted)
> 
> Your allusion to pointers is misguided.  Python is not like C or
> assembler.  You don't, and don't need to know where objects are
> stored.  Names are assigned to reference data objects

I'll have another look at it, I was just searching for a clear
explanation, but the page I found was not clear enough for me. I'll
have to take some time for it...

-- 
Richard Lucassen
http://contact.xaq.nl/
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: printing to stdout

2018-08-19 Thread Richard Lucassen
On Sun, 19 Aug 2018 12:37:18 -0400
Joel Goldstick  wrote:

> > I'll have another look at it, I was just searching for a clear
> > explanation, but the page I found was not clear enough for me. I'll
> > have to take some time for it...
> 
> try python.org tutorial, and search for terms like names, or name
> binding.  And also 'namespace'

I'll have to get used to the language and I think it's a nice language.
I just mucked about with the sqlite modules BTW. And it works :) 

-- 
Richard Lucassen
http://contact.xaq.nl/
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: printing to stdout

2018-08-23 Thread richard lucassen
On Mon, 20 Aug 2018 08:19:12 +1000
Cameron Simpson  wrote:

[sorry for late reply]

> Someone else has descibed zip tersely: it pairs it the elements of 2
> lists. In fact it joins up matching elements of an arbitrary number
> of iterables. Here is a 3 iterable example:
> 
> >>> zip( (1,2,3), (4,5,6), (7,8,9) )
> 
> >>> list( zip( (1,2,3), (4,5,6), (7,8,9) ) )
> [(1, 4, 7), (2, 5, 8), (3, 6, 9)]
> 
> See that is has collected the first element of each tuple, then the
> second and so forth?

Yep, an image or an example says more than 1000 pages of explanation
 
> In my sentence above, "iterable" means any object you can iterate
> over - any object you could use in a for-loop. So, obviously, a list
> as in your programme. And also a tuple like (1,2,3) as in the example
> above (a tuple is an unmodifiable list). ANd any number of other
> things that will yield a sequence of values.
> 
> In Python 3 (which you're using) zip returns a lazy object, which
> does the zipping as you request the values. That is why the example
> shows a base "zip()" returning a "zip object" - we hand it to list()
> to get an actual list of all the values. This is fast (instant return
> of the zip object without doing much work) and cheap in memory (no
> need to make a huge result if you're zipping big lists) and
> cheap in time (no need to make the whole result if you're only using
> the first part of it).
> 
> So, to the code using the zip:
> 
>   for device_nr, (pcf, pcf_value) in enumerate(zip(list_pcf,
> list_pcf_value)):
> 
> The inner zip yields (pcf, pcf_value) pairs from zipping list_pcf and 
> list_pcf_value, an iterable of:
> 
>   (pcf[0], pcf-value[0]), (pcf[1], pcf_value[1]), ...
> 
> and you can write a for loop like this:
> 
>   for pcf, pcf_value in zip(list_pcf, list_pcf_value):
> 
> to deal with each of those pairs in turn.
> 
> However, since you also need the index (device_nr) in order to update 
> list_pcf_value:
> 
>   list_pcf_value[device_nr] = output
> 
> we then hand the whole thing to enumerate:
> 
>   for device_nr, (pcf, pcf_value) in enumerate(zip(list_pcf,
> list_pcf_value)):
> 
> The enumerate does just what the previous one did, yields pairs of
> (index, value). Each value is a pair from the zip, so it yields:
> 
>   (0, (pcf[0], pcf-value[0])),
>   (1, (pcf[1], pcf_value[1])),
>   ...
> 
> and Python's tuple unpacking syntax is fairly generous, so you want
> write:
> 
>   device_nr, (pcf, pcf_value) = (0, (pcf[0], pcf-value[0]))
> 
> and you can stick that in the for loop, getting the syntax you're
> using in the programme:
> 
>   for device_nr, (pcf, pcf_value) in enumerate(zip(list_pcf,
> list_pcf_value)):

Well, that's a nice and clear explanation, at the prompt I played a bit
with the enumerate and zip functions and after all it's quite simple :)

> >The code is now as follows:
> 
> Much nicer. A few tiny nit picks:

[..] changes applied

> >while True:
> >  if GPIO.input(23) == 1: # if still 0, another event has occurred
> >GPIO.wait_for_edge(23, GPIO.FALLING)
> 
> Can the GPIO ops also raise IOErrors? Just wondering.

Probably, sounds logigal, the GPIO pin is read and if something is
wrong it will generate an I/O error. 

R.

-- 
richard lucassen
http://contact.xaq.nl/
-- 
https://mail.python.org/mailman/listinfo/python-list