Przejdź do treści

Przykład: monitoring temperatury

Zakres weryfikacji

Treść zachowana z obecnego źródła. Publikacja dokumentacji nie oznacza ponownego potwierdzenia wszystkich komend, przykładów i deklaracji możliwości.

Poziom: średniozaawansowany — trzy środowiska, jawne artefakty i kontrola przed lokalnym uruchomieniem.

Ten przykład pokazuje cały model Junexis w jednym projekcie: czujnik na urządzeniu, przetwarzanie na serwerze i prezentację alertów w interfejsie. Odpowiada projektowi examples/projects/01-temperature-monitor w repozytorium języka.

System

flowchart LR
    SENSOR["TempSensor<br/>@embedded"] -->|"chan&lt;TempReading&gt;"| PROCESS["TempProcessor<br/>@server"]
    PROCESS -->|"chan&lt;Alert&gt;"| DASH["AlertDashboard<br/>@report"]
    SENSOR -.->|"zdarzenia"| OBS["Obserwacja"]
    PROCESS -.->|"zdarzenia"| OBS
    DASH -.->|"zdarzenia"| OBS
    OBS --> STORY["Narrative<br/>historia wykonania"]

Manifest projektu

name = "temperature-monitor"
entry = "src/main.jnx"
targets = ["embedded", "server", "report"]
outDir = "out"

Manifest wskazuje jeden plik wejściowy i trzy środowiska docelowe. Kod generowany trafia do out/, natomiast pliki należące do autora projektu można utrzymywać w katalogu user/.

Wspólne dane

struct TempReading {
    celsius: Float
    device_id: Text
    timestamp: Time
}

struct Alert {
    level: Text
    message: Text
    value: Float
    at: Time
}

Te same typy są sprawdzane po obu stronach granic między urządzeniem, serwerem i interfejsem.

Zadanie urządzenia

extern task dht_read_celsius(pin: u8) @embedded -> Float

task TempSensor() @embedded(kitchen_sensor) -> chan<TempReading> {
    config {
        dht22_pin: u8 : 4
        device_id: Text : "kitchen"
    }

    every 5s {
        let temp = dht_read_celsius(config.dht22_pin)
        send TempReading {
            celsius: temp,
            device_id: config.device_id,
            timestamp: now()
        }
    }
}

extern task wyznacza granicę kodu należącego do autora. Junexis opisuje kontrakt odczytu, ale implementacja sterownika czujnika pozostaje w kodzie urządzenia.

Zadanie serwerowe

task TempProcessor(
    readings: chan<TempReading>
) @server -> chan<Alert> {
    config {
        high_threshold: Float : 30.0
        low_threshold: Float : 10.0
    }

    loop {
        let reading = recv readings
        if reading.celsius > config.high_threshold {
            send Alert {
                level: "HIGH",
                message: "Temperature too high",
                value: reading.celsius,
                at: reading.timestamp
            }
        }
    }
}

Serwer odbiera typowane dane i publikuje alert. Kompilator sprawdza typy, liczbę argumentów i zgodność połączeń przed wygenerowaniem Go.

Zadanie interfejsu

extern task render_alert(alert: Alert) @report

task AlertDashboard(alerts: chan<Alert>) @report {
    for alert in alerts {
        log("ALERT {alert.message}")
        render_alert(alert)
    }
}

Warstwa @report otrzymuje TypeScript oraz kontrakt funkcji, którą autor łączy z własnym interfejsem.

Potok wykonania

pipeline TempMonitoring {
    use TempSensor -> TempProcessor
    use TempProcessor -> AlertDashboard
}

Potok pozwala kompilatorowi zbudować topologię, dobrać generatory i wykryć niezgodne lub brakujące połączenia.

Sprawdzenie i budowanie

Z katalogu zawierającego repozytoria platformy:

$project = ".\junexis-lang\examples\projects\01-temperature-monitor"
junexis check $project
junexis build $project

Wynik

out/
├── embedded/       # C++ i projekt PlatformIO
├── server/         # moduł Go
├── report/         # projekt TypeScript
├── analysis/       # model systemu dla narzędzi
├── debug/          # mapy źródeł i manifest debugowania
└── junexis.artifacts.json
flowchart TB
    BUILD["Sprawdzony projekt"] --> E["out/embedded"]
    BUILD --> S["out/server"]
    BUILD --> R["out/report"]
    BUILD --> A["out/analysis"]
    BUILD --> D["out/debug"]
    E --> PACKAGE["Pakiet systemu"]
    S --> PACKAGE
    R --> PACKAGE
    A --> PACKAGE
    D --> PACKAGE

Pakowanie i lokalne uruchomienie

$bundle = Join-Path $project "temperature-monitor.system-bundle.zip"
$preflight = Join-Path $project "deployment-preflight.json"

junexis package $project --out $bundle
junexis deploy preflight $bundle --report-out $preflight --target server --target report
junexis deploy local $bundle --preflight $preflight --target server --target report --duration 5

package zapisuje zweryfikowaną paczkę pod jawną ścieżką, deploy preflight tworzy raport gotowości, a deploy local uruchamia ograniczoną czasowo sesję części serwerowej i raportowej. Programowanie urządzenia pozostaje jawną, osobną operacją wymagającą wyboru fizycznego portu.

Co zostało udowodnione

  • jeden opis tworzy artefakty C++, Go i TypeScript,
  • typy i topologia są sprawdzane przed generowaniem,
  • kod autora pozostaje poza katalogiem generowanym,
  • artefakty można związać w jedną paczkę systemu,
  • identyfikatory budowania łączą paczkę, uruchomienie, obserwację i Narrative.

Ten przykład jest reprezentatywną ścieżką rozwojową. Nie dowodzi jeszcze, że każda konstrukcja języka działa jednakowo na każdym urządzeniu i środowisku.