Python Script - loop it or not?

I run a python script from a rule every minute to query a couple of sensors every 2 seconds, calculate an average over 40 seconds and return the results to the console, I launch the script using executeCommandline with a timeout in case it doesn’t work correctly.
is this the best way of doing this or would it be better to get the script to loop, so it will run 24/7, and if I do is there a way to detect it has stopped and restart it? If possible I’d like it to run on one of the other cores of the Raspberry Pi3 to avoid adding to the load of OH which seems to only run on 2 of the 4 cores.
Another idea I have is to add MQTT to the script and have it run as a Linux Daemon, returning the results over MQTT.
The script does fail from time to timel with a “exception occurred, press enter to exit” type message, which I could modify so the script just exits cleanly

This is what I do. See

I wouldn’t recommend running a script that never exits from a Rule as it will tie up a Rule execution thread and the rest of your OH performance will suffer.

You could convert your script to an addon to sensorReporter and all the communication stuff, LWT, etc will already be done for you. Or you and use it as inspiration to write your own.

I’m not sure if there is a way to pin a program to a specific core, but the kernel should be smart enough to run it on a less used core. But a python script that only does something once a minute is not going to be a strain on the CPU.

If you run it as a daemon you would absolutely want it to exit cleanly, or even messily so long as it doesn’t block on awaiting user input.

Yes, I run sensorReporter already to add bluetooth presence detection of iphones,
The python script currently starts with the command

var PHandORP = executeCommandLine("python /home/pi/data/phidgets/combined.py " + (PoolTemperature.state.toString), 55000)

and it returns

{ ORP:524, PH:7.72783778947 }

As the water temperature value is added to the end of the command line, it may mean that I’m better sticking with starting it from a rule with a timeout.

I translate the result into 2 numbers for further validation. Is this easy to add to sensorReporter, and can it add a command line parameter to the beginning?

:smiley:

Not necessarily. You can create an actuator that triggers when you publish the PoolTemperature to a specific topic. And then the actuator will know the PoolTemp based on the received message.

For example, if you look at the execActuator, it has an on_message function that gets called whenever a message is received on the topic configured in the .ini file. You can parse out (if necessary) the pool temp and then perform your combined.py logic right there in that function (or functions called by that function).

However, this kind of puts you back in the situation where you have to do the polling from a Rule. But all OH has to do is publish a message and your combined.py will run independently and publish the results back without OH blocking.

So, to summarize:

  1. Rule triggers once a minute and publishes the PoolTemperature.state to an MQTT Topic (another option is to publish whenever the PoolTemperature changes or receives update)

  2. sensorReporter receives the message and calls on_message on your actuator with the contents of the message.

  3. You implement your combined.py in the on_message function and publish the result back to OH over MQTT.

Use the execActuator as a guide and you should be able to figure it out.

For completeness, here is my OH and sensorReporter config for using hping3 to detect my phones using this execActuator (I run in Docker so can’t run exec stuff inside of OH itself).

Items:

// Manticore sensorReporter sensors
String aHping3 "Ask sensorReporter to hping3 and arping device [%s]"
  <present> (gPresent)
  { mqtt=">[mosquitto:scripts/presence/iphone/cmd:command:*:default]" }

Switch vJennPhone_Manticore_Net "Jenn's Phone Manticore Net"
  <present> (gPresent, gResetExpire)
  { mqtt="<[mosquitto:scripts/presence/iphone/results:command:REGEX(123.45.67.89 (.*)):123.45.67.89 .*]", expire="10m" }

Switch vRichPhone_Manticore_Net "Rich's Phone Manticore Net"
  <present> (gPresent, gResetExpire)
  { mqtt="<[mosquitto:scripts/presence/iphone/results:command:REGEX(123.45.67.90 (.*)):123.45.67.90 .*]", expire="10m" }

Rules:

rule "Ask sensorReporter to hping the phones"
when
        Time cron "*/10 * * * * ? *"
then
        aHping3.sendCommand("123.45.67.89 aa:bb:cc:dd:ee:ff")
        createTimer(now.plusSeconds(5), [|aHping3.sendCommand("123.45.67.90 ff:ee:dd:cc:bb:aa")]) // I don't want them running at the same time
end

sensorReporter .ini section

[Actuator2]
Class: execActuator.execActuator
Type: Exec
Connection: MQTT
Poll: 0
Command: ./iphoned.sh
CMDTopic: scripts/presence/iphone/cmd
ResultTopic: scripts/presence/iphone/results

iphone.sh script

#!/bin/bash

# https://community.openhab.org/t/iphone-presence-detection-with-hping3-and-arp/18171/28

# detect iphone by IP and MAC address.
# use MAC address too, to prevent false positives if IP might change
# return ON or OFF so output can be directly bound to a switch item

# number of retries, less is faster, but less accurate
MAXRETRIES=20

# exit immediately if no parameters supplied
if [ $# -lt 2 ]
        then
                echo "UNDEF"
                exit 1
fi

# Set variables
IP=$1
MAC=$2

COUNT=0
while [ ${COUNT} -lt ${MAXRETRIES} ];
do
        ip neigh flush dev eth0 ${IP}
        hping3 -q -2 -c 10 -p 5353 -i u1 ${IP} >/dev/null 2>&1
        sleep 1

        # Only arp specific device, grep for a mac-address
        STATUS=`arp -an ${IP} | awk '{print $4}' | grep "${MAC}"`

        if [ ${#STATUS} -eq 17 ]; then
                # exit when phone is detected
                echo "${IP} ON"
                exit 0
        fi
        let COUNT=COUNT+1
        sleep .1
done

# consider away if reached max retries
echo "${IP} OFF"

I send a command with the IP address and MAC address of the phone I want to detect using the aHping3 Item.

This publishes the message on the scripts/presence/iphone/cmd topic with those two values separated by a space.

This causes on_message in execActuator to be called with the message.

I parse out the IP address and MAC from the message and use them as command line arguments to the iphone.sh script.

The script prints out the IP address with “ON” or “OFF” depending on whether the phone was seen or not.

This output gets published to scripts/presence/iphone/results.

I have two Items subscribed to that topic so I use a RegEx filter so each Item only processes the messages with the indicated IP address, and then transform the message to forward the ON/OFF to the binding to apply to the Item.

Note: I’ve found this to be as accurate and more responsive than the BT detection for which I wrote sensorReporter in the first place. If you are not running in Docker, I would highly recommend the new arping capability built into the Network binding now in its stead. Again, arpping is not available inside the Docker container so I can’t use it.

Thanks for the very comprehensive reply, I run OH directly on the Pi, so I think I’ll stick with the current rule for now. Experience tells me that adding extra complication usually results in more troubleshooting when something doesn’t behave as expected.

This interests me, using the Bluetooth part of sensorReporter is a great addition, but OH has on occasion missed the odd Bluetooth gone command.
Is this detection capability in the latest snapshot binding? I’m on OH 2.1, is there an easy way of getting the binding with the extra capabilities or do I need to update the whole lot to a 2.2 Snapshot build? I also have a Fritzbox, although I’m not sure that the Fritzbox binding would add anything to my presence detection

To reply to my own post for those following on, I’ve updated to the latest snapshot, and am running the revised network binding. I needed to install arping using apt-get, and I followed the instructions here Moving from Stable to Snapshot
to change builds. To speed the transition I moved all my rules files elsewhere before the update. Before putting my rules back on the new version I had to get rid of any duplicated groups defined at the start of my items files as they seem to be a global thing and now can only appear once across all the item files. When I returned my rules files I discovered that when anything could return null != needs to change to !==, and == needs to change to ===
Apart from that the snapshot build seems good so far