{"id":20,"date":"2025-05-28T17:09:40","date_gmt":"2025-05-28T17:09:40","guid":{"rendered":"https:\/\/papaya.hopto.org\/?p=20"},"modified":"2025-05-28T17:11:06","modified_gmt":"2025-05-28T17:11:06","slug":"running-commands-remotely-on-the-pi","status":"publish","type":"post","link":"https:\/\/papaya.hopto.org\/?p=20","title":{"rendered":"Running commands remotely on the pi"},"content":{"rendered":"\n<pre><code>Using ssh to run commands on a remote Linux host to the pi.\n1. Setup ssh-keys, using name socjcare for example.\n2.  Generate  keys in Linux host, giving it a name in default location ~\/.ssh.\n3. Make sure the key is added, using\n     ssh-add ~\/ssh\/socjcare\n3. copy the public keys to the pi's ~\/.ssh\/authorized keys\n4. test\n5. To avoid entering the password, in the Linux host ~\/.ssh\/config\n    enter this\na\n6. Test by doing \n     ssh raspberrypi \n7. Should connect with entering the password.\n8. Sometimes the key is not recognized because the ssh-agent is \n    not    running. To ensure that agent is running everytime, add\n    this to .bashrc file\n     # start ssh-agent\n     eval \"$(ssh-agent -s)\"\n9. <\/code><\/pre>\n\n\n\n<p>Once done, create a python file on the Linux host, linux_to_pi.py<\/p>\n\n\n\n<pre><code>import subprocess\n# Replace with your Pi's hostname or IP\n#pi_host = \"scarelo@192.9.0.213\"  # Or whatever user\/IP your Pi has\npi_host = \"raspberrypi\"  # Or whatever user\/IP your Pi has\n#script_path_on_pi = \"\/home\/scarelo\/myscript.py\"  # The Python script to run on the Pi\n#script_path_on_pi = \"\/home\/scarelo\/progress_bar.py\"  # The Python script to run on the Pi\nscript_path_on_pi = \"\/home\/scarelo\/toggle_pin6.py\"  # The Python script to run on the Pi\n# Run the script on the Pi via SSH\ncmd = [\"ssh\", pi_host, f\"python3 -u  {script_path_on_pi}\"]\n# Start the subprocess and stream output live\nprocess = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True)\nprint(\"Running script on Pi and streaming output:\")\nfor line in process.stdout:\n    print(line, end=\"\")  # Already includes newline\nprocess.wait()\nprint(f\"Script exited with code {process.returncode}\")\n<\/code><\/pre>\n\n\n\n<p>On the Raspberry pi, create the file myscript.py in \/home\/scarelo<\/p>\n\n\n\n<pre><code>#!\/usr\/bin\/env python3\nimport pigpio\nimport time\nPIN = 6  # GPIO6 (physical pin 31)\n# Connect to local pigpiod daemon\npi = pigpio.pi()\nif not pi.connected:\n    print(\"Failed to connect to pigpiod. Is it running?\")\n    exit(1)\n# Set pin as output\npi.set_mode(PIN, pigpio.OUTPUT)\nprint(\"Toggling GPIO pin 6... (Ctrl+C to stop)\")\ntry:\n    while True:\n        pi.write(PIN, 1)  # Turn ON\n        print(\"ON\")  # Turn ON\n        time.sleep(1)\n        pi.write(PIN, 0)  # Turn OFF\n        time.sleep(1)\n        print(\"OFF\")  # Turn ON\nexcept KeyboardInterrupt:\n    print(\"Exiting...\")\nfinally:\n    pi.write(PIN, 0)      # Turn off the pin\n    pi.stop()             # Disconnect from pigpio daemon\n<\/code><\/pre>\n\n\n\n<p>Start pigpiod daemon on the pi.<\/p>\n\n\n\n<p>On the linux host, start the Python command<\/p>\n\n\n\n<p>python linux_to_pi.py<\/p>\n\n\n\n<p>&nbsp;<\/p>\n\n\n\n<p>should start seeing the output<\/p>\n\n\n\n<pre><code>$ python linux_to_pi.py\nRunning script on Pi and streaming output:\nToggling GPIO pin 6... (Ctrl+C to stop)\nON\nOFF\nON\nOFF\nON\nOFF\nON\nOFF\nON\nOFF\nON\nOFF\nON\n<\/code><\/pre>\n\n\n\n<p>Improved Linux to pi- using Flask<\/p>\n\n\n\n<p>&nbsp;<\/p>\n\n\n\n<div class=\"wp-block-group is-nowrap is-layout-flex wp-container-core-group-is-layout-ad2f72ca wp-block-group-is-layout-flex\">\n<p>\u00a9 All Rights Reserved.<\/p>\n<p><strong>Improved\u00a0 linux to pi communication<\/strong><\/p>\n<p>Running on Ubuntu<\/p>\n<p>&nbsp;<\/p>\n<p>Assumes &#8211; flask already installed<\/p>\n<p>ubuntu machine can access the pi using authorized keys<\/p>\n<p>&nbsp;<\/p>\n<p>start by python flask_gui_watcher.py<\/p>\n<p>&nbsp;<\/p>\n<p>starts flask and waits for a post from\u00a0 the Bitbucket runner or from another site<\/p>\n<\/div>\n\n\n\n<pre class=\"wp-block-code\"><code>from flask import Flask, request\nimport subprocess\nimport threading\nimport os\n\napp = Flask(__name__)\n\n# Optional: Set the correct display and Xauthority if needed\nprint(f\"DISPLAY variable: {os.getenv('DISPLAY')}\")\nos.environ&#91;'DISPLAY'] = ':0'\nos.environ&#91;'XAUTHORITY'] = f\"\/home\/{os.getenv('USER')}\/.Xauthority\"\n\n@app.route('\/trigger-gui', methods=&#91;'POST'])\ndef trigger_gui():\n    def launch():\n        print(\"Launching PyQt5 GUI...\")\n        subprocess.Popen(&#91;\"python3\", \"\/home\/kelk\/ADLC_improved\/display.py\"])\n    threading.Thread(target=launch).start()\n    return {\"status\": \"GUI launched\"}, 200\n\nif __name__ == '__main__':\n    app.run(host='127.0.0.1', port=5001)\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p>This is the display routine that waits from streaming data from the pi<\/p>\n\n\n\n<div class=\"wp-block-group is-nowrap is-layout-flex wp-container-core-group-is-layout-ad2f72ca wp-block-group-is-layout-flex\">\n<pre class=\"wp-block-code\"><code>import sys, json, subprocess, threading\nfrom PyQt5.QtWidgets import QMainWindow, QApplication, QPushButton\nfrom PyQt5.QtCore import QTimer\nfrom adlc_ui import Ui_MainWindow\n\n\nQApplication.setStyle(\"Fusion\")\n\nclass Setup(QMainWindow, Ui_MainWindow):\n    def __init__(self, parent=None):\n        super().__init__(parent)\n        self.setupUi(self)\n        self.latest_data = {\"analog\": &#91;0]*4, \"digital\": &#91;0]*8}\n        self.setdata()\n        self.start_ssh_stream(\"scarelo@raspberrypi\", \"\/home\/scarelo\/pi_streamer.py\")  # \u2190 Update Pi IP\/path as needed\n\n    def setdata(self):\n        button_style = \"\"\"\n               QPushButton {\n                   background-color: transparent;\n                   color: black;\n                   border: 2px solid gray;\n                   border-radius: 4px;\n               }\n               QPushButton:disabled {\n                   background-color: lightgray;\n                   color: yellow;\n               }\n           \"\"\"\n        button_width = 80\n        button_height = 25\n\n        for i in range(8):\n            dout = getattr(self, f\"DOut{i}\")\n            dout.setFixedSize(button_width, button_height)\n            dout.setEnabled(True)\n            dout.setText('OFF')\n            dout.setStyleSheet(button_style)\n\n        for i in range(8):\n            din = getattr(self, f\"DIn{i}\")\n            din.setFixedSize(button_width, button_height)\n            din.setEnabled(True)\n            din.setText('OFF')\n            din.setStyleSheet(button_style)\n\n        self.DOut0.setStyleSheet(\"background-color: green; color: blue; \")\n        self.DOut0.setText(\"ON\")\n\n        new_width = 120\n        new_height = 40\n        for lcd in &#91;self.AOut0, self.AOut1, self.AOut2, self.AOut3]:\n            geo = lcd.geometry()\n            lcd.setGeometry(geo.x(), geo.y(), new_width, new_height)\n\n        self.rx_timer = QTimer(self)\n        self.rx_timer.timeout.connect(self.update_ui)\n        self.rx_timer.start(500)\n\n    def update_ui(self):\n        data = self.latest_data\n        for i, lcd in enumerate(&#91;self.AOut0, self.AOut1, self.AOut2, self.AOut3]):\n            lcd.display(data&#91;\"analog\"]&#91;i])\n\n        for i in range(8):\n            dout = getattr(self, f\"DOut{i}\")\n            value = data&#91;\"digital\"]&#91;i]\n            if value:\n                dout.setStyleSheet(\"background-color: green; color: blue; \")\n                dout.setText(\"ON\")\n            else:\n                dout.setStyleSheet(\"background-color: cyan; color: gray; \")\n                dout.setText(\"OFF\")\n\n    def start_ssh_stream(self, pi_host, script_path_on_pi):\n        def stream():\n            while True:\n                cmd = &#91;\"ssh\", pi_host, f\"python3 -u {script_path_on_pi}\"]\n                try:\n                    print(f\"Connecting to {pi_host}...\")\n                    process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True)\n\n                    for line in process.stdout:\n                        line = line.strip()\n                        try:\n                            self.latest_data = json.loads(line)\n                        except json.JSONDecodeError:\n                            print(\"Invalid JSON:\", line)\n\n                except Exception as e:\n                    print(\"SSH stream error:\", e)\n\n                print(\"SSH connection lost. Reconnecting in 5 seconds...\")\n                QTimer.singleShot(5000, lambda: None)  # Just a non-blocking wait\n                time.sleep(5)\n\n        thread = threading.Thread(target=stream, daemon=True)\n        thread.start()\n\n\nif __name__ == '__main__':\n    app = QApplication(sys.argv)\n    window = Setup()\n    window.show()\n    sys.exit(app.exec())\n\n<\/code><\/pre>\n<\/div>\n\n\n\n<p>Running on the pi pi_streamer.py<\/p>\n\n\n\n<p><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import pigpio\nimport json\nimport time\nimport random  # Import the random module to generate random values\n\npi = pigpio.pi()\nDIGITAL_PINS = &#91;4, 17, 27, 22, 5, 6, 13, 19]\n\ndef get_random_analog_value():\n    # Generate a random float between 9 and 10, rounded to the nearest 0.2\n    return round(random.uniform(9, 10) \/ 0.2) * 0.2\n\nwhile True:\n    # Generate random values for each digital pin (0 or 1)\n    digital = &#91;random.randint(0, 1) for _ in DIGITAL_PINS]\n\n    # Generate 4 random analog values between 9 and 10, varying by 0.2\n    analog = &#91;get_random_analog_value() for _ in range(4)]  # Simulate 4 random analog values\n\n    print(json.dumps({\"digital\": digital, \"analog\": analog}), flush=True)\n    time.sleep(0.5)\n<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Once done, create a python file on the Linux host, linux_to_pi.py On the Raspberry pi, create the file myscript.py in \/home\/scarelo Start pigpiod daemon on the pi. On the linux host, start the Python command python linux_to_pi.py &nbsp; should start seeing the output Improved Linux to pi- using Flask &nbsp; \u00a9 All Rights Reserved. Improved\u00a0 &#8230; <a title=\"Running commands remotely on the pi\" class=\"read-more\" href=\"https:\/\/papaya.hopto.org\/?p=20\" aria-label=\"Read more about Running commands remotely on the pi\">Read more<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_regular_price":[],"currency_symbol":[],"footnotes":""},"categories":[1],"tags":[],"class_list":["post-20","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"post_slider_layout_featured_media_urls":{"thumbnail":"","post_slider_layout_landscape_large":"","post_slider_layout_portrait_large":"","post_slider_layout_square_large":"","post_slider_layout_landscape":"","post_slider_layout_portrait":"","post_slider_layout_square":"","full":""},"_links":{"self":[{"href":"https:\/\/papaya.hopto.org\/index.php?rest_route=\/wp\/v2\/posts\/20","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/papaya.hopto.org\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/papaya.hopto.org\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/papaya.hopto.org\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/papaya.hopto.org\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=20"}],"version-history":[{"count":11,"href":"https:\/\/papaya.hopto.org\/index.php?rest_route=\/wp\/v2\/posts\/20\/revisions"}],"predecessor-version":[{"id":106,"href":"https:\/\/papaya.hopto.org\/index.php?rest_route=\/wp\/v2\/posts\/20\/revisions\/106"}],"wp:attachment":[{"href":"https:\/\/papaya.hopto.org\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=20"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/papaya.hopto.org\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=20"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/papaya.hopto.org\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=20"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}