From d637ee76f4d1dc4a6b01745d5b3f0a7e1e7d8e0c Mon Sep 17 00:00:00 2001 From: Stephen M Moraco Date: Tue, 28 Feb 2023 18:03:44 -0700 Subject: [PATCH] repaired MQTT subscript and LWT online/offline reporting --- ChangeLog | 9 +++++++- ISP-RPi-mqtt-daemon.py | 49 +++++++++++++++++++++++++----------------- README.md | 31 +++++++++++--------------- RMTECTRL.md | 4 ++-- config.ini.dist | 2 +- 5 files changed, 52 insertions(+), 43 deletions(-) diff --git a/ChangeLog b/ChangeLog index dbcd777..bd84388 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,9 +1,16 @@ # ChangeLog ----- Next Rls -------- v1.8.1 +Tue, 28 Feb 2023 17:24:07 -0700 v1.8.2 + +- fix LWT online/offline status updates of Daemon +- repair MQTT command subscription mechanism +- repaired the remote-control setup instructions for restart-service, updated config.ini.dist + +Sun Feb 26 18:28:36 2023 -0700 v1.8.1 - Repair temperature units regression (#82) - Disk Used sensor repaired (was reporting free vs. used) (#83) +- Refine the advertisement of the command endpoints Sat, 25 Feb 2023 19:36:42 -0700 v1.8.0 diff --git a/ISP-RPi-mqtt-daemon.py b/ISP-RPi-mqtt-daemon.py index f54653b..3058d3c 100755 --- a/ISP-RPi-mqtt-daemon.py +++ b/ISP-RPi-mqtt-daemon.py @@ -34,7 +34,7 @@ except ImportError: apt_available = False -script_version = "1.8.1" +script_version = "1.8.2" script_name = 'ISP-RPi-mqtt-daemon.py' script_info = '{} v{}'.format(script_name, script_version) project_name = 'RPi Reporter MQTT2HA Daemon' @@ -143,8 +143,6 @@ def clean_identifier(name): '* init mqtt_client_connected=[{}]'.format(mqtt_client_connected), debug=True) mqtt_client_should_attempt_reconnect = True -command_base_topic = '{not-set}/command/{not-set}' - def on_connect(client, userdata, flags, rc): global mqtt_client_connected if rc == 0: @@ -157,15 +155,6 @@ def on_connect(client, userdata, flags, rc): mqtt_client_connected), debug=True) client.on_publish = on_publish - # ------------------------------------------------------------------------- - # Commands Subscription - if (len(commands) > 0): - print_line('MQTT subscription to {}/+ enabled'.format(command_base_topic), console=True, sd_notify=True) - client.on_message = on_message - client.subscribe('{}/+'.format(command_base_topic)) - else: - print_line('MQTT subscripton to {}/+ disabled'.format(command_base_topic), console=True, sd_notify=True) - # ------------------------------------------------------------------------- else: print_line('! Connection error with result code {} - {}'.format(str(rc), mqtt.connack_string(rc)), error=True) @@ -191,16 +180,17 @@ def on_subscribe(client, userdata, mid, granted_qos): print_line('on_subscribe() - {} - {}'.format(str(mid),str(granted_qos)), debug=True, sd_notify=True) def on_message(client, userdata, message): - print_line('on_message(). Topic=[{}] payload=[{}]'.format(message.topic, message.payload), console=True, sd_notify=True, debug=True) + print_line('on_message() Topic=[{}] payload=[{}]'.format(message.topic, message.payload), console=True, sd_notify=True, debug=True) decoded_payload = message.payload.decode('utf-8') command = message.topic.split('/')[-1] - if command in commands: - print_line('- Command "{}" Received - Run {} {} -'.format(command, commands[command], decoded_payload), console=True, debug=True) - subprocess.Popen(["/usr/bin/sh", "-c", commands[command].format(decoded_payload)]) - else: - print_line('* Invalid Command received.', error=True) + if command != 'status': + if command in commands: + print_line('- Command "{}" Received - Run {} {} -'.format(command, commands[command], decoded_payload), console=True, debug=True) + subprocess.Popen(["/usr/bin/sh", "-c", commands[command].format(decoded_payload)]) + else: + print_line('* Invalid Command received.', error=True) # ----------------------------------------------------------------------------- # Load configuration file @@ -1180,6 +1170,9 @@ def getNumberOfAvailableUpdates(): if apt_available: getNumberOfAvailableUpdates() +command_base_topic = '{}/command/{}'.format(base_topic, sensor_name.lower()) + + # ----------------------------------------------------------------------------- # timer and timer funcs for ALIVE MQTT Notices handling # ----------------------------------------------------------------------------- @@ -1190,7 +1183,12 @@ def getNumberOfAvailableUpdates(): def publishAliveStatus(): print_line('- SEND: yes, still alive -', debug=True) mqtt_client.publish(lwt_sensor_topic, payload=lwt_online_val, retain=False) + mqtt_client.publish(lwt_command_topic, payload=lwt_online_val, retain=False) +def publishShuttingDownStatus(): + print_line('- SEND: shutting down -', debug=True) + mqtt_client.publish(lwt_sensor_topic, payload=lwt_offline_val, retain=False) + mqtt_client.publish(lwt_command_topic, payload=lwt_offline_val, retain=False) def aliveTimeoutHandler(): print_line('- MQTT TIMER INTERRUPT -', debug=True) @@ -1273,6 +1271,16 @@ def isAliveTimerRunning(): error=True, sd_notify=True) sys.exit(1) else: + # ------------------------------------------------------------------------- + # Commands Subscription + if (len(commands) > 0): + print_line('MQTT subscription to {}/+ enabled'.format(command_base_topic), console=True, sd_notify=True) + mqtt_client.on_message = on_message + mqtt_client.subscribe('{}/+'.format(command_base_topic)) + else: + print_line('MQTT subscripton to {}/+ disabled'.format(command_base_topic), console=True, sd_notify=True) + # ------------------------------------------------------------------------- + mqtt_client.publish(lwt_sensor_topic, payload=lwt_online_val, retain=False) mqtt_client.publish(lwt_command_topic, payload=lwt_online_val, retain=False) mqtt_client.loop_start() @@ -1378,8 +1386,6 @@ def isAliveTimerRunning(): )) ]) -command_base_topic = '{}/command/{}'.format(base_topic, sensor_name.lower()) - for [command, _] in commands.items(): #print_line('- REGISTER command: [{}]'.format(command), debug=True) iconName = 'mdi:gesture-tap' @@ -1809,5 +1815,8 @@ def afterMQTTConnect(): finally: # cleanup used pins... just because we like cleaning up after us + publishShuttingDownStatus() stopPeriodTimer() # don't leave our timers running! stopAliveTimer() + mqtt_client.disconnect() + print_line('* MQTT Disconnect()', verbose=True) diff --git a/README.md b/README.md index a3e5899..d0397f7 100644 --- a/README.md +++ b/README.md @@ -12,20 +12,19 @@ A simple Linux python script to query the Raspberry Pi on which it is running fo ![Discovery image](./Docs/images/DiscoveryV4.png) -This script should be configured to be run in **daemon mode** continously in the background as a systemd service (or optionally as a SysV init script). Instructions are provided below. - +This script should be configured to be run in **daemon mode** continuously in the background as a systemd service (or optionally as a SysV init script). Instructions are provided below. ## Table of Contents On this Page: - [Features](#features)- key features of this reporter -- [Prerequisites](#prerequisites) +- [Prerequisites](#prerequisites) - [Installation](#installation) - install prerequisites and the daemon project - [Configuration](#configuration) - configuring the script to talk with your MQTT broker - [Execution](#execution) - initial run by hand, then setup to run from boot - [Integration](#integration) - a quick look at what's reported to MQTT about this RPi -- [Troubleshooting](#troubleshooting) - having start up issues? Check here for common problems +- [Troubleshooting](#troubleshooting) - having start up issues? Check here for common problems Additional pages: @@ -34,7 +33,6 @@ Additional pages: - [The Associated Lovelace RPi Monitor Card](https://github.com/ironsheep/lovelace-rpi-monitor-card) - This is our companion Lovelace Card that makes displaying this RPi Monitor data very easy - [ChangeLog](./ChangeLog) - We've been repairing or adding features to this script as users report issues or wishes. This is our list of changes - ## Features - Tested on Raspberry Pi's 2/3/4 with Jessie, Stretch and Buster @@ -111,7 +109,7 @@ The monitored topic reports the following information: | `throttle` | | reports the throttle status value plus interpretation thereof | | `timestamp` | | date, time when this report was generated | -_NOTE: cpu load averages are divided by the number of cores_ +NOTE: _cpu load averages are divided by the number of cores_ ## Prerequisites @@ -143,10 +141,10 @@ sudo apt-get install libraspberrypi-bin net-tools ### Packages for Arch Linux ```shell -sudo pacman -S python python-pip python-tzlocal python-notify2 python-colorama python-unidecode python-paho-mqtt python-requests inetutils +sudo pacman -S python python-pip python-tzlocal python-notify2 python-colorama python-unidecode python-paho-mqtt python-requests inetutils ``` -**NOTE**: *for users of Arch Linux the number of updates available will NOT be reported (will always show as '-1'.) This is due to Arch Linux not using the apt package manager.* +**NOTE**: _for users of Arch Linux the number of updates available will NOT be reported (will always show as '-1'.) This is due to Arch Linux not using the apt package manager._ ### With these extra packages installed, verify access to network information @@ -185,7 +183,7 @@ wlan0: flags=4163 mtu 1500 ``` -If you are seeing output from the `ifconfig` tool then continue on with the following steps. If you don't you may have missed installing `net-utils` in an earlier step. +If you are seeing output from the `ifconfig` tool then continue on with the following steps. If you don't you may have missed installing `net-utils` in an earlier step. ### Now finish with the script install @@ -436,10 +434,7 @@ An example: "load_5min_prcnt": 0, "load_15min_prcnt": 0 }, - "throttle": [ - "throttled = 0x0", - "Not throttled" - ], + "throttle": ["throttled = 0x0", "Not throttled"], "temperature_c": 25.8, "temp_gpu_c": 25.8, "temp_cpu_c": 25.8, @@ -450,11 +445,10 @@ An example: } ``` -**NOTE:** Where there's an IP address that interface is connected. Also, there are new `tx_data` and `rx_data` values which show traffic in bytes for this reporting interval for each network interface. +**NOTE:** Where there's an IP address that interface is connected. Also, there are new `tx_data` and `rx_data` values which show traffic in bytes for this reporting interval for each network interface. This data can be subscribed to and processed by your home assistant installation. How you build your RPi dashboard from here is up to you! - ## Troubleshooting ### Issue: Some of my RPi's don't show up in HA @@ -467,7 +461,7 @@ We occasionaly have reports of users with more than one RPi on their network but Most often fix: _reboot the missing RPi._ -When you remove a sensor from Home Assistant it tells the MQTT broker to 'forget' everything it knows about the RPi. Some of the information is actually `stored by the MQTT broker` so it is available while the RPi is offline. Our Daemon script only broadcasts this `stored` information when it is first started. As a result the RPi will not re-appear after delete from Home Assistant until you reboot the RPi in question. (or, alternatively, stop then restart the script.). You may find reboot easier to do. +When you remove a sensor from Home Assistant it tells the MQTT broker to 'forget' everything it knows about the RPi. Some of the information is actually `stored by the MQTT broker` so it is available while the RPi is offline. Our Daemon script only broadcasts this `stored` information when it is first started. As a result the RPi will not re-appear after delete from Home Assistant until you reboot the RPi in question. (or, alternatively, stop then restart the script.). You may find reboot easier to do. To reboot: @@ -510,13 +504,12 @@ I find [MQTT Explorer](http://mqtt-explorer.com/) to be an excellent tool to use Alternatively I also use **MQTTBox** when I want to send messages by hand to interact via MQTT. it is affered as a web extension or a native application. - #### Viewing the Daemon logs When your script is being run as a Daemon it is logging. You can view the log output since last reboot with: ```bash -$ journalctl -b --no-pager -u isp-rpi-reporter.service +journalctl -b --no-pager -u isp-rpi-reporter.service ``` Alternatively you can create a simple script which you can run any time you want to see the log. Here's my show Daemon log script `showRpiLog`: @@ -527,7 +520,7 @@ Alternatively you can create a simple script which you can run any time you want (set -x;journalctl -b --no-pager -u isp-rpi-reporter.service) ``` -**NOTE**: *the -b says 'since last boot' the --no-pager says just show it all without breaking it up into pages and requiring the enter key press for each page.* +**NOTE**: _the -b says 'since last boot' the --no-pager says just show it all without breaking it up into pages and requiring the enter key press for each page._ --- diff --git a/RMTECTRL.md b/RMTECTRL.md index 8ef05ed..92e351b 100644 --- a/RMTECTRL.md +++ b/RMTECTRL.md @@ -87,7 +87,7 @@ An example to reboot or shutdown the Pi: [Commands] shutdown = /usr/bin/sudo /sbin/shutdown -h now 'shutdown rqst via MQTT' reboot = /usr/bin/sudo /sbin/shutdown -r now 'reboot rqst via MQTT' -restart_service = /usr/bin/sudo systemctl restart {} +restart_service = /usr/bin/sudo systemctl restart isp-rpi-reporter.service ``` *NOTE* the message in the `{action} rqst via MQTT` message is logged in `/var/log/auth.log` so one can keep track of when commands are executed via MQTT. @@ -109,7 +109,7 @@ the sudoers configuration file: # add the following lines at the bottom. # note that every service that we want to allow to restart must be specified here - daemon =NOPASSWD: /usr/bin/systemctl restart isp-rpi-reporter,/sbin/shutdown + daemon =NOPASSWD: /usr/bin/systemctl restart isp-rpi-reporter.service,/sbin/shutdown ``` NOTE: In some systems the path for `systemctl` / `reboot` / `shutdown` can be different. Make sure the path you specify is correct for your system. diff --git a/config.ini.dist b/config.ini.dist index 1961c18..4464897 100644 --- a/config.ini.dist +++ b/config.ini.dist @@ -22,7 +22,7 @@ [Commands] #shutdown = /usr/bin/sudo /sbin/shutdown -h now 'shutdown rqst via MQTT' #reboot = /usr/bin/sudo /sbin/shutdown -r now 'reboot rqst via MQTT' -#restart_service = /usr/bin/sudo systemctl restart {} +#restart_service = /usr/bin/sudo systemctl restart isp-rpi-reporter.service [MQTT]