Python mqtt client script(polling/ping state and controlling tv/receiver/gpio)

Hello everyone!

I wanna share some code i made tonight using python…
Sure it could be written better but it works for me :slight_smile:
It checks the state of my tv and receiver using a ping / wget to webinterface of device and getstatus_tv.sh or getstatus_receiver.sh returns ON or OFF to python script. wget response is fast! :stuck_out_tongue:
I also use lircd to turn these devices on or off etc…
Timeout is 10sec but can be adjusted to what you want.
So every 10secs it checks devices and if state changed publishes using mqtt

Example of getstatus_receiver.sh:

#!/bin/bash
wget -O /dev/null -o /dev/null -t 1 -T 1 http://192.168.1.225
STATUS=$?
if [ $STATUS -ne 0 ]; then
  echo "OFF"
else
  echo "ON"
fi

The python mqtt-client.py script:

#!/usr/bin/python3

import paho.mqtt.client as paho
import paho.mqtt.publish as publish
import RPi.GPIO as GPIO
import datetime
import time
import json
import sys
import os

log = open("mqtt-client.log","a")

# redirect print to logfile...
# comment this line below to print to std instead of logfile
sys.stdout = log

from datetime import datetime
from threading import Thread

auth = {
  'username':"user",
  'password':"password"
}

topics = {
	"home/receiver"         : { "topic" : "home/receiver"       , "function" : "stateReceiver" },
	"home/receiver/state"   : { "topic" : "home/receiver/state" , "status"   : "OFF"           }, 
	"home/tv"               : { "topic" : "home/tv"             , "function" : "stateTV"       },
	"home/tv/state"         : { "topic" : "home/tv/state"       , "status"   : "OFF"           },
	"home/testled1"         : { "topic" : "home/testled1"       , "function" : "gpioLight"     },
	"home/testled1/state"   : { "topic" : "home/testled1/state" , "status"   : "OFF"           }
}

# key = topics item, switch = do turn on or off device
def stateTV(key, switch):
	import subprocess
	if switch is not None: 
		out = topics[key + "/state"]["status"]
	else:
		# get state of device (using ping or wget...) 
		# script returns ON or OFF
		proc = subprocess.Popen(["sudo", "sh",  "/home/pi/getstatus_tv.sh", "> /dev/null 2>&1"], stdout=subprocess.PIPE)
		out, err = proc.communicate()
		out.decode('ascii')

	if "OFF" in str(out):    
		if switch == None: 
			client.publish(key + "/state", "OFF")
			topics[key + "/state"]["status"] = "OFF"
		elif switch is not None: 
			topics[key + "/state"]["status"] = "ON"
			subprocess.call(["irsend", "SEND_ONCE", "TV", "KEY_POWER"])
	else:
		if switch == None: 
			client.publish(key + "/state", "ON")
			topics[key + "/state"]["status"] = "ON"
		elif switch is not None: 
			topics[key + "/state"]["status"] = "OFF"
			subprocess.call(["irsend", "SEND_ONCE", "TV", "KEY_POWER"])
			
	return topics[key+"/state"]["status"]
	
# key = topics item, switch = do turn on or off device
def stateReceiver(key, switch):
	import subprocess
	if switch is not None: 
		out = topics[key + "/state"]["status"]
	else:
		# get state of device (using ping or wget...) 
		# script returns ON or OFF
		proc = subprocess.Popen(["sudo", "sh",  "/home/pi/getstatus_receiver.sh", "> /dev/null 2>&1"], stdout=subprocess.PIPE)
		out, err = proc.communicate()
		out.decode('ascii')

	if "OFF" in str(out):   
		if switch == None: 
			client.publish(key + "/state", "OFF")
			topics[key + "/state"]["status"] = "OFF"
		elif switch is not None: 
			topics[key + "/state"]["status"] = "ON"
			subprocess.call(["irsend", "SEND_ONCE", "Receiver", "KEY_POWER"])
	else:
		if switch == None: 
			client.publish(key + "/state", "ON")
			topics[key + "/state"]["status"] = "ON"
		elif switch is not None: 
			topics[key + "/state"]["status"] = "OFF"
			subprocess.call(["irsend", "SEND_ONCE", "Receiver", "KEY_POWER"])
			
	return topics[key+"/state"]["status"]
	
# key = topics item, switch = do turn on or off device
def gpioLight(key, switch): 
	# read state of GPIO pin
	state = "ON" if GPIO.input(23) == 1 else "OFF"
	if "OFF" in state:    
		if switch == None: 
			client.publish(key + "/state", "OFF")
			topics[key + "/state"]["status"] = "OFF"
		else: 
			GPIO.setup(23, GPIO.OUT) 
			GPIO.output(23, GPIO.HIGH)
			topics[key + "/state"]["status"] = "ON"
	else:
		if switch == None: 
			client.publish(key + "/state", "ON")
			topics[key + "/state"]["status"] = "ON"
		else: 
			GPIO.setup(23, GPIO.OUT) 
			GPIO.output(23, GPIO.LOW)
			topics[key + "/state"]["status"] = "OFF"
			
	return(topics[key + "/state"]["status"])
		
def on_subscribe(client, userdata, mid, granted_qos):
	print (datetime.now().strftime('%d-%m-%Y %H:%M:%S') + " - " + "Subscribed: " + str(mid) + " " + str(granted_qos))
 
def on_message(client, userdata, msg):
	import subprocess
	print (datetime.now().strftime('%d-%m-%Y %H:%M:%S') + " - " + "Received message: " + msg.topic + " " + str(msg.qos) + " " + str(msg.payload))
	print (  
		datetime.now().strftime('%d-%m-%Y %H:%M:%S') + " -",
		"State changed:",
		msg.topic,
		eval(topics[msg.topic].get("function") + "('"+msg.topic+"', " + ("1" if "OFF" in str(msg.payload) else "0") + ")")
	)
	
def on_connect(client, userdata, flags, rc):
	if rc == 0:
		print (datetime.now().strftime('%d-%m-%Y %H:%M:%S') + " - " + "Connected to broker")
		
		# loop thru topics dictionary and subscribe to topics...
		for key, val in topics.items():
			if (topics[key].get("function") is not None):
				print (datetime.now().strftime('%d-%m-%Y %H:%M:%S') + " - " + "Subscribed to topic: " + topics[key].get("topic"))
				client.subscribe(topics[key].get("topic"))
	else:
		print (datetime.now().strftime('%d-%m-%Y %H:%M:%S') + " - " + "Connection failed")
 
client = paho.Client()
client.on_subscribe = on_subscribe
client.on_message = on_message
client.on_connect = on_connect   
client.username_pw_set("user", "password")
client.connect("192.168.1.2", 1883)

GPIO.setwarnings(False)
GPIO.setmode(GPIO.BOARD)
GPIO.setup(23, GPIO.OUT)

client.loop_start()

try:
	# loop thru devices and execute functions to check if online / offline or whatever...
	while True:
		for key, val in topics.items():
			if (topics[key].get("function") is not None):
				print (
					datetime.now().strftime('%d-%m-%Y %H:%M:%S') + " -",
					"Device state: " + topics[key].get("topic"),
					eval(topics[key].get("function") + "('" + topics[key].get("topic") + "', None)")
				)
				
		# keep logfile filesize at max 1MB (1024(1KB) * 1024) = 1MB...
		if os.stat('mqtt-client.log').st_size >= (1024 * 1024):
			log.close()
			log = open('mqtt-client.log', 'w')
			sys.stdout = log
			
		sys.stdout.flush()
		time.sleep(10)

except KeyboardInterrupt:
	print (datetime.now().strftime('%d-%m-%Y %H:%M:%S') + " - " + "Exiting")
	client.disconnect()
	client.loop_stop()

switches in configuration.yaml:

- platform: mqtt
  name: tv
  state_topic: "home/tv/state"
  command_topic: "home/tv"
  payload_on: "ON"
  payload_off: "OFF"
- platform: mqtt
  name: receiver
  state_topic: "home/receiver/state"
  command_topic: "home/receiver"
  payload_on: "ON"
  payload_off: "OFF"
- platform: mqtt
  name: testled1
  state_topic: "home/testled1/state"
  command_topic: "home/testled1"
  payload_on: "ON"
  payload_off: "OFF"

To make things complete make a .service file /etc/systemd/system/mqtt-client.service and enable it systemctl daemon etc.:

[Unit]
Description=MQTT-Client
After=multi-user.target

[Service]
Type=simple
ExecStart=/home/pi/mqtt-client.py
User=pi
WorkingDirectory=/home/pi/
Restart=on-failure
StandardOutput=journal

[Install]
WantedBy=multi-user.target

Questions suggestions? Let me know!

Ciao!

Sicco

Thanks for sharing. Would you mind tagging it as “share your projects”?

Thnx! Changed it! :+1:

Hi thanks for the share.

Does this work on any tv?

Also I tried running on my rpi terminal the following but it didn’t return anything:

wget -O /dev/null -o /dev/null -t 1 -T 1 http://192.168.0.19 STATUS=$?

No, but it does work if your tv has an webinterface or any thing like that… i just call it to see if it is on or not. You also can try to ping it but wget is faster just to check this.

For my philips android tv(55POS901F) i use:

#!/bin/bash
wget -O /dev/null -o /dev/null -t 1 -T 1 http://192.168.1.235:1925/system
STATUS=$?
if [ $STATUS -ne 0 ]; then
  echo "OFF"
else
  echo "ON"
fi