Skip to content

Commit 2e081ee

Browse files
committed
refactor: Save last_seen_ip in database
`last_seen_ip` is contained in the Device Status but it's also received in device connected triggers. It is now stored in the database and used for IP based Geolocation, without requesting the device status from Astarte each time. Signed-off-by: Emina Muminovic <emina.muminovic@secomind.com>
1 parent c09e7de commit 2e081ee

File tree

6 files changed

+364
-9
lines changed

6 files changed

+364
-9
lines changed

backend/lib/edgehog/devices/device/changes/initialize_from_device_status.ex

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#
22
# This file is part of Edgehog.
33
#
4-
# Copyright 2024 SECO Mind Srl
4+
# Copyright 2024 - 2025 SECO Mind Srl
55
#
66
# Licensed under the Apache License, Version 2.0 (the "License");
77
# you may not use this file except in compliance with the License.
@@ -22,7 +22,7 @@ defmodule Edgehog.Devices.Device.Changes.InitializeFromDeviceStatus do
2222
@moduledoc false
2323
use Ash.Resource.Change
2424

25-
@device_status_attributes [:last_connection, :last_disconnection, :online]
25+
@device_status_attributes [:last_connection, :last_disconnection, :online, :last_seen_ip]
2626

2727
@impl Ash.Resource.Change
2828
def change(changeset, _opts, _context) do

backend/lib/edgehog/devices/device/device.ex

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,8 @@ defmodule Edgehog.Devices.Device do
8585
:online,
8686
:realm_id,
8787
:last_connection,
88-
:last_disconnection
88+
:last_disconnection,
89+
:last_seen_ip
8990
]
9091
end
9192

@@ -281,7 +282,7 @@ defmodule Edgehog.Devices.Device do
281282
end
282283

283284
update :from_device_status do
284-
accept [:online, :last_connection, :last_disconnection]
285+
accept [:online, :last_connection, :last_disconnection, :last_seen_ip]
285286
end
286287

287288
update :set_led_behavior do
@@ -428,6 +429,11 @@ defmodule Edgehog.Devices.Device do
428429
description "The date at which the device last disconnected from Astarte."
429430
end
430431

432+
attribute :last_seen_ip, :string do
433+
public? true
434+
description "The IP address at which the device last connected to Astarte."
435+
end
436+
431437
attribute :serial_number, :string do
432438
public? true
433439
description "The serial number of the device."

backend/lib/edgehog/geolocation/providers/ipbase.ex

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#
22
# This file is part of Edgehog.
33
#
4-
# Copyright 2021-2024 SECO Mind Srl
4+
# Copyright 2021 - 2025 SECO Mind Srl
55
#
66
# Licensed under the Apache License, Version 2.0 (the "License");
77
# you may not use this file except in compliance with the License.
@@ -27,16 +27,16 @@ defmodule Edgehog.Geolocation.Providers.IPBase do
2727
alias Edgehog.EdgehogTeslaClient
2828
alias Edgehog.Geolocation.Position
2929

30+
@device_status_attributes [:last_connection, :last_disconnection, :last_seen_ip]
31+
3032
@impl Edgehog.Geolocation.GeolocationProvider
3133
def geolocate(%Device{} = device) do
32-
with {:ok, device} <- Ash.load(device, :device_status),
33-
:ok <- validate_device_status_exists(device.device_status) do
34+
with {:ok, device_status} <- fetch_device_status(device) do
3435
%{
3536
last_seen_ip: last_seen_ip,
3637
last_connection: last_connection,
3738
last_disconnection: last_disconnection
38-
} =
39-
device.device_status
39+
} = device_status
4040

4141
last_seen_timestamp =
4242
[last_connection, last_disconnection]
@@ -48,6 +48,26 @@ defmodule Edgehog.Geolocation.Providers.IPBase do
4848
end
4949
end
5050

51+
defp fetch_device_status(%Device{} = device) do
52+
if uninitialized_device_status?(device) do
53+
with {:ok, device_data} <- Ash.load(device, :device_status),
54+
:ok <- validate_device_status_exists(device_data.device_status) do
55+
{:ok, device_data.device_status}
56+
end
57+
else
58+
{:ok,
59+
%{
60+
last_seen_ip: device.last_seen_ip,
61+
last_connection: device.last_connection,
62+
last_disconnection: device.last_disconnection
63+
}}
64+
end
65+
end
66+
67+
defp uninitialized_device_status?(device) do
68+
Enum.any?(@device_status_attributes, &(Map.get(device, &1) == nil))
69+
end
70+
5171
defp validate_device_status_exists(nil), do: {:error, :device_status_not_found}
5272
defp validate_device_status_exists(_), do: :ok
5373

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#
2+
# This file is part of Edgehog.
3+
#
4+
# Copyright 2025 SECO Mind Srl
5+
#
6+
# Licensed under the Apache License, Version 2.0 (the "License");
7+
# you may not use this file except in compliance with the License.
8+
# You may obtain a copy of the License at
9+
#
10+
# http://www.apache.org/licenses/LICENSE-2.0
11+
#
12+
# Unless required by applicable law or agreed to in writing, software
13+
# distributed under the License is distributed on an "AS IS" BASIS,
14+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
# See the License for the specific language governing permissions and
16+
# limitations under the License.
17+
#
18+
# SPDX-License-Identifier: Apache-2.0
19+
#
20+
21+
defmodule Edgehog.Repo.Migrations.AddLastSeenIpToDevice do
22+
@moduledoc """
23+
Updates resources based on their most recent snapshots.
24+
25+
This file was autogenerated with `mix ash_postgres.generate_migrations`
26+
"""
27+
28+
use Ecto.Migration
29+
30+
def up do
31+
alter table(:devices) do
32+
add :last_seen_ip, :text
33+
end
34+
end
35+
36+
def down do
37+
alter table(:devices) do
38+
remove :last_seen_ip
39+
end
40+
end
41+
end

0 commit comments

Comments
 (0)