diy solar

diy solar

JK-BMS + Grafana in one evening.

A hypothetical synchronous operation, a REQUEST->RESPONSE call using a message bus is not 'that' difficult.

Publish the request to a specific topic with a specific request ID. Store this request in the service state. Subscribe to the response topic and filter until you get a payload with your response or you timeout.

Adding to that, for more fine grained control, the topic itself can contain the transaction id. So the topic is created per request, replied to by the 'server' with the response and then... something clean it up later.

It's not "difficult" to do, it's difficult to cover the multitude of concurrency issues that can occur and also difficult to make it fully fail-safe. Persistence of messages and the ability to replay in "passive" mode to recover state all start to surface.

My solution is not an example of how best to do this. My solution is an example of how to be lazy and avoid the bigger problems entirely.
 
A hypothetical synchronous operation, a REQUEST->RESPONSE call using a message bus is not 'that' difficult.

Publish the request to a specific topic with a specific request ID. Store this request in the service state. Subscribe to the response topic and filter until you get a payload with your response or you timeout.

Adding to that, for more fine grained control, the topic itself can contain the transaction id. So the topic is created per request, replied to by the 'server' with the response and then... something clean it up later.

It's not "difficult" to do, it's difficult to cover the multitude of concurrency issues that can occur and also difficult to make it fully fail-safe. Persistence of messages and the ability to replay in "passive" mode to recover state all start to surface.

My solution is not an example of how best to do this. My solution is an example of how to be lazy and avoid the bigger problems entirely.
There are many things you are explaining which I am not fully seeing in my head yet.

And I did quite a bit of programming, but totally new to MQTT.

I guess it's just a matter of getting started and then I'll probably understand better. Nothing beats first hand experience I guess
 
Start with the basic "ITTT". If this then that.

Subscribe to an MQTT topic of choice.
Write an on_message() handler for it.
Run blocking.

In the on_message() send another message to a device to do something.

Lights in the most simple sense are a motion sensor on MQTT. You subscribe to that topic. If it includes the occupancy field and it's true, turn the light on. if it's false, turn it off. Done. Effectively, but limited. 3 lines of code (in the on_message)
 
Adding... Always consider "idempotency". It's a fancy term for saying repeated requests should have no additional effect.(many caveats).

If a light needs to be ON. There should be no concern sending it an ON if it already is on. The output state satisfies the requirement.
If the light is OFF sending it the ON message will turn it on, also solving the original request.

Therefore the only penalty for repeatedly sending the "ON" event (or the "OFF" event) is purely "non-functional requirements" like performance and resource cost.

A more "textbook" example is a call to delete a file. In one implementation calling delete for a file that doesn't exist would produce an error. This is non-idempotent. Sending 2 request to delete the same file result in different outcomes. In an idempoently ideal world, sending "delete this file" and the file doesn't exist, then the output state has already been achieved and so it is successful.

These are software engineering and systems engineering principles and techniques. I am lucky to use them in work so I am current. But really they are just logical. Almost always they exist to limit the amount of "work" or "code" required and thus reduce the number of bugs.

A very modern focus has been on "prescriptive target state" mechanisms. IaaS and SaaS cloud stuff like Kubernetes and others work to this principle. You describe the resultant state which will "pass". You then define dependencies etc. A control loop runs which looks at the current state, then selects the next best action to move it one step towards the correct state and goes back to step one.

When this repeats over and over forever, the system will always and repeatedly move itself towards it's ideal state. This is the fundamentals of K8S etc. There are reasons this works so effectively.

For the future I want to explore this aspect more closely. Publishing the required outcome. Then have whatever service that wants to volunteer to aid it's progression towards that goal to get involved.

In the panel limit controller without specifically targetting that technique, it is effectively what it does. One service works out the maximum charge rate (the ideal state) and publishes it. Another service monitors that ideal state and modifies the MPPT controller output to try and achieve it. In tandem they work together to "help" the BMS out on achieving a full absorb without tripped the High voltage disconnect on the charge side due to a cell spike due to high current.
 
Last edited:
A perfect example of an anti-idempotent operation would be a call to an "increment counter".

A more real example from real world day to day code.... using a call to get the current date and time inside the scope of the operation. No matter when you call that method/operation you will get a different result, potentially. It also makes the code untestable outside of "time". So unit tests are incapable of testing different dates/times. This is something you see far, far, far too often in code. It invariably needs to be split into two (or more parts). That which decides what "Now" is and the part that responds to that prescribed time. If you call the later with the same time 100 times, it should produce the same output. Thus it is testable with hard coded values.

I mention it as "date time" and "when" are frequent things to deal with in automation.
 
A perfect example of an anti-idempotent operation would be a call to an "increment counter".

A more real example from real world day to day code.... using a call to get the current date and time inside the scope of the operation. No matter when you call that method/operation you will get a different result, potentially. It also makes the code untestable outside of "time". So unit tests are incapable of testing different dates/times. This is something you see far, far, far too often in code. It invariably needs to be split into two (or more parts). That which decides what "Now" is and the part that responds to that prescribed time. If you call the later with the same time 100 times, it should produce the same output. Thus it is testable with hard coded values.

I mention it as "date time" and "when" are frequent things to deal with in automation.
Yeah I understand, for sure you cannot run automated test with random input - random output kind of data. There needs to be a way to be able to control (and change) what the input is, and check if that change produces the expected output.
 
Back
Top