diff --git a/README.md b/README.md
index 7483be2..43cd3e3 100644
--- a/README.md
+++ b/README.md
@@ -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.
diff --git a/raspend.pyproj b/raspend.pyproj
index e81e7d1..ec7e824 100644
--- a/raspend.pyproj
+++ b/raspend.pyproj
@@ -5,7 +5,7 @@
2.0
{d0fd4413-717c-4da2-b189-4cc8bdecbc68}
- example2.py
+ example1.py
.
.
diff --git a/raspend/http.py b/raspend/http.py
index 4c84fe5..c3132b7 100644
--- a/raspend/http.py
+++ b/raspend/http.py
@@ -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
#
@@ -11,6 +11,7 @@
from functools import partial
from http.server import BaseHTTPRequestHandler
import json
+import urllib
from .utils import stoppablehttpserver
@@ -181,6 +182,49 @@ 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
@@ -188,21 +232,31 @@ def do_GET(self):
'/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')
diff --git a/raspend/utils/commandmapping.py b/raspend/utils/commandmapping.py
index f6162cd..51b1b75 100644
--- a/raspend/utils/commandmapping.py
+++ b/raspend/utils/commandmapping.py
@@ -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():
diff --git a/setup.py b/setup.py
index f08e169..d4b6b32 100644
--- a/setup.py
+++ b/setup.py
@@ -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.",