Thanks for the link. “/sbin/ifdown” instead “ifdown,” I think that might be the problem in my script.
I know wired is better than wireless, but all LAN ports on my router are occupied and I don’t want to buy more hardware. Besides, I need to keep the Pi close to my desktop in case I need to plug in the monitor to see if it’s dead. A wired connection probably won’t help much - I reboot my router at 3am every Sunday. After last night’s reboot I couldn’t ssh to the Pi, so I connected it with a cable, but still nothing happened. I had to power cycled it.
Okay, got it to work with this line in the crontab: @reboot sleep 60 && /usr/bin/mono /home/pi/STHostPinger.exe </dev/null >>/home/pi/sthp.log 2>&1
I am using an ASUS router with dual WAN support. My primary ISP is a cable company, and I use a mobile hotspot as the failover WAN. Last month the cable company had an outage, and my kid used almost 4GB cell data streaming Netflix. That’s why I want to use this smart app to prevent surprises.
I just configured the “Notify Me When” smart app, hoping it would notify me when the Host Pinger’s virtual switch for the mobile hotspot turns on, but so far I have only received one notification and it was delayed by 30 minutes.
I have two wish list items:
“HH:mm” for 24-hour display in the log since “tt” is not used for AM/PM.
If SendGetRequest() failed, add the host to a ResendList and resend the status next time regardless whether the host is Active or Inactive. Something like this:
if (pingable)
{
if (!ActiveClients.Contains(element) || ResendList.Contains(element) ) {
Otherwise a status change during an outage might not be reflected after the connection is restored.
Thanks!
04-Mar-18 06:07 [ONLINE] 192.168.100.1
04-Mar-18 06:07 [OFFLINE] 192.168.0.1
04-Mar-18 06:10 [WENT OFFLINE] 192.168.100.1
04-Mar-18 06:10 [ONLINE] 192.168.0.1
04-Mar-18 06:15 [WENT OFFLINE] 192.168.0.1
04-Mar-18 06:16 [ONLINE] 192.168.100.1
04-Mar-18 06:26 [WENT OFFLINE] 192.168.100.1
Failed to SendGetRequest: The request timed out
04-Mar-18 06:27 [ONLINE] 192.168.0.1
Failed to SendGetRequest: Error: ConnectFailure (No route to host)
04-Mar-18 06:33 [ONLINE] 192.168.100.1
04-Mar-18 06:33 [WENT OFFLINE] 192.168.0.1
The update to time shouldn’t be an issue, I thought it was 24 hours, will need to see how best to handle the error handling… will need to parse the response or lack of from ST and not update the previous state if not sent… will have a look this evening…
Actually for my use it’s good enough to remove a host from both Active and Inactive lists when there is an error connecting to ST. No Resend list will be necessary. It’s just like restarting the program.
My thinking is not to have a re-send list anyway… it just wont log the state change unless it’s successful… so will continue re-sending the same change until it’s successful, but wont send if the state device comes back online… if you start queuing you could be sending an old state…
To be honest I can’t remember how the code held previous state… but will take a look in a bit when I get home and see what I can do…
@camedia EXE V3 uploaded… time now in 24 hour format and it will retry sending to SmartThings at your specified interval until either successful or until the ping state returns to the last known state in ST.
I tested it by rebooting the Raspberry Pi, unplugging the cable modem, and reconnecting the cable modem after 10 minutes. I received SMS messages and notifications from ST after the ISP changed.
Here is the log. The initial message still shows V2.0.
—SmartThings Host Pinger V2.0—
Loading config…
Loaded
DebugLevel is set to 1
Running …
05-Mar-18 17:30 [OFFLINE] 192.168.100.1
Failed to send request to SmartThings: Error: NameResolutionFailure [RETRYING…]
05-Mar-18 17:30 [OFFLINE] 192.168.0.1
Failed to send request to SmartThings: Error: NameResolutionFailure [RETRYING…]
05-Mar-18 17:31 [ONLINE] 192.168.100.1
Failed to send request to SmartThings: Error: NameResolutionFailure [RETRYING…]
05-Mar-18 17:31 [OFFLINE] 192.168.0.1
Failed to send request to SmartThings: Error: NameResolutionFailure [RETRYING…]
05-Mar-18 17:31 [ONLINE] 192.168.100.1
Failed to send request to SmartThings: Error: NameResolutionFailure [RETRYING…]
05-Mar-18 17:31 [OFFLINE] 192.168.0.1
Failed to send request to SmartThings: Error: NameResolutionFailure [RETRYING…]
05-Mar-18 17:32 [ONLINE] 192.168.100.1
Successfully sent to SmartThings
05-Mar-18 17:32 [OFFLINE] 192.168.0.1
Successfully sent to SmartThings
05-Mar-18 17:40 [WENT OFFLINE] 192.168.100.1
Failed to send request to SmartThings: Error: ConnectFailure (Network is unreachable) [RETRYING…]
05-Mar-18 17:41 [WENT OFFLINE] 192.168.100.1
Failed to send request to SmartThings: The request timed out [RETRYING…]
05-Mar-18 17:43 [ONLINE] 192.168.0.1
Successfully sent to SmartThings
05-Mar-18 17:43 [WENT OFFLINE] 192.168.100.1
Successfully sent to SmartThings
05-Mar-18 17:50 [ONLINE] 192.168.100.1
Successfully sent to SmartThings
05-Mar-18 17:50 [WENT OFFLINE] 192.168.0.1
Successfully sent to SmartThings
Yesterday Samsung sent out an email saying the current ST app would be replaced soon. Hopefully everything will continue working after Samsung merged its smart home apps.
I’m running this on an Wemos D1 Mini (ESP8266) which is tiny, very low power, connects to Wifi and only costs 2-3 £ or $, connect it to a USB power supply and you have an always on method of pinging devices and sending to SmartThings without running the EXE on a dedicated PC…
I am not running this in a real world scenario so can’t confirm on reliability, as I have only just written the code and I’m not at home right now to leave it going… but if anyone wants to give it a go you will need to add the details in the settings section, load the sketch to your device using the Arduino IDE and it should then start running, output will be to the serial monitor…
By the way this is the first thing I have written for Arduino so any changes or suggestions welcome… feel free to put in a pull request…
Tagging @Jason_Brown as I expect you may be interested…
EDIT: V1.1 now loaded with change so WiFi AP is not broadcast
I decided to use bash and wget to write a pinger. Everything in one file.
I’d appreciate it if someone can tell me how to format the code below. The site doesn’t allow me to add more replies to this topic because I am a new user. All I know is to use the HTML pre tag to enclose the entire script.
#!/bin/bash
# SmartThings IDE configuration
IDE="https://graph-na04-useast2.api.smartthings.com"
# SmartThings application ID and access token
# Get them from the Host Pinger SmartApp under Endpoint Setup Details.
ACCESS_TOKEN="paste-your-access-token-here"
APP_ID="paste-your-app-id-here"
ST_ENDPOINT="${IDE}/api/smartapps/installations/${APP_ID}/statechanged"
# Add hosts you want to ping.
declare -A HOST_STATUS_MAP=(
[192.168.100.1]="unknown"
[192.168.0.1]="unknown"
)
# ping interval in seconds
PING_INTERVAL=30
FORCE_UPDATE_INTERVAL=86400
LAST_UPDATE="$(date +%s)"
echo `date` "- Starting SmartThings Host Pinger..."
while true
do
FORCE_UPDATE=false
CURR_TIME="$(date +%s)"
if (( CURR_TIME - LAST_UPDATE > FORCE_UPDATE_INTERVAL ))
then
FORCE_UPDATE=true
echo -e "\nForcing SmartThings update..."
fi
for IP_ADDR in "${!HOST_STATUS_MAP[@]}"
do
HOST_STATUS="unknown"
WGET_STATUS=0
if /bin/ping -c 2 ${IP_ADDR} > /dev/null
then
HOST_STATUS="online"
else
HOST_STATUS="offline"
fi
ST_URL="${ST_ENDPOINT}/${HOST_STATUS}?access_token=${ACCESS_TOKEN}&ipadd=${IP_ADDR}"
# Only update the status if it has changed or forced update is due.
if [ "${HOST_STATUS}" != "${HOST_STATUS_MAP[${IP_ADDR}]}" ] || ${FORCE_UPDATE}
then
/usr/bin/wget -q -O /dev/null -T 10 "${ST_URL}"
WGET_STATUS=$?
echo
# Update the status map if SmartThings was successfully updated.
if [ ${WGET_STATUS} -eq 0 ]
then
HOST_STATUS_MAP[${IP_ADDR}]=${HOST_STATUS}
LAST_UPDATE="$(date +%s)"
echo `date` "- ${IP_ADDR} status: [${HOST_STATUS}]"
else
echo `date` "- Unable to reach SmartThings Endpoint."
fi
fi
done
# echo "All hosts: ${!HOST_STATUS_MAP[@]}"
# echo "All status: ${HOST_STATUS_MAP[@]}"
# echo "sleeping..."
sleep ${PING_INTERVAL}
echo -n "*"
done
A Bourne shell script that runs on an Asus router with original firmware to detect if a failover has happened. I use it to turn on an orange light behind my TV when the router fails over to the secondary WAN, which is a mobile hotspot.
I am not using ping to detect the change. Instead I use the router’s “nvram get wanX_realip_ip” command. It shows that the Host Pinger smart app can be used as a more general purpose resource state tracker.
The BEGIN_DATA and END_DATA variables should have the values below. They didn’t display correctly when I used the HTML pre tag to enclose the entire script.
BEGIN_DATA=’<?xml version="1.0" encoding="utf-8"?><s:Envelope xmlns:s=“http://schemas.xmlsoap.org/soap/envelope/” s:encodingStyle=“http://schemas.xmlsoap.org/soap/encoding/”><s:Body><u:SetBinaryState xmlns:u=“urn:Belkin:service:basicevent:1”>‘
END_DATA=’</u:SetBinaryState></s:Body></s:Envelope>’
#!/bin/sh
#### This script runs on a Asus router with original Asus firmware.
#### It checks the status of the primary and secondary/failover WAN
#### and updates the Host Pinger smart app when the status changes.
#### It also turns on a Wemo Mini smart plug on the LAN when a
#### failover happens.
# SmartThings IDE configuration. Change it to your own IDE URL.
IDE="https://graph-na04-useast2.api.smartthings.com"
# SmartThings application ID and access token
# Get them from the Host Pinger SmartApp under Endpoint Setup Details.
ACCESS_TOKEN="paste-your-access-token-here"
APP_ID="paste-your-app-id-here"
ST_ENDPOINT="${IDE}/api/smartapps/installations/${APP_ID}/statechanged"
# ping interval in seconds
PING_INTERVAL=30
FORCE_UPDATE_INTERVAL=14400
FORCE_UPDATE=false
LAST_UPDATE=$(date +%s)
# Primary WAN
WAN0_IP_ADDR=192.168.100.1
WAN0_PREV_STAT=unknown
# Failover WAN
WAN1_IP_ADDR=192.168.0.1
WAN1_PREV_STAT=unknown
# IP of Wemo Mini smart plug
WEMO_IP=192.168.1.137
H_ACCEPT="Accept: "
H_CONTENT='Content-type: text/xml; charset=utf-8'
H_SOAPACTION="SOAPACTION: \"urn:Belkin:service:basicevent:1#SetBinaryState\""
BEGIN_DATA=' '
END_DATA=' '
#### Turn on/off Wemo Mini
toggle_wemo()
{
ON_OFF=$1
# Wemo's web service port can change periodically.
# Test which port is currently open.
for PTEST in 49152 49153 49154 49155
do
PORTTEST=$(wget -q -t 1 -T 5 -O - http://$WEMO_IP:$PTEST/setup.xml | grep "root")
if [ "$PORTTEST" != "" ]; then
PORT=$PTEST
break
fi
done
# echo "${BEGIN_DATA}${ON_OFF}${END_DATA}"
if [ "${PORT}" != "" ]; then
wget --header="${H_ACCEPT}" \
--header="${H_CONTENT}" \
--header="${H_SOAPACTION}" \
--post-data="${BEGIN_DATA}${ON_OFF}${END_DATA}" \
-q -t 1 -T 10 -o /dev/null -O /dev/null http://$WEMO_IP:$PORT/upnp/control/basicevent1
fi
}
#### Update device status in SmartThings
update_st_status()
{
WAN_NUM=$1
IP_ADDR=$2
HOST_STATUS=$3
ST_URL="${ST_ENDPOINT}/${HOST_STATUS}?access_token=${ACCESS_TOKEN}&ipadd=${IP_ADDR}"
wget -q -t 1 -T 10 -o /dev/null -O /dev/null --no-check-certificate "${ST_URL}"
WGET_STATUS=$?
if [ ${WGET_STATUS} -eq 0 ]; then
LAST_UPDATE=$(date +%s)
eval "WAN${WAN_NUM}_PREV_STAT=${HOST_STATUS}"
fi
}
#### Use Asus router's "nvram get wanX_realip_ip" command
#### to check if a WAN is active. X is 0 for the primary WAN
#### and 1 for the secondary/failover WAN.
check_wan_status()
{
WAN_NUM=$1
IP_ADDR=$2
PREV_STATUS=$3
WAN_IP_ADDR=$(nvram get wan${WAN_NUM}_realip_ip)
if [ "${WAN_IP_ADDR}" != "" ]; then
WAN_STATUS=online
else
WAN_STATUS=offline
fi
if [ "${WAN_STATUS}" != "${PREV_STATUS}" ] || ${FORCE_UPDATE} ; then
# Update the Wemo plug directly instead of waiting for SmartThings
# because during failover the ST hub might take minutes to
# reconnect to the cloud.
if [ ${WAN_NUM} -eq 1 ] && [ ${WAN_STATUS} = "online" ]; then
toggle_wemo 1
elif [ ${WAN_NUM} -eq 1 ] && [ ${WAN_STATUS} = "offline" ]; then
toggle_wemo 0
fi
echo $(date) ${WAN_NUM} "${IP_ADDR}" "${WAN_STATUS}"
update_st_status ${WAN_NUM} "${IP_ADDR}" "${WAN_STATUS}"
fi
}
#### Main
echo $(date) "Starting SmartThings Pinger..."
while true
do
CURR_TIME=$(date +%s)
TIME_LAPSED=$(expr ${CURR_TIME} - ${LAST_UPDATE} )
# echo "Time lapsed: ${TIME_LAPSED}"
if [ ${TIME_LAPSED} -ge ${FORCE_UPDATE_INTERVAL} ]; then
FORCE_UPDATE=true
echo $(date) "Forced update: $FORCE_UPDATE"
else
FORCE_UPDATE=false
fi
check_wan_status 0 ${WAN0_IP_ADDR} ${WAN0_PREV_STAT}
check_wan_status 1 ${WAN1_IP_ADDR} ${WAN1_PREV_STAT}
sleep ${PING_INTERVAL}
done
Something strange here, I wanted to transfer my sthostpinger to another rpi device so I copied the exact sthostpinger and config file to another rpi. However now when I run I got the following
Failed to SendGetRequest: Error getting response stream (Write: The authentication or decryption has failed.): SendFailure
Any settings I need to reset or reconfigure when changing to another rpi?