Calling Functions in Flask - python

Apologies in advance as this is probably the most basic question to be found here but I'm the greenest of newbies and cannot get my head around how to call a function in flask so it runs when I land on the URL.
My purpose is to try and get a python script to run when a GET request is made to the URL from WebCore (for those who don't know it's a program that allows you to code smart home functionality for SmartThings) or when I simply land at the URL. I will then tie this to a virtual switch which will start the code which controls a motor in a cat feeder so I can feed my cat remotely/by voice.
All very frivolous stuff but trying to learn some basics here, can anyone help?
As it stands I have two files, both in a root directory named 'CatFeeder'
catfeeder.py
from flask import Flask
from feed import start
app = Flask(__name__)
#app.route('/')
def feed()
return feed.start
if __name__ == '__main__':
app.run(host='0.0.0.0', port='5000', debug=True)
feed.py
import time
import RPi.GPIO as GPIO
def start():
# Next we setup the pins for use!
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
Motor1Forward = 17
Motor1Backwards = 18
GPIO.setup(Motor1Forward,GPIO.OUT)
GPIO.setup(Motor1Backwards,GPIO.OUT)
print('Feeding Lola')
# Makes the motor spin forward for x seconds
# James Well Beloved - 11 seconds = 28g food (RDA Portion = 52g/4kg cat or 61g/5kg cat)
# XXXX - X seconds - Xg food
GPIO.output(Motor1Forward, True)
GPIO.output(Motor1Backwards, False)
time.sleep(11)
print('Lola Fed!')
GPIO.output(Motor1Forward, False)
GPIO.output(Motor1Backwards, False)
GPIO.cleanup()
quit()
When I set export FLASK_APP=catfeeder.py and then flask run the service runs but nothing happens when I land on the page. I assume there is something wrong in the way I am calling things.
I guess it would be easiest if I just integrated the code from feed.py into catfeeder.py but I wasn't sure what the syntax would be for this and it felt like a messy way to go about it.
Thanks in advance!

you've imported the function but didn't actually invoke it as you missed adding your brackets (), try return start()
In case you meant to return a function object and not invoke the function, you should return it by typing return start

Related

Updating DataFrame while API is running in Python

So I am trying to create an API that constantly reads from a CSV and returns information about it when requested. So far, I have created a flask API that reads the CSV file once and returns correctly. However, I can't seem to make it constantly update. My working code is something like this.
app = flask.Flask(__name__)
app.config["DEBUG"] = True
dfchat = pd.read_csv(path)
escaper = None
# for now, this is just to make sure the program keeps running even if there is an error
def escape_route():
global escaper
while escaper != "Y":
escaper = str(input("Exit now? Enter \'Y\': \n")).strip()
os._exit(os.X_OK)
def sample_function(dfchat):
#app.route('/sample_text', methods=['GET'])
def sample_endpoint():
# this function filters dfchat and returns whatever
def main():
global dfchat
escape_route_thread = threading.Thread(target = escape_route)
escape_route_thread.start()
sample_function(dfchat)
app.run()
main()
I have tried creating another thread that updates the CSV file:
def retrieve_database():
global dfchat
while True:
time.sleep(0.1)
dfchat = pd.read_csv(path)
along with:
escape_route_thread = threading.Thread(target = retrieve_database)
escape_route_thread.start()
in the main function.
But that fails to update the dfchat data frame when the API launches. I have tested the thread by itself and it does update and return an updated data frame.
From what I understand so far, once an API runs, python code cannot change the API itself.
So,
Is there a way to update a running API with just python?
I'm asking for just python because I will not be able to manually enter a link like "/refresh" to do this. It has to be done by python.
Am I missing something?
Thank you very much for helping!
Edit:
I also tried to update the csv file for every API call. But that does but work either:
def sample_function():
dfchat = pd.read_csv(path)
#app.route('/sample_text', methods=['GET'])
def sample_endpoint():
# this function filters dfchat and returns whatever
Code defined at the root of the script (as was dfchat definition in your example) is executed once at the moment you start the flask server.
Code inside a Flask app route (function decorated with #app.route(...)) is executed at each API call to this route.
from flask import Flask
app = Flask(__name__)
path = "path/to/your/csv/file.csv"
#app.route('/sample_text', methods=['GET'])
def sample_endpoint():
dfchat = pd.read_csv(path)
# do what you have to do with the DF
Also note that Flask handles errors without stopping the API, and has great documentation to help you : https://flask.palletsprojects.com/en/2.0.x/quickstart/#a-minimal-application
So I realized that the solution is really simple. I'm new to CS and APIs in general so I did not realize how #app.route worked in Flask. Outside of #app.route cannot change a route but updating a variable inside a route does work. I accidentally kept updating dfchat outside of #app.route.
def sample_function():
# instead of putting dfchat here
#app.route('/sample_text', methods=['GET'])
def sample_endpoint():
dfchat = pd.read_csv(path) # it should go here.
# this function filters dfchat and returns whatever
Thank you yco for helping me realize this.

How do I call a function every 24 hours in Python? I'm currently using Threading to run a Flask server and the function at the same time

Right now, I'm trying to make a graphing website that tracks the progress (XP) of Discord users with a bot called MEE6, here is my repl. Right now, I'm using Threading to create two separate threads - one for a web server, and one containing a while loop with the function inside:
def func():
while True:
backend.get_details()
time.sleep(86400)
This should make the function run every 24 hours, but as evidenced by the time stamps in the database:
"05-November-2021 00:02:58": 2106855,
"05-November-2021 00:52:48": 2106855,
"05-November-2021 01:23:21": 2106855,
"05-November-2021 03:48:13": 2106874,
"05-November-2021 07:13:40": 2106874
It is not. How can I fix this?
Here is my threading code:
def keep_alive():
server = Thread(target=run)
data = Thread(target=func)
server.start()
data.start()
def run():
app.run(host="0.0.0.0", port=8000)
if __name__ == '__main__':
# s.run()
# os.system('cls')
keep_alive()
# print('i')
Have you tried fixing it using the schedule package? For an example see this post:
Python script to do something at the same time every day
For running a scheduler in the background (i.e. while running an app) see this excellent post:
How to schedule a function to run every hour on Flask?

How to delay the GPIO when using Flask-ask on Pi

I've followed a tutorial on getting Amazon Echo to talk to my Raspberry and it works beautifully.
The part I have added is the GPIO parts in the yes intent so that it flashed an LED when it receives a yes answer from the Echo. Again, it works perfectly.
Now I want to make it so there is a delay on the GPIO so that the Alexa response speaks then the LED flashes. How can I do this?
I've tried creating a variable in the yes intent that gets set to '1' when she answers. Then I tried to return it at the end by adding , variableName then creating an if command outside of the yes intent function, but the variable never seems to come out of the yesintent. I also tried defining the variable as global but still no joy. I just can't think of anything else to Google to do this and I wondered if anyone could help?
The code is as follows:
from flask import Flask
from flask_ask import Ask, statement, question, session
import json
import requests
import time
import unidecode
import RPi.GPIO as GPIO
import time
GPIO.setmode(GPIO.BOARD)
app = Flask(__name__)
ask = Ask(app, "/shocker")
#app.route('/')
def homepage():
welcome = 'hi there, how the fluff is it?'
return statement(welcome)
#ask.launch
def start_skill():
welcome_message = 'Hello there, would you like me to do something?'
return question(welcome_message)
#ask.intent("YesIntent")
def yes_intent():
GPIO.setwarnings(False)
GPIO.setup(7, GPIO.OUT)
GPIO.output(7,1)
time.sleep(1)
GPIO.output(7,0)
yes_message = 'the thing has been done'
return statement(yes_message)
#ask.intent("NoIntent")
def no_intent():
no_message = 'well then why are you wasting my time?'
return statement(no_message)
if __name__ == '__main__':
app.run()

Threading with Bottle.py Server

I'm having an issue with threading that I can't solve in any way I've tried. I searched in StackOverflow too, but all I could find was cases that didn't apply to me, or explanations that I didn't understand.
I'm trying to build an app with BottlePy, and one of the features I want requires a function to run in background. For this, I'm trying to make it run in a thread. However, when I start the thread, it runs twice.
I've read in some places that it would be possible to check if the function was in the main script or in a module using if __name__ == '__main__':, however I'm not able to do this, since __name__ is always returning the name of the module.
Below is an example of what I'm doing right now.
The main script:
# main.py
from MyClass import *
from bottle import *
arg = something
myObject = Myclass(arg1)
app = Bottle()
app.run('''bottle args''')
The class:
# MyClass.py
import threading
import time
class MyClass:
def check_list(self, theList, arg1):
a_list = something()
time.sleep(5)
self.check_list(a_list, arg1)
def __init__(self, arg1):
if __name__ == '__main__':
self.a_list = arg.returnAList()
t = threading.Thread(target=self.check_list, args=(a_list, arg1))
So what I intend here is to have check_list running in a thread all the time, doing something and waiting some seconds to run again. All this so I can have the list updated, and be able to read it with the main script.
Can you explain to me what I'm doing wrong, why the thread is running twice, and how can I avoid this?
This works fine:
import threading
import time
class MyClass:
def check_list(self, theList, arg1):
keep_going=True
while keep_going:
print("check list")
#do stuff
time.sleep(1)
def __init__(self, arg1):
self.a_list = ["1","2"]
t = threading.Thread(target=self.check_list, args=(self.a_list, arg1))
t.start()
myObject = MyClass("something")
Figured out what was wrong thanks to the user Weeble's comment. When he said 'something is causing your main.py to run twice' I remembered that Bottle has an argument that is called 'reloader'. When set to True, this will make the application load twice, and thus the thread creation is run twice as well.

Python Serial Port with threading - freezing computer

Okay, time for another question/post...
So currently i am trying to develop a simple python program that has a webkit/ webpage view and a serial port interface.. Not that it should matter, but this is also running on a raspberry pi.
The following code works fine.. But it will freeze the system as soon as i uncomment the serial port line that you can see commented out.
The day has been long and this one for some reason has my brain fried.. Python is not my strongest point, but mind you this is just a quick test script for now... Yes i have used google and other resources...
#!/usr/bin/env python
import sys
import serial
import threading
import time
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from PyQt4.QtWebKit import *
sURL = ""
sURL2 = ""
objSerial = serial.Serial(0)
def SerialLooper():
global objSerial
if objSerial.isOpen() == True:
print("is_responding")
#objSerial.write("is_responding")
time.sleep(10)
SerialLooper()
class TestCLASS(object):
def __init__(self):
global sURL
global sURL2
global objSerial
objSerial = serial.Serial(0)
sURL = "http://localhost/tester"
app = QApplication(sys.argv)
webMain = QWebView()
webMain.loadFinished.connect(self.load_finished)
webMain.load(QUrl(sURL))
webMain.show()
thread = threading.Thread(target=SerialLooper)
thread.start()
sys.exit(app.exec_())
def load_finished(boolNoErrors):
global sURL
print("Url - " + sURL)
#something here
#something else here
newObjClass = TestCLASS()
EDIT
Futher on this, it appears its not the multithreading but the serial.write()
It has been a while since I used serial, but IIRC it is not threadsafe (on Windows at least). You are opening the port in the main thread and performing a write in another thread. It's a bad practice anyway. You might also consider writing a simple single-threaded program to see if the serial port is actually working.
PS Your program structure could use some work. You only need one of the global statements (global objSerial), the rest do nothing. It would be better to get rid of that one, too.
And the recursive call to SerialLooper() will eventually fail when the recursion depth is exceeded; why not just use a while loop...
def SerialLooper():
while objSerial().isOpen(): # Drop the == True
# print something
# write to the port
# Sleep or do whatever

Categories

Resources