2

Base Idea

I am using the MQTT protocol (Broker: Mosquitto and Client implementation via Eclipse Paho) to get periodic data. I want to show an image upon getting a particular number x in the data and change the image if I get another number y.

In layman terms, I am getting some data in JSON format in an interval of 10 seconds, and want to display or change an image with respect to the data received.

Code

from tkinter import *
from PIL import ImageTk, Image
import datetime
import paho.mqtt.client as mqtt
import json

root = Tk()
canvas = Canvas(root, width=500, height=500)
canvas.pack()


def drawImage(payload):
    pic = payload['camera']
    canvas.delete("all")
    img = ImageTk.PhotoImage(Image.open(str(pic) + ".png"))
    canvas.create_image(20, 20, anchor=NW, image=img)
    root.mainloop()


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


def on_message(client, userdata, msg):
    t = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    payload = json.loads(msg.payload)
    print("Data received at: {0} || Topic: {1} || Message: {2}".format(t, msg.topic, str(msg.payload)))
    drawImage(payload)


client = mqtt.Client(client_id="cameratester")
client.on_connect = on_connect
client.on_message = on_message
client.connect("127.0.0.1", 1883, 60)
client.loop_forever()

Brief explaining of how the code works:

Whenever new data is received on_message gets called which in-turn calls the drawImage function that draws the image.

Problem

Image draws upon receiving the first message, but code seems to hang there. My client doesn't accept any of the other incoming messages. Upon closing the image window, the print("Data received at: {0} || Topic: {1} || Message: {2}".format(t, msg.topic, str(msg.payload))) line of code starts executing again, but no image gets displayed.

Some Research

After going through the plathora of How to change image in Tkinter questions on StackOverflow, like this and this, it became evident that root.mainloop() is a blocking call and the flow wouldn't execute further until the window is closed. It was mentioned that if I want to change the image, I would need to assigned a callback to an event, like clicking a button and do panel.configure(image=img2) to change the image.

But since my design doesn't have any buttons, I cannot follow the button-callback methodology.

So, how can I trigger a change the image on Tkinter window upon receiving data from a Publisher (MQTT)?

Should I not use Tkinter, some other package is better suited for this requirement? Or am I missing something really basic.

Please advice.

Mono Jamoon
  • 4,437
  • 17
  • 42
  • 64
  • tkinker works bad with external event loop. You have internal one for tkinter even loop and making mqtt.Client event loop, which one should proceed? drawImage starts tkinter's so it is. – outoftime Jun 07 '20 at 15:41

0 Answers0