I'm making an energy meter using a Raspberry Pi, which gets its reading from a flashing LED (1000 flashes/kWh). It counts the flashes for 60 seconds through an interrupt and then it sends the data to a database. This works great, none of the flashes are missed this way, but because it just constantly checks if 60 seconds have passed it pegs the given thread to a 100% which is less than optimal for a 24/365 usecase.
Here is the important part of the code:
sampleFreqency = 60 #seconds
flashCount = 0
time1 = time.time()
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BCM)
GPIO.setup(17, GPIO.IN, pull_up_down=GPIO.PUD_UP)
def flashCounter(self):
global flashCount
if not GPIO.input(17):
print("Light!")
flashCount = flashCount + 1
GPIO.add_event_detect(17, GPIO.BOTH, callback=flashCounter, bouncetime=50)
while True:
if time.time() > time1+sampleFreqency:
energy = flashCount #Wh
power = energy * 0.36/(sampleFreqency/10) # kW
print("Power: " + str(power) + "kW, Energy: " + str(energy) + "Wh")
logData(power, energy)
flashCount = 0
time1 = time.time()
I have tried using the threading Timer module without success, as it blocks everything else until it runs.
Turns out interrupts in fact do trigget while the program is doing time.sleep() , only my code was not functioning as I would have wanted it to. I have rewritten the ISR like this:
def flashCounter(self):
global flashCount
print("Light!")
flashCount = flashCount + 1
GPIO.add_event_detect(17, GPIO.FALLING, callback=flashCounter, bouncetime=50)
Now it works flawlessly.
The issue was that for sensing the blinking I'm using a photoresistor which has a slow reaction time, and when the interrupt triggered on the falling edge, the voltage probably has not had fallen to a level which would read as low, so the if statement did not get fulfilled.
I have a python program I wrote that moves my solar panel with the sun throughout the day. It works fine, but about twice a week I get RecursionError: maximum recursion depth exceeded
I'm pretty new to python and I've looked up Recursion Errors, it says when a function calls itself too many times, I don't see where that is happening in this program.
from datetime import date
from datetime import datetime, timezone, timedelta
import astral
from astral import Astral
import time
import pytz
# import RPi.GPIO as GPIO
# Global Variables
ast = Astral()
city_Name = 'Cleveland'
local_City = ast[city_Name]
# sun_Position = local_City.sun(local=True)
reset_Solar = True
# Retrieves and returns current time
def get_Current_Time():
eastern = pytz.timezone('America/New_York')
curr_Time = datetime.now(eastern)
return curr_Time
def main_Function():
global local_City
sun_Position = local_City.sun(local=True)
current_Time = get_Current_Time()
solar_Sunrise = sun_Position.get('sunrise')
solar_Noon = sun_Position.get('noon')
solar_Sunset = sun_Position.get('sunset')
calc_Sunrise_Noon = solar_Noon - solar_Sunrise
total_Seconds = calc_Sunrise_Noon.seconds
calc_Hours, remainder = divmod(total_Seconds, 3600)
calc_Minutes, calc_Seconds = divmod(remainder, 60)
time_To_Adjust = total_Seconds / 24
print (current_Time)
print (solar_Sunrise)
if current_Time >= solar_Sunrise and current_Time < solar_Sunset:
solar_Adjust_Active(time_To_Adjust)
elif reset_Solar == True:
reset_Solar_Panel()
else:
solar_Adjust_Deactive()
def solar_Adjust_Active(time_To_Adjust):
while time_To_Adjust > 0:
current_Time = get_Current_Time()
time_To_Adjust = time_To_Adjust - 1
time.sleep(1)
print (current_Time)
print (time_To_Adjust)
daylight_Adjustment()
def solar_Adjust_Deactive():
global local_City
curr_Time = get_Current_Time()
calc_Tomorrow = curr_Time.date() + timedelta(days=1)
sun_Position_Tomorrow = local_City.sun(local=True, date = calc_Tomorrow)
solar_Sunrise_Tomorrow = sun_Position_Tomorrow.get('sunrise')
time_Till_Sunrise = solar_Sunrise_Tomorrow - curr_Time
sunrise_Total_Seconds = time_Till_Sunrise.seconds
calc_Sunrise_Hours, remainder = divmod(sunrise_Total_Seconds, 3600)
calc_Sunrise_Minutes, calc_Sunrise_Seconds = divmod(remainder, 60)
while sunrise_Total_Seconds > 0:
sunrise_Total_Seconds = sunrise_Total_Seconds - 1
time.sleep(1)
# print ('Seconds till Sunrise', sunrise_Total_Seconds)
print (solar_Sunrise_Tomorrow)
main_Function()
def daylight_Adjustment():
global reset_Solar
# Adustment to Solar Panel
#GPIO.setmode(GPIO.BCM)
# init pin numbers
#pin_Open = [6]
# set mode default state is 'low'
#GPIO.setup(pin_Open, GPIO.OUT)
# Activate Open Relay to High (High turns Relay on)
#GPIO.output(pin_Open, GPIO.HIGH) # Activate Open relay
# Start Timer for duration actuator will be activated
timer = 0
while timer < 1:
time.sleep(1)
timer = timer + 1
print ('Panal adjusted')
# set Open relay back to low (Turns Relay off)
#GPIO.output(pin_Open, GPIO.LOW)
# Reset GPIO settings
#GPIO.cleanup()
reset_Solar = True
main_Function()
def reset_Solar_Panel():
global reset_Solar
print ('Setting panel back to original position')
# Adustment to Solar Panel
# GPIO.setmode(GPIO.BCM)
# init pin numbers
# pin_Open = [XX]
# set mode default state is 'low'
# GPIO.setup(pin_Open, GPIO.OUT)
# Activate Open Relay to High (High turns Relay on)
# GPIO.output(pin_Open, GPIO.HIGH) # Activate Open relay
# Start Timer for duration actuator will be activated
timer = 0
while timer <= 48:
time.sleep(1)
timer = timer + 1
# set Open relay back to low (Turns Relay off)
# GPIO.output(pin_Open, GPIO.LOW)
# Reset GPIO settings
# GPIO.cleanup()
reset_Solar = False
main_Function()
main_Function()
You have (at least one) a loop in your code:
def main_Function():
-> solar_Adjust_Active(time_To_Adjust)
-> daylight_Adjustment()
-> main_Function() -> .... # lets run that for a couple of days ...
Normally you have a main loop (f.e. while True:) and call/return from functions into your main loop without recursing:
Pseudocode:
def resetToStart():
move panels to sunrise position
return
def movePanel():
get_currnt_optimal_position_for_datetime
move_to_that_position
return
resetToStart() # start at a well known position
while True:
if NightTime: # sun is down
resetToStart()
sleep till daytime
elif DayTime: # sun is up
movePanel()
sleep some till adjustment needed
I have Python code running on my raspberry pi 2b and a light sensor, which measures the amount of time it takes for the capacitor of the light sensor to charge and send the pin high:
import RPi.GPIO as GPIO
import time
GPIO.setmode(GPIO.BOARD)
pin_to_circuit = 7
def rc_time (pin_to_circuit):
count = 0
#Output on the pin for
GPIO.setup(pin_to_circuit, GPIO.OUT)
GPIO.output(pin_to_circuit, GPIO.LOW)
time.sleep(0.1)
#Change the pin back to input
GPIO.setup(pin_to_circuit, GPIO.IN)
#Count until the pin goes high
while (GPIO.input(pin_to_circuit) == GPIO.LOW):
count += 1
if count > 1000000:
return True
else:
return count
#Catch when script is interrupted, cleanup correctly
try:
# Main loop
while True:
print rc_time(pin_to_circuit)
except KeyboardInterrupt:
pass
finally:
GPIO.cleanup()
I want when the count goes higher than 1000000, a MG90S, that I have also connected to the pi and a 4AA battery pack, moves about 90 degrees.
The code I was trying to integrate to move the servo:
import RPi.GPIO as GPIO
import time
GPIO.setmode(GPIO.BOARD)
GPIO.setup(12, GPIO.OUT)
p.ChangeDutyCycle(7.5) # turn towards 90 degree
time.sleep(1) # sleep 1 second
p.stop()
GPIO.cleanup()
I want to combine these two Python codes. I tried for a bit, but I have almost no Python experience.
The code is now:
import RPi.GPIO as GPIO
import time
GPIO.setmode(GPIO.BOARD)
pin_to_circuit = 7
def move_90_degrees():
GPIO.setmode(GPIO.BOARD)
GPIO.setup(12, GPIO.OUT)
p = GPIO.PWM(12, 50)
p.start(7.5)
p.ChangeDutyCycle(7.5) # turn towards 90 degree
time.sleep(1) # sleep 1 second
p.stop()
def rc_time (pin_to_circuit):
count = 0
#Output on the pin for
GPIO.setup(pin_to_circuit, GPIO.OUT)
GPIO.output(pin_to_circuit, GPIO.LOW)
time.sleep(0.1)
#Change the pin back to input
GPIO.setup(pin_to_circuit, GPIO.IN)
#Count until the pin goes high
while (GPIO.input(pin_to_circuit) == GPIO.LOW):
count += 1
if count > 1000000:
return True
move_90_degrees()
else:
return count
#Catch when script is interrupted, cleanup correctly
try:
# Main loop
while True:
print rc_time(pin_to_circuit)
except KeyboardInterrupt:
pass
finally:
GPIO.cleanup()
The code does print True when the count exceeds 1000000, but the servo still doesn't move. The servo code on its own does however work correctly. (I forgot a bit of the servo code, that's why p wasn't defined, sorry.)
You could just integrate the code block you are using to move the MG90S into a function, insert it before or below your def rc_time (pin_to_circuit): (but first you have to define p inside, its not really clear what p refers to):
New Function from second code block:
def move_90_degrees():
p = '???'
GPIO.setup(12, GPIO.OUT)
p.ChangeDutyCycle(7.5) # turn towards 90 degree
time.sleep(1) # sleep 1 second
p.stop()
After defining this function, call it inside your first block like:
if count > 1000000:
move_90_degrees()
return True
else:
return count
That should work.
I've made a mistake in the code. I changed the order of the function call inside of the
if count > 1000000:
return True
move_90_degrees()
else:
return count
block to :
if count > 1000000:
move_90_degrees()
return True
else:
return count
otherwise, the code returns before the function call is executed. Is it working now?
So basically we're using raspberry pi for a project and a part of it includes the usage of ultrasonic sensors. We have three, and we've been able to get readings from all of them (I actually came from multi-threading but decided to move to multiprocessing). Here is my code:
#Libraries
from multiprocessing import Process, Lock
import RPi.GPIO as GPIO
import time
#GPIO Mode (BOARD / BCM)
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
#set GPIO Pins
GPIO_TRIGGER1 = 23
GPIO_ECHO1 = 24
GPIO_TRIGGER2 = 27
GPIO_ECHO2 = 22
GPIO_TRIGGER3 = 25
GPIO_ECHO3 = 17
#set GPIO direction (IN / OUT)
GPIO.setup(GPIO_TRIGGER1, GPIO.OUT)
GPIO.setup(GPIO_ECHO1, GPIO.IN)
GPIO.setup(GPIO_TRIGGER2, GPIO.OUT)
GPIO.setup(GPIO_ECHO2, GPIO.IN)
GPIO.setup(GPIO_TRIGGER3, GPIO.OUT)
GPIO.setup(GPIO_ECHO3, GPIO.IN)
def sense_distance(lock, processName):
#lock.acquire()
gpio_echo_var = ''
gpio_trigger_var = ''
if processName == "Sensor-1":
gpio_echo_var = GPIO_ECHO1
gpio_trigger_var = GPIO_TRIGGER1
elif processName == "Sensor-2":
gpio_echo_var = GPIO_ECHO2
gpio_trigger_var = GPIO_TRIGGER2
elif processName == "Sensor-3":
gpio_echo_var = GPIO_ECHO3
gpio_trigger_var = GPIO_TRIGGER3
print "%s process created." % (processName)
try:
while True:
# set Trigger to HIGH
GPIO.output(gpio_trigger_var, True)
# set Trigger after 0.01ms to LOW
time.sleep(0.00001)
GPIO.output(gpio_trigger_var, False)
StartTime = time.time()
StopTime = time.time()
# save StartTime
while GPIO.input(gpio_echo_var) == 0:
StartTime = time.time()
# save time of arrival
while GPIO.input(gpio_echo_var) == 1:
StopTime = time.time()
# time difference between start and arrival
TimeElapsed = StopTime - StartTime
# multiply with the sonic speed (34300 cm/s)
# and divide by 2, because there and back
distance = (TimeElapsed * 34300) / 2
if distance <= 10:
print "%s has read less than 10 cm." % (processName)
else:
pass
# Reset by pressing CTRL + C
except KeyboardInterrupt:
print("Measurement stopped by User")
GPIO.cleanup()
#lock.release()
if __name__ == '__main__':
lock = Lock()
Process(target=sense_distance, args=(lock, "Sensor-1")).start()
Process(target=sense_distance, args=(lock, "Sensor-2")).start()
Process(target=sense_distance, args=(lock, "Sensor-3")).start()
It successfully reads the input and prints out the text when input goes smaller than 10 cm. However, after some time, they stop. I have run out of ideas and have searched all over only to come up short. Any sort of help will be appreciated.
Can someone please tell me how I would modify this code to come on more than once a day? I am very new to python and trying to get my pi to run this timer. I tried adding an additional variable to the array such as SatOn2 but it is ignored. Clearly I do not understand how this works in Python. This was originally intended to run xmas lights but I am modifying to run an irrigation drip timer.
Any help greatly appreciated. Thank You!
# Raspberry Pi custom Christmas light timer
# import GPIO module
import RPi.GPIO as GPIO
# set up GPIO pins as outputs
# This convention is for the "P1" header pin convention
# where the pins start with P1 in the upper left
# and go to P26 in the lower right, with odds in the
# left column and evens in the right column.
# So, pins P1-11 and P1-12 correspond to GPIO17 and
# GPIO18 respectively.
GPIO.setmode(GPIO.BOARD)
GPIO.setup(11, GPIO.OUT)
GPIO.setup(12, GPIO.OUT)
# import date and time modules
import datetime
import time
# Enter the times you want the lights to turn on and off for
# each day of the week. Default is for lights to turn on at
# 5:30pm and off at 10:30pm on weekdays, on at 5:00pm and off
# at 11:30pm on weekends. Note that this is using a 24-hour clock.
MonOn = datetime.time(hour=17,minute=30,second=0)
MonOff = datetime.time(hour=22,minute=30,second=0)
TueOn = datetime.time(hour=17,minute=30,second=0)
TueOff = datetime.time(hour=22,minute=30,second=0)
WedOn = datetime.time(hour=17,minute=30,second=0)
WedOff = datetime.time(hour=22,minute=30,second=0)
ThuOn = datetime.time(hour=17,minute=30,second=0)
ThuOff = datetime.time(hour=22,minute=30,second=0)
FriOn = datetime.time(hour=17,minute=30,second=0)
FriOff = datetime.time(hour=22,minute=30,second=0)
SatOn = datetime.time(hour=17,minute=0,second=0)
SatOff = datetime.time(hour=23,minute=30,second=0)
SunOn = datetime.time(hour=17,minute=0,second=0)
SunOff = datetime.time(hour=23,minute=30,second=0)
# Store these times in an array for easy access later.
OnTime = [MonOn, TueOn, WedOn, ThuOn, FriOn, SatOn, SunOn]
OffTime = [MonOff, TueOff, WedOff, ThuOff, FriOff, SatOff, SunOff]
# Set a "wait time" in seconds. This ensures that the program pauses
# briefly after it turns the lights on or off. Otherwise, since the
# loop will execute more than once a second, it will try to keep
# turning the lights on when they are already on (or off when they are
# already off.
waitTime = 3
# Start the loop that will run until you stop the program or turn
# off your Raspberry Pi.
while True:
# get the current time in hours, minutes and seconds
currTime = datetime.datetime.now()
# get the current day of the week (0=Monday, 1=Tuesday, 2=Wednesday...)
currDay = datetime.datetime.now().weekday()
#Check to see if it's time to turn the lights on
if (currTime.hour - OnTime[currDay].hour == 0 and
currTime.minute - OnTime[currDay].minute == 0 and
currTime.second - OnTime[currDay].second == 0):
# set the GPIO pin to HIGH, equivalent of
# pressing the ON button on the remote
GPIO.output(11, GPIO.HIGH)
# wait for a very short period of time then set
# the value to LOW, the equivalent of releasing the
# ON button
time.sleep(.5)
GPIO.output(11, GPIO.LOW)
# wait for a few seconds so the loop doesn't come
# back through and press the "on" button again
# while the lights ae already on
time.sleep(waitTime)
#check to see if it's time to turn the lights off
elif (currTime.hour - OffTime[currDay].hour == 0 and
currTime.minute - OffTime[currDay].minute == 0 and
currTime.second - OffTime[currDay].second == 0):
# set the GPIO pin to HIGH, equivalent of
# pressing the OFF button on the remote
GPIO.output(12, GPIO.HIGH)
# wait for a very short period of time then set
# the value to LOW, the equivalent of releasing the
# OFF button
time.sleep(.5)
GPIO.output(12, GPIO.LOW)
# wait for a few seconds so the loop doesn't come
# back through and press the "off" button again
# while the lights ae already off
time.sleep(waitTime)
Something like this should work:
# Raspberry Pi custom Christmas light timer
# import GPIO module
import RPi.GPIO as GPIO
# set up GPIO pins as outputs
# This convention is for the "P1" header pin convention
# where the pins start with P1 in the upper left
# and go to P26 in the lower right, with odds in the
# left column and evens in the right column.
# So, pins P1-11 and P1-12 correspond to GPIO17 and
# GPIO18 respectively.
GPIO.setmode(GPIO.BOARD)
GPIO.setup(11, GPIO.OUT)
GPIO.setup(12, GPIO.OUT)
# import date and time modules
import datetime
import time
# Enter the times you want the lights to turn on and off for
# each day of the week. Default is for lights to turn on at
# 5:30pm and off at 10:30pm on weekdays, on at 5:00pm and off
# at 11:30pm on weekends. Note that this is using a 24-hour clock.
MonOn = datetime.time(hour=17,minute=30,second=0)
MonOff = datetime.time(hour=22,minute=30,second=0)
TueOn = datetime.time(hour=17,minute=30,second=0)
TueOff = datetime.time(hour=22,minute=30,second=0)
WedOn = datetime.time(hour=17,minute=30,second=0)
WedOff = datetime.time(hour=22,minute=30,second=0)
ThuOn = datetime.time(hour=17,minute=30,second=0)
ThuOff = datetime.time(hour=22,minute=30,second=0)
FriOn = datetime.time(hour=17,minute=30,second=0)
FriOff = datetime.time(hour=22,minute=30,second=0)
SatOn = datetime.time(hour=17,minute=0,second=0)
SatOff = datetime.time(hour=23,minute=30,second=0)
SunOn = datetime.time(hour=17,minute=0,second=0)
SunOff = datetime.time(hour=23,minute=30,second=0)
MonOnTwo = datetime.time(hour=12,minute=30,second=0)
MonOffTwo = datetime.time(hour=13,minute=30,second=0)
# Store these times in an array for easy access later.
OnTime = [[MonOn, MonOnTwo], [TueOn], [WedOn], [ThuOn], [FriOn], [SatOn], [SunOn]]
OffTime = [[MonOff, MonOffTwo], [TueOff], [WedOff], [ThuOff], [FriOff], [SatOff], [SunOff]]
# Set a "wait time" in seconds. This ensures that the program pauses
# briefly after it turns the lights on or off. Otherwise, since the
# loop will execute more than once a second, it will try to keep
# turning the lights on when they are already on (or off when they are
# already off.
waitTime = 3
halfWait = waitTime / 2
# Start the loop that will run until you stop the program or turn
# off your Raspberry Pi.
while True:
# get the current time in hours, minutes and seconds
currTime = datetime.datetime.now()
# get the current day of the week (0=Monday, 1=Tuesday, 2=Wednesday...)
currDay = datetime.datetime.now().weekday()
for dtimes in OnTime[currDay]:
#Check to see if it's time to turn the lights on
if (currTime.hour - dtimes.hour == 0 and
currTime.minute - dtimes.minute == 0 and
currTime.second - dtimes.second > -halfWait and
currTime.second - dtimes.second < halfWait):
# set the GPIO pin to HIGH, equivalent of
# pressing the ON button on the remote
GPIO.output(11, GPIO.HIGH)
# wait for a very short period of time then set
# the value to LOW, the equivalent of releasing the
# ON button
time.sleep(.5)
GPIO.output(11, GPIO.LOW)
for dtimes in OffTime[currDay]:
#check to see if it's time to turn the lights off
if (currTime.hour - dtimes.hour == 0 and
currTime.minute - dtimes.minute == 0 and
currTime.second - dtimes.second > -halfWait and
currTime.second - dtimes.second < halfWait):
# set the GPIO pin to HIGH, equivalent of
# pressing the OFF button on the remote
GPIO.output(12, GPIO.HIGH)
# wait for a very short period of time then set
# the value to LOW, the equivalent of releasing the
# OFF button
time.sleep(.5)
GPIO.output(12, GPIO.LOW)
# wait for a few seconds because it's pointless to burn energy
# with no benefit
time.sleep(waitTime)