Yes, Greg is right. This has nothing really to do with MQTT itself;
it's a system design issue. The same problems would arise with a
different messaging systems (AMQP, ActiveMQ, etc), or really any
other service architecture where inputs and commands are coming at
you from a variety of sources.
Remember, too, that you're thinking in terms of the implementation
language that you've chosen - Python. MQTT clients are used in
dozens of different languages. Python was invented long ago when
single-threaded apps were the norm. Since then, a lot of libraries
and modules were added on to help with doing multiple things at
once, such as threads, timers, async I/O, event loops, and so on.
But alternately, a lot of new languages and platforms have been
developed to handle parallel tasks, and make efficient use of
multi-cores. Languages like _javascript_, Rust, Go, Elixir, etc.
So it's not that you need to make something new. The problem is that
there are *so many* options for this all with pros and cons. A lot
comes down to personal preferences. What feels "right" to you.
ah, this makes sense.
So.. I hesitate to confes what I'm working with:
I think I have yet another event loop
How bad is the sleep?
I realize nothing will interrupt it, but as long as I am ok with 1 second response time?
(hopefully it doesn't matter how the 'timer' gets started)
class system:
time_till_light_off = 0
def tick(self):
if self.time_till_light_off:
self.time_till_light_off -= 1
time.sleep(1)
pub(tick)
else:
pub(light off)
client.loop_forever()
It is OK if the time spent on other events delays the light off.
It looks like I have a race condition (that always looses) when events come in during the sleep (which is most/all of the time?)
When I figured this out, I decided to stop trying to buld my own and find the recomended way.
And here we are.
Frank
On 10/6/19 2:16 PM, Carl Karsten wrote:
I appreciate the effort, but I'm surprised this isn't a FAQ
kinda thing.
Is what I am doing really that unique that it needs an
event architecture to be designed?
like Greg said:
> This is not an MQTT issue, but I can see it comes up
often in things
> that want to use MQTT.
You're looking at doing some "event
driven programming". The arriving MQTT messages are telling
your system what to do, but as you grow the system, there
will be other sources of events from sensors, timers, etc.
You want to handle these events as quickly as possible and
return control so that you're always responsive to new
events.
That means you need to do the actual processing of the
events outside of callbacks. Typical ways to do this,
depending on your language of choice, are with event loop
libraries, threads, and timers.
defhello():print("hello, world")t=Timer(30.0,hello)t.start()# after 30 seconds, "hello, world" will be printed
Tracking your internal progress as a state machine is a
great way to deal with all of this.
So, basically, in the callback that receives MQTT messages,
set a timer to fire some time later. Keep a reference to the
timer, "t", in case an event arrives indicating that the
action should be canceled before the timer fired. In that
case, you call:
t.cancel()
Frank
On 10/5/19 3:10 PM, Carl Karsten wrote:
opps, sorry, I thought this list was specifically
for python-paho.
I'm using Python.
> You basically have to avoid calling
sleep and use timers instead.
this sounds funny asking, but What is a timer?
Years ago I used a gui desktop database app
designer, I dragged a "timer widget" onto the form
and type in the function it should call every X amount
of time.
I understand what that did, I understand i need
something like that, but in this context I have no
idea how I should implement it.
I have a few guesses, like check for events in a
loop. maybe add a sleep so the cpu has some cycles to
do other things (no sure what other things are needed,
pretty sure incoming network traffic will take
priority? also pretty sure this is not a problem I
should be trying to solve. I am sure it has been
solved 100's of times.
I also guess "event loop" is a thing I need. Which
I also comprehend and could implement one from scratch
if I needed to, but I hope I don't need to.
On Sat, Oct 5, 2019
at 7:32 AM Greg Troxel <gdt@xxxxxxxxxx>
wrote:
> When the door opens, the light should stay on
for 60 seconds.
> or if the button is pressed, turn the light off
30 seconds later.
> every door open resets the 60 seconds.
>
> (this is the simplified version that I think is
the root of my problem)
This is not an MQTT issue, but I can see it comes up
often in things
that want to use MQTT.
> I can't do "on, sleep(60), off" because that
will block the on_button
> (right?)
If the main control program calls sleep, it will
ignore all other inputs
for that time. So don't do that :-)
> and when the button is pressed, if the door
opens again that should disable
> the "off in 30" thing.
A further complexity is humans asking for lights to
be in certain states
and automatic rules at the same time. In this case
I think you want a
virtual light controlled by the human and a virtual
light controlled by
the rules and the real light to be the OR of those.
> Is there a tutorial page or something I should
be reading?
This is really a fundamental programming issue; you
are constructing a
finite state machine with timers.
There are arguably two approaches to this sort of
thing, usually called
threads and async. It will seems that threads are
easier, but really
they just look easier and async is actually easier,
when you define that
as "work to get a 100% reliable system".
Frameworks that are set up for your problem include