├── LICENSE ├── README.md ├── launch_process.sh ├── monitor_process.py └── monitor_reboot.py /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Initial State 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Remotely Monitor Your Pi Processes and IP Addresses 2 | --- 3 | _by Jamie Bailey_ 4 | 5 | ![Process Dashboard Hero](https://github.com/InitialState/pi-process-dashboard/wiki/img/pi_process_dashboard.jpg) 6 | 7 | If you are using one or more Raspberry Pis to run a dedicated task (such as monitoring [who's at home](https://github.com/initialstate/pi-sensor-free-presence-detector/wiki) or [the weather](https://github.com/initialstate/wunderground-sensehat/wiki) or [your beer fridge](https://github.com/initialstate/beerfridge/wiki)), you need those processes to run uninterrupted. A task that exits unexpectedly may need your immediate attention to avoid lost data, project delays, or a system failure. It is impractical to manually babysit a bunch of Pis to make sure everything keeps running. A better way to ensure continuous operation is to be alerted when a process exits and be able to pull up a single dashboard at anytime to see the status of every important process running on every one of your deployed Pis. If your Pi is running headless, having the IP address of that Pi in the same dashboard will also come in handy. 8 | 9 | In this tutorial, we will use a couple of simple scripts to: 10 | - create a web-based dashboard that monitors the status of multiple processes and IP addresses of each device 11 | - configure our Pi to launch the dedicated process and its monitor on boot 12 | - create an email/SMS notification when a process exits 13 | 14 | [Read More ...](https://github.com/initialstate/pi-process-dashboard/wiki) 15 | -------------------------------------------------------------------------------- /launch_process.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # --------- User Settings --------- 3 | PROCESS2RUN="sudo python /home/pi/grovepi/weather.py" 4 | MONITOR_SCRIPT="/home/pi/grovepi/monitor_process.py" 5 | # --------------------------------- 6 | nohup $PROCESS2RUN & 7 | VAR=`pgrep -f "$PROCESS2RUN"` 8 | echo $VAR 9 | nohup python $MONITOR_SCRIPT $VAR & 10 | -------------------------------------------------------------------------------- /monitor_process.py: -------------------------------------------------------------------------------- 1 | import psutil 2 | import time 3 | import sys 4 | from ISStreamer.Streamer import Streamer 5 | from subprocess import PIPE, Popen 6 | 7 | # --------- User Settings --------- 8 | # Initial State settings 9 | BUCKET_NAME = ":computer: Processes" 10 | BUCKET_KEY = "pr1208" 11 | ACCESS_KEY = "PLACE YOUR INITIAL STATE ACCESS KEY HERE" 12 | PROCESS_NAME = "PLACE THE NAME OF YOUR PROCESS HERE" 13 | # Set the time between checks 14 | MINUTES_BETWEEN_READS = 15 15 | # --------------------------------- 16 | 17 | def main(): 18 | if len(sys.argv) != 2: 19 | print "Usage: " + sys.argv[0] + " " 20 | exit() 21 | pid = sys.argv[1] 22 | 23 | streamer = Streamer(bucket_name=BUCKET_NAME, bucket_key=BUCKET_KEY, access_key=ACCESS_KEY) 24 | if psutil.pid_exists(int(pid)) == False: 25 | print "Error: That process doesn't exist! Exiting ..." 26 | exit() 27 | else: 28 | streamer.log(PROCESS_NAME,"Running") 29 | streamer.flush() 30 | 31 | while True: 32 | if psutil.pid_exists(int(pid)) == False: 33 | streamer.log(PROCESS_NAME,"Exited") 34 | streamer.flush() 35 | exit() 36 | else: 37 | streamer.log(PROCESS_NAME,"Running") 38 | process = Popen(['hostname', '-I'], stdout=PIPE) 39 | output, _error = process.communicate() 40 | streamer.log(PROCESS_NAME + " IP Address", output.rstrip()) 41 | streamer.flush() 42 | time.sleep(60*MINUTES_BETWEEN_READS) 43 | 44 | if __name__ == "__main__": 45 | main() -------------------------------------------------------------------------------- /monitor_reboot.py: -------------------------------------------------------------------------------- 1 | import psutil 2 | import time 3 | import sys 4 | from ISStreamer.Streamer import Streamer 5 | 6 | # --------- User Settings --------- 7 | # Initial State settings 8 | BUCKET_NAME = ":computer: Processes" 9 | BUCKET_KEY = "pr1208" 10 | ACCESS_KEY = "PLACE YOUR INITIAL STATE ACCESS KEY HERE" 11 | PROCESS_NAME = "PLACE THE NAME OF YOUR PROCESS HERE" 12 | # Set the time to wait until you are sure reboot is complete and network connections are restored (i.e. power outage) 13 | MINUTES_DELAY = 5 14 | # --------------------------------- 15 | 16 | def main(): 17 | # Wait for ntpd to run for sync of the clock 18 | found_ntpd = False 19 | cnt = 0 20 | while found_ntpd == False: 21 | for proc in psutil.process_iter(): 22 | if proc.name() == "ntpd": 23 | found_ntpd = True 24 | cnt += 1 25 | if cnt == 60: # assume that ntpd has already run if not found in 60 seconds 26 | found_ntpd=True 27 | time.sleep(1) 28 | 29 | time.sleep(60*MINUTES_DELAY) 30 | streamer = Streamer(bucket_name=BUCKET_NAME, bucket_key=BUCKET_KEY, access_key=ACCESS_KEY) 31 | streamer.log(PROCESS_NAME,"Exited") 32 | streamer.flush() 33 | 34 | if __name__ == "__main__": 35 | main() --------------------------------------------------------------------------------