guiguiabloc / rpisurv-api

API for rpisurv
MIT License
2 stars 3 forks source link

FEATURE REQUEST: JQ output & status #2

Open dlasher opened 1 year ago

dlasher commented 1 year ago

First, thank you!

Second, two things more useful to me, coded/attached, in case you want to use my code:

  1. /camera/status - to see which camera we're using
  2. output in JQ format, which would allow an external service to know status, make change, confirm change, etc.

needs to be able to read/write to /tmp for status.

# Gruik coded by GuiguiAbloc
# Flask version 1.1.0 or better required
import flask
import time
import keyboard
app = flask.Flask(__name__)

@app.route('/')
def index():
  return 'Server Works!'

@app.route('/camera/pause')
def campause():
  try:
      text_file = open("/tmp/rpi.status", "w")
      text_file.write('pause')
      text_file.close()
      text_file = open("/tmp/rpi.camera", "r")
      rcamera = text_file.read()
      text_file.close()
      keyboard.press_and_release('p')
      return {
          "status": "pause",
          "camera": rcamera,
      }
  except:
      print("Error")
      return "Error"

@app.route('/camera/resume')
def camresume():
  try:
      text_file = open("/tmp/rpi.status", "w")
      text_file.write('resume')
      text_file.close()
      text_file = open("/tmp/rpi.camera", "r")
      rcamera = text_file.read()
      text_file.close()
      keyboard.press_and_release('r')
      return {
          "status": "resume",
          "camera": rcamera,
      }
  except:
      print("Error")
      return "Error"

@app.route('/camera/status')
def camstatus():
   try:
      text_file = open("/tmp/rpi.status", "r")
      rstatus = text_file.read()
      text_file.close()
      text_file = open("/tmp/rpi.camera", "r")
      rcamera = text_file.read()
      text_file.close()
      return {
          "status": rstatus,
          "camera": rcamera
      }
   except:
      print("Error")
      return "Error"

@app.route('/camera/1')
def cam1():
  try:
      text_file = open("/tmp/rpi.status", "r")
      rstatus = text_file.read()
      text_file.close()
      text_file = open("/tmp/rpi.camera", "w")
      text_file.write('1')
      text_file.close()
      keyboard.press_and_release('F1')
      return {
          "status": rstatus,
          "camera": "1",
      }
  except:
      print("Error")
      return "Error"

@app.route('/camera/2')
def cam2():
  try:
      text_file = open("/tmp/rpi.status", "r")
      rstatus = text_file.read()
      text_file.close()
      text_file = open("/tmp/rpi.camera", "w")
      text_file.write('2')
      text_file.close()
      keyboard.press_and_release('F2')
      return {
          "status": rstatus,
          "camera": "2",
      }
  except:
      print("Error")
      return "Error"

@app.route('/camera/3')
def cam3():
  try:
      text_file = open("/tmp/rpi.status", "r")
      rstatus = text_file.read()
      text_file.close()
      text_file = open("/tmp/rpi.camera", "w")
      text_file.write('3')
      text_file.close()
      keyboard.press_and_release('F3')
      return {
          "status": rstatus,
          "camera": "3",
      }
  except:
      print("Error")
      return "Error"

@app.route('/camera/4')
def cam4():
  try:
      text_file = open("/tmp/rpi.status", "r")
      rstatus = text_file.read()
      text_file.close()
      text_file = open("/tmp/rpi.camera", "w")
      text_file.write('4')
      text_file.close()
      keyboard.press_and_release('F4')
      return {
          "status": rstatus,
          "camera": "4",
      }
  except:
      print("Error")
      return "Error"

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000, debug=False)
dlasher commented 1 year ago

used like this:

root@nvr2:~# curl -q http://10.1.1.100:5000/camera/1 | jq { "camera": "1", "status": "resume" }

stevenhorner commented 1 year ago

@dlasher This doesn't work for me.

If I run your modified version of the code and tried any of the urls I am returned "error" and the action such as changing to screen 2 does not happen

I believe this is because rpi.status has not been created at this point. If I create rpi.status either manually or by modifying the code to create it when the code is executed then the action 1 was trying to take happens, such as changing the screen, pausing etc. However, I am then returned "Internal Server Error" and not the expected JSON. rpi.status is being updated with paused or resume once I created the file, it just isn't returning which was the point of your changed code.

It is highly likely that I am doing something wrong here, I can more or less understand what python is doing and modify the code but don't enough to fix it. Although changing the return value just to a string stops the error but then it's returning valid JSON.

log.txt shows the following:

[2023-09-22 16:59:42,204] ERROR in app: Exception on /camera/1 [GET]
Traceback (most recent call last):
  File "/usr/lib/python3/dist-packages/flask/app.py", line 1974, in make_response
    rv = self.response_class.force_type(rv, request.environ)
  File "/usr/lib/python3/dist-packages/werkzeug/wrappers.py", line 929, in force_type
    response = BaseResponse(*_run_wsgi_app(response, environ))
  File "/usr/lib/python3/dist-packages/werkzeug/test.py", line 923, in run_wsgi_app
    app_rv = app(environ, start_response)
TypeError: 'dict' object is not callable

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/lib/python3/dist-packages/flask/app.py", line 2292, in wsgi_app
    response = self.full_dispatch_request()
  File "/usr/lib/python3/dist-packages/flask/app.py", line 1816, in full_dispatch_request
    return self.finalize_request(rv)
  File "/usr/lib/python3/dist-packages/flask/app.py", line 1831, in finalize_request
    response = self.make_response(rv)
  File "/usr/lib/python3/dist-packages/flask/app.py", line 1982, in make_response
    reraise(TypeError, new_error, sys.exc_info()[2])
  File "/usr/lib/python3/dist-packages/flask/_compat.py", line 34, in reraise
    raise value.with_traceback(tb)
  File "/usr/lib/python3/dist-packages/flask/app.py", line 1974, in make_response
    rv = self.response_class.force_type(rv, request.environ)
  File "/usr/lib/python3/dist-packages/werkzeug/wrappers.py", line 929, in force_type
    response = BaseResponse(*_run_wsgi_app(response, environ))
  File "/usr/lib/python3/dist-packages/werkzeug/test.py", line 923, in run_wsgi_app
    app_rv = app(environ, start_response)
TypeError: 'dict' object is not callable
The view function did not return a valid response. The return type must be a string, tuple, Response instance, or WSGI callable, but it was a dict.
stevenhorner commented 1 year ago

@dlasher it appears that you need Flask version 1.1.0 or above for JSON to be returned as written, the latest version available on buster is 1.0.2 that I am currently running rpisurv on.

dlasher commented 1 year ago

@dlasher it appears that you need Flask version 1.1.0 or above for JSON to be returned as written, the latest version available on buster is 1.0.2 that I am currently running rpisurv on.

Excellent find - I suspected it was a library version issue of some sort. Added an inline comment above.