Skip to content

Support AWS IoT #146

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

Merged
merged 12 commits into from
Feb 28, 2025
Merged
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),

### Added

- Support for AWS IoT.

### Changed

### Deprecated
Expand Down
61 changes: 57 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,12 @@ Binaries are available on [GitHub](https://github.com/TheThingsNetwork/lorawan-s
## Support

- [x] The Things Network Stack V2
- [x] [ChirpStack Network Server v4](https://www.chirpstack.io/)
- [x] [ChirpStack Network Server v3](https://www.chirpstack.io/docs/v3-documentation.html) (only versions `v0.11.x`).
- [x] [ChirpStack Network Server v4](https://www.chirpstack.io/)
- [x] [The Things Stack](https://www.github.com/TheThingsNetwork/lorawan-stack/)
- [x] [Firefly](https://fireflyiot.com/)
- [x] [Wanesy](https://www.kerlink.com/)
- [x] [AWS IoT](https://aws.amazon.com/iot-core/)
- [ ] [LORIOT Network Server](https://www.loriot.io/)

Support for different sources is done by creating Source plugins. List available sources with:
Expand Down Expand Up @@ -192,7 +194,7 @@ $ export CHIRPSTACK_API_URL="localhost:8080" # ChirpStack Application Server
$ export CHIRPSTACK_API_KEY="eyJ0eX........" # Generate from ChirpStack GUI
$ export JOIN_EUI="0101010102020203" # JoinEUI for exported devices
$ export FREQUENCY_PLAN_ID="EU_863_870" # Frequency Plan for exported devices
$ export CHIRPSTACK_EXPORT_SESSION="true" # Set to true for session migration.
$ export CHIRPSTACK_EXPORT_SESSION="true" # Set to true for session migration
```

See [Frequency Plans](https://thethingsstack.io/reference/frequency-plans/) for the list of frequency plans available on The Things Stack. For example, to use `United States 902-928 MHz, FSB 1`, you need to specify the `US_902_928_FSB_1` frequency plan ID.
Expand All @@ -211,7 +213,7 @@ See [Frequency Plans](https://thethingsstack.io/reference/frequency-plans/) for

To export a single device using its DevEUI (e.g. `0102030405060708`):

```
```bash
$ ttn-lw-migrate chirpstack device '0102030405060708' > devices.json
```

Expand Down Expand Up @@ -426,9 +428,60 @@ In order to export all devices from the CSV file, use the `application` command.
$ ttn-lw-migrate wanesy application --all
```

## AWS IoT

### Configuration

> Note: `awsiot` source uses the Shared AWS Configuration (~/.aws/config) file. To setup this configuration file please check out the [AWS SDK documentation](https://docs.aws.amazon.com/sdk-for-go/v2/developer-guide/configure-gosdk.html)

Configure with environment variables, or command-line arguments. See `--help` for more details:

```bash
$ export APP_ID="my-app" # Application ID for the exported devices
$ export FREQUENCY_PLAN_ID="EU_863_870" # Frequency Plan ID for the exported devices
```

> Important: AWS IoT does not provide a way to export session information. Therefore OTAA devices needs to rejoin after the import. For ABP devices is not possible to import the session counters (**FCntUp** and **FCntDown**).
> For more details please check the [AWS IoT API documentation](https://docs.aws.amazon.com/iot-wireless/2020-11-22/apireference/API_GetWirelessDevice.html)

### Notes

- The export process will halt if any error occurs.
- Execute commands with the `--dry-run` flag to verify whether the outcome will be as expected.

### Export Device

To export a single device using its Device ID (e.g. `f198fd57-e52d-49fd-bcec-5b5494748469`):

```bash
# dry run first, verify that no errors occur
$ ttn-lw-migrate awsiot device 'f198fd57-e52d-49fd-bcec-5b5494748469' --dry-run --verbose > devices.json
# export device
$ ttn-lw-migrate awsiot device 'f198fd57-e52d-49fd-bcec-5b5494748469' > devices.json
```

In order to export a large number of devices, create a file named `device_ids.txt` with one device ID per line:

```
f198fd57-e52d-49fd-bcec-5b5494748469
3b4c29ea-6c2f-4d2a-a2b4-494a6c0fc33b
393306e1-73f8-42c5-b593-21eb64a3bf0b
bed4284c-ebaf-4a34-970b-2ff1d0008daf
c5b08612-af8b-41cf-80fa-da3d861ed81c
```

And then export with:

```bash
# dry run first, verify that no errors occur
$ ttn-lw-migrate awsiot device --dry-run --verbose < device_ids.txt > devices.json
# export devices
$ ttn-lw-migrate awsiot device < device_ids.txt > devices.json
```

## Development Environment

Requires Go version 1.16 or higher. [Download Go](https://golang.org/dl/).
Requires Go version 1.23 or higher. [Download Go](https://golang.org/dl/).

### Building from source

Expand Down
30 changes: 30 additions & 0 deletions cmd/awsiot/awsiot.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Copyright © 2024 The Things Network Foundation, The Things Industries B.V.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package awsiot

import (
"go.thethings.network/lorawan-stack-migrate/pkg/commands"
_ "go.thethings.network/lorawan-stack-migrate/pkg/source/awsiot"
)

const sourceName = "awsiot"

// Command represents the awsiot source.
var Command = commands.Source(sourceName,
"Export devices from AWS IoT",
commands.WithSourceOptions(
commands.WithAliases([]string{"aws-iot"}),
),
)
6 changes: 3 additions & 3 deletions cmd/chirpstack/chirpstack.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright © 2023 The Things Network Foundation, The Things Industries B.V.
// Copyright © 2024 The Things Network Foundation, The Things Industries B.V.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand All @@ -21,8 +21,8 @@ import (

const sourceName = "chirpstack"

// ChirpStackCmd represents the chirpstack source.
var ChirpStackCmd = commands.Source(sourceName,
// Command represents the chirpstack source.
var Command = commands.Source(sourceName,
"Export devices from ChirpStack v4",
commands.WithDevicesOptions(
commands.WithShort("Export devices by DevEUI"),
Expand Down
6 changes: 3 additions & 3 deletions cmd/firefly/firefly.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright © 2023 The Things Network Foundation, The Things Industries B.V.
// Copyright © 2024 The Things Network Foundation, The Things Industries B.V.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand All @@ -21,7 +21,7 @@ import (

const sourceName = "firefly"

// FireflyCmd represents the firefly source.
var FireflyCmd = commands.Source(sourceName,
// Command represents the firefly source.
var Command = commands.Source(sourceName,
"Export devices from Digimondo's Firefly",
)
16 changes: 10 additions & 6 deletions cmd/root.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright © 2023 The Things Network Foundation, The Things Industries B.V.
// Copyright © 2024 The Things Network Foundation, The Things Industries B.V.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand All @@ -19,6 +19,7 @@ import (
"os"

"github.com/spf13/cobra"
"go.thethings.network/lorawan-stack-migrate/cmd/awsiot"
"go.thethings.network/lorawan-stack-migrate/cmd/chirpstack"
"go.thethings.network/lorawan-stack-migrate/cmd/firefly"
"go.thethings.network/lorawan-stack-migrate/cmd/ttnv2"
Expand Down Expand Up @@ -78,9 +79,12 @@ func init() {
Title: "Sources:",
})

rootCmd.AddCommand(ttnv2.TTNv2Cmd)
rootCmd.AddCommand(tts.TTSCmd)
rootCmd.AddCommand(chirpstack.ChirpStackCmd)
rootCmd.AddCommand(firefly.FireflyCmd)
rootCmd.AddCommand(wanesy.WanesyCmd)
rootCmd.AddCommand(
awsiot.Command,
chirpstack.Command,
firefly.Command,
ttnv2.Command,
tts.Command,
wanesy.Command,
)
}
6 changes: 3 additions & 3 deletions cmd/ttnv2/ttnv2.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright © 2023 The Things Network Foundation, The Things Industries B.V.
// Copyright © 2024 The Things Network Foundation, The Things Industries B.V.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand All @@ -21,5 +21,5 @@ import (

const sourceName = "ttnv2"

// TTNv2Cmd represents the ttnv2 source.
var TTNv2Cmd = commands.Source(sourceName, "Export devices from TTN V2")
// Command represents the ttnv2 source.
var Command = commands.Source(sourceName, "Export devices from TTN V2")
6 changes: 3 additions & 3 deletions cmd/tts/tts.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright © 2023 The Things Network Foundation, The Things Industries B.V.
// Copyright © 2024 The Things Network Foundation, The Things Industries B.V.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand All @@ -21,8 +21,8 @@ import (

const sourceName = "tts"

// TTSCmd represents the tts source.
var TTSCmd = commands.Source(sourceName,
// Command represents the tts source.
var Command = commands.Source(sourceName,
"Export devices from The Things Stack",
commands.WithSourceOptions(
commands.WithAliases([]string{"ttnv3"}),
Expand Down
6 changes: 3 additions & 3 deletions cmd/wanesy/wanesy.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright © 2023 The Things Network Foundation, The Things Industries B.V.
// Copyright © 2024 The Things Network Foundation, The Things Industries B.V.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand All @@ -21,7 +21,7 @@ import (

const sourceName = "wanesy"

// WanesyCmd represents the Wanesy source.
var WanesyCmd = commands.Source(sourceName,
// Command represents the Wanesy source.
var Command = commands.Source(sourceName,
"Migrate from Wanesy Management Center",
)
14 changes: 14 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ require (
github.com/TheThingsNetwork/go-utils v0.0.0-20200807125606-b3493662e4bf
github.com/TheThingsNetwork/ttn/core/types v0.0.0-20190516112328-fcd38e2b9dc6
github.com/apex/log v1.9.0
github.com/aws/aws-sdk-go-v2 v1.32.5
github.com/aws/aws-sdk-go-v2/config v1.28.5
github.com/aws/aws-sdk-go-v2/service/iotwireless v1.44.2
github.com/chirpstack/chirpstack/api/go/v4 v4.11.0
github.com/mdempsky/unconvert v0.0.0-20230125054757-2661c2c99a9b
github.com/mgechev/revive v1.6.0
Expand All @@ -30,6 +33,17 @@ require (
github.com/TheThingsNetwork/ttn/utils/errors v0.0.0-20190516081709-034d40b328bd // indirect
github.com/TheThingsNetwork/ttn/utils/random v0.0.0-20190516092602-86414c703ee1 // indirect
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d // indirect
github.com/aws/aws-sdk-go-v2/credentials v1.17.46 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.20 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.24 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.24 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.1 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.5 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.24.6 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.5 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.33.1 // indirect
github.com/aws/smithy-go v1.22.1 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/blang/semver v3.5.1+incompatible // indirect
github.com/brocaar/lorawan v0.0.0-20170626123636-a64aca28516d // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,8 @@ github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.5 h1:wtpJ4zcwr
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.5/go.mod h1:qu/W9HXQbbQ4+1+JcZp0ZNPV31ym537ZJN+fiS7Ti8E=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.5 h1:P1doBzv5VEg1ONxnJss1Kh5ZG/ewoIE4MQtKKc6Crgg=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.5/go.mod h1:NOP+euMW7W3Ukt28tAxPuoWao4rhhqJD3QEBk7oCg7w=
github.com/aws/aws-sdk-go-v2/service/iotwireless v1.44.2 h1:AkocH6/PAgUwsi5CfCSj/d0iDCrUP+2pRqO7iXvBvDg=
github.com/aws/aws-sdk-go-v2/service/iotwireless v1.44.2/go.mod h1:wOgnKZTgxWdzeIp4I50HcsI6d+Ir2YVgSf5qK36jTIU=
github.com/aws/aws-sdk-go-v2/service/s3 v1.69.0 h1:Q2ax8S21clKOnHhhr933xm3JxdJebql+R7aNo7p7GBQ=
github.com/aws/aws-sdk-go-v2/service/s3 v1.69.0/go.mod h1:ralv4XawHjEMaHOWnTFushl0WRqim/gQWesAMF6hTow=
github.com/aws/aws-sdk-go-v2/service/sso v1.24.6 h1:3zu537oLmsPfDMyjnUS2g+F2vITgy5pB74tHI+JBNoM=
Expand Down
31 changes: 31 additions & 0 deletions pkg/source/awsiot/awsiot.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Copyright © 2025 The Things Network Foundation, The Things Industries B.V.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package awsiot

import (
"go.thethings.network/lorawan-stack-migrate/pkg/source"
"go.thethings.network/lorawan-stack-migrate/pkg/source/awsiot/config"
)

func init() {
cfg := config.New()

source.RegisterSource(source.Registration{
Name: "awsiot",
Description: "Migrate from AWS IoT",
FlagSet: cfg.Flags(),
Create: createNewSource(cfg),
})
}
Loading
Loading