MQTT trigger remote camera

I have a pi running in a while true python loop listening for RF signals. I also want it to listen for an MQTT signal and on receipt take a singe image with the camera. How do I set this up?

while true:
  if MQTT received:
    take photo
  else 
    pass

I though about having a string variable that gets over-written by the MQTT message, then the camera picture is taken, and the string variable set to its original value, but I am sure there must be a better way…

You need to use the paho-mqtt python package in async or threaded mode. Since RF signals are probably time critical, I think you will need to go with threaded mode, to keep the delays waiting for mqtt messages out of the main loop.

I did much the same in my Energenie MQTT Client, but that’s in C rather than Python, so not much direct help.

1 Like

Solved, as per the example at https://pypi.python.org/pypi/paho-mqtt/1.1#subscribe-unsubscribe
Just place some processing in the on_message function:

def on_message(client, userdata, msg):
    payload = str(msg.payload.decode('ascii'))  # decode the binary string
    print(msg.topic + " " + payload)
    process_trigger(payload)

def process_trigger(payload):
    if payload == 'ON':
        print('ON triggered')

Full script - camera on remote pi triggered either by rf or mqtt and posts the captured image to HASS using mqtt:

import paho.mqtt.client as mqtt
import paho.mqtt.publish as publish
import picamera
import argparse
import signal
import sys
import time
import logging
from rpi_rf import RFDevice
rfdevice = None

### camera
camera = picamera.PiCamera()
camera.vflip=True

def post_image():
    print('Taking photo')
    camera.capture('img.jpg')
    with open('img.jpg', "rb") as imageFile:
        myFile = imageFile.read()
        data = bytearray(myFile)
    client.publish('dev/camera', data, mqttQos, mqttRetained)  #
    print('image published')

### MQTT
broker = '192.168.0.100'
topic ='dev/test'
mqttQos = 0
mqttRetained = False

def on_connect(client, userdata, flags, rc):
    print("Connected with result code "+str(rc))
    client.subscribe(topic)

# The callback for when a PUBLISH message is received from the server.
def on_message(client, userdata, msg):
    payload = str(msg.payload.decode('ascii'))  # decode the binary string
    print(msg.topic + " " + payload)
    process_trigger(payload)

def process_trigger(payload):
    if payload == 'ON':
        print('ON triggered')
        post_image()

client = mqtt.Client()
client.on_connect = on_connect    # call these on connect and on message
client.on_message = on_message

client.username_pw_set(username='user',password='pass')  # need this
client.connect(broker)
client.loop_start()    #  run in background and free up main thread

### RF
# pylint: disable=unused-argument
def exithandler(signal, frame):
    rfdevice.cleanup()
    sys.exit(0)

logging.basicConfig(level=logging.INFO, datefmt='%Y-%m-%d %H:%M:%S',
                    format='%(asctime)-15s - [%(levelname)s] %(module)s: %(message)s', )

parser = argparse.ArgumentParser(description='Receives a decimal code via a 433/315MHz GPIO device')
parser.add_argument('-g', dest='gpio', type=int, default=27,
                    help="GPIO pin (Default: 27)")
args = parser.parse_args()

signal.signal(signal.SIGINT, exithandler)
rfdevice = RFDevice(args.gpio)
rfdevice.enable_rx()
timestamp = None
logging.info("Listening for codes on GPIO " + str(args.gpio))

code_of_interest = '9812234'
while True:
    if rfdevice.rx_code_timestamp != timestamp:
        timestamp = rfdevice.rx_code_timestamp
        print(str(rfdevice.rx_code))
        if str(rfdevice.rx_code) == code_of_interest:
            post_image()
    time.sleep(0.01)
rfdevice.cleanup()