Z21Client

En C#-klasse til kommunikation med z21, z21Start, Z21 og Z21 XL centralstationerne til modeltogsbaner fra Roco/Fleischmann.

Z21Client-klassen understøtter følgende funktioner:

  • Sprogversionering, dansk/tysk når sprog i Windows er sat til dansk/tysk. For alle andre sprog vises tekster på engelsk
  • Forbindelse til Z21 via UDP
  • Modtage information om lokomotiver (hastighed, retning, funktioner, protokol), når andre styreenheder bruges
  • Modtage information om sporskifter/points (position, protokol), når andre styreenheder bruges
  • Sende kommandoer til styring af lokomotiver (hastighed, retning, funktioner, protokol)
  • Sende kommandoer til styring af sporskifter/points (position, protokol)
  • Læse feedback fra Z21 (f.eks. lokomotivstatus)
  • Understøttelse af flere lokomotiver
  • Event-drevet arkitektur til håndtering af svar og opdateringer
  • Asynkrone operationer for ikke-blokerende kommunikation
  • Fejlhåndtering og genforbindelseslogik
  • Understøttelse af protokoller brugt af z21/Z21 (DCC, Märklin Motorola)
  • Logging-muligheder til fejlfinding og overvågning
  • Z21Client er udviklet efter “AI Pair Programming” metoden

Du kan se og hente kildekoden til Z21Client i mit Github repo her:

https://github.com/J-Wachs/Z21Client

Nyheder i version af 3. august 2026

  • Tilføjet meddelelser på tysk. Bemærk venligst, at de tyske meddelelser er oversat af en AI, og derfor kan være mindre korrekte end de danske og engelske meddelelser.
  • Tilføjet mange nye tests til testprojektet

z21 og z21Start låseinformation

Hvis din z21 eller z21Start er låst, kan du stadig sende kommandoer til den med denne klasse. Dog vil kommandoerne blive ignoreret af z21/z21Start.

Hvis z21/z21Start er låst, kan du stadig bruge Z21Client-klassen til at skrive et overvågningsprogram, der læser status for lokomotiver og sporskifter/points. Du kan også kalde metoder i Z21Client til at skifte protokol på lokomotiver og sporskifter/sporskiftedekodere. Du kan læse mere om hvilke metoder (der pakker z21 kommandoer ind) der kan kaldes når z21/z21Start er låst, i den officielle Z21 LAN Protcol dokomentation, på Z21s hjemmeside.

Bemærk, at da z21 (i hvidt kabinet) oprindeligt blev lanceret, var nogle låste og andre ulåste. For at låse din z21 eller z21Start op, kan du købe en oplåsningskode:

  • Roco varenummer 10814. Indeholder et trådløst access-point samt oplåsningskode til z21Start og z21 (hvidt kabinet)
  • Roco varenummer 10818. Indeholder oplåsningskode til z21Start og z21 (hvidt kabinet)

Fra nu af vil betegnelsen Z21 blive brugt om alle fire versioner af Z21-familien af centralstationer. Hvis noget kun gælder én af versionerne, vil det blive angivet.

Z21Client blev udviklet og testet ved brug af to z21Start centralstationer: én låst og én ulåst. Dette er grunden til, at hverken LocoNet- eller CAN-bus-funktionalitet er implementeret i Z21Client-klassen.

Implementeringen er baseret på Roco-dokumentet “Z21 LAN Protocol Specification”, version 1.13 EN, dateret 6. november 2023. Dokumentet kan downloades fra Z21-websitet.

Fuldt funktionelt eksempelprojekt

For at se et eksempel på brugen af Z21Client, besøg venligst mit projekt Z21Dashboard på Github:

https://github.com/J-Wachs/Z21Dashboard

Hvordan virker det?

Z21Client-klassen bruger UDP til at kommunikere med Z21-centralen. I din applikation skal du først oprette forbindelse til Z21.

Da arkitekturen i Z21Client-klassen er event-drevet, skal du abonnere på de events, du ønsker at håndtere i din applikation. For eksempel skal du abonnere på eventet LocoStatusReceived for at håndtere opdateringer af lokomotivstatus.

De nødvendige ændringer af broadcast-flagene på Z21 bliver automatisk håndteret af Z21Client-klassen, når du tilføjer din metode til Z21Client-eventet.

Eksempel på abonnement på LocoStatusReceived-eventet:

...
@using IZ21Client Z21Client
...

...
Z21Client.LocoInfoReceived += OnLocoInfoReceived;
...

private async void OnLocoInfoReceived(object? sender, LocoInfo e)
{
	// Håndter modtaget lokomotivinfo
	Console.WriteLine($"Loco Info Received: Address={e.Address}, Speed={e.CurrentSpeed}, Direction={e.Direction}");
}

Implementering af Märklin Motorola-protokol i Z21Client vs i Z21

Z21 understøtter både DCC og Märklin Motorola protokoller til styring af lokomotiver. Følgende versioner af protokollerne er implementeret som følger:

  • DCC, 14 trin: Protokol = DCC, hastighedstrin = 14
  • DCC, 28 trin: Protokol = DCC, hastighedstrin = 28
  • DCC, 128 trin: Protokol = DCC, hastighedstrin = 128
  • Märklin Motorola 1, 14 trin: Protokol = Märklin Motorola, hastighedstrin = 14
  • Märklin Motorola 2, 14 trin: Protokol = Märklin Motorola, hastighedstrin = 28
  • Märklin Motorola 2, 28 trin: Protokol = Märklin Motorola, hastighedstrin = 128

På grund af dette rapporterer Z21 hastighedstrinene som 14, 28 eller 128, også når Märklin Motorola benyttes. Z21Client er udviklet til at afspejle protokollen og hastighedstrinene, som man normalt ville forvente. Derfor vil hastighedstrinene ved Märklin Motorola være hhv. 14, 14 eller 28.

Klassen LocoInfo, som bruges i Z21Client, afspejler denne implementering og indeholder to hastigheds-egenskaber:

  • SpeedSteps: Hastighedstrin som implementeret i Z21Client (DCC: 14, 28, 128; MM: 14, 14, 28)
  • NativeSpeedSteps: Hastighedstrin som implementeret i Z21. Altid 14, 28 eller 128 – også for MM-protokollen.

Ansvarsfraskrivelse: Implementering af ikke-dokumenteret ‘Locomotive Slot Information’

Roco har i deres værktøj Maintenance Tool en mulighed for at se de 120 lokomotiv-slots, der findes i Z21. Men den officielle “Z21 LAN Protocol Specification” dokumentation nævner ikke kommandoen og svaret til at læse disse slots. Ved at overvåge dataudvekslingen mellem mine Z21 (to z21Start, én låst, én ulåst) kunne jeg se kommandoerne. På grund af dette har jeg implementeret udokumenteret funktionalitet. Den virker i firmware 1.43 (en del af Maintenance Tool V1.18.3). Der gives ingen garanti for, at den vil virke i fremtidige firmwareudgaver.

Workaround for Z21 firmware-fejl

I den seneste firmwareversion (1.43) for Z21-familien er der efter min vurdering en fejl. Når man eksplicit forespørger lokomotivinformation (dvs. kalder Z21-kommandoen LAN_X_GET_LOCO_INFO, indkapslet i Z21Client.GetLocoInfoAsync()), vil protokol-bitten i byte DB2 i svaret ikke blive sat for lokomotiver, der er konfigureret til Märklin Motorola. Dog er protokol-bitten korrekt sat i events, der skyldes ændringer af lokomotivet (f.eks. hastighed, retning, funktionstaster).

For at omgå denne fejl forespørger Z21Client protokollen for lokomotivet separat og leverer derefter korrekt protokol i LocoInfoReceived-eventet.

Installationsvejledning

Hentning og afprøvning af Z21Client-klassen

Download repoet og opret et projekt, hvor du vil bruge Z21Client. Hvis du mangler inspiration, kan du se mit projekt Z21Dashboard på Github:

https://github.com/J-Wachs/Z21Dashboard

Opsætning af dit eget projekt til at bruge Z21Client-klassen

For at bruge Z21Client-klassen i dine egne projekter skal du tilføje komponentprojektet til din løsning. Derefter skal du tilføje Z21Client til Program.cs eller MauiProgram.cs i dit projekt:

...
// Tilføjet for Z21Client
builder.Services.AddSingleton<IZ21UdpClient, Z21UdpClient>();
builder.Services.AddSingleton<IZ21Client, Z21Client>();
// Slut
...

Tilpasning af Z21Client til eget brug

Måske har du brug for flere oplysninger. Måske skal du bruge en konfigurationsværdi til nogle af de data, der returneres. Måske har du brug for én af LocoNet- eller CAN-bus-kommandoerne/events.

Du er meget velkommen til at tilpasse en lokal version til dine behov.

Fundet en fejl?

Opret venligst et issue i repoet.

Kendte problemer (pågør)

Ingen på nuværende tidspunkt.

FAQ

Når jeg kalder metoden QueryForZ21s vises min Z21 ikke

Listen som metoden returnerer er tom, og du får ingen fejl. Du kan forbinde med Z21Client til din Z21 centralstation (alle modeller), og sende kommandoer og modtage data. At metoden returnerer en tom liste, sker typisk når pc’en er koblet på netværket trådløst.

For at finde Z21’ere på netværket udsender QueryForZ21s en UDP-broadcast som Z21 centralstationerne skal svare på. Mange access points og routere blokerer for UDP-broadcasts, og det er derfor muligt, at din Z21 ikke modtager broadcastet og derfor ikke svarer på det. Det er også muligt, at din pc ikke modtager svaret fra Z21.

Kik i opsætningen af dit access point eller router og se, om der er en indstilling for at blokere for UDP-broadcasts. Hvis det er tilfældet, skal du slå denne indstilling fra. Visse routere og access points har også en indstilling for at blokere for UDP-broadcasts på det trådløse net alene. Andre access points og routere har ikke en indstilling, men blokerer for UDP-broadcasts på det trådløse net som standard. I dette tilfælde kan du prøve at forbinde din pc til netværket med kabel for at se, om det løser problemet. Hvis det gør det, er det sandsynligt, at dit access point eller router blokerer for UDP-broadcasts på det trådløse net.

Vil du implementere LocoNet- og CAN-bus-funktionalitet?

Det korte svar er nej. Det lange svar er, at jeg ikke ejer en Z21 eller Z21 XL, derfor har jeg ikke behovet og kan ikke teste funktionaliteten.

Vil du implementere understøttelse af trådløs forbindelse til Z21?

Faktisk – hvis dit netværk er konfigureret korrekt, og du har Roco 10814 eller bruger dit eget access-point, kan du få trådløs adgang til Z21. Mit projekt Z21Dashboard er testet over trådløst LAN, og det virker fint. Nogle gange skulle jeg dog oprette forbindelse mere end én gang.

Hvordan kommer jeg i gang med at skrive min egen applikation?

Tag et kig på Z21Client – særligt Z21Dashboard-applikationen – for at se, hvordan den er implementeret og for inspiration til, hvad du selv kan lave.

Liste over implementerede Z21 LAN Protokol-kommandoer

Z21 Protocol Command (v1.13)Implementation Status (Public Method)
System, Status & Version
LAN_GET_SERIAL_NUMBERGetSerialNumberAsync
LAN_LOGOFFDisconnectAsync
LAN_X_GET_VERSION[Not implemented]
LAN_X_GET_STATUSGetSystemStateAsync
LAN_X_SET_TRACK_POWER_OFFSetTrackPowerOffAsync
LAN_X_SET_TRACK_POWER_ONSetTrackPowerOnAsync
LAN_X_SET_STOPSetEmergencyStopAsync
LAN_GET_FIRMWARE_VERSIONGetFirmwareVersionAsync
LAN_SET_BROADCASTFLAGSSetBroadcastFlags (Private)
LAN_GET_BROADCASTFLAGSGetBroadcastFlagsAsync
LAN_SYSTEMSTATE_GETDATAGetSystemStateAsync
LAN_GET_HWINFOGetHardwareInfoAsync
LAN_GET_CODEGetZ21CodeAsync
Settings
LAN_GET_LOCOMODEGetLocoModeAsync
LAN_SET_LOCOMODESetLocoModeAsync
LAN_GET_TURNOUTMODEGetTurnoutModeAsync
LAN_SET_TURNOUTMODESetTurnoutModeAsync
Driving
LAN_X_GET_LOCO_INFOGetLocoInfoAsync
LAN_X_SET_LOCO_DRIVESetLocoDriveAsync
LAN_X_SET_LOCO_FUNCTIONSetLocoFunctionAsync
LAN_X_SET_LOCO_FUNCTION_GROUP[Not implemented]
LAN_X_SET_LOCO_BINARY_STATE[Not implemented]
LAN_X_SET_LOCO_E_STOP[Not implemented]
LAN_X_PURGE_LOCO[Not implemented]
Switching
LAN_X_GET_TURNOUTINFOGetTurnoutInfoAsync
LAN_X_SET_TURNOUTSetTurnoutPositionAsync
LAN_X_GET_TURNOUT_MODEGetTurnoutModeAsync
LAN_X_SET_TURNOUT_MODESetTurnoutModeAsync
LAN_X_SET_EXT_ACCESSORY[Not implemented]
LAN_X_GET_EXT_ACCESSORY_INFO[Not implemented]
Reading and writeing decoder CVs
LAN_X_CV_READGetCVValueFromProgTrackAsync
LAN_X_CV_WRITESetCVValueOnProgTrackAsync
LAN_X_CV_POM_WRITE_BYTESetCVValueOnPOMAsync
LAN_X_CV_POM_WRITE_BITSetCVBitOnPOMAsync
LAN_X_CV_POM_READ_BYTEGetCVValueFromPOMAsync
LAN_X_CV_POM_ACCESSORY_WRITE_BYTE[Not Implemented]
LAN_X_CV_POM_ACCESSORY_WRITE_BIT[Not Implemented]
LAN_X_CV_POM_ACCESSORY_READ_BYTE[Not Implemented]
LAN_X_MM_WRITE_BYTE[Not Implemented]
LAN_X_DCC_READ_REGISTER[Not Implemented]
LAN_X_DCC_WRITE_REGISTER[Not Implemented]
Feedback (R-Bus)
LAN_RMBUS_GETDATAGetRBusDataAsync
LAN_RMBUS_PROGRAMMODULE[Not Implemented]
RailCom
LAN_RAILCOM_GETDATAGetRailComDataAsync / GetNextRailComDataAsync
LocoNet
LAN_LOCONET_FROM_LAN[Not Implemented]
LAN_LOCONET_DISPATCH_ADDR[Not Implemented]
LAN_LOCONET_DETECTOR[Not Implemented]
CAN
LAN_CAN_DETECTOR[Not Implemented]
LAN_CAN_DEVICE_GET_DESCRIPTION[Not Implemented]
LAN_CAN_DEVICE_SET_DESCRIPTION[Not Implemented]
LAN_CAN_BOOSTER_SET_TRACKPOWER[Not Implemented]
Fast Clock
LAN_FAST_CLOCK_CONTROL[Not implemented]
LAN_FAST_CLOCK_DATA[Not implemented]
LAN_FAST_CLOCK_SETTINGS_GET[Not implemented]
LAN_FAST_CLOCK_SETTINGS_SET[Not implemented]