1

I have asked a few questions about this before, but still haven't solved my problem.

I am trying to allow Salesforce to remotely send commands to a Raspberry Pi via JSON (REST API). The Raspberry Pi controls the power of some RF Plugs via an RF Transmitter called a TellStick. This is all setup, and I can use Python to send these commands. All I need to do now is make the Pi accept JSON, then work out how to send the commands from Salesforce.

Someone kindly forked my repo on GitHub, and provided me with some code which should make it work. But unfortunately it still isn't working.

Here is the previous question: How to accept a JSON POST?

And here is the forked repo: https://github.com/bfagundez/RemotePiControl/blob/master/power.py

What do I need to do? I have sent test JSON messages n the Postman extension and in cURL but keep getting errors.

I just want to be able to send various variables, and let the script work the rest out.

I can currently post to a .py script I have with some URL variables, so /python.py?power=on&device=1&time=10&pass=whatever and it figures it out. Surely there's a simple way to send this in JSON?

Here is the power.py code:

# add flask here
from flask import Flask
app = Flask(__name__)
app.debug = True
# keep your code
import time
import cgi
from tellcore.telldus import TelldusCore
core = TelldusCore()
devices = core.devices()

# define a "power ON api endpoint"
@app.route("/API/v1.0/power-on/<deviceId>",methods=['POST'])
def powerOnDevice(deviceId):
    payload = {}
    #get the device by id somehow
    device = devices[deviceId]
    # get some extra parameters 
    # let's say how long to stay on
    params = request.get_json()
    try:
        device.turn_on()
        payload['success'] = True
        return payload
    except:
        payload['success'] = False
        # add an exception description here
        return payload

# define a "power OFF api endpoint"
@app.route("/API/v1.0/power-off/<deviceId>",methods=['POST'])
def powerOffDevice(deviceId):
    payload = {}
    #get the device by id somehow
    device = devices[deviceId]
    try:
        device.turn_off()
        payload['success'] = True
        return payload
    except:
        payload['success'] = False
        # add an exception description here
        return payload

app.run()
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
Lewis Lebentz
  • 817
  • 4
  • 13
  • 24
  • What is the error you get? How do you run your application? – piotrekw Apr 25 '14 at 14:56
  • 1
    You do need to show us your errors and your `curl` command line. [`request.get_json()` method](https://flask.readthedocs.org/en/latest/api/#flask.Request.get_json) states clearly that the mime-type of the request must be `application/json` for it to work, for example. – Martijn Pieters Apr 25 '14 at 14:57
  • Posting your code to GitHub is not sufficient, btw; please include all relevant code *here* in your post. – Martijn Pieters Apr 25 '14 at 14:57
  • use `request.data` instead. check if your data is a valid json before using `request.get_json`. – salmanwahed Apr 25 '14 at 15:12
  • @piotrekw 'sudo python power.py' that starts correctly, it just gives me errors when I try to post JSON to it. See here: https://imgur.com/PsN7Hl0 – Lewis Lebentz Apr 30 '14 at 14:28
  • @MartijnPieters I have posted the code here. Please see my above screenshot for the errors. So application/json needs to be at the top of every JSON request? – Lewis Lebentz Apr 30 '14 at 14:36
  • @Lewis: that error is text; you can copy and paste that into your question too. – Martijn Pieters Apr 30 '14 at 14:43

2 Answers2

1

To retrieve the Json Post values you must use request.json

if request.json and 'email' in request.json:
    request.json['email']
Pirata21
  • 439
  • 3
  • 8
  • So if I include that in power.py, where will it return the values? I just want to be able to send some values to it, and for it to translate that into Python and run the command. – Lewis Lebentz Apr 30 '14 at 15:10
1

Your deviceID variable is a string, not an integer; it contains a '1' digit, but that's not yet an integer.

You can either convert it explicitly:

device = devices[int(deviceId)]

or tell Flask you wanted an integer parameter in the route:

@app.route("/API/v1.0/power-on/<int:deviceId>", methods=['POST'])
def powerOnDevice(deviceId):

where the int: part is a URL route converter.

Your views should return a response object, a string or a tuple instead of a dictionary (as you do now), see About Responses. If you wanted to return JSON, use the flask.json.jsonify() function:

# define a "power ON api endpoint"
@app.route("/API/v1.0/power-on/<int:deviceId>", methods=['POST'])
def powerOnDevice(deviceId):
    device = devices[deviceId]

    # get some extra parameters 
    # let's say how long to stay on
    params = request.get_json()
    try:
        device.turn_on()
        return jsonify(success=True)
    except SomeSpecificException as exc:
        return jsonify(success=False, exception=str(exc))

where I also altered the exception handler to handle a specific exception only; try to avoid Pokemon exception handling; do not try to catch them all!

Community
  • 1
  • 1
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • Thank you. I have now changed that, I can get it to turn a device when posting something... but it works when I post *anything*? If I try and send a time variable (Turns on for the amount) it doesn't turn off, and it doesn't need a password either. – Lewis Lebentz Apr 30 '14 at 15:43
  • 1
    @Lewis: The device name is taken from the route, and your view doesn't require any kind of authentication, so yes, that's how it works. – Martijn Pieters Apr 30 '14 at 15:44
  • How do I now add in variables, and be able to ask for a password, device, time etc.? I can do it via URL Variables – Lewis Lebentz Apr 30 '14 at 16:06
  • 1
    @Lewis: This is getting too broad for comments, I am afraid. You can come and join us in the [Python chat room](http://chat.stackoverflow.com/rooms/6/python), but I recommend you read up more about Flask development and web development in general. The [Flask mega tutorial](http://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-i-hello-world) could be helpful here. – Martijn Pieters Apr 30 '14 at 16:10