Lorawan-stack: Unterstützt mehrere resultierende Nachrichten aus einem Format

Erstellt am 13. Aug. 2019  ·  12Kommentare  ·  Quelle: TheThingsNetwork/lorawan-stack

Zusammenfassung

Ein ttnpb.ApplicationUp sollte zu mehreren Front-End-Nachrichten führen können, anstatt nur einer.

Warum brauchen wir das?

Derzeit wird ein ttnpb.ApplicationUp in nur einen Byte-Slice gemarshallt, der zu einer Front-End-Nachricht führt (ein HTTP-Aufruf, eine MQTT-Nachricht usw.). Wenn die Nutzlast des Uplinks jedoch mehrere Messungen enthält (denken Sie an mehrere Sensoren, die an ein Gerät angeschlossen sind), wäre es hilfreich, bestimmte Formate zuzulassen, um mehrere Nachrichten für jede Messung zu erstellen.

Was ist schon da? Was siehst du jetzt?

https://github.com/TheThingsNetwork/lorawan-stack/blob/9112dd7bcd3f1f0319005542908b427b27acd1c/pkg/applicationserver/io/formatters/formatter.go#L23
Das Format gibt derzeit nur eine Nachricht zurück, die an die Front-Ends gesendet werden soll.

Was fehlt? Was willst du sehen?

Das Ergebnis sollte von []byte in [][]byte geändert werden.

Umfeld

93ea01b4b5af2672da5883b570be825a54b8afc1

Wie wollen Sie dies umsetzen?

Ändern Sie die Format Schnittstelle. Danach sollte jedes Frontend so geändert werden, dass alle Nachrichten statt nur einer gesendet werden:

Können Sie dies selbst tun und einen Pull Request senden?

Ja, aber das überlasse ich der Community.

application server needtriage

Alle 12 Kommentare

@adriansmares Ich arbeite gerade an diesem Thema. Nachdem ich für die Funktion *ttnpb.ApplicationUp in der Datei formatter.go von []byte zu [][]byte gewechselt habe, habe ich sie auch in den Dateien json.go und protobuf.go geändert. Aber jetzt gibt es folgenden Fehler:
image
Bitte geben Sie einen Vorschlag. Dankeschön.

@mihirr93 Da Sie jetzt die [][]byte{ slice-containing-result } .

Hallo Herr @adriansmares . Ich bin etwas verwirrt über unseren Ansatz. Wir versuchen, die Front-End-Nachricht (rohe Nutzlast) in mehrere Nachrichten aufzuteilen. Aber in diesem Fall hängt der Punkt, an dem die Nachricht geschnitten wird, von ihrer Codierung (Cayenne oder eine andere benutzerdefinierte Codierung) ab, die uns unbekannt ist. Dazu müssen wir also die decodierte Nutzlast verwenden. Sobald der Benutzer den Decoder im Payload-Format-Tab des TTN eingibt, zeigt die Anwendung die decodierten Werte tatsächlich in JSON an (wie im Bild zu sehen). Sollten wir diese dekodierte Nutzlast nicht direkt aufteilen und mit http weiter pushen?
image
Könnten Sie bitte etwas Licht in diese Verwirrung bringen?
Und ändern wir nur die pkg-Dateien und die .proto-Dateien werden automatisch aktualisiert?
Vielen Dank für Ihre freundliche Unterstützung und Zeit.

_Denken Sie daran, dass dieses Repository die V3-Version unseres LoRaWAN-Stacks enthält und das bereitgestellte Bild von TTN stammt, auf dem die V2- Version ausgeführt wird._

Bitte beachten Sie, dass dieses Problem nur die Unterstützung für die Erstellung mehrerer Nutzlasten aus einer Nachricht betrifft, und das neue Formatproblem, an dem Sie wahrscheinlich interessiert sind, ist https://github.com/TheThingsNetwork/lorawan-stack/issues/1158. Bitte überprüfen Sie, ob dieses Problem tatsächlich das ist, nach dem Sie suchen.

Trotzdem würde ich in diesem Fall vorschlagen, ein neues Format einzuführen, das auf JSON basiert, das basierend auf den decodierten Informationen im Uplink mehrere Nutzlasten erzeugt.
Sie werden wahrscheinlich die Uplink-Nachricht ApplicationUp_UplinkMessage speziell behandeln wollen, da sie die Felder enthält, die Sie als Teil des Feldes DecodedPayload interessieren.

Sie sollten die Proto-Dateien für diesen Anwendungsfall nicht ändern müssen.

Ich versuche immer noch, die interne Arbeitsweise und den Code des Stapels zu verstehen. Derzeit konzentriere ich mich nur auf dieses Thema und nicht auf #1158. Da Sie vorgeschlagen haben, ApplicationUp_Uplinkmessage zu ändern, versuche ich, das herauszufinden. Ich habe im Moment folgende Fragen:
1) Die Struktur ApplicationUplink und die Funktion ApplicationUp_UplinkMessage sind in der Datei messages.pb.go im Verzeichnis ttnpb definiert. Im Header der Datei steht jedoch "DO NOT EDIT". Soll ich es ignorieren? oder gibt es einen alternativen Ansatz, um es zu ändern?
2) Können Sie dies bitte genauer beschreiben " introduce a new format, based on the JSON one "? Ich dachte, wir müssen nur das bestehende Format ändern, anstatt ein neues zu erstellen.
3) Sie haben auch das Umschließen von Ergebnissen erwähnt, bei dem nur ein Ergebnis zurückgegeben wird. Was genau wird das bewirken? Wird es die Mehrfachnachricht wieder zu einer kombinieren und nur ein Ergebnis zurückgeben? Und müssen wir das nur für Uplink-Nachrichten tun?

[Danke @adriansmares für deine kontinuierliche Anleitung. Obwohl ich das Golang-Tutorial besucht habe, ist dies meine erste Interaktion mit der GO-Sprache, bitte entschuldigen Sie, dass ich Sie mit so vielen Zweifeln belästigt habe]

  • Sie müssen weder diese Datei noch irgendwelche *.pb.* Dateien bearbeiten. Diese werden automatisch aus den *.proto Dateien generiert, wenn Sie mage proto:all ausführen. Für die Zwecke dieser Ausgabe müssen jedoch keine derartigen Änderungen vorgenommen werden.
  • Bitte gehen Sie dem in der anderen Ausgabe nach.
  • Der Vorschlag zum Umschließen ermöglicht es Ihnen, den vorhandenen Code intakt zu halten (und dennoch eine Nutzlast zurückzugeben, die von einer Uplink-Nachricht gesendet werden soll).

Lassen Sie mich versuchen, die gesamte Pipeline besser zu erklären, vielleicht bringt dies etwas Licht in die Funktionsweise

  1. Ein Gerät sendet 1 Uplink.
  2. Der 1-Uplink wird vom Gateway empfangen und an den Gateway-Server gesendet, der ihn an den Netzwerkserver weiterleitet, der ihn dann an den Anwendungsserver weiterleitet. Die Nachricht, die das AS erreicht, ist vom Typ *ttnpb.ApplicationUplink .
  3. Der AS nimmt diesen 1 Uplink und versucht, seine binäre Nutzlast in die dekodierten Felder zu dekodieren (die Bytes im FRMPayload Feld in die dekodierte Struktur von DecodedPayload ) unter Verwendung des Geräte-Payload-Formatierers.
  4. Es verpackt es dann in ein *ttnpb.ApplicationUp und sendet es an die Frontends (MQTT, Webhooks, PubSub, Anwendungspakete).
  5. Die Frontends erhalten diese 1 *ttnpb.ApplicationUp und wählen basierend auf ihren Einstellungen (dem Format) den zu verwendenden Formatierer aus (die Formatiererschnittstelle ist in pkg/applicationserver/io/formatters ).
  6. Das Frontend ruft formatter.FromUp mit 1 *ttnph.ApplicationUp und empfängt ein Stück Byte ( []byte ), das den Textkörper von 1 Nachricht darstellt.

Was dieses Problem betrifft, hoffe ich, dass es sichtbar ist, dass nur Schritt 6 Änderungen erfordert:

  • Ändern der Rückgabetypen sowohl der Schnittstelle als auch der Implementierungen, sodass FromUp mehrere Nutzlasten (ein Stück von Byte-Slices) zurückgeben kann.
  • Die vorhandenen Formate Protobuf und JSON sollten ihr Verhalten nicht ändern und sollten daher weiterhin nur 1 Nutzlast zurückgeben (deshalb ist der Wrap erforderlich).
  • Nachdem Sie diese 2 (die Schnittstelle und die Formatierer) so geändert haben, dass sie [][]byte Sie Fehler sehen (da die meisten Orte, die FromUp aufrufen, nur eine Nutzlast empfangen - Sie müssen aktualisieren diese Aufrufstellen und lassen sie die Liste der Nutzlasten durchlaufen und jede von ihnen senden.

Erst nachdem dieses Problem, das das Verhalten überhaupt nicht ändert, behoben wurde, können Sie mit der Implementierung Ihres eigenen Formatierers fortfahren, der einen Teil mehrerer Nutzdaten zurückgibt, einen für jede Messung (bedenken Sie jedoch, dass dieses neue Format ist für dieses Problem nicht relevant!).

Vielen Dank @adriansmares für diese ausführliche Erklärung und Anleitung. Ich glaube, ich habe es jetzt geschafft, dieses Problem zu lösen. Ich habe es auch mit ./mage go:test js:test jsSDK:test getestet und es gibt keinen Fehler. Die wichtigsten Änderungen am Code sind im Folgenden hervorgehoben:
formatter.go

type Formatter interface {
    FromUp(*ttnpb.ApplicationUp) ([][]byte, error)
    ToDownlinks([]byte) (*ttnpb.ApplicationDownlinks, error)
    ToDownlinkQueueRequest([]byte) (*ttnpb.DownlinkQueueRequest, error)
}

json.go

func (json) FromUp(msg *ttnpb.ApplicationUp) ([][]byte, error) {
    m, e := jsonpb.TTN().Marshal(msg)
    return [][]byte{m}, e
}

protobuf.go
Das gleiche wie oben

mqtt.go

buf, err := c.format.FromUp(up.ApplicationUp)
                if err != nil {
                    logger.WithError(err).Warn("Failed to marshal upstream message")
                    continue
                }
                logger.Debug("Publish upstream message")
                for _, v := range buf {
                    c.session.Publish(&packet.PublishPacket{
                        TopicName:  topic.Join(topicParts),
                        TopicParts: topicParts,
                        QoS:        qosUpstream,
                        Message:    v,
                    })
                }

pubsub.go
Das gleiche wie oben

webhooks.go

unc (w *webhooks) newRequest(ctx context.Context, msg *ttnpb.ApplicationUp, hook *ttnpb.ApplicationWebhook) ([]*http.Request, error) {
    var cfg *ttnpb.ApplicationWebhook_Message
    switch msg.Up.(type) {
    case *ttnpb.ApplicationUp_UplinkMessage:
        cfg = hook.UplinkMessage
    case *ttnpb.ApplicationUp_JoinAccept:
        cfg = hook.JoinAccept
    case *ttnpb.ApplicationUp_DownlinkAck:
        cfg = hook.DownlinkAck
    case *ttnpb.ApplicationUp_DownlinkNack:
        cfg = hook.DownlinkNack
    case *ttnpb.ApplicationUp_DownlinkSent:
        cfg = hook.DownlinkSent
    case *ttnpb.ApplicationUp_DownlinkFailed:
        cfg = hook.DownlinkFailed
    case *ttnpb.ApplicationUp_DownlinkQueued:
        cfg = hook.DownlinkQueued
    case *ttnpb.ApplicationUp_LocationSolved:
        cfg = hook.LocationSolved
    }
    if cfg == nil {
        return nil, nil
    }
    url, err := url.Parse(hook.BaseURL)
    if err != nil {
        return nil, err
    }
    url.Path = path.Join(url.Path, cfg.Path)
    expandVariables(url, msg)
    if err != nil {
        return nil, err
    }
    format, ok := formats[hook.Format]
    if !ok {
        return nil, errFormatNotFound.WithAttributes("format", hook.Format)
    }
    buf, err := format.FromUp(msg)
    if err != nil {
        return nil, err
    }
    var requests []*http.Request
    for i, v := range buf {
        req, err := http.NewRequest(http.MethodPost, url.String(), bytes.NewReader(v))
        requests[i] = req
        if err != nil {
            return nil, err
        }
        for key, value := range hook.Headers {
            req.Header.Set(key, value)
        }
        if hook.DownlinkAPIKey != "" {
            req.Header.Set(downlinkKeyHeader, hook.DownlinkAPIKey)
            req.Header.Set(downlinkPushHeader, w.createDownlinkURL(ctx, hook.ApplicationWebhookIdentifiers, msg.EndDeviceIdentifiers, "push"))
            req.Header.Set(downlinkReplaceHeader, w.createDownlinkURL(ctx, hook.ApplicationWebhookIdentifiers, msg.EndDeviceIdentifiers, "replace"))
        }
        req.Header.Set("Content-Type", format.ContentType)
        req.Header.Set("User-Agent", userAgent)
    }
    return requests, nil
}

Bitte geben Sie Ihr Feedback und Ihre Kommentare. Ich werde die Korrekturen (Var-Benennung, Einrückung usw.) gemäß den Codestilrichtlinien vornehmen, sobald die Aufgabe vollständig abgeschlossen ist. Und wenn das richtig aussieht, könnten Sie mich bitte weiter für Ausgabe #1158 führen. Vielen Dank noch mal.

@mihir93 sieht gut aus! Bitte übernehmen Sie Ihre Änderungen und senden Sie einen Pull-Request für dieses Problem. Nach dem Zusammenführen können wir mit dem neuen Formatierer fortfahren, der in #1158 erwähnt wird.

@adriansmares Klar, das werde ich tun. Sollte dieser Pull Request auf der genannten Umgebung oder auf der neuesten Version des Stacks basieren?

Wir empfehlen Ihnen, Ihre Änderungen auf die neuesten master umzubasieren, um spätere Konflikte zu vermeiden.

Dieses Problem ist seit einiger Zeit inaktiv, also verschieben wir es zurück in die Triage, um zu sehen, ob es noch Nachfrage dafür gibt oder ob wir es einfach fallen lassen sollten.

Dies wird nicht mehr benötigt, da es schlecht skaliert.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen