Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add architecture and data flow diagrams to README #45

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
106 changes: 105 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,113 @@
# AprsWeather

Weather maps backed by data from the Automatic Position Reporting System (APRS).
Weather maps backed by data from the Automatic Packet Reporting System (APRS).

Deployed at: [hamwx.bielstein.dev](https://hamwx.bielstein.dev)

## Diagrams

As the [Automatic Packet Reporting System](http://aprs.org/) and its component
[Automatic Packet Reporting System - Internet Service](https://aprs-is.net/) may not be familiar to
all who wish to work on this project, I've included a few diagrams on the architecture of this app,
how it relates to existing APRS infrastructure, and how data will typically flow through the full
system.

The following diagrams are written in [Mermaid](https://mermaid.js.org) and may require an [editor extension](https://mermaid.js.org/ecosystem/integrations-community.html#editor-plugins) to render properly in your dev environment.

### Architecture

This diagram lays out the following pieces:

1. AprsWeather frontend (WebAssembly in the browser for visualization)
2. AprsWeather backend (web server receiving and storing APRS packets from the APRS-IS and serving to frontend via a RESTful API)
3. APRS-IS servers streaming data via TCP
4. APRS iGate radio stations receiving and decoding packets from radio transmissions

```mermaid
C4Context
title System architecture diagram for AprsWeather and APRS

Person(webUser, "AprsWeather User", "Someone Checking the AprsWeather web app for nearby weather reports")

System_Boundary(aprsWeather, "AprsWeather") {
System(aprsWeatherFrontend, "AprsWeather frontend", "WebAssembly UI")
System(aprsWeatherBackend, "AprsWeather backend", ".NET Server Process")

Rel(aprsWeatherFrontend, aprsWeatherBackend, "calls")
}

Rel(webUser, aprsWeatherFrontend, "uses")

System_Boundary(aprsIs, "APRS-IS", "Internet Service for APRS") {
System(aprsServer, "APRS-IS Server Network", "Network of many APRS-IS servers")
System(iGate, "iGate", "Internet Gateway Service")

Rel(iGate, aprsServer, "forwards packet")
}

Rel(aprsServer, aprsWeatherBackend, "forwards packet")

System_Boundary(aprsRf, "APRS Radio Network", "The network of radio transceivers communicating via radio frequency transmissions") {
System(transmitter, "Radio Transmitter", "Origin of a report")
}

Rel(transmitter, iGate, "RF transmission")
```

### Data Flow Example

This diagram lays out a a flow for a weather report to move through the APRS, APRS-IS, and AprsWeather
systems from the weather station to the end user.
Steps are:

1. A weather station takes measurements
2. A radio transmitter encodes those measurements in an APRS data packet and transmits the packet over the air
3. An APRS iGate station receives the packet via antenna and receiver then decodes and forwards to the APRS-IS servers
4. APRS-IS server infrastructure forward messages through network
5. APRS-IS servers forward message to subscribed servers (based on [filters](https://aprs-is.net/javAPRSFilter.aspx)) via TCP connection
6. AprsWeather backend receives packet via TCP, decodes, and stores
7. AprsWeather frontend requests reports via REST API from backend and displays to user

```mermaid
flowchart TD

subgraph weatherStation [Weather Station]
station["Weather Station"]
radio["Radio Transmitter"]
end

subgraph aprsPhysical [APRS Physical Network]
digi["APRS Digital Repeater (digipeater)"]
igate["APRS Internet Gateway (iGate)"]
end

subgraph aprsIsSystem [APRS Internet System]
aprsIs((("APRS Servers")))
end

subgraph aprsWeather [AprsWeather]
backend["AprsWeather Backend: AprsIsClient"]
db[("AprsWeather Backend: In-Memory Storage")]
api{{"AprsWeather Backend: API Query"}}
frontend[/"AprsWeather Frontend"/]
end

user["user"]

station-- report measurements (physical connection) ---radio
radio-. "transmit packet (radio freq.)" .->digi
radio-. "transmit packet (radio freq.)" .->igate
digi-. "repeat packet (radio freq.)" .->igate

igate-- forward packet (TCP) -->aprsIs
aprsIs-- forward packet to subscribers (TCP) -->backend

backend-- save packet ---db
db-- retrieve packet ---api
api-. fetch data (REST) .->frontend
frontend-. "view reports!" .-user
```

## Running Locally

Before running, you'll have to set a value for the `APRS_IS_CALLSIGN` environment variable.
Expand Down