danielwippermann / resol-vbus-java

A Java library for processing RESOL VBus data
7 stars 6 forks source link

ConfigurationOptimizer for DeltaSol MX #15

Closed iodb closed 4 years ago

iodb commented 6 years ago

How would I go about creating a ConfigurationOptimizer for my DeltaSol MX? My main purpose is to switch relays between Auto/On/Off in 'Manual Mode'.

ramack commented 6 years ago

That would be also in interesting feature for the openhab binding. - a simple way to control the outputs of the relays of the controllers. Best would be even to control also in 0-100% for PWM output and 0-10V if configured accordingly.

I guess we need to do that via configuration isn't it? Or is there a simpler way?

danielwippermann commented 6 years ago

How would I go about creating a ConfigurationOptimizer for my DeltaSol MX?

Well, the basic steps for any ConfigurationOptimizer is to take the "menu.xml" for your controller of choice out of RESOL's RPT software and convert it. I have a slightly modified version of https://github.com/danielwippermann/resol-vbus/tree/master/tools/configuration-importer for that task and follow the steps in its documentation. But...

The tools currently only works for small controllers. For the MX the getAdjustableValues method gets too big and cannot be compiled any longer. I have to tweak the tool to split up the list of values into multiple chunks, create a method per chunk and then call them in order to get the full list...

My main purpose is to switch relays between Auto/On/Off in 'Manual Mode'.

Then you would not need a full ConfigurationOptimizer anyway.

The ConfigurationOptimizer is focused on transfering the complete configuration and optionally ignoring values that are not used (e.g. because their corresponding option is not activated). That last part is not implemented for the DeltaSol CS Plus because the configuration is already quiet small without having to optimize it.

Since you don't need the full config of the MX things get much simpler. You only need:

  1. the value ID hashes of the values you are interested in
  2. the value IDs for them, gathered using Connection#getValueIdByIdHash and
  3. set the values using Connection#setValueById.

The reason for step 2 is that the value IDs can change if you update the MX firmware, but the value ID hashes should stay the same. That also means that you could cache the result of step 2 and skip it until you do a MX firmware update.

You get the value ID hashes from the menu.xml in the RPT.

Best would be even to control also in 0-100% for PWM output and 0-10V if configured accordingly.

I don't know whether that is possible at the moment. The manual mode allows you the switch between Off, Min, Auto, Max and On (100%). So you would have to alter both the manual mode and the respective min speed to achieve something like this. And to be honest: I have not tested that yet...

!!! One paragraph of warning though: every time you issue a Connection#setValueById you will be triggering a countdown to write that change to the non-volatile memory. Be careful not to spam the controller with unnecessary setValueById since you might wear out the NVM chip's lifetime !!!

ramack commented 6 years ago

Thanks foe the explaination. I somehow feared iy would be like that. So for the MX it seem much better to emulate an EM device and switch relays via temperature signals...

iodb commented 6 years ago

Thanks @danielwippermann, this is very useful. I already found in the menu xml the necessary info to locate my relays, so the next step would be to figure out which of its fields I need to manipulate. Given the fields (here for relay 13): Relais_Regler_R13: 0 Relais_Regler_R13_Nr: 13 Relais_Regler_R13_AktorFunktion: 303 Relais_Regler_R13_Wert: 0 Relais_Regler_R13_ODrehzahl: 0 Relais_Regler_R13_MinDrehzahl: 100 Relais_Regler_R13_MaxDrehzahl: 100 Relais_Regler_R13_Status: 9 Relais_Regler_R13_Handbetrieb: 2 Relais_Regler_R13_Betriebssekunden: 0 Relais_Regler_R13_OAdapter: 0 Relais_Regler_R13_OInvertiert: 0 Relais_Regler_R13_OBlockierschutz: 0

Fields that change when I change manual mode via the controller are Relais_Regler_R13_Wert [on: 100, off: 0] Relais_Regler_R13_Status [on: 5 (Hand Ein), off:2 (Hand Aus)] Relais_Regler_R13_Handbetrieb [on: 4 (Ein), off: 0 (Aus)] Any idea which one(s) I need to change?

danielwippermann commented 6 years ago

The ..._Handbetrieb value is the one you are searching for ("Handbetrieb" is the german word for "manual mode"). Both ..._Wert and ..._Status are updated by the firmware in response to you setting the manual mode, no need to set them yourself.

iodb commented 6 years ago

Setting the manual mode works as expected, thanks. I assume there isn't actually any work done to 'emulate an EM device', like @ramack mentioned?

ramack commented 6 years ago

I thought about doing that in the openhab plugin, but for sure, if it would be here in resol-vbus-java I'd have an easy job there :-)

danielwippermann commented 6 years ago

It should be fairly easy to create something like this. It would implement ConnectionListener and would add itself to a Connection. It then listens for the EM1 packets, decode their payload, store it in instance variables, transfer other instance variables into a reply packet and send that off to the requester. The only detail to decide: how should the plugin be informed of new data in the instance variables? A classic PropertyChangeListener concept or something different? If you have preferences I try to follow them when proposing such a device emulation impl.

ramack commented 6 years ago

Sounds good to me.

danielwippermann commented 6 years ago

Just a small progress update: I pushed the first draft of the Em1DeviceEmulator in commit f4ad992. Up to now it has only been dry-tested. I'll try to do a test with a real MX controller tomorrow if time permits and then bump the version / release a new JAR / add an additional example the illustrates how to use the class a bit better.

iodb commented 6 years ago

When doing a test with a real controller, it would be interesting to know what happens if the emulator goes down for a (short) while (seconds, minutes). Does the controller remember the last values? Will it re-connect when the emulator comes back up?

danielwippermann commented 6 years ago

In theory a short blackout of the emulator up to 30 seconds should not bother the controller. After that it would start reporting a module fault and sensor faults if one or more of the emulator's sensors is used for a controlling function. The behaviour of the controlling function in case of a sensor fault differs, but normally they switch off corresponding relais to enter a kind of safe mode.

After the emulator is back the controller resumes normal operation.

But I'll try that on the real device when I have time tomorrow.

danielwippermann commented 6 years ago

I just commited and pushed 624c12cef9e0ec2ee4f8c7bf5c4df00113447c4a which includes a simple example on how to use the (freshly renamed) EmDeviceEmulator.

I tested the the example against a DeltaSol MX. Here are a few notes I took during testing:

iodb commented 6 years ago

Currently I'm a bit stuck when I try to both continuously read sensor data and try to read some configuration by calling connection.getValueById(). Either when I use the same connection or a separate one, I get a massive amount of DISCONNECT / RECONNECTs as soon as configuration data is requested from the controller. Any idea how I can avoid this?

danielwippermann commented 6 years ago

I have put the following code at the end of my run() method for testing:

        while (true) {
            Datagram dgram1 = connection.waitForFreeBus(20000);

            if (dgram1 != null) {
                int peerAddress = dgram1.getSourceAddress();

                Datagram dgram2 = connection.getValueById(peerAddress, 0x0000, 500, 500, 3);
                System.out.println(dgram2.getValue());

                connection.releaseBus(peerAddress, 1500, 500, 2);
            }
        }

And it worked okay, without interruptions. How do you access the VBus? A datalogger or KM2 or something other?

iodb commented 6 years ago

Ok, the immediate problem seemed to have been the missing releaseBus() call.

Occasionally I noticed a ConcurrentModificationException in Connection.emitHeaderReceived(), probably when flooding the device with too many requests. Unfortunately the exception kills the TcpConnection's background thread, requiring a restart.

connection.waitForFreeBus() seems to take around 5 seconds. This seems about right? Doing multiple getValueById() calls within a single bus goes much faster (around 50 ms), but I'm guessing there's a limit to the number of operation you can do before DISCONNECTs start to occur.

Strangely enough, I didn't get the getValueIdHashById() and getValueIdByIdHash() to work yet. Command 0x1000 doesn't seem to appear in the protocol specification either, but I might be misreading that.

I have a DL2 datalogger.

danielwippermann commented 6 years ago

I just pushed commit 70b8e720506baab1ea0d95b809d2103e5c9e4c78 to hopefully prevent the ConcurrentModificationException you encountered.

Yes, the waitForFreeBus() can take up to 10 seconds when used on a MX with maxed-out configuration. Once you have the bus control you can issue multiple getValueById commands before returning the control again.

But keep in mind that the VBus also supplies voltage / power to attached equipment. Sending large amounts of data without interruption will cause the VBus voltage to slowly decrease up to a point where the attached equipment is unable to detect data transmission on the VBus anymore. That is the reason why most functions have a retry / timeout options to give the bus some time to recharge.

The DL2 should not be the cause for the DISCONNECTS. As far as I remember the DISCONNECTs happen it the Java socket connected to the DL2 does not receive ANY data for 5 seconds. This can for example happen if the MX fails to receive the releaseBus() command. If you send that command and simply wait for the MX to continue its normal sending operation, but the MX misses that command, there will be a VBus "silence" of approx. 10 seconds. And this silence can cause the Java scoket to DISCONNECT / RECONNECT.

Which firmware version does your MX currently run? Older versions might not yet support the ID hash commands...

andrewFKL commented 5 years ago

Hi all, Experimenting and extending the resol-vbus binding for openHAB, i have following problems with my Deltasol MX: Method tcpConnection.getValueIdByIdHash, returns the value '0' for some idHash and I wanted to ask if anyone knows why and maybe there is another way to get the following values:

Thanks in advance Andreas

danielwippermann commented 5 years ago

Hi Andreas,

in newer versions of the DeltaSol MX only persistently stored values have a value ID hash associated. Both the ..._Status and ..._AktorFunktion values are volatile, since the controller recalculates them on a regular basis.

The only alternative I can imagine is to get the value ID for a persistently stored value nearby (like ..._ODrehzahl) and offset the resulting value ID by a hardcoded distance. This approach has the downside that it breaks once the controller firmware inserts values in between between those values.

Did that answer your questions?

Best regards, Daniel

ramack commented 4 years ago

Experimenting and extending the resol-vbus binding for openHAB, i have following problems with my Deltasol MX:

@andrewFKL what are your plans? Did you work on the binding I started? Anyhow, just wanted to let you know that @codeworkx also works on an update?

danielwippermann commented 4 years ago

Closing this issue due to lack of activity. Feel free to reopen it if additional information is necessary.