Closed beetlegigg closed 7 months ago
I haven't tried this but it should be possible. You are correct in that micropython-touch
starts asyncio
which runs until the GUI terminates - or forever. If you look at the mqtt_as
demos, such as range.py
, the demo itself starts asyncio
- line 78. The whole try...finally
block could be replaced by a line
asyncio.create_task(main(client))
This line of code would need to be run by the GUI. It could be run in an after_open
method of your base Screen
which would start mqtt_as
automatically, or you could run it in (say) a Button
callback.
Following your comment I had a quick noddy test with a couple of updating labels on the screen and the range.py being called from an after_open method. Wonderful working like a charm.
Just to note that importing range into my screen program and issuing asyncio.create_task(main(client)) from the after_open did not work (NameError: name 'client' isn't defined) but putting that code into the range.py, replacing the try...finally, and then importing range in the after_open method did the trick.
Too late in the day for me to think this through but you've put me on the right path and I will delve into a more sophisticated program test when I've got a pcb for the pico and ili9341 done and then built my own mp with the touch and mqtt-as as frozen modules.
I'll close this now and many thanks for the comment, (and for touch and mqtt-as of course :-) )
This is something I've had in the back of my mind to try, so I've written some code (I may post this as a demo). Salient points:
mqtt_as
.import hardware_setup # Create a display instance
from gui.core.tgui import Screen, ssd
from gui.widgets import Label, Button, CloseButton, LED
from gui.core.writer import CWriter
# Font for CWriter
import gui.fonts.arial10 as arial10
from gui.core.colors import *
# MQTT stuff
from mqtt_as import MQTTClient
from mqtt_local import wifi_led, blue_led, config
import asyncio
TOPIC = "shed" # For demo publication and last will use same topic
outages = 0
# Define configuration
config["will"] = (TOPIC, "Goodbye cruel world!", False, 0)
config["keepalive"] = 120
config["queue_len"] = 1 # Use event interface with default queue
# Set up client. Enable optional debug statements.
MQTTClient.DEBUG = True
async def pulse(): # This demo pulses blue LED each time a subscribed msg arrives.
blue_led(True)
await asyncio.sleep(1)
blue_led(False)
class BaseScreen(Screen):
mqtt_task = None # Ensure task is a singleton
def __init__(self):
def my_callback(button, arg):
print("Button pressed", arg)
super().__init__()
wri = CWriter(ssd, arial10, GREEN, BLACK) # Verbose
col = 2
row = 2
Label(wri, row, col, "Topic")
self.lbltopic = Label(wri, row, col + 50, 200, bdcolor=GREEN)
self.lbltopic.value("Waiting...")
row = 20
Label(wri, row, col, "Message")
self.lblmsg = Label(wri, row, col + 50, 200, bdcolor=GREEN)
self.lblmsg.value("Waiting...")
row = 60
Label(wri, row + 15, col, "Network")
self.led = LED(wri, row, col + 50, color=RED, bdcolor=WHITE)
self.led.value(True)
row = 150
self.btnyes = Button(
wri, row, col, text="Yes", litcolor=WHITE, callback=self.pub, args=("Yes",)
)
self.btnyes.greyed_out(True)
col += 60
self.btnno = Button(
wri, row, col, litcolor=WHITE, text="No", callback=self.pub, args=("No",)
)
self.btnno.greyed_out(True)
CloseButton(wri, 30) # Quit the application
self.client = MQTTClient(config)
if BaseScreen.mqtt_task is None:
BaseScreen.mqtt_task = asyncio.create_task(self.main())
async def main(self):
try:
await self.client.connect()
except OSError:
print("Connection failed.")
Screen.back() # Abort: probable MQTT or WiFi config error
for task in (self.up, self.down, self.messages):
asyncio.create_task(task())
n = 0
while True:
await asyncio.sleep(60)
print("publish", n)
# If WiFi is down the following will pause for the duration.
await self.client.publish(
TOPIC,
"{} repubs: {} outages: {}".format(n, self.client.REPUB_COUNT, outages),
qos=1,
)
n += 1
async def messages(self):
async for topic, msg, retained in self.client.queue:
print(f'Topic: "{topic.decode()}" Message: "{msg.decode()}" Retained: {retained}')
self.lbltopic.value(topic.decode())
self.lblmsg.value(msg.decode())
asyncio.create_task(pulse())
async def down(self):
global outages
while True:
await self.client.down.wait() # Pause until connectivity changes
self.client.down.clear()
self.led.color(RED)
self.btnyes.greyed_out(True)
self.btnno.greyed_out(True)
outages += 1
print("WiFi or broker is down.")
async def up(self):
while True:
await self.client.up.wait()
self.client.up.clear()
self.led.color(GREEN)
self.btnyes.greyed_out(False)
self.btnno.greyed_out(False)
print("We are connected to broker.")
await self.client.subscribe("foo_topic", 1)
def pub(self, button, msg): # Button callback
asyncio.create_task(self.client.publish(TOPIC, msg, qos=1))
def test():
print("MQTT demo: button presses publish.")
Screen.change(BaseScreen) # A class is passed here, not an instance.
test()
Publications are on a button press, with a status pub every minute. Subscription messages are shown on screen. A screen LED
widget shows WiFi status.
Thats a very nice demo of the capabilities of the touch and mqtt.
When you say you pre-complied the mqtt-as.py I take it this means that the mqtt-as.py should be run on its own first, before then running the demo program and it does not mean that an mqtt-as.mpy is required. Anyway I had run the range.py to ensure the mqtt-as.py had all the supporting stuff set up correctly, and the demo then ran without a hitch.
With that very nice framework of how to use both modules together I now keen to get stuck in to my project, the grass cutting will have to wait :-)
No, I created mqtt_as.mpy
. Loading the .py
first may work by forcing an early compilation, but I am wary of loading anything until the Framebuf
is instantiated because the buffer requires so much contiguous RAM.
There are some obvious simplifications to the above code - e.g. my_callback
is completely redundant.
I added an extra LED
and a few explanatory Label
items but soon hit a limit, with an allocation fail occurring after it received a few messages. It's clearly running close to the limit, but given that you're prepared to freeze code I don't think you'll have any problems.
Using litcolor
with Button
instances is handy as it provides confirmation of a touch.
Good luck with your project!
This is not an issue as such, but seeking a knowledgeable comment on the best way to proceed with utilising the mp-touch lib together with the mqtt-as lib.
Delving too deep into the code is rather hard for my level of expertise, but I think the mp-touch starts an async loop when a user created sub class of the Screen class is instantiated.
I suppose that in this Screen subclass, apart from creating all the screen widgets, I could also include all the necessary task creations to get the mqtt-as up and running in the async loop as well.
Before going too far into having a go at this I thought I would check with you to see if I'm spouting nonsense or if you have any tips how (or if) one should go about using a touch screen that receives and publishes data via mqtt messages.
My scenario is the touch screen is linked to a temperature sensor (directly or via an mqtt message) that displays this temperature reading and also displays a current thermostat setting.
This Thermostat setting can be changed via up/down buttons. The new thermostat reading is published via mqtt to the boiler control / boiler status program (on another computer), and receives mqtt messages back from the same to display the boiler status on the screen.
This is all currently working on a raspberry pi with a large screen and I'm looking to package this up with a smaller display unit. Currently I also have a small display unit (ili9341) which runs nano-gui and mqtt-as as a display only screen.
I could quite easily use this ili9341 screen with manual buttons and its the way I will go if my thoughts on getting the touch screen ability of the ili9341 working with mqtt-as prove to be too complicated (for me :-) ). So before I embark on checking this out I thought I would get your quick thoughts on the feasibility of getting the mp-touch and mqtt-as working together on a rpi-pico board.
Thanks.