Skip to content

Commit

Permalink
Merge pull request #1 from jobe3774/command_via_get
Browse files Browse the repository at this point in the history
Enabled command invocation via HTTP GET request
  • Loading branch information
jobe3774 authored Sep 29, 2019
2 parents 3d8ca25 + fe8898b commit 287cccf
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 11 deletions.
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,20 @@ and invokes the method. The response of this HTTP POST request will be your JSON
```
Since remain untouched, you can attach any other information with that command such as an element-id of your frontend invoking it.

Starting with version 1.1.0, you can also use HTTP GET requests to invoke commands. The request has to following structure:

```
/cmd?name=command&arg1=val1&arg2=val2...&argN=valN
```

So for the above mentioned example **theDoorBell.switchDoorBell**, the correct request would be:

```
/cmd?name=theDoorBell.switchDoorBell&onoff=off
```

The **RaspendHTTPServerThread** invokes the command and responds with the result of the invocation as a JSON string.

## How to install?

Make sure you have installed Python 3.5 or higher. I've tested the package on my Raspberry Pi 3 Model B+ running **Raspbian GNU/Linux 9 (stretch)** with Python 3.5.3 installed.
Expand Down
2 changes: 1 addition & 1 deletion raspend.pyproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{d0fd4413-717c-4da2-b189-4cc8bdecbc68}</ProjectGuid>
<ProjectHome />
<StartupFile>example2.py</StartupFile>
<StartupFile>example1.py</StartupFile>
<SearchPath />
<WorkingDirectory>.</WorkingDirectory>
<OutputPath>.</OutputPath>
Expand Down
68 changes: 61 additions & 7 deletions raspend/http.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# -*- coding: utf-8 -*-
#
# The HTTP request handling interface for raspend.
# 'raspend' stands for RaspberryPi EndPoint.
# 'raspend' stands for RaspberryPi Backend.
#
# License: MIT
#
Expand All @@ -11,6 +11,7 @@
from functools import partial
from http.server import BaseHTTPRequestHandler
import json
import urllib

from .utils import stoppablehttpserver

Expand Down Expand Up @@ -181,28 +182,81 @@ def onGetCmds(self):
self.dataLock.release()
return strJsonResponse

def onGetCmd(self, queryParams):
""" Call a command via HTTP GET. The response will be the command's return value as a JSON string.
"""
strJsonResponse = ""

cmdName = queryParams["name"][0]
cmdArgs = dict()

cmd = self.commandMap.get(cmdName)

if cmd == None:
self.send_error(404, ("Command '{0}' not found!".format(cmdName)))
return

del (queryParams["name"])

for k,v in queryParams.items():
cmdArgs[k] = v[0]

result = ""

try:
result = cmd.execute(cmdArgs)
except Exception as e:
self.send_error(500, "An unexpected error occured during execution of '{0}'! Exception: {1}".format(cmdName, e))
return

strJsonResponse = json.dumps(result, ensure_ascii=False)

try:
self.send_response(200)
self.send_header('Content-type', 'application/json; charset=utf-8')
self.send_header('Access-Control-Allow-Origin', '*')
self.end_headers()
self.wfile.write(bytes(strJsonResponse, 'utf-8'))
except OSError:
self.send_error(500)
except BlockingIOError:
self.send_error(500)
except Exception as e:
self.send_error(500, "An unexpected error occured during execution of '{0}'! Exception: {1}".format(cmdName, e))
return

def do_GET(self):
""" Handle HTTP GET request
'/data' : returns the whole 'dataDict' as JSON string
'/data/key' : returns sub-element of 'dataDict' as JSON string
'/cmds' : returns the list of available commands
"""
urlComponents = urllib.parse.urlparse(self.path)
queryParams = urllib.parse.parse_qs(urlComponents.query)

strJsonResponse = ""
if self.path.lower() == "/cmds":

if urlComponents.path.lower() == "/cmds":
if self.commandMap == None or len(self.commandMap) == 0:
self.send_error(501, "No commands available.")
self.send_error(501, "No commands available")
return
else:
strJsonResponse = self.onGetCmds()
elif self.path == "/data" and self.dataDict != None:
elif urlComponents.path.lower() == "/cmd":
if self.commandMap == None or len(self.commandMap) == 0:
self.send_error(501, "No commands available")
return
else:
return self.onGetCmd(queryParams)
elif urlComponents.path.lower() == "/data" and self.dataDict != None:
strJsonResponse = self.onGetRootDataPath()
elif self.path.startswith("/data/") and self.dataDict != None:
elif urlComponents.path.startswith("/data/") and self.dataDict != None:
strJsonResponse = self.onGetDetailedDataPath()
else:
self.send_error(404)
return

try:
self.send_response(200)
self.send_header('Content-type', 'application/json; charset=utf-8')
Expand Down
4 changes: 2 additions & 2 deletions raspend/utils/commandmapping.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,10 +79,10 @@ def invoke(self, args):
Check args and invoke callback method.
"""
if not type(args) is dict:
return False
raise TypeError("Arguments need to be passed in a dictionary!")
for key in args.keys():
if not self.hasParameter(key):
return False
raise KeyError("No argument '{0}' found!".format(key))
return self.__function(**args)

class Command():
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

setuptools.setup(
name="raspend",
version="1.0.2",
version="1.1.0",
author="Joerg Beckers",
author_email="pypi@jobe-software.de",
description="A small and easy to use HTTP backend framework for the Raspberry Pi which is ideal for small to medium-sized home automation projects.",
Expand Down

0 comments on commit 287cccf

Please sign in to comment.