MichielVanwelsenaere / HomeAutomation.CoDeSys3

Home Automation system build in CoDeSys 3 with MQTT communication to any third party Home Automation software
MIT License
112 stars 37 forks source link

Wago 750-559 expects WORD input instead of BYTE #72

Closed mchlrv closed 3 years ago

mchlrv commented 3 years ago

The Wago 750-559 expects a WORD input instead of a BYTE. The input range is from 0 - 32767, see below reference table. Any value between 0 and 32767 is valid.

Volt Word Value
0 0
1.25 4096
2.50 8192
3.75 12288
5.00 16384
6.25 20480
7.50 24576
8.75 28672
10.00 32767
MichielVanwelsenaere commented 3 years ago

Adding some more details; this is related to FB_OUTPUT_DIMMER_MQTT which outputs a Byte value and not a word.

I'll check what makes sense to deal with this as it does makes sense to keep the 0-255 range for the MQTT interface as that's what most (if not all) home automation software packages use for a dimmer range.

How about just updating the docs with a note to use 'BYTE_TO_WORD' when your specific output requires a WORD value? What did you do now?

mchlrv commented 3 years ago

Adding some more details; this is related to FB_OUTPUT_DIMMER_MQTT which outputs a Byte value and not a word.

I'll check what makes sense to deal with this as it does makes sense to keep the 0-255 range for the MQTT interface as that's what most (if not all) home automation software packages use for a dimmer range.

How about just updating the docs with a note to use 'BYTE_TO_WORD' when your specific output requires a WORD value? What did you do now?

I've tried to use BYTE_TO_WORD but all that does change the type, it does not convert the value. Also a WORD is 2 bytes not 1.

mchlrv commented 3 years ago

What I've done now is creating two new VARS

AO_001_BYTE_VALUE           :BYTE; // To which the OUT value is assigned.
TestDivider             :REAL := 128.4980392157; // 32767/255

Now my WRITE_SWITCHES looks like this:

FB_AO_DIMMER_001(SINGLE:=   FB_DI_PB_002.SINGLE,    (* for toggling the output Q *)
    DOUBLE:=                FB_DI_PB_002.DOUBLE,    (* for controlling the output DBL *)
    LONG:=                  FB_DI_PB_002.LONG,      (* for controlling the dimmer output OUT *)
    P_LONG:=                FB_DI_PB_002.P_LONG,    (* for controlling the dimmer output OUT *)
//    Q=>                     DO_002,                 (* couple the function block to the physical digital output *)
    OUT:=                   AO_001_BYTE_VALUE
);
AO_001:= REAL_TO_WORD(BYTE_TO_WORD(AO_001_BYTE_VALUE)*TestDivider);
Sandolution commented 3 years ago

Lenze uses 16384 for max output voltage, Siemens uses 27648. So I guess you need to make some sort of adaptable scaling module. CoDeSys Utils contains LINTRAFO which you could use for that.

mchlrv commented 3 years ago

Thanks to @Sandolution I've now implemented LINTRAFO.

In PLC_PRG_MAIN I define the following:

    (* DIMMER FUNCTION BLOCKS *)
    MqttPubDimmerPrefix         :STRING(100) := 'WAGO-PFC200/Out/Dimmers/';
    MqttSubDimmerPrefix         :STRING(100) := 'WAGO-PFC200/In/Dimmers/';
    FB_AO_DIMMER_001            :FB_OUTPUT_DIMMER_MQTT;
    AO_001_BYTE_OUT             :BYTE;

    (* LIN TRAFO FUNCTION*)
    LIN_TRAFO_AO_001: Util.LIN_TRAFO;

In WRITE_SWITCHES now have below code. Not sure if this can be written any shorter / better.

FB_AO_DIMMER_001(SINGLE:=   FB_DI_PB_002.SINGLE,    (* for toggling the output Q *)
    DOUBLE:=                FB_DI_PB_002.DOUBLE,    (* for controlling the output DBL *)
    LONG:=                  FB_DI_PB_002.LONG,      (* for controlling the dimmer output OUT *)
    P_LONG:=                FB_DI_PB_002.P_LONG,    (* for controlling the dimmer output OUT *)
//    Q=>                     DO_002,                 (* couple the function block to the physical digital output *)
    OUT:=                   AO_001_BYTE_OUT
);
LIN_TRAFO_AO_001(
        IN:= AO_001_BYTE_OUT,
        IN_MIN:= 0,
        IN_MAX:= 255,
        OUT_MIN:=0,
        OUT_MAX:=32767
    );
AO_001:= REAL_TO_WORD(LIN_TRAFO_AO_001.OUT);
MichielVanwelsenaere commented 3 years ago

I'll adopt the dimmer output function block so it has the linear transform functionality build in. Should make things easier and more readable.

MichielVanwelsenaere commented 3 years ago

Could you have a look at the project in this branch? I incorporated the linear scale function in the function block itself there and modified the 'OUT' output of the dimmer function block so it has type 'WORD'

You need to do two things to test;

  1. update the function block in your project
  2. update the call to the InitMqtt method with an additional parameter:
(* INIT DIMMER OUTPUT STUFF *)
FB_AO_DIMMER_001.InitMQTT(MQTTPublishPrefix:= ADR(MqttPubDimmerPrefix),    (* pointer to string prefix for the MQTT publish topic *)
    MQTTSubscribePrefix:= ADR(MqttSubDimmerPrefix),                         (* pointer to string prefix for the MQTT subscribe topic *)
    pMQTTPublishQueue := ADR(MQTTVariables.fbMQTTPublishQueue),         (* pointer to MQTTPublishQueue to send a new MQTT event *)
    pMqttCallbackCollector := ADR(MqttVariables.collector_FB_DIMMER_MQTT),  (* pointer to CallbackCollector to receive Mqtt subscription events *)
    TRUE,                                                               (* specify whether dimmer value should be outputted on MQTT topic *)
    SD_MQTT.QoS.ExactlyOnce,                                            (* specify the QoS for the dimmer mqtt events (values 0-255) *)    
    5,                                                                   (* specify the resolution for the dimmer mqtt events *)     
    32767                                                                (* specify the value to which the output should scaled maximum *)    
);

I don't have a device laying around on which I can test this at the moment, so your help would be very much appreciated.

mchlrv commented 3 years ago

Could you have a look at the project in this branch? I incorporated the linear scale function in the function block itself there and modified the 'OUT' output of the dimmer function block so it has type 'WORD'

You need to do two things to test;

  1. update the function block in your project
  2. update the call to the InitMqtt method with an additional parameter:
(* INIT DIMMER OUTPUT STUFF *)
FB_AO_DIMMER_001.InitMQTT(MQTTPublishPrefix:= ADR(MqttPubDimmerPrefix),    (* pointer to string prefix for the MQTT publish topic *)
  MQTTSubscribePrefix:= ADR(MqttSubDimmerPrefix),                         (* pointer to string prefix for the MQTT subscribe topic *)
    pMQTTPublishQueue := ADR(MQTTVariables.fbMQTTPublishQueue),         (* pointer to MQTTPublishQueue to send a new MQTT event *)
  pMqttCallbackCollector := ADR(MqttVariables.collector_FB_DIMMER_MQTT),  (* pointer to CallbackCollector to receive Mqtt subscription events *)
    TRUE,                                                               (* specify whether dimmer value should be outputted on MQTT topic *)
    SD_MQTT.QoS.ExactlyOnce,                                            (* specify the QoS for the dimmer mqtt events (values 0-255) *)    
    5,                                                                   (* specify the resolution for the dimmer mqtt events *)     
    32767                                                                (* specify the value to which the output should scaled maximum *)    
);

I don't have a device laying around on which I can test this at the moment, so your help would be very much appreciated.

It works perfectly now. Can you also please add the IN_MIN value to the InitMqtt? Or set these values as a var with a default value.

MichielVanwelsenaere commented 3 years ago

why would you need that exactly? I don't see why it should differ from 0 as the input range for the dimmer is always expected between 0-255.

If you want to play with the behavior of the dimmer, I suggest having a look at the 'ConfigureDimmer' method described here.

Thanks for testing!

mchlrv commented 3 years ago

Because in at the value of 11000 my leds go out. So from 11000 - 0 and back to 11000 nothing happens for a few seconds.

MichielVanwelsenaere commented 3 years ago

would it then not make more sense to have 'OUT_MIN' configurable? then the full 0-255 range can be used to control the linear scaled out range? That would give more fine grained control as you have more possible input values to control the output range.

mchlrv commented 3 years ago

would it then not make more sense to have 'OUT_MIN' configurable? then the full 0-255 range can be used to control the linear scaled out range? That would give more fine grained control as you have more possible input values to control the output range.

You're completely right, that was also the variable I meant, sorry for the confusion.

MichielVanwelsenaere commented 3 years ago

no problem! makes indeed sense to add that as a settable value through a method call. I'll check this further next week as it will take some more time to update the docs and everything as well but do note that I'll probably update the 'ConfigureDimmer' method with these params as the 'InitMqtt' method is intented for MQTT setup purposes which is not really related to the actual behavior of the dimmer.

MichielVanwelsenaere commented 3 years ago

I made a final version. Could you retest it? for clarity;

Could you also check if you send a value to the FB using MQTT (range 0-255) that is scales as expected? I don't think it did in the version I previously provided.

Again, thanks for testing! 👍

mchlrv commented 3 years ago

Just tested the updated version and it works perfectly. The MQTT is also working now as this was not the case before.

Why did you move the output range out of the InitMqtt? As you say now I can't set different values for different kind of leds.

Thank you for adopting the code, it makes it a lot easier to configure the PLC!

MichielVanwelsenaere commented 3 years ago

you can modify the scaleout behavior (and all the other dimmer behavior for that matter) using the 'ConfigureFunctionBlock' method. Just call it once during the 'init/setup' period of the code to configure the dimming behavior as desired.

I prefer to implement it in that method for multiple reasons:

Let me know if that makes sense or if you require any help to get it configured as desired using the 'ConfigureFunctionBlock' method.

mchlrv commented 3 years ago

Your first point makes sense as this is no MQTT functionality.

The thing that does not make sense is 'ConfigureFunctionBlock'. It states that the values can be overwritten. Does this mean that I can have different OUT_MIN and OUT_MAX for each dimmer? If so can you tell me how to implement this?

Another thing that is currently not clear to me is the single and double press. From the documentation I understand that a single press can switch as DO. So my setup is as follow: DO_001 -> relay -> dimmer -> light. Whenever I single press the button the DO_001 output is true and switches a relay which turns on the dimmer. Now I can control (with the same button) the dimmer of the light. Is this intended to work like this? Can you also provide an example of the double press? I'm now sure what to expect from it right now.

MichielVanwelsenaere commented 3 years ago

yes, using the 'ConfigureFunctionBlock' method you'll be able to have different OUT_MIN & OUT_MAX values for each Function block (so each dimmer indeed). I've updated the function block docs and the project with a sample call.

Yes, normally things should work as you are describing. Do you have a test setup? what are you experiencing?

MichielVanwelsenaere commented 3 years ago

regarding your question on the double press; the OSCAT documentation mentions the below:

The output DBL can be switched to the input SET and the dimmer can be set to a predefined value VAL using a double-click.

That being said it's probably more logical to wire the double output of a pushbutton function block directly to the 'SET' input instead of using the DBL output. Ofcourse you still need to hardcode a value on the 'VAL' input.

It might make sense to modify the function block so it doesn't have the DBL output and DOUBLE input to simplify things. I'll check this tomorrow!

mchlrv commented 3 years ago

yes, using the 'ConfigureFunctionBlock' method you'll be able to have different OUT_MIN & OUT_MAX values for each Function block (so each dimmer indeed). I've updated the function block docs and the project with a sample call.

Yes, normally things should work as you are describing. Do you have a test setup? what are you experiencing?

Thank you for the sample call, it really helps to understand it better. I do have a test setup, so If you want to test something please let me know I'm happy to do so.

regarding your question on the double press; the OSCAT documentation mentions the below:

The output DBL can be switched to the input SET and the dimmer can be set to a predefined value VAL using a double-click.

That being said it's probably more logical to wire the double output of a pushbutton function block directly to the 'SET' input instead of using the DBL output. Ofcourse you still need to hardcode a value on the 'VAL' input.

It might make sense to modify the function block so it doesn't have the DBL output and DOUBLE input to simplify things. I'll check this tomorrow!

It took me some time to get it working but I've managed it now with using below code.

FB_AO_DIMMER_001(SINGLE:=   FB_DI_PB_002.SINGLE,    (* for toggling the output Q *)
    DOUBLE:=                FB_DI_PB_002.DOUBLE,    (* for controlling the output DBL *)
    LONG:=                  FB_DI_PB_002.LONG,      (* for controlling the dimmer output OUT *)
    P_LONG:=                FB_DI_PB_002.P_LONG,    (* for controlling the dimmer output OUT *)
    Q=>                     DO_002,                 (* couple the function block to the physical digital output *)
    OUT:=           AO_001,
    VAL:=           255,
    SET:=           FB_AO_DIMMER_001.DBL
);

The only downside of the whole setup now is that when I press the button (single) it takes 1 second before the light turns on due to the fact that the relay is being switched which powers the dimmer which turns on the light. Apart from that it is now functioning like I expect.

One more request 😄 Is it possible that with a double click it goes to the pre-defined value (in my case: 255) and with another double click it goes back the minimal dim level. I thought 'Dbl_Toggle' would do that but it doesn't look like it does. Reading the documentation (yours and OSCAT) I'm not completely sure what it does.

MichielVanwelsenaere commented 3 years ago

I've updated the code a bit more so that the dimmer output function block makes more sense. Docs & sample project have again been updated. For clarity: this is how you should use the function block now:

FB_AO_DIMMER_001(
    SINGLE:=FB_DI_PB_041.SINGLE,
    LONG:=FB_DI_PB_041.LONG, 
    P_LONG:=FB_DI_PB_041.P_LONG, 
    OUT := TestOUT,
    SET:=  FB_DI_PB_041.DOUBLE
);

I removed the DOUBLE input and DBL output as they don't make sense and the same can be accomplished by connecting directly to the SET input using whatever you want.

Regarding your question to have VAL switch on double-push, you could use something like the below (best to put it before the FB call):

IF (FB_AO_DIMMER_001.OUT_Internal = 50) THEN FB_AO_DIMMER_001.VAL := 125; ELSE FB_AO_DIMMER_001.VAL := 50; END_IF

It's just an example, you'll need to fine-tune it more yourself if necessary.

Regarding the delay:

Please retest, I think we're almost there.

MichielVanwelsenaere commented 3 years ago

I just had an idea. I added an additional output on the dimmer output function block called 'Q_OUT' (datatype WORD), the behavior of the output is quite simple:

If I'm not mistaken you should be able to wire 'Q_OUT' directly to your dimmer module (dropping the relay) as it will turn off the dimmer by providing a 0 voltage.

Please adopt your test setup and validate if possible.

Out of curiosity: what dimmer module are you using exactly?

mchlrv commented 3 years ago

Your idea works great and I'm now using below code. I need to specify both 'Q_OUT' and 'OUT' although they are the same thing in my case.

FB_AO_DIMMER_001(SINGLE:=   FB_DI_PB_002.SINGLE,    (* for toggling the output Q *)
    LONG:=                  FB_DI_PB_002.LONG,      (* for controlling the dimmer output OUT *)
    P_LONG:=                FB_DI_PB_002.P_LONG,    (* for controlling the dimmer output OUT *)
    Q_OUT=>         AO_001,
    OUT:=                   AO_001,
    VAL:                    255,
    SET:=                   FB_DI_PB_002.DOUBLE
);

One other downside I noticed is that when using above methode and provide 0 volt to my dimmer it still consumes 19 volts. With the relay in between is was really 0 volt.

For my setup I use the following:

MichielVanwelsenaere commented 3 years ago

Are you still experiencing the 1s delay? could you remove 'OUT:=' from the function block call? Either you use Q_OUT or Q and OUT but not both. In your case, Q_OUT should be sufficient.

Volts are not something that is consumed, what the current usage of the dimmer when it's provided with 0V on the input?

mchlrv commented 3 years ago

Are you still experiencing the 1s delay? could you remove 'OUT:=' from the function block call? Either you use Q_OUT or Q and OUT but not both. In your case, Q_OUT should be sufficient.

Volts are not something that is consumed, what the current usage of the dimmer when it's provided with 0V on the input?

There still certainly is a delay, however it feels marginal (almost not noticeable) shorter.

I tried using 'Q_OUT' only but then the code does not compile and throughs an error stating it needs 'OUT'. I'm thinking of using 'Q_OUT' with 'Q' so that I can use 'Q' to turn on the led of the switch I'm using whenever there is a light on.

You're right about the voltage I meant to say that there is still 19 volts on the output of the dimmer. There seems to be no consumption as I can't measure any ampere when 'Q_OUT' is 0.

MichielVanwelsenaere commented 3 years ago

I did one more push that allows 'OUT' to not be used. Could you do one more thorough test? (MQTT and everything?). If successful I think me can considered this fixed and merge it to the master branch.

mchlrv commented 3 years ago

I did one more push that allows 'OUT' to not be used. Could you do one more thorough test? (MQTT and everything?). If successful I think me can considered this fixed and merge it to the master branch.

Just removed the 'OUT' and retested everything. It works perfectly as expected! I think we can consider this indeed as fixed and merge it into the master branch.

Again thank you so much, whenever it is safer to travel again I'll buy you a few drinks.

MichielVanwelsenaere commented 3 years ago

I'll keep that last part in mind :smile: Thank you for your testing efforts and feedback, much appreciated!