I'm new to python and the RaspberryPi. For my RaspberryPi 3 I created two scripts. The first (bash script) detects the push of a button and executes a python3 script when the button is pushed.
The python3 script checks some API, saves the data to a dictionary and then asks for input. When the input is equal to the data action #1 is executed and when not action #2. Input comes from a usb barcode scanner.
Everything works perfect when I run the scripts manually either in desktop or cli mode of the RaspberryPi.
Now I wanted to autostart the bash script while starting the RaspberryPi in cli mode. I did this by adding the script to my rc.local file. This worked too, but when I press the button and the python script comes to the point where it asks for the input I directly get the following error:
Traceback (most recent call last):
File "*my python script*", line 36, in <module>
scan = input()
EOFError: EOF when reading a line
I really don't know why, because this doesn't happen when I run the bash script manually and I already searched for similar questions, but the given solutions didn't worked for me or the questions didn't include something like my problem.
Thank you!
Here are my two scripts:
bash script
#!/bin/bash
# Define pin as input
echo "23" > /sys/class/gpio/export
echo "in" > /sys/class/gpio/gpio23/direction
# Read value of pin
previous=$(cat /sys/class/gpio/gpio23/value)
# Loop
while true
do
# Read value of input
pin=$(cat /sys/class/gpio/gpio23/value)
# If input changes from 1 to 0
if [ $pin -gt $previous ]
then
# Start the script
python3 /home/pi/okey/get_api.py
else
# Sleep
sleep 2.5
fi
# Current value becomes old value for the next time
previous=$pin
done
python3 script
# -*- coding: utf-8 -*-
import requests
import json
from nested_lookup import nested_lookup
import time
import RPi.GPIO as GPIO
from Adafruit_CharLCD import Adafruit_CharLCD
# Set pin numbers
#GPIO.setmode(GPIO.BOARD)
# Set pin 11, 12 & 13 as output
GPIO.setup(17, GPIO.OUT)
GPIO.setup(18, GPIO.OUT)
GPIO.setup(27, GPIO.OUT)
# Set LCD & clear
lcd = Adafruit_CharLCD(rs=26, en=19, d4=13, d5=6, d6=5, d7=11, cols=16, lines=2)
lcd.clear()
# Get API JSON data from URL
lcd.message("Abfrage der\nPaketnummern...")
api = requests.get('my api')
# Serialize data into a python dictionary
data = api.json()
# Extract tracking numbers and create python list
trackingnumbers = nested_lookup('content', data)
# Get input
GPIO.output(27, GPIO.HIGH)
lcd.clear()
lcd.message("Warten auf\nEingabe...")
scan = input()
GPIO.output(27, GPIO.LOW)
# Check if input equals a number in the list
if scan in trackingnumbers:
lcd.clear()
lcd.message("Nummer vorhanden!")
GPIO.output(18, GPIO.HIGH)
time.sleep(2.5)
GPIO.output(18, GPIO.LOW)
else:
lcd.clear()
lcd.message("Nummer nicht\nvorhanden.")
GPIO.output(17, GPIO.HIGH)
time.sleep(2.5)
GPIO.output(17, GPIO.LOW)
# Clear LCD
lcd.clear()
# Clean GPIO resources
GPIO.cleanup()
Related
I am attempting to create a daemon that will execute my script at boot.
using this code as my template Running a python script
my python script works interactively when a user is logged in.
def wait_for_network():
while os.system("ping -c 1 8.8.8.8") != 0:
time.sleep(1)
return
from getmac import get_mac_address
from datetime import datetime
import RPi.GPIO as GPIO
import os
import time
import random
import RPi.GPIO as GPIO
import requests
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)
GPIO.setup(5, GPIO.IN)
GPIO.setup(6, GPIO.IN)
GPIO.setup(23, GPIO.IN)
GPIO.setup(24, GPIO.IN)
GPIO.setup(14, GPIO.IN)
eth_mac = get_mac_address()
#print(eth_mac)
API_ENDPOINT = "https://xxxxxx.com/handlers/receiveStatus.ashx"
CUSTOMER_KEY = "1234567890"
# Define a callback function that will be called by the GPIO
# event system:
def onButton(channel):
if channel == 14:
dt_string = (datetime.now().strftime('%Y-%m-%dT%H:%M:%S.%f')[:-3])
data = {'ID':CUSTOMER_KEY,
'UUID':str(eth_mac),
'DT':dt_string,
'A':str(GPIO.input(6)),
'B':str(GPIO.input(24)),
'C':str(GPIO.input(23)),
'D':str(GPIO.input(5))
}
r = requests.post(url = API_ENDPOINT, data = data)
#print r.text
#print data
GPIO.add_event_detect(14, GPIO.RISING, callback=onButton, bouncetime=20)
#input()
My question is this - the #input() do i need it when running as a daemon?
With it, the script runs until the users presses ctrl-c to break out of.
When I comment it out, the script runs once then returns to the prompt.
The GPIO is making a thread and the main thread needs to wait for it. That was done with the input(). What you can do instead is to make a loop that sleeps instead in place of the input().
while True:
time.sleep(1)
That will hold the process from exiting until a ctrl c happens.
I have a python script in my Raspberry Pi that is connected to a rain gauge. When the rain gauge detects rain, the script shows 0.2 and write it to file. This is the code:
#!/usr/bin/env python3
import time
import RPi.GPIO as GPIO
BUTTON_GPIO = 16
if __name__ == '__main__':
GPIO.setmode(GPIO.BCM)
GPIO.setup(BUTTON_GPIO, GPIO.IN, pull_up_down=GPIO.PUD_UP)
pressed = False
while True:
# button is pressed when pin is LOW
if not GPIO.input(BUTTON_GPIO):
if not pressed:
print("0.2")
pressed = True
# button not pressed (or released)
else:
pressed = False
time.sleep(0.1)
My idea is to use a code like that to save the total amount of rain. When the python script show 0.2 > write it to file.
python3 rain.py >> rain.txt
The code creates a file but doesn't write anything until execution is finished by Ctrl + C.
I need to execute it on boot. I have tried to add it to crontab and rc.local but doesn't work.
I tried to execute it with sudo and pi. The permissions are 755.
Thank you!
try this
import time
import RPi.GPIO as GPIO
BUTTON_GPIO = 16
if __name__ == '__main__':
outputfile=open("/var/log/rain.txt","a",0)
GPIO.setmode(GPIO.BCM)
GPIO.setup(BUTTON_GPIO, GPIO.IN, pull_up_down=GPIO.PUD_UP)
pressed = False
while True:
# button is pressed when pin is LOW
if not GPIO.input(BUTTON_GPIO):
if not pressed:
openputfile.write("0.2\n")
pressed = True
# button not pressed (or released)
else:
pressed = False
time.sleep(0.1)
open a file in append mode with non buffered write.
Then when an event occurs, write to that file.
Do not use shell redirect as it will (in this case) buffer all the program output until exit and then write to a file. Of course, the exit never happens as you have a "while True" with no break
Indeed, this construct command >> file takes the whole of stdout and flushes into the file. It's done only when command execution is over. You must write to the file as soon as your intermediate result is ready:
#!/usr/bin/env python3
import sys
import time
import RPi.GPIO as GPIO
BUTTON_GPIO = 16
if __name__ == '__main__':
GPIO.setmode(GPIO.BCM)
GPIO.setup(BUTTON_GPIO, GPIO.IN, pull_up_down=GPIO.PUD_UP)
pressed = False
# command line arguments
if len(sys.argv) > 1: ## file name was passed
fname = sys.argv[1]
else: ## standard output
fname = None
## this will clear the file with name `fname`
## exchange 'w' for 'a' to keep older data into it
outfile = open(fname, 'w')
outfile.close()
try:
while True:
# button is pressed when pin is LOW
if not GPIO.input(BUTTON_GPIO):
if not pressed:
if fname is None: ## default print
print("0.2")
else:
outfile = open(fname, 'a')
print("0.2", file=outfile)
outfile.close()
pressed = True
# button not pressed (or released)
else:
pressed = False
time.sleep(0.1)
except (Exception, KeyboardInterrupt):
outfile.close()
In this approach you should run python3 rain.py rain.txt and everything will be fine. The try except pattern ensures the file will be properly closed when execution is interrupted by errors or keyboard events.
Notice the file keyword argument in call to print. It selects an open file object to write printed stuff. It defaults to sys.stdout.
I'm doing a project which I got to move two motors and they have differents movements. There are the codes:
import RPi.GPIO as GPIO ## Import GPIO library
import time ## Import 'time' library. Allows us to use 'sleep'
import sys
GPIO.setmode(GPIO.BOARD) ## Use board pin numbering
GPIO.setup(19, GPIO.OUT) ## Setup GPIO Pin 11(motor b enable) to OUT
GPIO.setup(16, GPIO.OUT) ## Setup GPIO Pin 11(motor a enable) to OUT
GPIO.setup(22, GPIO.OUT) ## Setup GPIO Pin 11(motor a control) to OUT
GPIO.setup(18, GPIO.OUT) ## Setup GPIO Pin 11(motor a control) to OUT
GPIO.setup(23, GPIO.OUT) ## Setup GPIO Pin 11(motor b control) to OUT
GPIO.setup(21, GPIO.OUT) ## Setup GPIO Pin 11(motor b control) to OUT
GPIO.output(16, False) ## disable motor a
GPIO.output(19, True) ## enable motor b
p=GPIO.PWM(19,50) ## frequency 50
p.start(1)
try:
while True:
GPIO.output(22, False) ## dont run motor a
GPIO.output(18, False) ## dont run motor a
GPIO.output(23, True) ## run motor b
GPIO.output(21, False) ## run motor b
p.ChangeDutyCycle(35) ## duty cycle 10%
except KeyboardInterrupt:
pass
p.stop()
GPIO.cleanup()
sys.exit()
Code #2
import RPi.GPIO as GPIO
from time import sleep
import sys
GPIO.setmode(GPIO.BOARD)
Motor1A = 22
Motor1B = 18
Motor1E = 16
Motor2A = 23
Motor2B = 21
Motor2E = 19
GPIO.setup(Motor1A,GPIO.OUT)
GPIO.setup(Motor1B,GPIO.OUT)
GPIO.setup(Motor1E,GPIO.OUT)
GPIO.setup(Motor2A,GPIO.OUT)
GPIO.setup(Motor2B,GPIO.OUT)
GPIO.setup(Motor2E,GPIO.OUT)
print "Going forwards"
GPIO.output(Motor1A,GPIO.HIGH)
GPIO.output(Motor1B,GPIO.LOW)
GPIO.output(Motor1E,GPIO.HIGH)
GPIO.output(Motor2A,GPIO.HIGH)
GPIO.output(Motor2B,GPIO.LOW)
GPIO.output(Motor2E,GPIO.HIGH)
sleep(2)
print "Now stop"
GPIO.output(Motor1E,GPIO.LOW)
GPIO.output(Motor2E,GPIO.LOW)
GPIO.cleanup()
sys.exit()
I want to mix both codes in one. I mean, convert these two codes in one which has two differents speed.
Or If someone knows another code I'll be very thankful
How do I do that?
Seriously, use gpiozero, it's a lot more fun and turns your code into:
from gpiozero import Motor
from time import sleep
motorA = Motor(22, 18) # your gpio pins go here
motorB = Motor(23, 21)
motorA.forward(0.5) # half speed
motorB.forward(0.5)
sleep(2) # wait 2 seconds before stopping the motors
motorA.stop()
motorB.stop()
Then, you can go a step further and use the Robot class instead (Documentation here), and make everything even easier:
from gpiozero import Robot
from time import sleep
robot = Robot(left=(22, 18), right=(23, 21))
robot.forward(1) # full speed
sleep(2)
robot.stop()
The robot class also has some more functions, for example:
robot.left()
robot.right()
Most likely, you'll have to install the library first if you haven't used it yet. Type the following on the terminal in order to do so.
pip install gpiozero
Here is script (/shutdown.py). It monitors button press and if button is pressed more than 3 seconds, it runs poweroff command.
#!/usr/bin/python
# Import the modules to send commands to the system and access GPIO pins
from subprocess import call
from time import sleep
import RPi.GPIO as gpio
import time
# Define a function to keep script running
def loop():
raw_input()
# Define a function to run when an interrupt is called
def shutdown(pin):
button_press_timer = 0
while True:
if (gpio.input(17) == False) : # while button is still pressed down
button_press_timer += 1 # keep counting until button is released
if button_press_timer == 3:
#print "powering off"
call('poweroff', shell=True)
sleep(1)
else: # button is released, figure out for how long
#print "Poga atlaista. nospiesta bija " + str(button_press_timer) + " sekundes"
#button_press_timer = 0
return
# sleep(1) # 1 sec delay so we can count seconds
# print "powering off"
gpio.setmode(gpio.BCM) # Use BCM GPIO numbers
gpio.setup(17, gpio.IN, pull_up_down=gpio.PUD_UP) # Set up GPIO 17 as an input
gpio.add_event_detect(17, gpio.FALLING, callback=shutdown, bouncetime=200) # Set up an interrupt to look for button presses
loop() # Run the loop function to keep script running
If I run script from console like /shutdown.py all is fine. Button press is detected and system shutdown is initialed. But if i add that script to /etc/rc.local (/shutdown.py &), then it fails at startup with this error:
Traceback (most recent call last):
File "/shutdown.py", line 35, in <module>
loop() # Run the loop function to keep script running
File "/shutdown.py", line 11, in loop
raw_input()
EOFError: EOF when reading a line
If I comment out loop() line, then there is no error and script does not run in background. I just start and exit and button press not detected. So, how i can run that script at startup and keep running in background?
EDIT
I am not python guru and i think that loop() is python internal function. Now i seen that it is defined function which calls raw_input(). That script I found and modified to fit my needs.
Thanks.
What you really need is a Python daemon which runs in the background. The raw_input method you are trying to use looks like an ugly hack to me.
Have a look at python-daemon package, which is meant exactly for your use case and is quite simple to use. There is also an updated fork with Python 3 support.
After installing python-daemon, add this line to the beginning of your script
import daemon
Then substitute the loop() call at the end of your script with this code:
with daemon.DaemonContext():
while True:
time.sleep(10)
This code is untested, but you get the idea.
I have a problem with my code working with raspberry pi.
I just started with python so i need some help.
This is the code:
import RPi.GPIO as GPIO
import time
GPIO.setmode(GPIO.BCM)
led1=22
led2=17
GPIO.setup(led1, GPIO.OUT)
GPIO.setup(led2, GPIO.OUT)
def blink():
GPIO.output(led1, 1)
time.sleep(1)
GPIO.output(led1, 0)
GPIO.output(led2, 1)
time.sleep(1)
GPIO.output(led2, 0)
while(blink):
blink()
try:
main()
except KeyboardInterrupt:
GPIO.cleanup()
when I run this error appear in the console:
RuntimeWarning: This channel is already in use, continuing anyway. Use
GPIO.setwarnings(False) to disable warnings. GPIO.setup(led1,
GPIO.OUT) and:
RuntimeWarning: This channel is already in use, continuing anyway. Use
GPIO.setwarnings(False) to disable warnings. GPIO.setup(led2,
GPIO.OUT)
If I understand correctly the command GPIO.cleanup() should reset all pin of GPIO port and turn off the led.
but this in not happening in fact one of the led remain on.
How can change my code to resolve this issue?
Here is a little help, how to effectively separate your functions, and make them more general. Although this is a working Python script I provided, I didn't tested it on my raspi, but I think it will work -- anyway, let me know if there were any problems!
import RPi.GPIO as GPIO
import time
# Module level constants
LED1 = 22
LED2 = 17
# Sets up pins as outputs
def setup(*leds):
GPIO.cleanup()
GPIO.setmode(GPIO.BCM)
for led in leds:
GPIO.setup(led, GPIO.OUT)
GPIO.output(led, GPIO.LOW)
# Turn on and off the leds
def blink(*leds):
# Blink all leds passed
for led in leds:
GPIO.output(led, GPIO.HIGH)
time.sleep(1)
GPIO.output(led, GPIO.LOW)
if __name__ == '__main__':
# Setup leds
setup(LED1, LED2)
# Run blinking forever
try:
while True:
blink(LED1, LED2)
# Stop on Ctrl+C and clean up
except KeyboardInterrupt:
GPIO.cleanup()
A friendly recommendation:
There is a dedicated Raspberry Pi StackExchange site too: https://raspberrypi.stackexchange.com/
You don't seem to have included main in your question. However the problem may occur if the programs exits for some reason other than KeyboardInterrupt. It's better to free the resource in a finally block
try:
main()
except KeyboardInterrupt:
pass
finally:
GPIO.cleanup()
You are calling main() function but it's not declared (defined), you are using while(blink). So You need to delete the "main()" and put the "Try" before your main function which is the while(blink) loop. Don't forget the proper tabs there.