HASS Monitoring script using CloudMQTT + AWS and python script

Hello,

Last week I setup the uptimerobot to monitor my HA server (synology NAS). it is working fine so far, but there are 2 things i dont really like on it:
1/ I am monitoring the interface webpage, and I am not 100% if this is the best way to do it.
2/ I have to open the firewall ports to let the external server connect in my place, which is something i don’t like. funny enough, after i open the port 8123 i saw logs in the FW for other IPs messing around. I did fix that by only allowing the uptimerobot IP traffic in, but I still dont like open ports on the FW.

To solve my own problem, I start a quick adventure to built a watchdog server, that will be listing for periodic messages from HA, if HA stop to send those messages, then the server will send me a notification and let me know about it.

I plan the following setup:
1/ HA send a message to MQTT broker
2/ server will be listening to the message
3/ server to send alert in case no message arrive during 10 min.

to make it work, I could have used a RPi in my house, but it still wont alert me in case my internet die for example.
so i setup a tiny server installation on AWS which is free of charge. so I have

HASS server → Cloud MQTT ↔ AWS server → pushover

the HASS part is quite simple, it is a time triggered automation that publish a message to the broker:

  • alias: ‘tovivo’
    trigger:
    • platform: time
      minutes: ‘/3’
      seconds: 0
      action:
      • service: mqtt.publish
        data:
        topic: “watchdog”
        payload: “hass”

the cloudMQTT i setup as indicated here: MQTT - Home Assistant

the AWS I had setup more than 6 months ago to play around, I dont have any links on how to do it, but google have alot!

the pushover setup was quite straight forward in their website, inclusive on how to send POST messages.

the last part was to create the python server. and surprisingly was not that hard (please keep in mind, I am a computer engineer that did its last code line around 10 years ago) i use to program in C, python was not my strongest skill, also, I AM REALLY RUSTY, the code is “quick and dirty” but solve my problem, I am quite sure it can be optimized, but is stable enough (well, it is working for the last 6 hours, so far, so good.
any helpful idea/improvements suggestions are appreciated.
the code is:
import requests
import paho.mqtt.client as mqtt
import datetime
import time

# The callback for when the client receives a CONNACK response from the server.
def on_connect(client, userdata, flags, rc):
    print("Connected with result code "+str(rc))
    # Subscribing in on_connect() means that if we lose the connection and
    # reconnect then subscriptions will be renewed.
    client.subscribe("watchdog/#")
    client.subscribe("checktime/#")
    client.subscribe("paranoid/#")
    client.subscribe("status/#")
    client.subscribe("execute/#")


# The callback for when a PUBLISH message is received from the server.
def on_message(client, userdata, msg):
    global counter
    global checktime 
    global paranoid
    global comeback 
    global dead
    global execute
    global schedule

    old_counter = counter
    counter = 0
    if dead == 1:
      comeback = 1
    if msg.topic == 'checktime':
      checktime = str(msg.payload, 'utf-8')
    if msg.topic == 'execute':
      execute = str(msg.payload, 'utf-8')
    if msg.topic == 'paranoid':
      paranoid = str(msg.payload, 'utf-8')
    if msg.topic == 'status':
      message = 'Current timer: '+ str(old_counter)+ ' Server Time: '+ schedule +' checktime: ' + checktime + ' paranoid: '+ paranoid
      title = 'Watchdog Status'
      pushover = requests.post ( url , data = {'token': token, 'user': user , 'message' : message , 'title' : title })      
      print (message)

#initiate global variables
checktime = '2000' # daily check on format HHMM
paranoid = 'off'
counter = 0
comeback = 0
dead = 0
firstdead = 0
execute = 'true'
schedule = '1900'

token = 'XXXXXXXXXX' # token for app on pushover
user = 'XXXXXXXXXX' # pushover user
message = 'just started'
title = 'just started'
url = 'https://api.pushover.net/1/messages.json'

client = mqtt.Client()
client.username_pw_set('XXXXX', password='XXXXXX') #Cloud MQTT user and pass
client.on_connect = on_connect
client.on_message = on_message

client.connect("XXXXX", XXXXXX, 60) #cloud MQTT server / port
client.loop_start()

while execute == 'true':
  now = datetime.datetime.now()
  hour = '{str_0:0>2}'.format(str_0=now.hour)
  minute = '{str_0:0>2}'.format(str_0=now.minute)
  schedule = hour + minute
  if schedule == checktime: #daily check to return server status
    message = 'Daily Check passed'
    title = 'Daily Check'
    pushover = requests.post ( url , data = {'token': token, 'user': user , 'message' : message , 'title' : title })      
    time.sleep(62)
  if comeback == 1: #to track if the server was dead, then return
    message = 'HASS is back to Life at ' + schedule
    title = 'Back to Life'
    pushover = requests.post ( url , data = {'token': token, 'user': user , 'message' : message , 'title' : title })      
    comeback = 0
    dead = 0
  if counter == 600: #main loop, my system is flagged for 10 min = 600 secs
    if dead == 0:  #main alert, server just died
      firstdead = schedule
      message = 'HASS stop to respond at ' + schedule
      title = 'HASS is dead!'
      pushover = requests.post ( url , data = {'token': token, 'user': user , 'message' : message , 'priority': '2' , 'retry' : '30' , 'expire': '3600', 'title' : title })      
      dead = 1
    if dead == 1: #follow up alert in case paranoid flag is on
        message = 'HASS stop to respond at ' + firstdead
        title = 'HASS is still dead!'
        pushover = requests.post ( url , data = {'token': token, 'user': user , 'message' : message , 'priority': '2' , 'retry' : '30' , 'expire': '3600', 'title' : title })      
    if paranoid == 'on':
      counter = 300
    else:
      counter = 700
  if counter == 760: # second loop, in case paranoid id off. also aimed to prevent variable overflow
    counter = 700
  time.sleep(1)
  counter = counter + 1

#full pushover post message
# pushover = requests.post ('https://api.pushover.net/1/messages.json' , data = {'token': XXXXX, 'user': XXXXXX , 'message' : 'Hello' , 'priority': '2' , 'retry' : '30' , 'expire': '3600', 'title' : 'HELP!!'})

I hope someone else have a use for it!

Luis

1 Like

This looks awesome, but I’ve been having some issues with CloudMQTT going down lately. I’m on m12.cloudmqtt.com; what server are you using?

I am on m21.cloudmqtt.com.
well… i don’t know about cloudMQTT stability. but i would assume if it starts to fail, I could setup a mosquitto broker on the same AWS server.
the part of the code which is prone to failure (my view) is that i dont do any validation on the input i could get.
for example, I am setting the daily check at 2000, i can modify this sending a message to the topic checktime, and the payload will be the new checktime variable.
the problem is, if someone pass wrong data (either format or rubbish info) the program isn’t checking before use it. this is something i can fix in the version 2.0

Luis

Are you on a paid plan? Also what country/region are you in? I’m on a free plan and my only option on the East Coast US seems to be this m12 server… :frowning:

I am in UK and using the free tier.
there is another thing that bothers me… HASS is connecting to the secure port.
my program is connecting only on the non secure port. I need to dig a bit to find how to use the certificates there.

1 Like

That would explain the different server then.

I’ve only been able to get it to connect non-SSL. Another reason I’m thinking of setting up mosquitto on the Pi and just opening a port on the router. It’s a bummer because when I lose the mqtt connection, I not only lose my mqtt switches, but for some reason the ZWave switches too. I’m starting to wonder if HASS uses mqtt to make the ZWave switches in native mode…

quick fix.
I added:
client.tls_set(’/etc/ssl/certs/ca-certificates.crt’)
before i call the connect function.
change the door to the secure TLS door (2XXXX)
now it is working with TLS enabled :slight_smile:

Luis