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

Sending ArtNet #60

Closed Petorrrrr closed 2 years ago

Petorrrrr commented 4 years ago

As posted on Gitter, I managed to get the pfc200 to output ArtNet communication.

Included you find my project (I've anonimized the IP adresses used, but not my home setup). It's written in codesys 3.5 SP15 patch 3 homeAutomation export.zip

In essence, I've created another Global Variable List (OtherVariables) where I store the var DMX. In here I store the artnet characters to be send.

In the program DMX_SEND the first 18 characters get initialized (mandatory for ArtNet) and then it loops through the DMX variable to add the DMX values to the send buffer. If it detects a value has changed a flag "send" is set to true. If send is true, an ArtNet message is sent over UDP to the specified IP address. This program runs in Freewheeling mode (if you do it cyclic it doesn't always pick up all the changes if you change more than 5 channels through MQTT).

I'm sure that the code can be cleaned up. I've mostly copy-pasted it and adjusted it so that it's working (stable).

Also in here are some minor changes to some of the functions, if needed I can provide some more detail. Also I've done some visualization. Since this issue is focusses on the ArtNet part I won't describe this further.

MichielVanwelsenaere commented 4 years ago

Thanks for this. Question: what hardware do you use exactly in you ArtNet setup? (just out of curiosity)

If I'm going to implement ArtNet I'm more inclined to do it in a separate library and use that library in this project. do you have any docs that helped you understand the ArtNet protocol?

Petorrrrr commented 4 years ago

I'm using this very cheaply to build artnet node: https://github.com/mtongnz/ESP8266_ArtNetNode_v2 and the S1-DR DMX dimmer (2 channels) from aliexpress

Works really stable. I haven't developed it myself, just creative searching on the web and copy-pasting and adjusting along the way. Found it originally here: http://www.oscat.de/community/index.php?topic=880.0

jaccospelt commented 3 years ago

I have been working with the code that @Petorrrrr has posted and integrated into this project code. I am not a full time progammer so improvements are probably possible.

I've created a variable as Petorrrr stated, created the DMXSend PRG and created a DMX task, running in freewheeling mode.

I wanted to use the FB_OUTPUT_DIMMER_MQTT functionblock. I copied it to a DMX specific one FB_OUTPUT_DIMMER_MQTT_DMX (this shouldn't be necessary, could be integrated in the normal one). In the new FB created these VARS:

    DmxChannel              :INT;
    pDmxValues              :POINTER TO oscat_network.NETWORK_BUFFER_SHORT;
    InitDmxDone             :BOOL;
    OUT_Target              :BYTE;
    SoftDimToValue          :BOOL;
    SoftDimToQFalse         :BOOL;
    UpdateValueStep         :BYTE := 4;
    OUT_Internal_tmp                :BYTE;

I added a method to intitialize the DMX variables:

    METHOD InitDmx
    VAR_INPUT
        DmxChannel              :INT;
        pDmxValues              :POINTER TO oscat_network.NETWORK_BUFFER_SHORT;
    END_VAR

    THIS^.DmxChannel := DmxChannel;
    THIS^.pDmxValues := pDmxValues;

    THIS^.InitDmxDone := TRUE;

In the PublishReceived method I changed:

    THIS^.OUT_Internal:=STRING_TO_BYTE(Data.PayloadString^);

to

    THIS^.OUT_Target:=STRING_TO_BYTE(Data.PayloadString^);
    THIS^.SoftDimToValue:=TRUE;

Then inside the main functions I added this on the top of the code:

    IF SoftDimToValue = TRUE THEN
        IF OUT_Target > OUT_Internal THEN // we are moving up to OUT_Internal 
            IF OUT_Target - OUT_Internal > UpdateValueStep THEN
                OUT_Internal := OUT_Internal + UpdateValueStep;
            ELSE
                OUT_Internal := OUT_Target;
            END_IF
        ELSIF OUT_Target < OUT_Internal THEN // we are moving down to OUT_Internal
            IF OUT_Internal - OUT_Target > UpdateValueStep THEN
                OUT_Internal := OUT_Internal - UpdateValueStep;
            ELSE
                OUT_Internal := OUT_Target;
                IF SoftDimToQFalse THEN
                    Q := FALSE;
                END_IF
            END_IF
        END_IF
    END_IF

And changed the "ELSIF SINGLE THEN" to:

        (* a single click reverses output Q *)
        Q := NOT Q;
        (* when dimmer is turned on we need to limit out to min and max limits *)
        IF Q THEN 
            OUT_Target := LIMIT(MAX(OUT_Internal,1), OUT_Internal, MAX_ON);
            OUT_Internal := 0;
            SoftDimToValue := TRUE;
        ELSE
            IF OUT_Internal > 0 THEN
                OUT_Target := 0;
                OUT_Internal_tmp := OUT_Internal;
                Q := TRUE; // back to true while soft dimming to 0
                SoftDimToValue := TRUE;
                SoftDimToQFalse := TRUE;
            END_IF
        END_IF;
        (* set the appropriate direction of dimmer dir is reversed because next action will reverse again *)
        dir := OUT_Internal > 127;

At the end I've added:

    IF InitDmxDone THEN 
        IF Q THEN
            IF pDmxValues^.BUFFER[DmxChannel-1] <> OUT_Internal THEN
                pDmxValues^.BUFFER[DmxChannel-1] := OUT_Internal;
            END_IF
        ELSE 
            IF pDmxValues^.BUFFER[DmxChannel-1] <> 0 THEN
                pDmxValues^.BUFFER[DmxChannel-1] := 0;
            END_IF
        END_IF
    END_IF
    IF SoftDimToValue AND OUT_Internal = OUT_Target THEN // If the same, softdim to value is done
        SoftDimToValue := FALSE;
        IF SoftDimToQFalse THEN
            SoftDimToQFalse := FALSE;
            OUT_Internal := OUT_Internal_tmp;
            PreviousOUT:=OUT_Internal;
        END_IF
    END_IF

Works very nice (I think), when I click a pushbutton (single) the light fades out, when I click it again it fades in. When I set a value through MQTT the light fades to this value. This is currently running on my test setup. I'm planning to push to my production system later this week. Please let me know if you like it or if there is improvements.. (this was probably not the easiest way of posting this code... I cannot get used to these WAGO source files :-( )

Petorrrrr commented 3 years ago

Cool! Unfortunately, this didn't work out fully for me. I use a slightly different setup where I created additional Virtual dimmers for use with my OpenHAB instance with MQTT. Don't recall the exact reasons, but I think it was the easiest way for me with limited knowledge.

But you inspired me to add the fade functionality in the DMX_SEND program. So I added/changed this:


    IF S_BUF1.BUFFER[i] <> OtherVariables.DMX.BUFFER[i-18] THEN
        IF OtherVariables.DMX.BUFFER[i-18] > S_BUF1.BUFFER[i] THEN //dimming up
            IF OtherVariables.DMX.BUFFER[i-18] - S_BUF1.BUFFER[i] > UpdateValueStep THEN
                S_BUF1.BUFFER[i] := S_BUF1.BUFFER[i] + UpdateValueStep;
            ELSE
                S_BUF1.BUFFER[i] := OtherVariables.DMX.BUFFER[i-18];
            END_IF
        ELSIF OtherVariables.DMX.BUFFER[i-18] < S_BUF1.BUFFER[i] THEN // dimming down
            IF S_BUF1.BUFFER[i] - OtherVariables.DMX.BUFFER[i-18] > UpdateValueStep THEN
                S_BUF1.BUFFER[i] := S_BUF1.BUFFER[i] - UpdateValueStep;
            ELSE
                S_BUF1.BUFFER[i] := OtherVariables.DMX.BUFFER[i-18];
            END_IF
        END_IF          
        send := TRUE;
    END_IF
MichielVanwelsenaere commented 3 years ago

@jaccospelt thanks for sharing, much appreciated! Could you perhaps share your project over here? I'm planning to add a dedicated page on it. For sure it will help other people as well.

RikVerstijnen commented 2 years ago

@jaccospelt any chance you could share your project? I tried to reconstruct your work based on the code snippets above, but that did not work out completely. I am not totally sure how to incorporate this in the main program and also https://github.com/MichielVanwelsenaere/HomeAutomation.CoDeSys3/pull/75 seems to interfere. Once I have it up and running, I will document this feature in order to help others.

MichielVanwelsenaere commented 2 years ago

thank you for the feedback on sharing on this one. Closing this one due to inactivity and lack of time (& Artnet hardware) to implement this in the project decently. Don't let this hold you back to use this thread for more code sharing :)

meijer3 commented 2 years ago

Does anyone have some updates, or is willing to share their code?