feat: Add database support for APRS items/objects and DAO extension
- Added item_name, object_name fields to store names - Added is_item, is_object boolean flags for filtering - Added dao field to store DAO extension data for extra position precision - Automatic detection during packet processing to populate these fields - Added database indexes for efficient queries - Now preserving itemname as item_name and dao data instead of discarding This enables future features like: - Showing/hiding items and objects separately from stations - Querying for specific objects (events, repeaters, etc.) - Using DAO data for high-precision applications 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
b63c3c547d
commit
cd79c3df7e
4 changed files with 100 additions and 6 deletions
|
|
@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
|
||||
## [Unreleased]
|
||||
|
||||
### Added
|
||||
- Database fields for APRS items and objects support:
|
||||
- `item_name`, `object_name` fields to identify items/objects
|
||||
- `is_item`, `is_object` boolean flags for filtering
|
||||
- `dao` field to store DAO (Datum As Offset) extension data for extra position precision
|
||||
- Automatic detection of items/objects during packet processing
|
||||
- Database indexes for efficient item/object queries
|
||||
|
||||
### Fixed
|
||||
- Fixed packet storage failure in production due to non-schema fields from updated APRS parser
|
||||
- Remove `type`, `digipeaters`, `daodatumbyte`, `mbits`, `message`, `phg`, `wx`, `resultcode`, `resultmsg` fields before database insertion
|
||||
|
|
|
|||
|
|
@ -96,6 +96,15 @@ defmodule Aprsme.Packet do
|
|||
|
||||
field(:device_identifier, :string)
|
||||
|
||||
# APRS Items/Objects support
|
||||
field(:item_name, :string)
|
||||
field(:object_name, :string)
|
||||
field(:is_item, :boolean, default: false)
|
||||
field(:is_object, :boolean, default: false)
|
||||
|
||||
# DAO (Datum As Offset) extension for extra position precision
|
||||
field(:dao, :map)
|
||||
|
||||
embeds_one(:data_extended, DataExtended)
|
||||
|
||||
timestamps(type: :utc_datetime)
|
||||
|
|
@ -172,7 +181,12 @@ defmodule Aprsme.Packet do
|
|||
:messaging,
|
||||
:rain_midnight,
|
||||
:has_weather,
|
||||
:device_identifier
|
||||
:device_identifier,
|
||||
:item_name,
|
||||
:object_name,
|
||||
:is_item,
|
||||
:is_object,
|
||||
:dao
|
||||
])
|
||||
|> validate_required([
|
||||
:base_callsign,
|
||||
|
|
|
|||
|
|
@ -303,6 +303,9 @@ defmodule Aprsme.PacketConsumer do
|
|||
# Extract additional data from the parsed packet including raw packet
|
||||
attrs = Aprsme.Packet.extract_additional_data(attrs, attrs[:raw_packet] || "")
|
||||
|
||||
# Detect and set item/object fields
|
||||
attrs = detect_item_or_object(attrs)
|
||||
|
||||
# Normalize data_type to string if it's an atom
|
||||
attrs = normalize_data_type(attrs)
|
||||
|
||||
|
|
@ -384,15 +387,11 @@ defmodule Aprsme.PacketConsumer do
|
|||
|> Map.delete("gpsfixstatus")
|
||||
|> Map.delete(:raw_weather_data)
|
||||
|> Map.delete("raw_weather_data")
|
||||
# Additional fields found in production logs
|
||||
|> Map.delete(:dao)
|
||||
|> Map.delete("dao")
|
||||
# Additional fields that need coordinate name mapping
|
||||
|> Map.delete(:longitude)
|
||||
|> Map.delete("longitude")
|
||||
|> Map.delete(:latitude)
|
||||
|> Map.delete("latitude")
|
||||
|> Map.delete(:itemname)
|
||||
|> Map.delete("itemname")
|
||||
end
|
||||
|
||||
# Helper functions for coordinate validation and point creation
|
||||
|
|
@ -424,6 +423,57 @@ defmodule Aprsme.PacketConsumer do
|
|||
defp valid_packet?(%{sender: sender}) when is_binary(sender) and byte_size(sender) > 0, do: true
|
||||
defp valid_packet?(_), do: false
|
||||
|
||||
# Detect if packet is an item or object and set appropriate fields
|
||||
defp detect_item_or_object(attrs) do
|
||||
cond do
|
||||
# Check for itemname field from parser
|
||||
Map.has_key?(attrs, :itemname) or Map.has_key?(attrs, "itemname") ->
|
||||
item_name = Map.get(attrs, :itemname) || Map.get(attrs, "itemname")
|
||||
|
||||
attrs
|
||||
|> Map.put(:item_name, item_name)
|
||||
|> Map.put(:is_item, true)
|
||||
|> Map.delete(:itemname)
|
||||
|> Map.delete("itemname")
|
||||
|
||||
# Check for object data type and extract object name from data_extended
|
||||
attrs[:data_type] == "object" or attrs["data_type"] == "object" ->
|
||||
object_name = extract_object_name(attrs)
|
||||
|
||||
attrs
|
||||
|> Map.put(:object_name, object_name)
|
||||
|> Map.put(:is_object, true)
|
||||
|
||||
# Check information field for object format (starts with ;)
|
||||
is_binary(attrs[:information_field]) and String.starts_with?(attrs[:information_field], ";") ->
|
||||
# Extract object name from information field
|
||||
object_name = extract_object_name_from_info_field(attrs[:information_field])
|
||||
|
||||
attrs
|
||||
|> Map.put(:object_name, object_name)
|
||||
|> Map.put(:is_object, true)
|
||||
|
||||
true ->
|
||||
attrs
|
||||
end
|
||||
end
|
||||
|
||||
defp extract_object_name(attrs) do
|
||||
case attrs[:data_extended] do
|
||||
%{name: name} when is_binary(name) -> name
|
||||
%{"name" => name} when is_binary(name) -> name
|
||||
_ -> nil
|
||||
end
|
||||
end
|
||||
|
||||
defp extract_object_name_from_info_field(info_field) do
|
||||
# Object format: ;OBJECTNAM*DDHHMMz...
|
||||
case Regex.run(~r/^;([A-Z0-9 ]{9})\*/, info_field) do
|
||||
[_, name] -> String.trim(name)
|
||||
_ -> nil
|
||||
end
|
||||
end
|
||||
|
||||
# Convert latitude/longitude to lat/lon if present at top level
|
||||
defp convert_coordinate_field_names(attrs) do
|
||||
attrs
|
||||
|
|
|
|||
|
|
@ -0,0 +1,22 @@
|
|||
defmodule Aprsme.Repo.Migrations.AddItemAndDaoFields do
|
||||
use Ecto.Migration
|
||||
|
||||
def change do
|
||||
alter table(:packets) do
|
||||
# For APRS items/objects
|
||||
add :item_name, :string
|
||||
add :object_name, :string
|
||||
add :is_item, :boolean, default: false
|
||||
add :is_object, :boolean, default: false
|
||||
|
||||
# DAO extension data for extra position precision
|
||||
add :dao, :map
|
||||
end
|
||||
|
||||
# Add indexes for querying items/objects
|
||||
create index(:packets, [:is_item])
|
||||
create index(:packets, [:is_object])
|
||||
create index(:packets, [:item_name])
|
||||
create index(:packets, [:object_name])
|
||||
end
|
||||
end
|
||||
Loading…
Add table
Reference in a new issue