-
Notifications
You must be signed in to change notification settings - Fork 12
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
waiter() function #3
Comments
On Sun, Feb 17, 2019 at 06:44:54AM +0000, qurm wrote:
Hi,
I came across this project while looking for a fully Python-based
SMA inverter tool, that would be easier to maintain & modify than
the various C language sbfspot projects. It looks like a well
structured code base - thanks for your efforts!
I have spent some hours understanding and commenting, but there's
one area that puzzles me still. Can you explain the function below,
and how it works with the various tx & rx functions & the @waiter
decorator?
Heh, it's a while since I wrote that.. had to figure out what I was
doing again.
So the waiter stuff is either a neat trick or a gross hack - take yor
pick - to deal with the fact that messages back from the inverter as
basically asynchronous, but we want to present a synchronous interface
to the user - call a function, something happens, you get a response
as the return from that function.
In particular it's a way of doing that without heavyweight
infrastructure like having a receiver thread, or having to write
nearly all of the Rx path as a hard to decipher state machine.
If you look at the rx_*() functions you'll see that they take some
data from the inverter, decipher one protocol layer (roughly speaking)
then pass that up to another rx_*() function to decipher the next
layer. At the end we reach rx_6560() which does.. basically nothing.
The trouble is that while the Rx functions know how to decipher
packets from the inverter, they don't actually know what kind of
information we're expecting from the inverter at the moment, so they
don't know what to do with the data.
If you look at the "operation" functions - the ones that do some
specific task and return some information obtained from the inverter,
you'll see they generally have the form:
...
tx_something()
wait_something()
...
The tx_*() function sends some request to the inverter, then we wait
for a response. The wait_*() functions are wrappers around wait(),
which is the magic bit.
wait() takes parameters saying what type of packet we're looking for
at what protocol layer. It pokes those into some special variables
then just calls rx() until another special variable is set.
The trick is that the Rx functions have been decorated with @waiter,
which augments the bare Rx function with code to check if the special
wait variables are set, and if so check the results of the Rx to see
if it's something we're currently waiting for, and if so put it
somewhere that wait will be able to find it.
The waiter() function implements that decorator - it's a function that
takes a function (the bare rx method) and returns a function (the rx
method augmented with the logic to check what we're waiting for).
This could all be done by open-coding the checks for what we're
waiting for in each of the relevant Rx functions, but there are quite
a lot of Rx layers and using the decorator avoids that boilerplate at
each level.
…--
David Gibson | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_
| _way_ _around_!
http://www.ozlabs.org/~dgibson
|
Thanks, and that all makes sense! I could not really identify the pattern, though could see it was a like a stack. There is a line in waitfn(), where you save the args, Anyway, it seems to work, so I'll leave it alone!! BTW I did see a different response to a "HELLO" to the one in your code, and was easily fixed, but I guess this may be dependent on the specific inverter model & firmware. I have a SMA 5000TL, about 5 years old. I am also getting Error responses from the inverter when using the Thanks for the response, Andy |
On Thu, Feb 21, 2019 at 12:09:23PM +0000, qurm wrote:
Thanks, and that all makes sense! I could not really identify the pattern, though could see it was a like a stack.
There is a line in waitfn(), where you save the args, `self.waitvar
= args`. Would that not get overwritten if there were async packets
being received out of order?
Theoretically, yes. The reason this works is that while the protocol
is asynchronous at the lower levels, it's effectively synchronous at
the higher levels. So when we request a wait, we don't expect to get
a packet matching the criteria we've set other than the one that's in
response to the command we've set.
Like I said, this is kind of a hack - it's not an approach I'd
recommend as a model for a protocol stack in most cases. In this case
it seemed to work out as a good balance between handling asynchrony to
the extent we need to, without having to structure the entire tool
around asynchronous events.
Anyway, it seems to work, so I'll leave it alone!!
BTW I did see a different response to a "HELLO" to the one in your
code, and was easily fixed, but I guess this may be dependent on the
specific inverter model & firmware. I have a SMA 5000TL, about 5
years old.
Yeah, it can definitely vary depending on the inverter model. It also
depends on the configuration - in particular there's a "net id" which
some people have at least partly worked out, but I don't have any
implementation of.
I believe mine is also an SB 5000TL (well, two of them).
I am also getting Error responses from the inverter when using the
`sma2-explore` tool and trying various send2 commands from your
protocol.txt file. Possibly another small difference, but I should
be able to work it out.
Yours could well be configured for a different "net id" mode; I
believe that changes a bunch of things about the protocol.
…--
David Gibson | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_
| _way_ _around_!
http://www.ozlabs.org/~dgibson
|
Hi,
I came across this project while looking for a fully Python-based SMA inverter tool, that would be easier to maintain & modify than the various C language sbfspot projects. It looks like a well structured code base - thanks for your efforts!
I have spent some hours understanding and commenting, but there's one area that puzzles me still. Can you explain the decorator function below, and how it works with the various tx & rx functions & the @waiter decorator? What is the purpose of creating the various _waitcond attributes and the waitvar ?
Thanks, Andy
The text was updated successfully, but these errors were encountered: