WinCC Unified Sprachumschaltung via Toggle Button und angezeigter Fahne

L4s3r73k

Level-2
Beiträge
167
Reaktionspunkte
44
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo zusammen,

ich mache gerade mein erstes Projekt mit Unified als solches. Dabei ist mir das Thema schon fast zu peinlich um es hier zu stellen, aber ich komme nicht weiter.

Zur Zielsetzung und was bisher unternommen wurde:
  • Button, der die verfügbaren Sprachen durchtoggelt.
    • Button mit ToggleLanguage() Befehl bzw. Nutzung der "WechsleSprache" Funktion.
  • Button soll die aktuelle Fahne der Sprache anzeigen.
    • Grafikliste mit Fahnen.
  • Projektunabhängige Benutzbarkeit.
    • Fahnengrafiken bekommen die Indizes der LCIDs der Sprachen
    • 1. Versuch die HMI Systemvariable "@CurrentLanguage" zu verwenden
      • Resultat: Der Inhalt der Variable lässt sich zwar als IO Wert anzeigen, die Nutzung der Variable zur Dynamisierung der Fahne/des Buttons taugt nicht.
    • 2. Versuch: Arbeiten mit Hilfsvariablen:
      • Hilfsvariablen im HMI angelegt für den LCID-Code als interne Variable und als PLC-Variable angelegt.
      • Java-Skript Code geschrieben um zuerst bei Tastendruck die Sprache umzuschalten um dann die Werte in den angelegten Variablen zu speichern.
      • Resultat: Funktioniert auf manchen Geräten ganz gut (9/10 Versuche), bei anderen eher schlecht (1/2 Versuche). Sprache wird weitergeschaltet, aber die Variablen übernehmen den Wert der vorherigen Sprache.
      • Code weiter unten.
  • HMI soll aufstarten/Browserfenster neu laden mit zuletzt eingestellter Sprache - was zumindest standardmäßig nicht tat.
    • Nutzung der internen HMI-Variable bzw. der PLC-Variable zur Widerherstellung der letzten Sprache via Java-Skript
      • Funktioniert soweit. Nutztung bei "Bild aufgebaut".
      • Code weiter unten.

Code zur Umschaltung.
Java:
export function Funktion_LCID_() {

// 1. Toggle Language.
HMIRuntime.UI.SysFct.ToggleLanguage();

// 2. Mirror back from system tag to HMI/PLC tag.

let LCID = Tags("@CurrentLanguage").Read();

Tags("HMI_LanguageLCID_HMI").Write(LCID);
Tags("HMI_LanguageLCID_PLC").Write(LCID);

}

Code zur Widerherstellung der Sprache beim "Bild-Aufgebaut-Ereignis".
Javascript:
export function Funktion_Restore_LCID() {


if (HMIRuntime.Tags.SysFct.GetTagValue("HMI_LanguageLCID_PLC") != 0)
{
HMIRuntime.UI.SysFct.SetLanguage(HMIRuntime.Tags.SysFct.GetTagValue("HMI_LanguageLCID_PLC"));
}
else if (HMIRuntime.Tags.SysFct.GetTagValue("HMI_LanguageLCID_PLC") != 0)
{
HMIRuntime.UI.SysFct.SetLanguage(HMIRuntime.Tags.SysFct.GetTagValue("HMI_LanguageLCID_HMI"));
}

}

Meine Fragen:

1. Was kann ich machen, dass dieser Button für seine Grafikliste die Systemvariable "@CurrentLanguage" akzeptiert?

2. Wie muss ich diese Code(s) ändern, dass der Vollzug des Sprachwechsels und die damit verbundene Änderung der Variabel "@CurrentLanguage" zwingend vor dem Schreiben der PLC/HMI Variablen passiert?

Ich bedanke mich für Eure Aufmerksamkeit.
 
1. Was kann ich machen, dass dieser Button für seine Grafikliste die Systemvariable "@CurrentLanguage" akzeptiert?
Bei mir wuppt das wunderbar ¯\_(ツ)_/¯
1753961722146.png
(TIA V20 Update 3)

Welche TIA-Version verwendest du?
Bitte generell immer TIA-Version / Runtime Version dazu schreiben.
Ist grade bei Unified wichtig, da sich über die einzelnen Versionen bisher viel getan hat.

2. Wie muss ich diese Code(s) ändern, dass der Vollzug des Sprachwechsels und die damit verbundene Änderung der Variabel "@CurrentLanguage" zwingend vor dem Schreiben der PLC/HMI Variablen passiert?
Thema: synchrone/asynchrone Scripte.
Teste mal ob sich mit nem asynchronen Script und await HMIRuntime.UI.SysFct.ToggleLanguage(); was machen lässt.
Ansonsten im Hauptbild Aufgebaut-Ereignis eine Subscription auf @CurrentLanguage starten & dort auf die Wertänderung reagieren.

Beachte wenn du den Webclient verwendest:
dann hast du für den jeweiligen Runtime-Server mehrere Clients, die mit jeweils unterschiedlicher Spracheinstellung auf die gleiche SPS-Variable schreiben würden. Das beißt sich...

HMI soll aufstarten/Browserfenster neu laden mit zuletzt eingestellter Sprache - was zumindest standardmäßig nicht tat.
  • Nutzung der internen HMI-Variable bzw. der PLC-Variable zur Widerherstellung der letzten Sprache via Java-Skript
    • Funktioniert soweit. Nutztung bei "Bild aufgebaut".
Das funktioniert nicht, wenn du beim Runtime-Start keine Verbindung zur SPS hast (wie du der Abfrage auf != 0 nach vermutlich schon festgestellt hast).
Schau dir vllt. mal das an:
 
Zuviel Werbung?
-> Hier kostenlos registrieren
@Botimperator
Mahlzeit und schönen Samstagnachmittag. Auf dem Panel bzw. in der Simulation wird Version 19.0.0.0 benutzt. TIA / Unified ist V19 Update 4.
Interessant, ich dachte nicht, dass das mit einer TIA/Unified Version weiter doch geht mit @CurrentLanguage. Aktuell sieht meine Lösung so aus:

1754041474719.png

Damit geht es zwar, aber mit Umwegen.
Ich habe meinen Code angepasst, da ich keine extra Datei erzeugen wollte. So klappt es doch ganz gut.
Code:
Javascript:
export function Funktion_Restore_LCID() {

//HMIRuntime.Tags.SysFct.SetTagValue("HMI_LanguageLCID_HMI", HMIRuntime.Tags.SysFct.GetTagValue("@CurrentLanguage"));
//HMIRuntime.Tags.SysFct.SetTagValue("HMI_LanguageLCID_PLC", HMIRuntime.Tags.SysFct.GetTagValue("HMI_LanguageLCID_HMI"));

let tagPLC = HMIRuntime.Tags.SysFct.GetTagValue("HMI_LanguageLCID_PLC");
let tagHMI = HMIRuntime.Tags.SysFct.GetTagValue("HMI_LanguageLCID_HMI");
let tagSystem = HMIRuntime.Tags.SysFct.GetTagValue("@CurrentLanguage");


if (tagPLC != 0)
{
if (tagPLC == tagHMI)
{
HMIRuntime.UI.SysFct.SetLanguage(tagPLC);
Tags("HMI_LanguageLCID_HMI").Write(tagPLC);
}
else
{
HMIRuntime.UI.SysFct.SetLanguage(tagHMI);
Tags("HMI_LanguageLCID_PLC").Write(tagHMI);
}
}
else if (tagHMI != 0)
{
HMIRuntime.UI.SysFct.SetLanguage(tagHMI);
Tags("HMI_LanguageLCID_PLC").Write(tagHMI);
}

}

Leider kann ich aktuell wieder nicht unter realen Bedingungen testen. Weil mein Test-Rack woanders steht. Das mit dem await werde ich ausprobieren. Kommt diese Zeile Code ergänzend zur Zeile mit ToggleLanguage() oder wird einfach nur das Wort "await" vor diese Zeile gesetzt.

Vielen Dank bis hier hin.
 
Interessant, ich dachte nicht, dass das mit einer TIA/Unified Version weiter doch geht mit @CurrentLanguage.
Deswegen bei Unified möglichst immer die neuste TIA-Version nehmen.
Ist irre wie viel sich zwischen den Versionen, und teilweise auch den Updates einer Hauptversion, tut.
(bzw. wie unfertig Siemens diese 💩 auf den Markt geworfen hat)

Dass du ältere Projekte in neuere Runtimes laden kannst, hast du aber auf dem Schirm?
Also z.B. V19 Projekt in eine V20 Runtime.
Gibt dann zwar nicht mehr Funktionen, aber zumindest die Bugfixes der neueren Version.

Damit geht es zwar, aber mit Umwegen.
Ich habe meinen Code angepasst, da ich keine extra Datei erzeugen wollte. So klappt es doch ganz gut.
Klappt das wirklich, wenn die Runtime startet ohne die SPS-Verbindung bereits aufgebaut zu haben?

Tipp, der dir Nerfen sparen wird:
Pack deinen Code IMMER in eine try/catch Struktur und gib per HMIRuntime.Trace() zumindest eine grundlegende Fehlermeldung raus.
Ansonsten wird dein Script bei einem Fehler ohne Feedback/Meldung an der Fehlerstelle abgebrochen.

Das mit dem await werde ich ausprobieren. Kommt diese Zeile Code ergänzend zur Zeile mit ToggleLanguage() oder wird einfach nur das Wort "await" vor diese Zeile gesetzt.

Wird aber nicht funktionieren, hab eben nachgeschaut.
ToggleLanguage() gibt lediglich einen Fehlercode zurück, kein Promise.
Also nichts um nen Callback dranzuhängen ¯\_(ツ)_/¯
Ich vermute mal ToggleLanguage() und die Funktion, die @CurrentLanguage beschreibt, sind Runtime-intern zwei getrennte Funktionen/Dienste.


Und schau dir wegen deinem Codestyle mal das hier an:
Alternativ tuts auch Notepad++ mit dem JSTools-Plugin zum automatischen Formatieren des Codes.
Mit dem Siemens-Editor verliest du zu schnell die Übersicht, sobald das Script aus mehr als ein paar Zeilen besteht.
 
Also ich fasse zusammen.
  • Mit TIA V19 Update 4 und projektierter V19.0.0.0 Runtime kann ich eine V20 Runtime bespielen!?
  • Ich habe meinen Code dahingehend getestet, dass ich Page-Reload mal ja, mal nein die SPS verbunden habe. Den Vorschlag von Siemens hab ich mir aber gespeichert.
  • Schade. dass await nicht funktionieren wird.
  • Ich weiß, der Code sieht grauenhaft aus. Aber sagen wir mal so, JS find ich jetzt so oder so nicht besonders sexy.

Schönes Wochenende.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Mit TIA V19 Update 4 und projektierter V19.0.0.0 Runtime kann ich eine V20 Runtime bespielen!?
Jup, sind (bisher) voll abwärtskompatibel.

Ich weiß, der Code sieht grauenhaft aus. Aber sagen wir mal so, JS find ich jetzt so oder so nicht besonders sexy.
Geht eigentlich...der TIA-eigene Editor ist halt 💩
Dein Code einmal durch den JSTool-Autoformatierer gejagt sieht so aus:
Javascript:
export function Funktion_Restore_LCID() {

    //HMIRuntime.Tags.SysFct.SetTagValue("HMI_LanguageLCID_HMI", HMIRuntime.Tags.SysFct.GetTagValue("@CurrentLanguage"));
    //HMIRuntime.Tags.SysFct.SetTagValue("HMI_LanguageLCID_PLC", HMIRuntime.Tags.SysFct.GetTagValue("HMI_LanguageLCID_HMI"));

    let tagPLC = HMIRuntime.Tags.SysFct.GetTagValue("HMI_LanguageLCID_PLC");
    let tagHMI = HMIRuntime.Tags.SysFct.GetTagValue("HMI_LanguageLCID_HMI");
    let tagSystem = HMIRuntime.Tags.SysFct.GetTagValue("@CurrentLanguage");

    if (tagPLC != 0) {
        if (tagPLC == tagHMI) {
            HMIRuntime.UI.SysFct.SetLanguage(tagPLC);
            Tags("HMI_LanguageLCID_HMI").Write(tagPLC);
        } else {
            HMIRuntime.UI.SysFct.SetLanguage(tagHMI);
            Tags("HMI_LanguageLCID_PLC").Write(tagHMI);
        }
    } else if (tagHMI != 0) {
        HMIRuntime.UI.SysFct.SetLanguage(tagHMI);
        Tags("HMI_LanguageLCID_PLC").Write(tagHMI);
    }

}

Schönes Wochenende.
Gleichfalls (✿◠‿◠)
 
Guten Morgen.

Hätte ich mal damit nicht angefangen. Ich habe heute morgen die Runtime V20 installiert mit zwei Resultaten:

  1. Dass der dynamisierte Button mit "@CurrentLanguage" und der entsprechenden Grafikliste mit LCIDs noch immer nicht funktioniert.
  2. Dass ich keine "grüne" Runtime mehr zustande bekomme.
1754297793608.png

Was muss ich veranstalten, damit dies wieder grün wird?

Vielen Dank.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Update:

Nach Installation von Update 2 V20 Unified Runtime geht wird die Runtime wieder grün, die Problematik der Grafikliste, die nicht mit "@CurrentLanguage" funktioniert, besteht weiterhin.

Update#2:

Auch das Hochziehen auf Hardware V19.0.0.2 hat nichts gebracht.
 
Zuletzt bearbeitet:
Update:

Nach Installation von Update 2 V20 Unified Runtime geht wird die Runtime wieder grün, die Problematik der Grafikliste, die nicht mit "@CurrentLanguage" funktioniert, besteht weiterhin.

Update#2:

Auch das Hochziehen auf Hardware V19.0.0.2 hat nichts gebracht.
Wenn das Problem mit der projektierten V19 Runtime zusammen hängt, wird dir ein Update der installierten V20 Runtime nichts bringen.
Das bringt "nur" Bugfixes, keine Features der V20.
Keine Ahnung ob dein Problem mit einem fehlenden Feature der V19 Projektierung zusammen hängt, hab Grad kein System zur Hand um das zu testen.

Wie stellt sich das "funktioniert nicht" genau dar?
Fehlermeldung beim Übersetzen?
Oder einfach keinen Reaktion in der laufenden Runtime?
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Der letzte Satz trifft zu: Es gibt einfach keine Reaktion in der laufenden Runtime.
Das sollte nicht sein.
Kannst du die Variable mal mit einem normalen ioField anzeigen?
Dann solltest du zumindest den numerischen Wert der LCID angezeigt bekommen.
Vllt gibt's ein generelles Problem mit deinem symbolicIoField...
 
Das sollte nicht sein.
Kannst du die Variable mal mit einem normalen ioField anzeigen?
Dann solltest du zumindest den numerischen Wert der LCID angezeigt bekommen.
Vllt gibt's ein generelles Problem mit deinem symbolicIoField...

Ich habe mehrere Elemente durch, die sich Anhand von Variablen und mit einer Grafikliste dynamisieren lassen.
Keins funktionierte mit dem "@CurrentLanguage" sehr wohl aber mit deiner anderen Variable des gleichen Datentyps.
Die Variable mit einem normalen IO Feld anzuzeigen ist hingegen kein Problem.
 
Zuletzt bearbeitet:
Ich habe mal mein letztes Projekt auseinander gepflückt.

HMI_10 -> Skripte -> Globales Modul -> LoadLanguage / UpdateLang

Grundbild -> Ereignisse -> Aufgebaut: LoadLanguage
Länderflagge -> Ereignisse -> Drücken: UpdateLang

Die dargestellte Grafik habe ich mit einer Ressourcen-Liste realisiert.
Es wird die Variable "LangIndex" (intern) und Ressourcen-Liste "Lang" verwendet.

Bei Text- und Grafiklisten ist das unter Grafiklisten zu finden.
Es wird der LCID Code verwendet.

Deutschland: 1031
USA: 1033
Polen: 1045

Eine Liste habe ich hier gefunden: https://help.tradestation.com/10_00/eng/tsdevhelp/elobject/class_el/lcid_values.htm

Findet man aber auch bei Siemens irgendwo auf der Seite.

Viel Erfolg.

PS: Hab den Anhang vergessen: Download entfernt. Update kommt morgen.

Fürs Forum ist die Datei leider zu groß.

PPS: Hier noch die beiden Scripte für diejenigen, die keine Lust haben das herunterzuladen:
Javascript:
export function LoadLanguage() {
  function set_language(data) {
    let lcid = parseInt(data, 10) >>> 0;
    HMIRuntime.Trace("Set runtime language to " + lcid + "\n");
    HMIRuntime.Language = lcid;
    Tags("LangIndex").Write(lcid);
  }

  function error(err_msg) {
    HMIRuntime.Trace("Could not read file '" + lang_path + "'\n" + err_msg);
  }

  function read_file() {
      // it's an async function
      // use .then().catch()
      HMIRuntime.FileSystem.ReadFile(lang_path, "utf8").then(set_language).catch(error);
  }

  read_file();
}

Javascript:
export function UpdateLang() {
  function error(err_msg) {
    HMIRuntime.Trace("Could not write to file '" + lang_path + "'\n" + err_msg);
  }

  function SaveNewLanguage() {
      HMIRuntime.FileSystem.WriteFile(lang_path, String(HMIRuntime.Language), "utf8").catch(error);
  }

  HMIRuntime.UI.SysFct.ToggleLanguage();
  Tags("LangIndex").Write(HMIRuntime.Language);
  SaveNewLanguage();
  HMIRuntime.Trace("Changed language to " + HMIRuntime.Language + "\n");
}
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
Irgendwie klingt das für mich nach nem Bug...
TIA dürfte keinen Unterschied zwischen Grafikliste und normalem IoField machen, solange die Variable prinzipiell zugänglich ist.
Funktioniert dein symbolicIoField mit einer anderen Variable?
Kannst du mal nen SR deswegen bei Siemens aufmachen?

Als Zwischenlösung könntest du @CurrentLanguage per Subscription überwachen & bei Wertänderung eine zweite Variable mit der LCID von @CurrentLanguage beschreiben.
 
Da haben sich wohl Antworten überschnitten.

@DeaD_EyE
Danke für diesen Ansatz, wenn alle Stricke reißen, werde ich wohl darauf zurück kommen.
Wobei ich noch nicht ganz sehe, wie das auf mein Problem eingeht.

@Botimperator
Wie du oben schon schriebst, das TIA Unified System ist vieles, aber noch nicht ansatzweise fehlerfrei oder gut IMHO.
Ich hab bisher kein Thema bei Siemens aufgemacht, da ich auf "Wechseln Sie nach TIA V20!" Antworten verzichten kann.
Das mit der Subscription, wie mache ich das?
 
Unified ist manchmal etwas...speziell.
Gerüchteweise war die Entwicklung teilweise nach Indien ausgelagert.
Und falls du noch nicht die Ehre hattest:
Ich hab noch keinen von dem Verein getroffen, der nicht mit Minimalaufwand strikt nach Lastenheft gearbeitet hat.
Mitdenken = Zusatzaufwand = nicht im Lastenheft.

Subscriptions sind Überwachungen, die du nach Ausführung des Scripts im aktuellen Scriptcontext auf ein Ereignis "Warten" lassen kannst.
Du startest sie & jedes mal wenn das Ereignis eintritt, wird die Callback-Funktion der Subscription ausgelöst.
Genaueres siehe F1-Hilfe.
Für deine Zweicke ein Beispiel:

Javascript:
export async function checkSystemLCID() {
    /*
    Dieses Script muss im Aufgebaut-Ereignis eines permanent sichtbaren Bildes aufgerufen werden, z.B. Header oder RootScreen.
     */

    try {//try..catch ist immer dabei, ohne das + Trace wird das Finden von Fehlern zum Glücksspiel. Dafür hat niemand genug Nerfen.
        
        //Deklaration der Subscription und deren Callback-Funktion
        let SubsTo_HmiTagTrigger = Tags.CreateSubscription("@CurrentLanguage", (tagResult) => {
            try {
                HMIRuntime.Trace("Überwachung der Systemsprache \n Triggervariable " + tagResult[0].Name + " wurde geändert, \n Wert " + tagResult[0].Value + "\n => Trigger ausgelöst.", HMIRuntime.Trace.Enums.hmiSeverity.Info);
                Tags("Variable zur Animation im HMI").Write(tagResult[0].Value, Tags.Enums.hmiWriteType.hmiWriteNoWait);
            } catch (ex) {
                HMIRuntime.Trace("Bei der Reaktion auf Änderung von @CurrentLanguage ist etwas schief gegangen. \n Triggervariable: " + tagResult[0].Name + "\n Wert " + tagResult[0].Value + "\n Fehler: " + ex, HMIRuntime.Trace.Enums.hmiSeverity.Error);
            }
        });
        //Start der deklarierten Subscription. Ab hier bleibt die Subscription im aktuellen Scriptkontext aktiv.
        SubsTo_HmiTagTrigger.Start();
        //Meldung fürs Log
        HMIRuntime.Trace("Subscription zu @CurrentLanguage wurde erzeugt", HMIRuntime.Trace.Enums.hmiSeverity.Info);
    } catch (ex) {
        HMIRuntime.Trace("Beim Erstellen der Subscription ist etwas schief gegangen, Fehler: " + ex, HMIRuntime.Trace.Enums.hmiSeverity.Error);
    }
}

Ich benutze das beispielsweise für Aufgabenplaner-Sachen, die aber auf UI-Elemente (oder sonstiges auf Client-Seite) zugreifen müssen.
Oder um nach Auslösen eines Befehls auf die OK/NOK-Rückmeldung der SPS zu warten & entsprechend zu reagieren.

Aufpassen:
Die Subscription wird beim Beenden des Scriptkontext auch automatisch gestoppt, z.B. wenn das Bild in dem diese gestartet wurde abgebaut wird.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Ich habe den Download mal entfernt. Mir ist gerade beim Baden eingefallen, dass die Datei so groß ist, weil wahrscheinlich noch die ganzen Bilder drin sind. Ich lade das morgen nochmal ohne Bilder hoch und aktualisiere den Link.

Das mit der Subscription gefällt mir auch. Werde ich mal bei der nächsten Anlage testen.
 
Zurück
Oben