From 24fe5c873d89d76bf79bd3b77b2bfc36cac2e186 Mon Sep 17 00:00:00 2001 From: Michael Clemens Date: Sat, 27 Nov 2021 23:58:18 +0000 Subject: [PATCH] moved client and server into a single project fixed a lot of bugs added pushable button with long and short press added antenna toggle script --- README.md | 49 ++++- hr50_fonts.h => client/hr50_fonts.h | 0 .../hr50_rd_client.ino | 108 ++++++----- server/__init__.py | 0 server/__pycache__/__init__.cpython-37.pyc | Bin 0 -> 134 bytes .../__pycache__/hr50_rd_server.cpython-37.pyc | Bin 0 -> 3809 bytes server/__pycache__/hr50_server.cpython-37.pyc | Bin 0 -> 3809 bytes server/__pycache__/hr50api.cpython-37.pyc | Bin 0 -> 3805 bytes server/bootstrap.sh | 2 + server/hr50_rd_server.py | 179 ++++++++++++++++++ server/scripts/toggle_antenna.sh | 16 ++ 11 files changed, 297 insertions(+), 57 deletions(-) rename hr50_fonts.h => client/hr50_fonts.h (100%) rename hr50-remote-display.ino => client/hr50_rd_client.ino (51%) create mode 100644 server/__init__.py create mode 100644 server/__pycache__/__init__.cpython-37.pyc create mode 100644 server/__pycache__/hr50_rd_server.cpython-37.pyc create mode 100644 server/__pycache__/hr50_server.cpython-37.pyc create mode 100644 server/__pycache__/hr50api.cpython-37.pyc create mode 100755 server/bootstrap.sh create mode 100644 server/hr50_rd_server.py create mode 100755 server/scripts/toggle_antenna.sh diff --git a/README.md b/README.md index 56b5f64..68bfa3a 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,7 @@ This is how the display looks like in action: ![Photo of the Heltec board](hr50-remote-display.jpg "Photo of the Heltec board") +# Client ## Preconditions @@ -25,7 +26,6 @@ This is how the display looks like in action: ### Software * Arduino IDE -* HR50-Api: [https://git.qrz.is/clemens/hr50-api] ### Libraries @@ -33,6 +33,7 @@ This is how the display looks like in action: * ArduinoJson * HTTPClient * WiFi +* EasyButton ## Configuration @@ -41,7 +42,7 @@ Edit the following lines inside the Arduino sketch: ``` const char* ssid = ""; const char* password = ""; -String api_url = "http://:5000/status"; +String api_base_url = "http://:5000"; ``` ## Error handling @@ -49,3 +50,47 @@ String api_url = "http://:5000/status"; * If wifi is unavailable or misconfigured, the device will show "No Wifi!" on the screen * HTTP Errors will also displayed on the OLED * When you key up your TRX and therefore the HR50, no serial communication is possible. The latest gathered information will still be displayed on the screen but there will be a "(!)" in the third row as an indicator for this situation. + + +# Server + +# Preconditions + +You need a computer connected to the Hardrock-50 via USB, e.g. a Raspberry Pi. This system needs to be able to run Python and has to be connected to your network. + +# Configuration + +Open the file _hr50_rd_server.py_ and adapt the following lines to your environment: + +``` +serial_port = '/dev/ttyUSB0' +baud = 19200 +``` + +# Execution + +Executing this script will spawn a web server running on port 5000. This is not meant for production use and/or public exposure. Anyone able to access this server via the network can alter any settings on your HR50. + +Run it as follows: + +``` +# cd server +# ./bootstrap.sh +``` + +# API Endpoints + +There are two API endpoints available: + +#### /exec_serial + +This method allows you to send commands to the HR50. The commands can be taken from the HR50 operator's manual and do not require the trailing ";" + +#### /exec_shell + +This method allows you to execute shell commands on the server + +#### /get_status + +This method returns all avalable information in JSON + diff --git a/hr50_fonts.h b/client/hr50_fonts.h similarity index 100% rename from hr50_fonts.h rename to client/hr50_fonts.h diff --git a/hr50-remote-display.ino b/client/hr50_rd_client.ino similarity index 51% rename from hr50-remote-display.ino rename to client/hr50_rd_client.ino index 5a66e51..d1b975a 100644 --- a/hr50-remote-display.ino +++ b/client/hr50_rd_client.ino @@ -4,38 +4,45 @@ #include "heltec.h" #include #include "hr50_fonts.h" +#include -#define ESP_INTR_FLAG_DEFAULT 0 -#define PRG_BUTTON 0 +// Pin 0 is the built-in upper button +#define BUTTON_PIN 0 +EasyButton button(BUTTON_PIN); const char* ssid = ""; const char* password = ""; String api_base_url = "http://:5000"; -//String api_button_url = api_base_url + "/?cmd=hrtu1"; -String api_button_url = api_base_url + "/exec"; -String api_status_url = api_base_url + "/status"; + +// Contruct API calls +String api_button_long = api_base_url + "/exec_serial"; +String api_button_short = api_base_url + "/exec_shell"; +String api_status_url = api_base_url + "/get_status"; + int first_row = 0; int second_row = 24; int third_row = 48; int left = 0; int right = 128; + String cmd_status = ""; -SemaphoreHandle_t semaphore = nullptr; +// milliseconds of button push until count as a long press +int duration = 1000; -void IRAM_ATTR handler(void* arg) { - xSemaphoreGiveFromISR(semaphore, NULL); +// This happens when the button will be pressed long +void long_button_press() { + cmd_status = send_http_request(api_button_long); } -void button_task(void* arg) { - for (;;) { - if (xSemaphoreTake(semaphore, portMAX_DELAY) == pdTRUE) { - cmd_status = send_http_request(api_button_url); - } - } +// This happens when the button will be pressed short +void short_button_press() { + cmd_status = send_http_request(api_button_short); } + +// Sends a HTTP request to the server and grabs the response String send_http_request(String url) { HTTPClient http; String response = ""; @@ -53,31 +60,27 @@ String send_http_request(String url) { } +// Things that need to be done after booting the device void setup() { + // Initialize Heltec display Heltec.begin(true /*DisplayEnable Enable*/, false /*LoRa Disable*/, false /*Serial Enable*/); Heltec.display->flipScreenVertically(); Heltec.display->setFont(DialogInput_plain_16); - + + // Log into Wifi and wait a bit WiFi.begin(ssid, password); delay(4000); - // Configure PRG button of the Heltec - semaphore = xSemaphoreCreateBinary(); - // Setup the button GPIO pin - gpio_pad_select_gpio(PRG_BUTTON ); - // Quite obvious, a button is a input - gpio_set_direction(GPIO_NUM_0, GPIO_MODE_INPUT); - // Trigger the interrupt when going from HIGH -> LOW ( == pushing button) - gpio_set_intr_type(GPIO_NUM_0, GPIO_INTR_NEGEDGE); - // Associate button_task method as a callback - xTaskCreate(button_task, "prg_button_task", 4096, NULL, 10, NULL); - // Install ISR service - gpio_install_isr_service(ESP_INTR_FLAG_DEFAULT); - // Add button handler to the ISR - gpio_isr_handler_add(GPIO_NUM_0, handler, NULL); - + // Initialize the PRG button + button.begin(); + // attach action to long button press + button.onPressedFor(duration, long_button_press); + // attach action to short button press + button.onPressed(short_button_press); } + +// Print error message on the display void printError(String err) { Heltec.display->clear(); Heltec.display->setTextAlignment(TEXT_ALIGN_LEFT); @@ -86,59 +89,54 @@ void printError(String err) { } +// Extracts data from the server response, formats it +// and writes it to the OLED void print_status_screen(JsonObject status_json) { - - if ( status_json != NULL and status_json["PTT"].as() != "ERR") { + if ( status_json != NULL ) { // and status_json["PTT"].as() != "ERR") { String band = status_json["BND"].as(); String pep = status_json["PEP"].as(); String avg = status_json["AVG"].as(); String swr = status_json["SWR"].as(); - String voltage = status_json["VLT"].as(); + String vlt = status_json["VLT"].as(); String power = pep + "W/" + avg + "W"; String ptt = status_json["PTT"].as(); String temp = status_json["TMP"].as(); + String return_msg = status_json["RET"].as(); // clear the display Heltec.display->clear(); // print left column Heltec.display->setTextAlignment(TEXT_ALIGN_LEFT); - Heltec.display->drawString(left, first_row, band ); - Heltec.display->drawString(left, second_row, power ); - if ( cmd_status == "" ) { - Heltec.display->drawString(left, third_row, voltage ); - } else { - Heltec.display->drawString(left, third_row, cmd_status ); - } + Heltec.display->drawString(left, first_row, band ); // top row + Heltec.display->drawString(left, second_row, power ); // mid row + Heltec.display->drawString(left, third_row, return_msg ); // bottom row // print right column Heltec.display->setTextAlignment(TEXT_ALIGN_RIGHT); - Heltec.display->drawString(right, first_row, swr ); - Heltec.display->drawString(right, second_row, ptt ); - Heltec.display->drawString(right, third_row, temp ); + Heltec.display->drawString(right, first_row, swr ); // top row + Heltec.display->drawString(right, second_row, ptt ); // mid row + Heltec.display->drawString(right, third_row, temp ); // bottom row Heltec.display->display(); } - else - { - // print a "(!)" centered in the third row - // this happens when the TRX/PA is transmitting - // or otherwise an empty response was send by the API - Heltec.display->setTextAlignment(TEXT_ALIGN_LEFT); - Heltec.display->drawString(58, third_row, "(!)" ); - Heltec.display->display(); - } - } void loop() { //Check WiFi connection status if (WiFi.status() == WL_CONNECTED) { + // read out button state + button.read(); + // get status data from server String response = send_http_request(api_status_url); + // The server sends the status data as json string + // This converts the string to a json object StaticJsonDocument<200> doc; deserializeJson(doc, response); JsonObject obj = doc.as(); + // print data to OLED screen print_status_screen(obj); - + // wait a bit + delay(500); } else { printError("No WiFi!"); } -} \ No newline at end of file +} diff --git a/server/__init__.py b/server/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/server/__pycache__/__init__.cpython-37.pyc b/server/__pycache__/__init__.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2c3228680c41d0347df656b13fb80534a2aa81a2 GIT binary patch literal 134 zcmZ?b<>g`kg58G}C4%V3AOZ#$feZ&AE@lA|DGb33nv8xc8Hzx{2;!H%enx(7s(wMH zenye0fo@T1ZhlFsZc1ixK~7?&esOA1S!$7fe0*kJW=VX!UP0w84x8Nkl+v73JCH%2 HftUdRl_Vb+ literal 0 HcmV?d00001 diff --git a/server/__pycache__/hr50_rd_server.cpython-37.pyc b/server/__pycache__/hr50_rd_server.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..396286e54a3fc5b39af5035d44ea53178eb08da5 GIT binary patch literal 3809 zcmd5MWtL*8x zr+cWbabh!$5Dq-C5|1FQRx>=oKj04_@f+$12?=3|N1pP;cWN%qt|ElQ%TB9LRh_D? zs#E7X->JDZJzZh={p~M*2!k49f2YRyM?E+2=Kq2aOz?!YdBEFF;I!Sq<)m{GFYs(x z2nx0=21Q$zf)YwM@!RE~JQ`aGDw4~oBOX+R7fg#nFe8e=tSAL@!Vl*K3u~erEQrci zo+(lNyc{fwX)*JX1*gQUm_xZF=0y$VvRDv{C{K%1VhQDntoB#M@_>ueV&x^nYG=-7J33$2+0ITPn_;SDnucq6D=4&-?tc5Ax-R72y4L$Y zesJq@%znU_Vey}*7<!xwcvhe6Ip{7;N%IHsVoZYqqY~yMa`b_9_w+zh4Yzv==5;>9`^s#dFt*~)K57( z1keuN(VlSo1sXYUjyPx9>$$cp_Dg~fpm{`a#ON39WA+o4I*-wU<=)0IEf0T{Xm9Y= z!N0d!vc8=qN%kyGcj{89Ox0UqUe6*JBSrmLD^6rR>&TS)HAchUI85qMmZmb&asBK3 z%hI~e>OViMKZ|vX$|qr0Ty6NKIJ6=tKCspVm0`Q9<0P0J>h3&`WJkwYY6=|{r`i;^ zGt~~Yar6D$c=CCy8=mnxnbO9idC?)2;qnAX>J*OKRCc5$l;G69k9Ix-!MMZcxW^YE zeXcG*6LHexSHL@g#!EB^!rD1<4mq6a?636z=4H6I$NR4K00nno-Hvu~zyJbg!2A9H zV;`~fDj-w_eD(kz5AZpwD}c|Gu4-olpGwao_>4f~z3|4M!F2?$^#WC3Y}tbSQ|qA+m!6;T}ULk^tX0?wv@vzNe` z1DsvdRZ;3s>zN78sy$0rm}{0$MU+H%egS$Kl2niXmaC4Q>+vHl{9TV)pu_SC)AOQo zov3lj)~mKYZR<0(?%VpTtWJ^##7hKA@eZuf@_b?U*#v!Y9o#*|B_`r8D9*YAe^7t{t&(!IJapMoxkM z$>!$cYdhp5+(bSc#hdyDTB-=~iobvG>Hi&kV|*VI5ESu_DnlIG8c~m0CV_0s6y?xk z%2uihG1}w3$Jf*}>4?h=zijxLnnm@%efRB#nn$g%XhTO`q)`+y>YF4MAWR`or0l47 zNzowj9%*r(KzfZNx;sg%)wihU%i*Hlr-5!FQ{(L=k+3P%`0aehCfkNVmdxD_mU^9uQCh0(`{JJ0qT^G!Mic_@Zz)=4AeY zk7GnQp_dkQh3;qC7e&nc3+?MEU<)(tvivtRFECfyb=2=rr^v7?S(KGGM%eOiSUd&Z zRyUQ_W2SItbMr@=Lpb;_#5%lDHD%o*W&@F%!WQlg%FI3qqum{Qduk?G)`81(h&1RE zC#h&pSh`WyXcFQib)AHDD4m_DlE*|>g_K@#5d-DvH#tn*#OPn+%?St0rCd4WHXmLg zek(dfeu3L@2UF`d(dtll^ND-tJ95!&yg6A#RA=vje52tg8vu5nCmd^QuVrpK;qU2t znus}yE_GN(t~ak$vi*)D@IyV8eUL} z^E-5-G^IAW!X1fwmOahelrKFI>JWb{Mt3i3AT2g@%A5SL@Y+7dR{arQjI8o3I2^7v zplh593fuILMUmHrb6OfZi>4_8Dp^NcK2j^BspQ=!9hH#{_Sn^jr1hK4G;GUe)3{-$ zqdumo?vXg*HM?aC@Q61Q`9Es4L}&m2 literal 0 HcmV?d00001 diff --git a/server/__pycache__/hr50_server.cpython-37.pyc b/server/__pycache__/hr50_server.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..14e72b64a23793a3b66ad377a08ecf9a9a7217f7 GIT binary patch literal 3809 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 literal 0 HcmV?d00001 diff --git a/server/bootstrap.sh b/server/bootstrap.sh new file mode 100755 index 0000000..a4413c4 --- /dev/null +++ b/server/bootstrap.sh @@ -0,0 +1,2 @@ +export FLASK_APP=hr50_rd_server.py +flask run --host=0.0.0.0 diff --git a/server/hr50_rd_server.py b/server/hr50_rd_server.py new file mode 100644 index 0000000..ebe1c49 --- /dev/null +++ b/server/hr50_rd_server.py @@ -0,0 +1,179 @@ +from flask import Flask, jsonify, request +import sys +import getopt +import time +import serial +from subprocess import check_output +import threading + +app = Flask(__name__) + +shell_cmd = "./scripts/toggle_antenna.sh" +serial_cmd = "hrtu1" + +# The serial/USB port the HR50 is connected to +serial_port = '/dev/ttyUSB0' + +# doesn't really matter but must match settings of the HR50 +baud = 19200 + +# the active command that has been sent via the API +# If populated: next connection to the HR50 will be used +# to send the command +# If empty: next connection to the HR50 will be used +# to query status information +cmd_rcvd = "" + +# time in milliseconds when we started to display a status message +msg_time = 0 + +# time in milliseconds a status message will be displayed +msg_duration = 3000 + +''' +bands = { + '6': '0', + '10': '1', + '12': '2', + '15': '3', + '17': '4', + '20': '5', + '30': '6', + '40': '7', + '60': '8', + '80': '9', + '160': '10' + } +''' + +vlcd = { + 'STA': '-', + 'PTT': '-', + 'BND': '-', + 'VLT': '-', + 'PEP': '-', + 'AVG': '-', + 'SWR': '-', + 'TMP': '-', + 'RET': 'ok' + } + +''' +keying_methods = { + "off" : "0", + "ptt" : "1", + "cor" : "2", + "qrp" : "3" + } +''' + +def current_milli_time(): + return round(time.time() * 1000) + + +def get_serial(port, baud): + try: + ser = serial.Serial(port, baud, timeout=2) + return ser + except serial.serialutil.SerialException as e: + print("The following error has occured while opening the serial connecti on to {} with {} baud:".format(port, baud)) + print(e) + sys.exit(2) + + +# sends a command to the +# Hardrock-50 via the serial interface +def send_cmd_via_serial(cmd): + ser = get_serial(serial_port, baud) + res = None + try: + command = cmd + ';' + ser.write(str.encode(command)) + res = ser.readline().decode("utf-8").rstrip() + except Exception as e: + print("The following error has occured while sending the command {} to t he HR50:".format(port, baud)) + print(e) + ser.close() + return res + + +# Executed two commands vie the serial interface, +# parsed the result ad polulates a dict with the +# collected information +def get_info(): + global msg_time + ser = get_serial(serial_port, baud) + try: + ser.write(b'HRRX;') + time.sleep(0.5) + res = ser.readline().decode("utf-8").rstrip().replace(';', '').split(',') + except Exception as e: + print("The following error has occured while sending the command {} to the HR50:".format(port, baud)) + print(e) + ser.close() + return None + if res and len(res) > 3: + vlcd['STA'] = res[0] + vlcd['PTT'] = res[1] + vlcd['BND'] = res[2] + vlcd['TMP'] = res[3] + vlcd['VLT'] = res[4] + ser.write(b'HRMX;') + time.sleep(0.5) + res = ser.readline().decode("utf-8").rstrip().split() + ser.close() + vlcd['PEP'] = res[1][1:] + vlcd['AVG'] = res[2][1:] + if res[3][1:] != "0": + vlcd['SWR'] = res[3][1:2] + "." + res[3][2:3] + else: + vlcd['RET'] = "(!)" + msg_time = current_milli_time() + + +def background_loop(): + global cmd_rcvd + global msg_time + threading.Timer(3.0, background_loop).start() + if cmd_rcvd != "": + ret = "" + try: + send_cmd_via_serial(cmd_rcvd) + vlcd['RET'] = 'Tune' + msg_time = current_milli_time() + except Exception as e: + ret = "ERROR" + cmd_rcvd = "" + else: + get_info() + if msg_time != 0 and msg_time + msg_duration < current_milli_time() or vlcd['RET'] == "ok": + vlcd['RET'] = vlcd['VLT'] + + +@app.route('/get_status') +def get_status(): + return jsonify(vlcd) + + +@app.route('/exec_shell') +def exec_shell_command(): + global msg_time + out = check_output([shell_cmd, ""]) + if out: + vlcd['RET'] = out.decode("utf-8") + msg_time = current_milli_time() + return out + + +@app.route('/exec_serial') +def exec_serial_command(): + global cmd_rcvd + cmd_rcvd = serial_cmd + return jsonify(isError= False, + message= "Success", + statusCode= 200, + data= "" ), 200 + +background_loop() + + diff --git a/server/scripts/toggle_antenna.sh b/server/scripts/toggle_antenna.sh new file mode 100755 index 0000000..345cbdc --- /dev/null +++ b/server/scripts/toggle_antenna.sh @@ -0,0 +1,16 @@ +#!/usr/bin/bash +eval $(sudo usbrelay 2>/dev/null) +#echo $BITFT_1 +if [ $BITFT_1 -eq 0 ] +then + sudo usbrelay BITFT_1=1 > /dev/null 2>&1 +else + sudo usbrelay BITFT_1=0 > /dev/null 2>&1 +fi +eval $(sudo usbrelay 2>/dev/null) +if [ $BITFT_1 -eq 0 ] +then + echo "Cobweb" +else + echo "Vertical" +fi