From a371a624b85fe64abb678b7e9c72cf2bb64ba65b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pascal=20H=C3=B6hnel?= <20238923+uupascal@users.noreply.github.com> Date: Fri, 6 Jan 2023 18:25:58 +0000 Subject: [PATCH 01/11] Added support for 3 new parameters in the codesend-binary --- Dockerfile | 2 +- rest-light.py | 14 +++++++++----- 2 files changed, 10 insertions(+), 6 deletions(-) mode change 100644 => 100755 rest-light.py diff --git a/Dockerfile b/Dockerfile index dbdf84f..86a79b0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -21,7 +21,7 @@ RUN export BUILD_TOOLS="git make gcc g++" && export WIRINGPI_SUDO="" \ && cd /opt/wiringPi && rm -rf .git && ./build \ && git clone --recursive https://github.com/ninjablocks/433Utils.git /opt/433Utils \ && cd /opt/433Utils \ - && git reset --hard "31c0ea4e158287595a6f6116b6151e72691e1839" \ + && git reset --hard "755cec14a7e16604f214beef2dcad8dbd09de324" \ && rm -rf .git && cd "RPi_utils" && make all \ && apt purge -y $BUILD_TOOLS && apt-get autoremove -y\ && rm -rf /tmp/* /var/lib/apt/lists/* \ diff --git a/rest-light.py b/rest-light.py old mode 100644 new mode 100755 index dce6c4d..ec49fd2 --- a/rest-light.py +++ b/rest-light.py @@ -1,3 +1,4 @@ +#!/usr/bin/env python3 ################################################## # Imports & Global variables ################################################## @@ -106,7 +107,7 @@ def check_access(input_args): return (False, {'error': 'No API-Key provided'}) # function to reveive arguments from request -def parse_request(request, required_arguments): +def parse_request(request, required_arguments, optional_arguments = []): input_args = None if request.is_json: input_args = request.get_json() @@ -119,10 +120,10 @@ def parse_request(request, required_arguments): return (valid, error) arguments = {} - for argument in required_arguments: + for argument in required_arguments + optional_arguments: if argument in input_args: arguments[argument] = sanitize_input(input_args[argument]) - else: + elif argument not in input_args and argument in required_arguments: logging.info('API-Request without mandory field ' + argument) return (False, {'error': 'Mandatory field ' + argument + ' not provided'}) @@ -187,12 +188,15 @@ def send(): @app.route('/codesend', methods=['POST']) def codesend(): request_valid, parsed_request = parse_request( - request, ['decimalcode']) + request, ['decimalcode'], ['protocol', 'pulselength', 'bitlength']) if not request_valid: return parsed_request return run_command([paths['433utils'] + "/codesend", - parsed_request['decimalcode']]) + parsed_request['decimalcode'], + parsed_request['protocol'] if 'protocol' in parsed_request else "", + parsed_request['pulselength'] if 'pulselength' in parsed_request else "", + parsed_request['bitlength'] if 'bitlength' in parsed_request else "" ]) ################################################## From c8bd4d540729ba3daa9a23b5de6888bec8504307 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pascal=20H=C3=B6hnel?= <20238923+uupascal@users.noreply.github.com> Date: Fri, 6 Jan 2023 18:27:59 +0000 Subject: [PATCH 02/11] fix piperline --- .github/workflows/publish_dev.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/publish_dev.yml b/.github/workflows/publish_dev.yml index a6c5d0b..3ae92d8 100644 --- a/.github/workflows/publish_dev.yml +++ b/.github/workflows/publish_dev.yml @@ -40,8 +40,8 @@ jobs: id: date run: echo "::set-output name=date::$(date +'%Y.%m.%d')" - - name: Pull image to leverage cache - run: docker pull "$IMAGE_NAME:DEV-latest" + # - name: Pull image to leverage cache + # run: docker pull "$IMAGE_NAME:DEV-latest" - name: Build the tagged Docker image run: > From 6eb1987f9bfa0ad75ac28fed066cb5ab38a222d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pascal=20H=C3=B6hnel?= <20238923+uupascal@users.noreply.github.com> Date: Fri, 6 Jan 2023 18:32:17 +0000 Subject: [PATCH 03/11] Empty-Commit From 58f63b255ece4e84981c2be4cf247c2ac7c7107a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pascal=20H=C3=B6hnel?= <20238923+uupascal@users.noreply.github.com> Date: Fri, 6 Jan 2023 18:35:08 +0000 Subject: [PATCH 04/11] update README with new codesend parameters --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index b15b8ad..db9099d 100644 --- a/README.md +++ b/README.md @@ -68,7 +68,10 @@ curl http://127.0.0.1:4242/send \ curl http://127.0.0.1:4242/codesend \ --data-urlencode "api_key=" \ - --data-urlencode "decimalcode=500000" + --data-urlencode "decimalcode=500000" \ + --data-urlencode "protocol=optional" \ + --data-urlencode "pulselength=optional" \ + --data-urlencode "bitlength=optional" ``` ## OpenHAB integration example From c7fb89ac78dc07ecfc5da194406f4dad9bb89bfc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pascal=20H=C3=B6hnel?= <20238923+uupascal@users.noreply.github.com> Date: Fri, 6 Jan 2023 18:36:43 +0000 Subject: [PATCH 05/11] fix pipeline --- .github/workflows/publish_dev.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/publish_dev.yml b/.github/workflows/publish_dev.yml index 3ae92d8..a640855 100644 --- a/.github/workflows/publish_dev.yml +++ b/.github/workflows/publish_dev.yml @@ -15,7 +15,7 @@ on: paths-ignore: - '**.md' - '.gitignore' - - '.github/**' + # - '.github/**' - '.doc/**' jobs: @@ -40,8 +40,8 @@ jobs: id: date run: echo "::set-output name=date::$(date +'%Y.%m.%d')" - # - name: Pull image to leverage cache - # run: docker pull "$IMAGE_NAME:DEV-latest" + - name: Pull image to leverage cache + run: docker pull "$IMAGE_NAME:DEV-latest" || true - name: Build the tagged Docker image run: > From b6767ec342d0ddba9c79b6e7476356d4d96f4c92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pascal=20H=C3=B6hnel?= <20238923+uupascal@users.noreply.github.com> Date: Fri, 6 Jan 2023 18:37:48 +0000 Subject: [PATCH 06/11] fix pipeline II --- .github/workflows/publish_dev.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/publish_dev.yml b/.github/workflows/publish_dev.yml index a640855..96d5cde 100644 --- a/.github/workflows/publish_dev.yml +++ b/.github/workflows/publish_dev.yml @@ -15,7 +15,6 @@ on: paths-ignore: - '**.md' - '.gitignore' - # - '.github/**' - '.doc/**' jobs: From 101bab4f40a8f1d3443be04e43dc241f3bc880e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pascal=20H=C3=B6hnel?= <20238923+uupascal@users.noreply.github.com> Date: Fri, 6 Jan 2023 18:38:22 +0000 Subject: [PATCH 07/11] fix pipeline III --- .github/workflows/publish_dev.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/publish_dev.yml b/.github/workflows/publish_dev.yml index 96d5cde..cabd05b 100644 --- a/.github/workflows/publish_dev.yml +++ b/.github/workflows/publish_dev.yml @@ -39,8 +39,8 @@ jobs: id: date run: echo "::set-output name=date::$(date +'%Y.%m.%d')" - - name: Pull image to leverage cache - run: docker pull "$IMAGE_NAME:DEV-latest" || true + - name: Pull image to leverage cache + run: docker pull "$IMAGE_NAME:DEV-latest" || true - name: Build the tagged Docker image run: > From 4f192eb716af02ae2e3ad097114750dda4d3d4d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pascal=20H=C3=B6hnel?= <20238923+uupascal@users.noreply.github.com> Date: Fri, 6 Jan 2023 18:43:36 +0000 Subject: [PATCH 08/11] try update to bullseye due to missing armv5 image on dockerhub for buster --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 86a79b0..c8f7462 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM python:3-slim-buster +FROM python:3-slim-bullseye LABEL authors="Pascal Höhnel" From 22cc4f3efa61d26d498a6245f52c74302be6e827 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pascal=20H=C3=B6hnel?= <20238923+uupascal@users.noreply.github.com> Date: Fri, 6 Jan 2023 18:56:07 +0000 Subject: [PATCH 09/11] pin version to older buster for armv5 compatibility --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index c8f7462..bb150f3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM python:3-slim-bullseye +FROM python:3.11.0b3-slim-buster LABEL authors="Pascal Höhnel" From 2a412076c482ec924466ea5b0b30ae3848ee7a8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pascal=20H=C3=B6hnel?= <20238923+uupascal@users.noreply.github.com> Date: Sat, 7 Jan 2023 06:01:48 +0000 Subject: [PATCH 10/11] Update README with codesend example --- README.md | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 52 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index db9099d..bf1e63d 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,8 @@ The project is an API-Wrapper around the famous [443Utils](https://github.com/ni + [docker run](#docker-run) + [docker-compose](#docker-compose) - [curl request example](#curl-request-example) -- [OpenHAB integration example](#openhab-integration-example) +- [OpenHAB integration example for the `send` binary](#openhab-integration-example-for-the--send--binary) +- [OpenHAB integration example for the `codesend` binary](#openhab-integration-example-for-the--codesend--binary) - [Security considerations](#security-considerations) - [Versioning & docker tags](#versioning---docker-tags) - [Contribution](#contribution) @@ -74,7 +75,7 @@ curl http://127.0.0.1:4242/codesend \ --data-urlencode "bitlength=optional" ``` -## OpenHAB integration example +## OpenHAB integration example for the `send` binary In this example, new devices can be added by simply adding a switch to the group `gREST_light`, whichs name is in the format `example__`. @@ -126,6 +127,55 @@ end ``` +## OpenHAB integration example for the `codesend` binary + +In this example, new devices can be added by simply adding a switch to the group `gREST_light`, whichs name is in the format +`example__`. + +The included rule receives the values from the item name, as soon as any item in the group is triggered. + +__RESTlight.items__ +``` +Group:Switch:OR(OFF, ON) gREST_light "REST-light" ["Location"] + +Switch RESTLight_10000_1 "Light" (mygroup, gREST_light) ["Switch"] +Switch RESTLight_01000_3 "Light2" (mygroup, gREST_light) ["Switch"] +Switch RESTLight_00100_3 "Light3" (mygroup, gREST_light) ["Switch"] +``` + +__RESTlight.rules__ +``` +rule "REST_light" + when + Member of gREST_light received command + then + logInfo("REST_light", "Member " + triggeringItem.name + " to " + receivedCommand) + + try { + // receive decimal codes from item name, e.g. zap_1234567_2345678_key1 + var decimal_code = "" + if(receivedCommand == ON) { + decimal_code = triggeringItem.name.toString.split("_").get(1) + } if(receivedCommand == OFF) { + decimal_code = triggeringItem.name.toString.split("_").get(2) + } + + var protocol = "1" + var pulselength = "150" + + var String jsonstring = ('{"api_key" : "", "decimalcode" : "' + decimal_code + '", "protocol" : "' + protocol + '", "pulselength" : "' + pulselength + '"}') + + sendHttpPostRequest("http://:4242/codesend", "application/json", jsonstring.toString, 5000) + logInfo("REST_light", jsonstring.toString) + logInfo("REST_light", "Finished command!") + + } catch(Throwable t) { + logInfo("REST_light", "Caught exception during attempt to contact REST_light API!") + } +end + +``` + ## Security considerations Although this project was developed with current security best-practices in mind, it is still built around software From 7d53d581b55726409a7f769c994f5db561241a03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pascal=20H=C3=B6hnel?= <20238923+uupascal@users.noreply.github.com> Date: Sat, 7 Jan 2023 06:16:40 +0000 Subject: [PATCH 11/11] python linting --- rest-light.py | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/rest-light.py b/rest-light.py index ec49fd2..677b963 100755 --- a/rest-light.py +++ b/rest-light.py @@ -2,14 +2,14 @@ ################################################## # Imports & Global variables ################################################## -from flask import Flask, request +import random +import sys +import subprocess import os import logging import re import string -import subprocess -import sys -import random +from flask import Flask, request app = Flask(__name__) DEBUG_MODE = False @@ -86,11 +86,11 @@ def load_key(): # function that cleans input from possible injections def sanitize_input(input): output = None - try: + try: output = re.findall("\w+", str(input))[0] except BaseException as e: - logging.error('Received unparsable web-request') - logging.error(str(e)) + logging.error('Received unparsable web-request') + logging.error(str(e)) return output # function to check, if a provided api-key is valid @@ -129,7 +129,7 @@ def parse_request(request, required_arguments, optional_arguments = []): return (True, arguments) -# function that runs a OS-Subprocess and generates a return-dict +# function that runs a OS-Subprocess and generates a return-dict def run_command(arguments): # Run Command and capture output run_result = None @@ -138,14 +138,17 @@ def run_command(arguments): except subprocess.SubprocessError as e: logging.fatal( "Running of subprocess resulted in SubprocessError: " + str(e.output)) - return {'status': 'Error', 'stdout': "Running of subprocess resulted in SubprocessError: " + str(e.output)} + return {'status': 'Error', + 'stdout': "Running of subprocess resulted in SubprocessError: " + str(e.output)} except FileNotFoundError as e: logging.fatal( "Running of subprocess resulted in FileNotFoundError: " + str(e.strerror)) - return {'status': 'Error', 'stdout': "Running of subprocess resulted in FileNotFoundError: " + str(e.strerror)} + return {'status': 'Error', + 'stdout': "Running of subprocess resulted in FileNotFoundError: " + str(e.strerror)} except BaseException as e: logging.fatal('Unkown exception when trying to run subprocess! ' + str(e)) - return {'status': 'Error', 'stdout': 'Unkown exception when trying to run subprocess! ' + str(e)} + return {'status': 'Error', + 'stdout': 'Unkown exception when trying to run subprocess! ' + str(e)} # treat output try: @@ -155,13 +158,15 @@ def run_command(arguments): elif run_result is not None and hasattr(run_result, 'stderr'): logging.error( "Running of command " + " ".join(arguments) + " failed with output: " + str(run_result.stderr)) - return {'status': 'Error', 'stdout': str(run_result.stdout), 'stdout': str(run_result.stderr) } + return {'status': 'Error', + 'stdout': str(run_result.stdout), 'stderr': str(run_result.stderr) } else: logging.error("Running of command " + " ".join(arguments) + " failed without output") return {'status': 'Error', 'stdout': 'Could not run command!'} except BaseException as e: logging.fatal('Unkown exception when trying to parse command " + " ".join(arguments) + " output! ' + str(e)) - return {'status': 'Error', 'stdout': 'Unkown exception when trying to parse subprocess output! ' + str(e)} + return {'status': 'Error', + 'stdout': 'Unkown exception when trying to parse subprocess output! ' + str(e)} ################################################## # Flask routes