Gira X1 – Delay in Millisekunden

TelegrammverzögererSo, mein erstes „echtes“ Projekt. Um meinen Türöffner zu steuern, brauche ich was schnelleres/kleineres als Sekunden. Also: C# lernen und drauf los programmieren – mein erster Logikblock.

using LogicModule.Nodes.Helpers;
using LogicModule.ObjectModel;
using LogicModule.ObjectModel.TypeSystem;

namespace flx_de.logic.a
{
    /// <summary>
    /// Delays a telegram for miliseconds.
    /// Caution: Uses active Waiting - no timers used.
    /// </summary>
    public class Delay_ms : LogicNodeBase
    {
        /// <summary>
        /// SleepTime for Thread - Standard Value
        /// </summary>
        int MillisecondsTimeout = 200;

        /// <summary>
        /// Initializes a new instance of the <see cref="Timer_ms"/> class.
        /// </summary>
        /// <param name="context">The node context.</param>
        public Delay_ms(INodeContext context) : base(context)
        {
            context.ThrowIfNull("context");
            var typeService = context.GetService<ITypeService>();
            this.Input = typeService.CreateAny(PortTypes.Any, "Input");
            this.Time = typeService.CreateInt(PortTypes.Integer, name: "Time", defaultValue: MillisecondsTimeout, unit: "ms");
            this.Output = typeService.CreateAny(PortTypes.Any, "Output");
        }

        /// <summary>
        /// Use any value type as input.
        /// The attribute <see cref="PortAttribute.IsRequired"/> is set to true, so the input cannot be disabled.
        /// </summary>
        [Input(IsRequired = true)]
        public AnyValueObject Input { get; private set; }

        [Input(DisplayOrder = 2, IsDefaultShown = true, IsInput = false, IsRequired = false)]
        public IntValueObject Time { get; private set; }

        /// <summary>
        /// Output after given time.
        /// </summary>
        [Output]
        public AnyValueObject Output { get; private set; }

        /// <summary>
        /// Delayed output.
        /// </summary>
        public override void Execute()
        {
            System.Threading.Thread.Sleep(this.Time);
            this.Output.Value = this.Input.Value;

        }
    }
}

VORSICHT: Das funktioniert so nicht! Also, irgendwie schon – in der Simulation im GPA sieht alles gut aus – nur, wenn ich das auf den Baustein lade, klappt das nicht.

Die oberen drei Zeilen sind standardmäßig vorhanden – damit werden die benötigten Bibliotheken für die Logikbausteine eingebunden. Danach kommt der namespace (siehe hier).

public class Delay_ms : LogicNodeBase – Dieser Logikblock bzw. die Klasse soll Delay_ms heißen. Die Basis bildet LogicNodeBase, das muss für alle Blöcke so sein. 

[… ggf weiter beschreiben?]

Okay, es ist auch etwas sehr quick & dirty: Thread.Sleep hält einfach den Thread an und ist nicht so wirklich guter Stil. Besser wäre sicher einen Timer zu nutzen. Auf jeden Fall habe ich folgende Beobachtung gemacht: Im GPA funktioniert es in der Simulation. Auf dem X1 funktioniert es nicht. Das kann auch daran liegen, dass im Mono auf dem X1 nicht alle .NET -Bibliotheken funktionieren. Gira schreibt, es wären folgende drauf:

  • Mono.Security
  • System
  • System.Configuration
  • System.Core
  • System.Data
  • System.Drawing (*)
  • System.Numerics
  • System.Runtime.Remoting (*)
  • System.Runtime.Serialization
  • System.Security
  • System.ServiceModel
  • System.ServiceModel.Web
  • System.Transactions
  • System.Web
  • System.Xml
  • System.Xml.Linq

Wenn man weitere braucht, solle man sie mit ins ZIP packen. Keine Ahnung, wie das geht.

Aber, jetzt wo ich rausgefunden habe, dass Thread.Sleep nicht in der Realität funktioniert, habe ich eine weitere Idee: System.Threading.Tasks.Delay

using LogicModule.Nodes.Helpers;
using LogicModule.ObjectModel;
using LogicModule.ObjectModel.TypeSystem;
using System.Threading.Tasks;

namespace flx_de.logic.a
{
    /// <summary>
    /// Delays a telegram for miliseconds.
    /// Caution: Uses active Waiting - no timers used.
    /// Toggles the output value between 1 and 0 whenever an input value is received.
    /// This node can be added to an output of a node by rightclicking the output of any logic node.
    /// </summary>
    public class Delay_ms : LogicNodeBase
    {
        /// <summary>
        /// SleepTime for Thread - Standard Value
        /// </summary>
        int MillisecondsTimeout = 200;

        /// <summary>
        /// Initializes a new instance of the <see cref="Timer_ms"/> class.
        /// </summary>
        /// <param name="context">The node context.</param>
        public Delay_ms(INodeContext context)
          : base(context)
        {
            context.ThrowIfNull("context");
            var typeService = context.GetService<ITypeService>();
            this.Input = typeService.CreateAny(PortTypes.Any, "Input");
            this.Time = typeService.CreateInt(PortTypes.Integer, name: "Time", defaultValue: MillisecondsTimeout, unit: "ms");
            this.Output = typeService.CreateAny(PortTypes.Any, "Output");
        }

        /// <summary>
        /// Use any value type as input.
        /// The attribute <see cref="PortAttribute.IsRequired"/> is set to true, so the input cannot be disabled.
        /// </summary>
        [Input(IsRequired = true)]
        public AnyValueObject Input { get; private set; }

        [Input(DisplayOrder = 2, IsDefaultShown = true, IsInput = false, IsRequired = false)]
        public IntValueObject Time { get; private set; }

        /// <summary>
        /// Output after given time.
        /// </summary>
        [Output]
        public AnyValueObject Output { get; private set; }

        /// <summary>
        /// Delayed output.
        /// </summary>
        public override async void Execute()
        {
            await Task.Delay(this.Time);
            this.Output.Value = this.Input.Value;
        }
    }
}

Alles was ich ändern musste, hier nochmal im Detail:

  • using System.Threading.Tasks; Oben einfügen.
  • public override async void Execute() Hiermit wird die Execute()-Methode asynchron.
  • await Task.Delay(this.Time); Das eigentliche Warten.

Damit sollte ich jetzt meinen Türöffner steuern können: Einfach 3-4 Stück davon parallel mit unterschiedlichen Zeiten und ggf. Invertern und fertig ist die Laube bzw. der Doppelklick. Oder, ich baue mir einfach einen eigenen Logikblock, der genau das tut: Der MultiClick.  

Kommentar verfassen

Deine E-Mail-Adresse wird nicht veröffentlicht.

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre mehr darüber, wie deine Kommentardaten verarbeitet werden.