Skip to content

Commit 287cccf

Browse files
authored
Merge pull request #1 from jobe3774/command_via_get
Enabled command invocation via HTTP GET request
2 parents 3d8ca25 + fe8898b commit 287cccf

File tree

5 files changed

+79
-11
lines changed

5 files changed

+79
-11
lines changed

README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,20 @@ and invokes the method. The response of this HTTP POST request will be your JSON
197197
```
198198
Since remain untouched, you can attach any other information with that command such as an element-id of your frontend invoking it.
199199

200+
Starting with version 1.1.0, you can also use HTTP GET requests to invoke commands. The request has to following structure:
201+
202+
```
203+
/cmd?name=command&arg1=val1&arg2=val2...&argN=valN
204+
```
205+
206+
So for the above mentioned example **theDoorBell.switchDoorBell**, the correct request would be:
207+
208+
```
209+
/cmd?name=theDoorBell.switchDoorBell&onoff=off
210+
```
211+
212+
The **RaspendHTTPServerThread** invokes the command and responds with the result of the invocation as a JSON string.
213+
200214
## How to install?
201215

202216
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.

raspend.pyproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
<SchemaVersion>2.0</SchemaVersion>
66
<ProjectGuid>{d0fd4413-717c-4da2-b189-4cc8bdecbc68}</ProjectGuid>
77
<ProjectHome />
8-
<StartupFile>example2.py</StartupFile>
8+
<StartupFile>example1.py</StartupFile>
99
<SearchPath />
1010
<WorkingDirectory>.</WorkingDirectory>
1111
<OutputPath>.</OutputPath>

raspend/http.py

Lines changed: 61 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
# -*- coding: utf-8 -*-
33
#
44
# The HTTP request handling interface for raspend.
5-
# 'raspend' stands for RaspberryPi EndPoint.
5+
# 'raspend' stands for RaspberryPi Backend.
66
#
77
# License: MIT
88
#
@@ -11,6 +11,7 @@
1111
from functools import partial
1212
from http.server import BaseHTTPRequestHandler
1313
import json
14+
import urllib
1415

1516
from .utils import stoppablehttpserver
1617

@@ -181,28 +182,81 @@ def onGetCmds(self):
181182
self.dataLock.release()
182183
return strJsonResponse
183184

185+
def onGetCmd(self, queryParams):
186+
""" Call a command via HTTP GET. The response will be the command's return value as a JSON string.
187+
"""
188+
strJsonResponse = ""
189+
190+
cmdName = queryParams["name"][0]
191+
cmdArgs = dict()
192+
193+
cmd = self.commandMap.get(cmdName)
194+
195+
if cmd == None:
196+
self.send_error(404, ("Command '{0}' not found!".format(cmdName)))
197+
return
198+
199+
del (queryParams["name"])
200+
201+
for k,v in queryParams.items():
202+
cmdArgs[k] = v[0]
203+
204+
result = ""
205+
206+
try:
207+
result = cmd.execute(cmdArgs)
208+
except Exception as e:
209+
self.send_error(500, "An unexpected error occured during execution of '{0}'! Exception: {1}".format(cmdName, e))
210+
return
211+
212+
strJsonResponse = json.dumps(result, ensure_ascii=False)
213+
214+
try:
215+
self.send_response(200)
216+
self.send_header('Content-type', 'application/json; charset=utf-8')
217+
self.send_header('Access-Control-Allow-Origin', '*')
218+
self.end_headers()
219+
self.wfile.write(bytes(strJsonResponse, 'utf-8'))
220+
except OSError:
221+
self.send_error(500)
222+
except BlockingIOError:
223+
self.send_error(500)
224+
except Exception as e:
225+
self.send_error(500, "An unexpected error occured during execution of '{0}'! Exception: {1}".format(cmdName, e))
226+
return
227+
184228
def do_GET(self):
185229
""" Handle HTTP GET request
186230
187231
'/data' : returns the whole 'dataDict' as JSON string
188232
'/data/key' : returns sub-element of 'dataDict' as JSON string
189233
'/cmds' : returns the list of available commands
190234
"""
235+
urlComponents = urllib.parse.urlparse(self.path)
236+
queryParams = urllib.parse.parse_qs(urlComponents.query)
237+
191238
strJsonResponse = ""
192-
193-
if self.path.lower() == "/cmds":
239+
240+
if urlComponents.path.lower() == "/cmds":
194241
if self.commandMap == None or len(self.commandMap) == 0:
195-
self.send_error(501, "No commands available.")
242+
self.send_error(501, "No commands available")
243+
return
196244
else:
197245
strJsonResponse = self.onGetCmds()
198-
elif self.path == "/data" and self.dataDict != None:
246+
elif urlComponents.path.lower() == "/cmd":
247+
if self.commandMap == None or len(self.commandMap) == 0:
248+
self.send_error(501, "No commands available")
249+
return
250+
else:
251+
return self.onGetCmd(queryParams)
252+
elif urlComponents.path.lower() == "/data" and self.dataDict != None:
199253
strJsonResponse = self.onGetRootDataPath()
200-
elif self.path.startswith("/data/") and self.dataDict != None:
254+
elif urlComponents.path.startswith("/data/") and self.dataDict != None:
201255
strJsonResponse = self.onGetDetailedDataPath()
202256
else:
203257
self.send_error(404)
204258
return
205-
259+
206260
try:
207261
self.send_response(200)
208262
self.send_header('Content-type', 'application/json; charset=utf-8')

raspend/utils/commandmapping.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,10 +79,10 @@ def invoke(self, args):
7979
Check args and invoke callback method.
8080
"""
8181
if not type(args) is dict:
82-
return False
82+
raise TypeError("Arguments need to be passed in a dictionary!")
8383
for key in args.keys():
8484
if not self.hasParameter(key):
85-
return False
85+
raise KeyError("No argument '{0}' found!".format(key))
8686
return self.__function(**args)
8787

8888
class Command():

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
setuptools.setup(
1414
name="raspend",
15-
version="1.0.2",
15+
version="1.1.0",
1616
author="Joerg Beckers",
1717
author_email="pypi@jobe-software.de",
1818
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.",

0 commit comments

Comments
 (0)