From 3df426d1ae6e38853ac495925613bb091522c662 Mon Sep 17 00:00:00 2001 From: f4exb Date: Sat, 28 Sep 2019 22:52:40 +0200 Subject: [PATCH] Added a config.py API script --- scriptsapi/Readme.md | 127 +++++++++++++++++++++++++++++++++++++++++++ scriptsapi/config.py | 85 +++++++++++++++++++++++++++++ 2 files changed, 212 insertions(+) create mode 100755 scriptsapi/config.py diff --git a/scriptsapi/Readme.md b/scriptsapi/Readme.md index 7f2ad9ecf..c602befa5 100644 --- a/scriptsapi/Readme.md +++ b/scriptsapi/Readme.md @@ -56,3 +56,130 @@ In this example we have a Rx device on index 0 and a Tx device on index 1. All s - Stop the running device (Rx or Tx) this will switch over automatically to the other Important: you should initiate switch over by stopping the active device and not by starting the other. + +

config.py

+ +Sends a sequence of commands recorded in a JSON file which is in the form of a list of commands. + +Each command is a JSON document with the following keys: + + - `endpoint`: URL suffix (API function) - mandatory + - `method`: HTTP method (GET, PATCH, POST, PUT, DELETE) - mandatory + - `params`: pairs of argument and values - optional + - `payload`: request body in JSON format - optional + - `msg`: descriptive message for console display - optional + - `delay`: delay in milliseconds after command - optional + +Example of a JSON file (delay is an example you normally do not need it): + +```json +[ + { + "endpoint": "/deviceset/0/device", + "method": "PUT", + "payload": { + "hwType": "HackRF" + }, + "msg": "Set HackRF on Rx 0" + }, + { + "endpoint": "/deviceset/0/device/settings", + "method": "PUT", + "payload": { + "deviceHwType": "HackRF", + "hackRFInputSettings": { + "LOppmTenths": 0, + "bandwidth": 1750000, + "biasT": 0, + "centerFrequency": 433800000, + "dcBlock": 1, + "devSampleRate": 1536000, + "fcPos": 2, + "iqCorrection": 0, + "lnaExt": 1, + "lnaGain": 32, + "log2Decim": 2, + "reverseAPIAddress": "127.0.0.1", + "reverseAPIDeviceIndex": 0, + "reverseAPIPort": 8888, + "useReverseAPI": 0, + "vgaGain": 24 + }, + "direction": 0 + }, + "msg": "Setup HackRF on Rx 0" + }, + { + "endpoint": "/deviceset/0/channel", + "method": "POST", + "payload": { + "channelType": "RemoteSink", + "direction": 0 + }, + "msg": "Add a remote sink channel" + }, + { + "endpoint": "/deviceset/0/channel/0/settings", + "method": "PUT", + "payload": { + "RemoteSinkSettings": { + "dataAddress": "192.168.1.5", + "dataPort": 9094, + "filterChainHash": 0, + "log2Decim": 3, + "nbFECBlocks": 8, + "reverseAPIAddress": "127.0.0.1", + "reverseAPIChannelIndex": 0, + "reverseAPIDeviceIndex": 0, + "reverseAPIPort": 8888, + "rgbColor": -7601148, + "title": "Channel 0", + "txDelay": 0, + "useReverseAPI": 0 + }, + "channelType": "RemoteSink", + "direction": 0 + }, + "msg": "Setup remote sink on channel 0", + "delay": 1000 + }, + { + "endpoint": "/deviceset/0/device/run", + "method": "POST", + "msg": "Start device on deviceset R0" + } +] +``` +If you have presets defined you may also use presets instead of having to set up the device and channels. In this case you only "PUT" the right device and apply the preset like this: + +```json +[ + { + "endpoint": "/deviceset/0/device", + "method": "PUT", + "payload": { + "hwType": "RTLSDR" + }, + "msg": "setup RTLSDR on Rx 0" + }, + { + "endpoint": "/preset", + "method": "PATCH", + "payload": { + "deviceSetIndex": 0, + "preset": { + "groupName": "QO100", + "centerFrequency": 489675000, + "type": "R", + "name": "Narrowband master" + } + }, + "msg": "load preset on Rx 0" + }, + { + "endpoint": "/deviceset/0/device/run", + "method": "POST", + "msg": "Start device on deviceset R0" + } +] +``` \ No newline at end of file diff --git a/scriptsapi/config.py b/scriptsapi/config.py new file mode 100755 index 000000000..5e2c3f9bc --- /dev/null +++ b/scriptsapi/config.py @@ -0,0 +1,85 @@ +#!/usr/bin/env python3 +""" +Sends a sequence of commands recorded in a JSON file which is in the +form of a list of commands. + +Each command is a JSON document with the following keys: + - endpoint: URL suffix (API function) - mandatory + - method: HTTP method (GET, PATCH, POST, PUT, DELETE) - mandatory + - params: pairs of argument and values - optional + - payload: request body in JSON format - optional + - msg: descriptive message for console display - optional + - delay: delay in milliseconds after command - optional +""" + +import requests, traceback, sys, json, time +from optparse import OptionParser + +base_url = "http://127.0.0.1:8091/sdrangel" + +requests_methods = { + "GET": requests.get, + "PATCH": requests.patch, + "POST": requests.post, + "PUT": requests.put, + "DELETE": requests.delete +} + +# ====================================================================== +def getInputOptions(): + + parser = OptionParser(usage="usage: %%prog [-t]\n") + parser.add_option("-a", "--address", dest="address", help="Address and port. Default: 127.0.0.1:8091", metavar="ADDRESS", type="string") + parser.add_option("-j", "--json-file", dest="json_file", help="JSON file containing commands. Mandatory", metavar="FILE", type="string") + + (options, args) = parser.parse_args() + + if (options.address == None): + options.address = "127.0.0.1:8091" + + return options + +# ====================================================================== +def main(): + try: + options = getInputOptions() + + global base_url + base_url = "http://%s/sdrangel" % options.address + + with open(options.json_file) as json_file: + commands = json.load(json_file) + for command in commands: + endpoint = command.get('endpoint', None) + if endpoint is None: + continue + url = base_url + endpoint + http_method = command.get('method', None) + method = requests_methods.get(http_method, None) if http_method is not None else None + if method is not None: + request_params = command.get('params', None) + request_json = command.get('payload', None) + r = method(url=url, params=request_params, json=request_json) + if r.status_code // 100 == 2: + print("Done: %s" % command.get('msg', '')) + else: + print("Error %d:%s" % (r.status_code, command.get('msg', ''))) + print(r.text) + exit(1) + else: + print("requests method error") + exit(1) + delay = command.get('delay', None) + if delay is not None and isinstance(delay, int): + time.sleep(delay/1000) + + print("All done!") + + except Exception as ex: + tb = traceback.format_exc() + print(tb, file=sys.stderr) + + +# ====================================================================== +if __name__ == "__main__": + main()