tagyoureit / nodejs-poolController

An application to control pool equipment from various manufacturers.
GNU Affero General Public License v3.0
317 stars 94 forks source link

Virtual Valve: MQTT support #240

Closed orrious closed 3 years ago

orrious commented 3 years ago

Please provide MQTT binding for Virtual Valves.

Binding should subscribe to a "state" topic and publish to a separate "command" topic. njsPC should not assume it is in complete control of the valve. If state on valve changes, update state in njsPC which may or may not trigger some other action in njsPC.
Topics should be easily configurable via API and config files.

This is how it is configure in Home Assistant:


    unique_id: valve_Spa_Drain
    name: "Valve Spa Drain"
    icon: mdi:valve
    state_topic: "pool/valveSpaDrain"
    command_topic: 'pool/valveSpaDrain/set'
    state_on: '{"state": "on"}'
    state_off: '{"state": "off"}'
    payload_on: '{"state": "on"}'
    payload_off: '{"state": "off"}'
    optimistic: false
    retain: true
    qos: 0``
rstrouse commented 3 years ago

Actually, the valve diversion is driven from the state of the circuit and that should be the controller for it. This is important as the said circuit could be involved with a group or a body intake/return. That state needs to be properly fixed by njspc or the control mechanisms will fall down. If you need to change the state of the valve, you need to change the state of the affiliated circuit.

A perfect example of this (and not the only one) is when you currently have the pool circuit on (no spillway on). In this case the intake should be not diverted and the return should be. In that instance the water is drawn from the pool body and returned to the pool body. When the spa circuit is energized then the diversions between the intake and return valves should be reversed and the pool circuit should be turned off in a shared configuration. If a spillway is activated then the intake and return should not be diverted. Another example includes control over the solar valve based upon the heating/cooling setpoints on the body.

Anyhow I have added the bindings for the valves. This follows the current bindings format that already exists. If you want different bindings simply make a copy of the mqtt.json file in the web/bindings directory and point your mqtt configuration to that file in your config.json. These are totally customizable and the bindings can coexist even on separate brokers.

orrious commented 3 years ago

I'm willing to concede on the valves being solely controlled by njspc, but not other items like lights or other features.

In the binding you've created, are you just publishing to the "command" topic or do you verify that it worked by reading the "state" topic? If not reading "state" can you?

orrious commented 3 years ago

Should valves be tied to circuits or bodies? I would think bodies. If valves are tied to bodies and pumps are tied to bodies, then if a valve fails to divert (by reading the mqtt "state") then the pump circuit would not turn on or turn off if already on for that body and that body would turn / remain off.

rstrouse commented 3 years ago

The opposite there is a state topic and no command. These are read only and the subscriber should rotate their valves accordingly. I honestly think we need to start building a custom OCP for this. In that instance, the hardware interfaced items will be notified when to do things like rotate valves, turn on heaters, click relays ...etc. From there, the entire configuration can be managed by an interface of your choosing.

That means that things like valve delays, manual overrides, ...etc can take place in homed logic based upon the configuration. As far as external means on the server all interfaces should be in control of state and config through the interfaces. That is how -dashPanel, -webClient, and the HA platforms that have been integrated actually work. Controllable items include setpoints, circuits, features, groups, themes. On the config side the entire configuration should be capable of being manipulated.

Valves should be attached to the circuit state not the body. The reason for this is that the positions for intake/return (which are the body related items) do not necessarily divert based upon the state of the body. For instance, if a feature for spillway is turned on it will override the diversion of the return valve. In this instance water comes from the pool body and is returned to the spa.

As for valves failing to divert I have had this situation. This wasn't caused because the OCP didn't rotate the valves it was caused by bad CV24s. Over the years on this pool I have had no less than 14 failures due to cracked cams, endpoint microswitches, and motor failures. That is why the plumbing should be designed in such a was as to never dead-head a pump. If it does however, it will likely fail the priming sequence. In one instance, the return valve just kept spinning which hammered the crap out of my plumbing. Since changing all 7 of them to IV I haven't had a failure like that yet so I can't complain about those.

As far as failure on the comms end, I am sure we can come up with a protocol to check the valve states and shut down the pumps on error. Perhaps the best way about this is to check for a processed flag. With REST, Webhooks, or even Modbus TCP this issue goes right away since we are dealing with request response and it is more performant.

orrious commented 3 years ago

I agreed with having a custom OCP, but I can also see folks wanting to expand their current implementation with additional valves. In mqtt, it's always good to verify the state of something you're setting as there is no guarantee that the message actually got to the destination. Therefore there is a state and command topic. On my Pi-I2C-Arduino setup, I validate all the way down to the pin and read the voltage off of it to send back to the state topic.

Case in point, intellibrite takes a long time to cycle. with 250 ms cycle times (that's the quickest I've been able to get it to reliably work) setting the 14 cycle magenta color takes 7 seconds. What happens if in the middle of a cycle it gets another request to cycle to a new color? Would you return the status of the new request or ignore the new request and return the state it will be in? I chose to ignore the new request, finish the prior and return the value or the prior, as that is what the color will be at the end of the cycle. The controller without verifying would think that the color was that last request though and would get out of sync.

In mqtt IMO it's a must to have command and status topics that reflect that actual state.

One last thing I've been thinking about. If a body requires a valve to be set to a certain state, if the valve doesn't change state within x seconds, the body should go off. If the valve changes state at any point, the body should go off. We should be able to configure notifications of failures and override state requirements.

rstrouse commented 3 years ago

I don't want to get too far in the weeds with Intellibrite (I hate it) when my first bulb fails it will get the DMX treatment. Anyhow, there are some things you are missing with your controller. The IB controller performs sAM functions and allow you to sync an array of lights and the theme is overwritten. This stupid process can take up to a minute to complete. The swim process can take even longer than that. When is is occurring, the OCP emits a Sequencing delay through its messages. The expectation is that additional commands to the IB controller are suspended while this is going on. If you want to read more about all this look at the Pentair docs for IntelliBrite regarding Sync, Set, Swim... and Hold/Recall. image

The reason I am bringing this up is because there is a similar byte emitted that is called valve delay. It is a little more complicated than simply waiting for valve rotation but the end result is that pump changes are suspended until the OCP removes the delay. I'm not so sure I want to get into cleaner timeouts and solar priming but all of this is a chaining of events that eventually results in a pump change. Bear in mind that much of this is dependent on the function of the circuit, which pumps are associated, and the priming options that have been set. You don't want to suspend a pump or process that has no bearing on the current operation.

I haven't really been involved with the MQTT protocol messaging but I will take a closer look at the publish/subscribe messaging to see if there is a two-phase commit in there somewhere. I think the focus may be more on HA and sensor feeds not synchronous processing.

tagyoureit commented 3 years ago

BTW, there are the equivalent of state and command channels in MQTT. The command channels are implemented more like the API's but you can set them however you want on HA. Also note that not all of them are set. Set values with MQTT. We won't update the state until the instructions sent through the command channel are verified.

tagyoureit commented 3 years ago

Closing due to lack of activity.