Skip to content

Commit

Permalink
Dotnet 8 updates.
Browse files Browse the repository at this point in the history
Use JSON serializer for payload

Note on FreeBSD .NET 8 support.
  • Loading branch information
joelp committed Nov 10, 2024
1 parent fbfeb64 commit 5df304d
Show file tree
Hide file tree
Showing 6 changed files with 84 additions and 107 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,6 @@ You don't need to set LATITUDE and LONGITUDE to your precise location (unlike wi
I replaced an aging RPi3 running [piaware](https://github.com/flightaware/piaware) with a 4gb Rock64 running dump1090-fa. Here's a repo for getting this to run: [rtl-sdr-bsd](https://github.com/idatum/rtl-sdr-bsd). Here are more details of the overall project: [Experimenting with RTL-SDR on NetBSD 10](https://www.idatum.net/experimenting-with-rtl-sdr-on-netbsd-10.html).

## FreeBSD 14 on the Rock64 running [dump1090-fa](https://github.com/flightaware/dump1090)
I've since switched from NetBSD 10 to running FreeBSD 14 on the Rock64 device and this resulted in a more stable host for dump1090. It's mainly about better support for RTL-SDR generally with USB on FreeBSD. Regardless of your O/S choice, adsb2mqtt should be able to connect to dump1090 and generate MQTT messages.
I've since switched from NetBSD 10 to running FreeBSD 14 on the Rock64 device and this resulted in a more stable host for dump1090. It's mainly about better support for RTL-SDR generally with USB on FreeBSD. FreeBSD 14 also now supports .NET 8.

Regardless of your O/S choice, adsb2mqtt should be able to connect to dump1090 and generate MQTT messages.
105 changes: 40 additions & 65 deletions app/Dump1090Reader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ namespace adsb2mqtt;
using System.Threading.Tasks;
using System.Timers;
using Microsoft.Extensions.Configuration;
using System.Text.Json;

using MQTTnet;
using MQTTnet.Client;
Expand Down Expand Up @@ -36,18 +37,9 @@ public Dump1090Reader(ILogger<Worker> logger,
IConfiguration configuration,
IFindAircraftType findAircraftType)
{
if (logger is null)
{
throw new ArgumentNullException("logger");
}
if (configuration is null)
{
throw new ArgumentNullException("configuration");
}
if (findAircraftType is null)
{
throw new ArgumentNullException("findAircraftType");
}
ArgumentNullException.ThrowIfNull(logger);
ArgumentNullException.ThrowIfNull(configuration);
ArgumentNullException.ThrowIfNull(findAircraftType);
_logger = logger;
_configuration = configuration;
_findAircraftType = findAircraftType;
Expand Down Expand Up @@ -79,10 +71,10 @@ private void GroomFlightsCallback(object? source, ElapsedEventArgs e)

foreach (var icao in staleFlights)
{
Flight staleFlight;
if (!_icaoFlight.TryRemove(icao, out staleFlight))
if (!_icaoFlight.TryRemove(icao, out Flight staleFlight))
{
_logger.LogInformation($"Unable to drop stale flight {staleFlight.Icao} last seen {staleFlight.LogDateTime} UTC");
_logger.LogInformation("Unable to drop stale flight {staleFlight.Icao} last seen {staleFlight.LogDateTime} UTC",
staleFlight.Icao, staleFlight.LogDateTime);
}
}
}
Expand All @@ -105,7 +97,7 @@ private bool MqttConnected()
// Loop through the AddressList to obtain the supported AddressFamily.
foreach (IPAddress address in hostEntry.AddressList)
{
IPEndPoint ipe = new IPEndPoint(address, port);
IPEndPoint ipe = new(address, port);
var tempSocket =
new Socket(ipe.AddressFamily, SocketType.Stream, ProtocolType.Tcp);

Expand Down Expand Up @@ -133,11 +125,11 @@ private async void PublishRecordsCallback(object? source, ElapsedEventArgs e)
}
catch (MqttClientDisconnectedException ex)
{
_logger.LogError(ex.ToString());
_logger.LogError("{ex}", ex);
}
catch (Exception ex)
{
_logger.LogError(ex.ToString());
_logger.LogError("{ex}", ex);
throw;
}
}
Expand All @@ -153,26 +145,35 @@ private async Task PublishRecordsAsync()
_logger.LogDebug("MQTT not connected; skipping publish.");
return;
}
Flight flight;
foreach (var icao in _trackedIcaoFlight.Keys)
{
if (!_trackedIcaoFlight.TryRemove(icao, out flight))
if (!_trackedIcaoFlight.TryRemove(icao, out Flight flight))
{
continue;
}
var nm = GetNauticalMiles(double.Parse(flight.Latitude), double.Parse(flight.Longitude));
if (nm < _radiusNauticalMiles)
{
var payloadText = $"{{ \"icao\":\"{flight.Icao}\",\"flt\":\"{flight.Callsign}\"," +
$"\"alt\":{flight.Altitude},\"dir\":{flight.Direction},\"lat\":{flight.Latitude}," +
$"\"lng\":{flight.Longitude},\"t\":\"{flight.AircraftType}\",\"nm\":{nm} }}";
var flightPayload = new FlightPayload
{
icao = flight.Icao,
flt = flight.Callsign,
alt = int.Parse(flight.Altitude),
dir = int.Parse(flight.Direction),
lat = double.Parse(flight.Latitude),
lng = double.Parse(flight.Longitude),
t = flight.AircraftType ?? string.Empty,
nm = nm
};
string payloadText = JsonSerializer.Serialize(flightPayload);
var payload = Encoding.UTF8.GetBytes(payloadText);
_logger.LogDebug("{payloadText}", payloadText);
var message = new MqttApplicationMessageBuilder()
.WithTopic($"{_topicBase}/{icao}")
.WithPayload(payload)
.WithQualityOfServiceLevel(MqttQualityOfServiceLevel
.AtLeastOnce).Build();
var pubResult = await _mqttClient.PublishAsync(message);
await _mqttClient.PublishAsync(message);
}
}
}
Expand Down Expand Up @@ -244,16 +245,14 @@ private void HandleRecord(String record)
string[] recordSplit = record.Split(',');
if (recordSplit.Length < 5)
{
_logger.LogInformation($"Invalid record: {record}");
_logger.LogInformation("Invalid record: {record}", record);
return;
}
var msgType = recordSplit[0];
var transType = recordSplit[1];
var icao = recordSplit[4];
Flight lastFlight;
_icaoFlight.TryGetValue(icao, out lastFlight);
Flight flight;
UpdateFlight(icao, recordSplit, lastFlight, out flight);
_icaoFlight.TryGetValue(icao, out Flight lastFlight);
UpdateFlight(icao, recordSplit, lastFlight, out Flight flight);
_icaoFlight.AddOrUpdate(icao, flight, (key, val) => flight);
if (flight.Complete)
{
Expand All @@ -263,11 +262,7 @@ private void HandleRecord(String record)

private void ReceiveDump1090(string server, int port, CancellationToken stoppingToken)
{
using var socket = ConnectSocket(server, port);
if (socket == null)
{
throw new ApplicationException("Socket connection failed");
}
using var socket = ConnectSocket(server, port) ?? throw new ApplicationException("Socket connection failed");
var readBuffer = new Byte[1024];
int bytesRead = 0;
var recordBytes = new List<Byte>();
Expand Down Expand Up @@ -316,33 +311,13 @@ public async Task ProcessAsync(CancellationToken stoppingToken)
_baseLatitudeRad = _configuration.GetValue<double>("LATITUDE") * Math.PI / 180.0;
_baseLongitudeRad = _configuration.GetValue<double>("LONGITUDE") * Math.PI / 180.0;
// TCP BaseStation output host and port.
var beastHost = _configuration["BEAST_HOST"];
if (beastHost is null)
{
throw new InvalidOperationException("BEAST_HOST");
}
var beastHost = _configuration["BEAST_HOST"] ?? throw new InvalidOperationException("BEAST_HOST");
int beastPort = _configuration.GetValue<int>("BEAST_PORT");
// MQTT
_topicBase = _configuration["TOPIC_BASE"];
if (_topicBase is null)
{
throw new InvalidOperationException("_topicBase");
}
var mqttUsername = _configuration["MQTT_USERNAME"];
if (mqttUsername is null)
{
throw new InvalidOperationException("MQTT_USERNAME");
}
var mqttPassword = _configuration["MQTT_PASSWORD"];
if (mqttPassword is null)
{
throw new InvalidOperationException("MQTT_USERNAME");
}
var mqttServer = _configuration["MQTT_SERVER"];
if (mqttServer is null)
{
throw new InvalidOperationException("MQTT_SERVER");
}
_topicBase = _configuration["TOPIC_BASE"] ?? throw new InvalidOperationException("_topicBase");
var mqttUsername = _configuration["MQTT_USERNAME"] ?? throw new InvalidOperationException("MQTT_USERNAME");
var mqttPassword = _configuration["MQTT_PASSWORD"] ?? throw new InvalidOperationException("MQTT_USERNAME");
var mqttServer = _configuration["MQTT_SERVER"] ?? throw new InvalidOperationException("MQTT_SERVER");
int mqttPort = _configuration.GetValue<int>("MQTT_PORT");
bool mqttUseTls = _configuration.GetValue<bool>("MQTT_USE_TLS");

Expand All @@ -365,25 +340,25 @@ public async Task ProcessAsync(CancellationToken stoppingToken)
if (!await ConnectMqtt(mqttUsername, mqttPassword, mqttServer, mqttPort, mqttUseTls))
{
_logger.LogInformation("Could not connect to MQTT");
await Task.Delay(5000);
await Task.Delay(5000, stoppingToken);
continue;
}
ReceiveDump1090(beastHost, beastPort, stoppingToken);
}
catch (SocketException ex)
{
_logger.LogWarning(ex.Message);
await Task.Delay(5000);
_logger.LogWarning("{ex.Message}", ex.Message);
await Task.Delay(5000, stoppingToken);
}
catch (MqttCommunicationException ex)
{
_logger.LogError(ex.ToString());
_logger.LogError("{ex}", ex);
await DisconnectMqtt();
await Task.Delay(5000);
await Task.Delay(5000, stoppingToken);
}
catch (Exception ex)
{
_logger.LogError(ex.ToString());
_logger.LogError("{ex}", ex);
await DisconnectMqtt();
throw;
}
Expand Down
41 changes: 14 additions & 27 deletions app/FindAircraftType.cs
Original file line number Diff line number Diff line change
@@ -1,32 +1,21 @@
namespace adsb2mqtt;

using System.Text.Json;

public class FindAircraftType : IFindAircraftType
{
private readonly ILogger<FindAircraftType> _logger;
private readonly IConfiguration _configuration;
private string? _aircraftDbPath;
private readonly string? _aircraftDbPath;

public FindAircraftType(ILogger<FindAircraftType> logger,
IConfiguration configuration)
{
if (logger is null)
{
throw new ArgumentNullException(nameof(logger));
}
if (configuration is null)
{
throw new ArgumentNullException(nameof(configuration));
}
ArgumentNullException.ThrowIfNull(logger);
ArgumentNullException.ThrowIfNull(configuration);
_logger = logger;
_configuration = configuration;
// dump1090 aircraft database path.
_aircraftDbPath = _configuration.GetValue<string>("AIRCRAFT_DB_PATH");
if (_aircraftDbPath is null)
{
throw new InvalidOperationException("AIRCRAFT_DB_PATH");
}
_aircraftDbPath = _configuration.GetValue<string>("AIRCRAFT_DB_PATH") ?? throw new InvalidOperationException("AIRCRAFT_DB_PATH");
}

public string? Find(string icao)
Expand All @@ -38,39 +27,37 @@ public FindAircraftType(ILogger<FindAircraftType> logger,
JsonDocument jsonDoc;
try
{
var filename = $"{_aircraftDbPath}/{icao.Substring(0, i)}.json";
var filename = $"{_aircraftDbPath}/{icao[..i]}.json";
if (!File.Exists(filename))
{
continue;
}
_logger.LogDebug($"Reading {filename}.");
_logger.LogDebug("Reading {filename}.", filename);
jsonText = File.ReadAllText(filename);
jsonDoc = JsonDocument.Parse(jsonText);
JsonElement icaoElement;
if (!jsonDoc.RootElement.TryGetProperty(icao.Substring(i), out icaoElement))
if (!jsonDoc.RootElement.TryGetProperty(icao.Substring(i), out JsonElement icaoElement))
{
_logger.LogDebug($"No property {icao.Substring(i)}.");
_logger.LogDebug("No property {icao[i..]}.", icao[i..]);
continue;
}
_logger.LogDebug($"Found icao element {icao.Substring(i)} in {filename}.");
JsonElement aircraftTypeElement;
if (!icaoElement.TryGetProperty("t", out aircraftTypeElement))
_logger.LogDebug("Found icao element {icao[..i]} in {filename}.", icao[i..], filename);
if (!icaoElement.TryGetProperty("t", out JsonElement aircraftTypeElement))
{
_logger.LogDebug("No property type property.");
continue;
}
var aircraftType = aircraftTypeElement.GetString();
_logger.LogDebug($"Aircraft type: {aircraftType}");
_logger.LogDebug("Aircraft type: {aircraftType}", aircraftType);
return aircraftType;
}
catch (Exception ex)
{
_logger.LogError(ex.ToString());
_logger.LogError("{ex}", ex);
continue;
}
}
_logger.LogDebug($"No aircraft info for {icao}.");
_logger.LogDebug("No aircraft info for {icao}.", icao);

return string.Empty;
}
}
}
3 changes: 1 addition & 2 deletions app/Flight.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
namespace adsb2mqtt;

using System;

public struct Flight
Expand All @@ -9,7 +8,7 @@ public struct Flight
public string Icao;
public string Callsign
{
get { return string.IsNullOrEmpty(callSign) ? Icao : callSign; }
readonly get { return string.IsNullOrEmpty(callSign) ? Icao : callSign; }
set { callSign = value; }
}
public string Altitude;
Expand Down
23 changes: 23 additions & 0 deletions app/FlightPayload.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using System.Text.Json.Serialization;

namespace adsb2mqtt;

public struct FlightPayload
{
[JsonInclude]
public string icao;
[JsonInclude]
public string flt;
[JsonInclude]
public int alt;
[JsonInclude]
public int dir;
[JsonInclude]
public double lat;
[JsonInclude]
public double lng;
[JsonInclude]
public string t;
[JsonInclude]
public double nm;
}
15 changes: 3 additions & 12 deletions app/Worker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,9 @@ public Worker(IConfiguration configuration,
ILogger<Worker> logger,
IFindAircraftType findAircraftType)
{
if (configuration is null)
{
throw new ArgumentNullException(nameof(configuration));
}
if (logger is null)
{
throw new ArgumentNullException(nameof(logger));
}
if (findAircraftType is null)
{
throw new ArgumentNullException(nameof(findAircraftType));
}
ArgumentNullException.ThrowIfNull(configuration);
ArgumentNullException.ThrowIfNull(logger);
ArgumentNullException.ThrowIfNull(findAircraftType);
_configuration = configuration;
_logger = logger;
_findAircraftType = findAircraftType;
Expand Down

0 comments on commit 5df304d

Please sign in to comment.