diff --git a/.github/workflows/update-firmware-releases-list.yml b/.github/workflows/update-firmware-releases-list.yml new file mode 100644 index 000000000..6ba6f28f6 --- /dev/null +++ b/.github/workflows/update-firmware-releases-list.yml @@ -0,0 +1,75 @@ +name: Update Firmware Releases List + +on: + schedule: + - cron: '0 * * * *' # Run every hour + workflow_dispatch: # Allow manual triggering + +jobs: + update-hardware-list: + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: '22' + + - name: Fetch latest firmware releases data + id: fetch-data + run: | + # Define variables for file paths + firmware_releases_json="app/src/main/assets/firmware_releases.json" + new_firmware_releases_json="/tmp/new_firmware_releases.json" + + # Fetch data from API + curl -s --fail https://api.meshtastic.org/github/firmware/list > "$new_firmware_releases_json" + + # Ensure the output is valid JSON + if ! jq empty "$new_firmware_releases_json" 2>/dev/null; then + echo "::error::API returned invalid JSON data" + exit 1 + fi + + # Check if "$firmware_releases_json" exists + if [ -f "$firmware_releases_json" ]; then + # Format both files for consistent comparison + jq --sort-keys . "$new_firmware_releases_json" > /tmp/new-formatted.json + jq --sort-keys . "$firmware_releases_json" > /tmp/existing-formatted.json + + # Compare files + if cmp -s /tmp/new-formatted.json /tmp/existing-formatted.json; then + echo "No changes detected in hardware list" + echo "has_changes=false" >> $GITHUB_OUTPUT + else + echo "Changes detected in hardware list" + echo "has_changes=true" >> $GITHUB_OUTPUT + fi + else + echo "firmware_releases.json doesn't exist yet" + echo "has_changes=true" >> $GITHUB_OUTPUT + fi + + # Copy new data to destination + cp "$new_firmware_releases_json" "$firmware_releases_json" + + - name: Create Pull Request + if: steps.fetch-data.outputs.has_changes == 'true' + uses: peter-evans/create-pull-request@v7 + with: + token: ${{ secrets.GITHUB_TOKEN }} + commit-message: "chore: update firmware releases list from Meshtastic API" + title: "chore: update firmware releases list from Meshtastic API" + body: | + This PR updates the firmware releases list with the latest data from the Meshtastic API. + + This PR was automatically generated by the update-hardware-list workflow. + branch: update-hardware-list + base: master + delete-branch: true diff --git a/app/build.gradle b/app/build.gradle index 062f12e65..d82a0b93a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -144,7 +144,7 @@ androidComponents { } dependencies { - + implementation project(":network") implementation(fileTree(dir: 'libs', include: ['*.jar'])) // Bundles @@ -159,6 +159,7 @@ dependencies { implementation(libs.bundles.hilt) implementation(libs.bundles.protobuf) implementation(libs.bundles.coil) + //OSM implementation(libs.bundles.osm) implementation(libs.osmdroid.geopackage){ exclude group: "com.j256.ormlite" } diff --git a/app/schemas/com.geeksville.mesh.database.MeshtasticDatabase/17.json b/app/schemas/com.geeksville.mesh.database.MeshtasticDatabase/17.json new file mode 100644 index 000000000..447a3b6ca --- /dev/null +++ b/app/schemas/com.geeksville.mesh.database.MeshtasticDatabase/17.json @@ -0,0 +1,695 @@ +{ + "formatVersion": 1, + "database": { + "version": 17, + "identityHash": "6f25f17fe4f83769489c264d4dae0398", + "entities": [ + { + "tableName": "my_node", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`myNodeNum` INTEGER NOT NULL, `model` TEXT, `firmwareVersion` TEXT, `couldUpdate` INTEGER NOT NULL, `shouldUpdate` INTEGER NOT NULL, `currentPacketId` INTEGER NOT NULL, `messageTimeoutMsec` INTEGER NOT NULL, `minAppVersion` INTEGER NOT NULL, `maxChannels` INTEGER NOT NULL, `hasWifi` INTEGER NOT NULL, `deviceId` TEXT, PRIMARY KEY(`myNodeNum`))", + "fields": [ + { + "fieldPath": "myNodeNum", + "columnName": "myNodeNum", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "model", + "columnName": "model", + "affinity": "TEXT" + }, + { + "fieldPath": "firmwareVersion", + "columnName": "firmwareVersion", + "affinity": "TEXT" + }, + { + "fieldPath": "couldUpdate", + "columnName": "couldUpdate", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "shouldUpdate", + "columnName": "shouldUpdate", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "currentPacketId", + "columnName": "currentPacketId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "messageTimeoutMsec", + "columnName": "messageTimeoutMsec", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "minAppVersion", + "columnName": "minAppVersion", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "maxChannels", + "columnName": "maxChannels", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "hasWifi", + "columnName": "hasWifi", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "deviceId", + "columnName": "deviceId", + "affinity": "TEXT" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "myNodeNum" + ] + } + }, + { + "tableName": "nodes", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`num` INTEGER NOT NULL, `user` BLOB NOT NULL, `long_name` TEXT, `short_name` TEXT, `position` BLOB NOT NULL, `latitude` REAL NOT NULL, `longitude` REAL NOT NULL, `snr` REAL NOT NULL, `rssi` INTEGER NOT NULL, `last_heard` INTEGER NOT NULL, `device_metrics` BLOB NOT NULL, `channel` INTEGER NOT NULL, `via_mqtt` INTEGER NOT NULL, `hops_away` INTEGER NOT NULL, `is_favorite` INTEGER NOT NULL, `is_ignored` INTEGER NOT NULL DEFAULT 0, `environment_metrics` BLOB NOT NULL, `power_metrics` BLOB NOT NULL, `paxcounter` BLOB NOT NULL, PRIMARY KEY(`num`))", + "fields": [ + { + "fieldPath": "num", + "columnName": "num", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "user", + "columnName": "user", + "affinity": "BLOB", + "notNull": true + }, + { + "fieldPath": "longName", + "columnName": "long_name", + "affinity": "TEXT" + }, + { + "fieldPath": "shortName", + "columnName": "short_name", + "affinity": "TEXT" + }, + { + "fieldPath": "position", + "columnName": "position", + "affinity": "BLOB", + "notNull": true + }, + { + "fieldPath": "latitude", + "columnName": "latitude", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "longitude", + "columnName": "longitude", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "snr", + "columnName": "snr", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "rssi", + "columnName": "rssi", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "lastHeard", + "columnName": "last_heard", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "deviceTelemetry", + "columnName": "device_metrics", + "affinity": "BLOB", + "notNull": true + }, + { + "fieldPath": "channel", + "columnName": "channel", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "viaMqtt", + "columnName": "via_mqtt", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "hopsAway", + "columnName": "hops_away", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isFavorite", + "columnName": "is_favorite", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isIgnored", + "columnName": "is_ignored", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + }, + { + "fieldPath": "environmentTelemetry", + "columnName": "environment_metrics", + "affinity": "BLOB", + "notNull": true + }, + { + "fieldPath": "powerTelemetry", + "columnName": "power_metrics", + "affinity": "BLOB", + "notNull": true + }, + { + "fieldPath": "paxcounter", + "columnName": "paxcounter", + "affinity": "BLOB", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "num" + ] + } + }, + { + "tableName": "packet", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uuid` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `myNodeNum` INTEGER NOT NULL DEFAULT 0, `port_num` INTEGER NOT NULL, `contact_key` TEXT NOT NULL, `received_time` INTEGER NOT NULL, `read` INTEGER NOT NULL DEFAULT 1, `data` TEXT NOT NULL, `packet_id` INTEGER NOT NULL DEFAULT 0, `routing_error` INTEGER NOT NULL DEFAULT -1, `reply_id` INTEGER NOT NULL DEFAULT 0)", + "fields": [ + { + "fieldPath": "uuid", + "columnName": "uuid", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "myNodeNum", + "columnName": "myNodeNum", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + }, + { + "fieldPath": "port_num", + "columnName": "port_num", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "contact_key", + "columnName": "contact_key", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "received_time", + "columnName": "received_time", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "read", + "columnName": "read", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "1" + }, + { + "fieldPath": "data", + "columnName": "data", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "packetId", + "columnName": "packet_id", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + }, + { + "fieldPath": "routingError", + "columnName": "routing_error", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "-1" + }, + { + "fieldPath": "replyId", + "columnName": "reply_id", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "uuid" + ] + }, + "indices": [ + { + "name": "index_packet_myNodeNum", + "unique": false, + "columnNames": [ + "myNodeNum" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_packet_myNodeNum` ON `${TABLE_NAME}` (`myNodeNum`)" + }, + { + "name": "index_packet_port_num", + "unique": false, + "columnNames": [ + "port_num" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_packet_port_num` ON `${TABLE_NAME}` (`port_num`)" + }, + { + "name": "index_packet_contact_key", + "unique": false, + "columnNames": [ + "contact_key" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_packet_contact_key` ON `${TABLE_NAME}` (`contact_key`)" + } + ] + }, + { + "tableName": "contact_settings", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`contact_key` TEXT NOT NULL, `muteUntil` INTEGER NOT NULL, PRIMARY KEY(`contact_key`))", + "fields": [ + { + "fieldPath": "contact_key", + "columnName": "contact_key", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "muteUntil", + "columnName": "muteUntil", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "contact_key" + ] + } + }, + { + "tableName": "log", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uuid` TEXT NOT NULL, `type` TEXT NOT NULL, `received_date` INTEGER NOT NULL, `message` TEXT NOT NULL, `from_num` INTEGER NOT NULL DEFAULT 0, `port_num` INTEGER NOT NULL DEFAULT 0, `from_radio` BLOB NOT NULL DEFAULT x'', PRIMARY KEY(`uuid`))", + "fields": [ + { + "fieldPath": "uuid", + "columnName": "uuid", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "message_type", + "columnName": "type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "received_date", + "columnName": "received_date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "raw_message", + "columnName": "message", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "fromNum", + "columnName": "from_num", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + }, + { + "fieldPath": "portNum", + "columnName": "port_num", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + }, + { + "fieldPath": "fromRadio", + "columnName": "from_radio", + "affinity": "BLOB", + "notNull": true, + "defaultValue": "x''" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "uuid" + ] + }, + "indices": [ + { + "name": "index_log_from_num", + "unique": false, + "columnNames": [ + "from_num" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_log_from_num` ON `${TABLE_NAME}` (`from_num`)" + }, + { + "name": "index_log_port_num", + "unique": false, + "columnNames": [ + "port_num" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_log_port_num` ON `${TABLE_NAME}` (`port_num`)" + } + ] + }, + { + "tableName": "quick_chat", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uuid` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT NOT NULL, `message` TEXT NOT NULL, `mode` TEXT NOT NULL, `position` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "uuid", + "columnName": "uuid", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "message", + "columnName": "message", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "mode", + "columnName": "mode", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "position", + "columnName": "position", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "uuid" + ] + } + }, + { + "tableName": "reactions", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`reply_id` INTEGER NOT NULL, `user_id` TEXT NOT NULL, `emoji` TEXT NOT NULL, `timestamp` INTEGER NOT NULL, PRIMARY KEY(`reply_id`, `user_id`, `emoji`))", + "fields": [ + { + "fieldPath": "replyId", + "columnName": "reply_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "userId", + "columnName": "user_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "emoji", + "columnName": "emoji", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "timestamp", + "columnName": "timestamp", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "reply_id", + "user_id", + "emoji" + ] + }, + "indices": [ + { + "name": "index_reactions_reply_id", + "unique": false, + "columnNames": [ + "reply_id" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_reactions_reply_id` ON `${TABLE_NAME}` (`reply_id`)" + } + ] + }, + { + "tableName": "metadata", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`num` INTEGER NOT NULL, `proto` BLOB NOT NULL, `timestamp` INTEGER NOT NULL, PRIMARY KEY(`num`))", + "fields": [ + { + "fieldPath": "num", + "columnName": "num", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "proto", + "columnName": "proto", + "affinity": "BLOB", + "notNull": true + }, + { + "fieldPath": "timestamp", + "columnName": "timestamp", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "num" + ] + }, + "indices": [ + { + "name": "index_metadata_num", + "unique": false, + "columnNames": [ + "num" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_metadata_num` ON `${TABLE_NAME}` (`num`)" + } + ] + }, + { + "tableName": "device_hardware", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`actively_supported` INTEGER NOT NULL, `architecture` TEXT NOT NULL, `display_name` TEXT NOT NULL, `has_ink_hud` INTEGER, `has_mui` INTEGER, `hwModel` INTEGER NOT NULL, `hw_model_slug` TEXT NOT NULL, `images` TEXT, `last_updated` INTEGER NOT NULL, `partition_scheme` TEXT, `platformio_target` TEXT NOT NULL, `requires_dfu` INTEGER, `support_level` INTEGER, `tags` TEXT, PRIMARY KEY(`hwModel`))", + "fields": [ + { + "fieldPath": "activelySupported", + "columnName": "actively_supported", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "architecture", + "columnName": "architecture", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "displayName", + "columnName": "display_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "hasInkHud", + "columnName": "has_ink_hud", + "affinity": "INTEGER" + }, + { + "fieldPath": "hasMui", + "columnName": "has_mui", + "affinity": "INTEGER" + }, + { + "fieldPath": "hwModel", + "columnName": "hwModel", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "hwModelSlug", + "columnName": "hw_model_slug", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "images", + "columnName": "images", + "affinity": "TEXT" + }, + { + "fieldPath": "lastUpdated", + "columnName": "last_updated", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "partitionScheme", + "columnName": "partition_scheme", + "affinity": "TEXT" + }, + { + "fieldPath": "platformioTarget", + "columnName": "platformio_target", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "requiresDfu", + "columnName": "requires_dfu", + "affinity": "INTEGER" + }, + { + "fieldPath": "supportLevel", + "columnName": "support_level", + "affinity": "INTEGER" + }, + { + "fieldPath": "tags", + "columnName": "tags", + "affinity": "TEXT" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "hwModel" + ] + } + }, + { + "tableName": "firmware_release", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `page_url` TEXT NOT NULL, `release_notes` TEXT NOT NULL, `title` TEXT NOT NULL, `zip_url` TEXT NOT NULL, `last_updated` INTEGER NOT NULL, `release_type` TEXT NOT NULL, PRIMARY KEY(`id`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "pageUrl", + "columnName": "page_url", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "releaseNotes", + "columnName": "release_notes", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "title", + "columnName": "title", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "zipUrl", + "columnName": "zip_url", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "lastUpdated", + "columnName": "last_updated", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "releaseType", + "columnName": "release_type", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id" + ] + } + } + ], + "setupQueries": [ + "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '6f25f17fe4f83769489c264d4dae0398')" + ] + } +} \ No newline at end of file diff --git a/app/src/main/assets/device_hardware/diy.svg b/app/src/main/assets/device_hardware/diy.svg deleted file mode 100644 index 823467edf..000000000 --- a/app/src/main/assets/device_hardware/diy.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/src/main/assets/device_hardware/heltec-ht62-esp32c3-sx1262.svg b/app/src/main/assets/device_hardware/heltec-ht62-esp32c3-sx1262.svg deleted file mode 100644 index c52534efd..000000000 --- a/app/src/main/assets/device_hardware/heltec-ht62-esp32c3-sx1262.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/src/main/assets/device_hardware/heltec-mesh-node-t114-case.svg b/app/src/main/assets/device_hardware/heltec-mesh-node-t114-case.svg deleted file mode 100644 index b2abe6392..000000000 --- a/app/src/main/assets/device_hardware/heltec-mesh-node-t114-case.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/src/main/assets/device_hardware/heltec-mesh-node-t114.svg b/app/src/main/assets/device_hardware/heltec-mesh-node-t114.svg deleted file mode 100644 index 779a8f6a6..000000000 --- a/app/src/main/assets/device_hardware/heltec-mesh-node-t114.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/src/main/assets/device_hardware/heltec-v3-case.svg b/app/src/main/assets/device_hardware/heltec-v3-case.svg deleted file mode 100644 index 1b1d3c55f..000000000 --- a/app/src/main/assets/device_hardware/heltec-v3-case.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/src/main/assets/device_hardware/heltec-v3.svg b/app/src/main/assets/device_hardware/heltec-v3.svg deleted file mode 100644 index 13a5fa645..000000000 --- a/app/src/main/assets/device_hardware/heltec-v3.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/src/main/assets/device_hardware/heltec-vision-master-e213.svg b/app/src/main/assets/device_hardware/heltec-vision-master-e213.svg deleted file mode 100644 index 2c1cca095..000000000 --- a/app/src/main/assets/device_hardware/heltec-vision-master-e213.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/src/main/assets/device_hardware/heltec-vision-master-e290.svg b/app/src/main/assets/device_hardware/heltec-vision-master-e290.svg deleted file mode 100644 index ca7d296af..000000000 --- a/app/src/main/assets/device_hardware/heltec-vision-master-e290.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/src/main/assets/device_hardware/heltec-vision-master-t190.svg b/app/src/main/assets/device_hardware/heltec-vision-master-t190.svg deleted file mode 100644 index 55db34f9b..000000000 --- a/app/src/main/assets/device_hardware/heltec-vision-master-t190.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/src/main/assets/device_hardware/heltec-wireless-paper-V1_0.svg b/app/src/main/assets/device_hardware/heltec-wireless-paper-V1_0.svg deleted file mode 100644 index cb3f188d8..000000000 --- a/app/src/main/assets/device_hardware/heltec-wireless-paper-V1_0.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/app/src/main/assets/device_hardware/heltec-wireless-paper.svg b/app/src/main/assets/device_hardware/heltec-wireless-paper.svg deleted file mode 100644 index cb3f188d8..000000000 --- a/app/src/main/assets/device_hardware/heltec-wireless-paper.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/app/src/main/assets/device_hardware/heltec-wireless-tracker-V1-0.svg b/app/src/main/assets/device_hardware/heltec-wireless-tracker-V1-0.svg deleted file mode 100644 index a5392595d..000000000 --- a/app/src/main/assets/device_hardware/heltec-wireless-tracker-V1-0.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/src/main/assets/device_hardware/heltec-wireless-tracker.svg b/app/src/main/assets/device_hardware/heltec-wireless-tracker.svg deleted file mode 100644 index a5392595d..000000000 --- a/app/src/main/assets/device_hardware/heltec-wireless-tracker.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/src/main/assets/device_hardware/heltec-wsl-v3.svg b/app/src/main/assets/device_hardware/heltec-wsl-v3.svg deleted file mode 100644 index 1741223eb..000000000 --- a/app/src/main/assets/device_hardware/heltec-wsl-v3.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/src/main/assets/device_hardware/nano-g2-ultra.svg b/app/src/main/assets/device_hardware/nano-g2-ultra.svg deleted file mode 100644 index 6dbe47afb..000000000 --- a/app/src/main/assets/device_hardware/nano-g2-ultra.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/src/main/assets/device_hardware/pico.svg b/app/src/main/assets/device_hardware/pico.svg deleted file mode 100644 index 82ce65261..000000000 --- a/app/src/main/assets/device_hardware/pico.svg +++ /dev/null @@ -1,2956 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/assets/device_hardware/promicro.svg b/app/src/main/assets/device_hardware/promicro.svg deleted file mode 100644 index 3dc26021b..000000000 --- a/app/src/main/assets/device_hardware/promicro.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/src/main/assets/device_hardware/rak-wismeshtap.svg b/app/src/main/assets/device_hardware/rak-wismeshtap.svg deleted file mode 100644 index 34e77876a..000000000 --- a/app/src/main/assets/device_hardware/rak-wismeshtap.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/src/main/assets/device_hardware/rak11200.svg b/app/src/main/assets/device_hardware/rak11200.svg deleted file mode 100644 index cac91a24a..000000000 --- a/app/src/main/assets/device_hardware/rak11200.svg +++ /dev/null @@ -1,5374 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - R15 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/assets/device_hardware/rak11310.svg b/app/src/main/assets/device_hardware/rak11310.svg deleted file mode 100644 index 8f526a471..000000000 --- a/app/src/main/assets/device_hardware/rak11310.svg +++ /dev/null @@ -1,2339 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/assets/device_hardware/rak2560.svg b/app/src/main/assets/device_hardware/rak2560.svg deleted file mode 100644 index b8514f016..000000000 --- a/app/src/main/assets/device_hardware/rak2560.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/src/main/assets/device_hardware/rak4631.svg b/app/src/main/assets/device_hardware/rak4631.svg deleted file mode 100644 index 6dc2957a2..000000000 --- a/app/src/main/assets/device_hardware/rak4631.svg +++ /dev/null @@ -1,3514 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/assets/device_hardware/rak4631_case.svg b/app/src/main/assets/device_hardware/rak4631_case.svg deleted file mode 100644 index a0b2bbb82..000000000 --- a/app/src/main/assets/device_hardware/rak4631_case.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/src/main/assets/device_hardware/rpipicow.svg b/app/src/main/assets/device_hardware/rpipicow.svg deleted file mode 100644 index cb4b1f68b..000000000 --- a/app/src/main/assets/device_hardware/rpipicow.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/src/main/assets/device_hardware/seeed-sensecap-indicator.svg b/app/src/main/assets/device_hardware/seeed-sensecap-indicator.svg deleted file mode 100644 index f7bf9db02..000000000 --- a/app/src/main/assets/device_hardware/seeed-sensecap-indicator.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/src/main/assets/device_hardware/seeed-xiao-s3.svg b/app/src/main/assets/device_hardware/seeed-xiao-s3.svg deleted file mode 100644 index 04e97fe00..000000000 --- a/app/src/main/assets/device_hardware/seeed-xiao-s3.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/src/main/assets/device_hardware/seeed_xiao_nrf52_kit.svg b/app/src/main/assets/device_hardware/seeed_xiao_nrf52_kit.svg deleted file mode 100644 index 95f7211ba..000000000 --- a/app/src/main/assets/device_hardware/seeed_xiao_nrf52_kit.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/src/main/assets/device_hardware/station-g2.svg b/app/src/main/assets/device_hardware/station-g2.svg deleted file mode 100644 index 8d2e0aed2..000000000 --- a/app/src/main/assets/device_hardware/station-g2.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/src/main/assets/device_hardware/t-deck.svg b/app/src/main/assets/device_hardware/t-deck.svg deleted file mode 100644 index cdc53c5d3..000000000 --- a/app/src/main/assets/device_hardware/t-deck.svg +++ /dev/null @@ -1 +0,0 @@ -QWERTYIUPOASDFGHKJLaltZXCVBMN \ No newline at end of file diff --git a/app/src/main/assets/device_hardware/t-echo.svg b/app/src/main/assets/device_hardware/t-echo.svg deleted file mode 100644 index e178a50f4..000000000 --- a/app/src/main/assets/device_hardware/t-echo.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/src/main/assets/device_hardware/t-watch-s3.svg b/app/src/main/assets/device_hardware/t-watch-s3.svg deleted file mode 100644 index 19084c197..000000000 --- a/app/src/main/assets/device_hardware/t-watch-s3.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/src/main/assets/device_hardware/tbeam-s3-core.svg b/app/src/main/assets/device_hardware/tbeam-s3-core.svg deleted file mode 100644 index f42e6d2cc..000000000 --- a/app/src/main/assets/device_hardware/tbeam-s3-core.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/src/main/assets/device_hardware/tbeam.svg b/app/src/main/assets/device_hardware/tbeam.svg deleted file mode 100644 index cd0475c6d..000000000 --- a/app/src/main/assets/device_hardware/tbeam.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/src/main/assets/device_hardware/thinknode_m1.svg b/app/src/main/assets/device_hardware/thinknode_m1.svg deleted file mode 100644 index 27e21a0bf..000000000 --- a/app/src/main/assets/device_hardware/thinknode_m1.svg +++ /dev/null @@ -1,109 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/assets/device_hardware/thinknode_m2.svg b/app/src/main/assets/device_hardware/thinknode_m2.svg deleted file mode 100644 index 5e5a0e3cd..000000000 --- a/app/src/main/assets/device_hardware/thinknode_m2.svg +++ /dev/null @@ -1,391 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/assets/device_hardware/tlora-c6.svg b/app/src/main/assets/device_hardware/tlora-c6.svg deleted file mode 100644 index 8b6266387..000000000 --- a/app/src/main/assets/device_hardware/tlora-c6.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/src/main/assets/device_hardware/tlora-t3s3-epaper.svg b/app/src/main/assets/device_hardware/tlora-t3s3-epaper.svg deleted file mode 100644 index 6f2e84520..000000000 --- a/app/src/main/assets/device_hardware/tlora-t3s3-epaper.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/src/main/assets/device_hardware/tlora-t3s3-v1.svg b/app/src/main/assets/device_hardware/tlora-t3s3-v1.svg deleted file mode 100644 index 1f8847d44..000000000 --- a/app/src/main/assets/device_hardware/tlora-t3s3-v1.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/src/main/assets/device_hardware/tlora-v2-1-1_6.svg b/app/src/main/assets/device_hardware/tlora-v2-1-1_6.svg deleted file mode 100644 index dbe36ef5e..000000000 --- a/app/src/main/assets/device_hardware/tlora-v2-1-1_6.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/src/main/assets/device_hardware/tlora-v2-1-1_8.svg b/app/src/main/assets/device_hardware/tlora-v2-1-1_8.svg deleted file mode 100644 index dbe36ef5e..000000000 --- a/app/src/main/assets/device_hardware/tlora-v2-1-1_8.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/src/main/assets/device_hardware/tracker-t1000-e.svg b/app/src/main/assets/device_hardware/tracker-t1000-e.svg deleted file mode 100644 index 6f7a06c96..000000000 --- a/app/src/main/assets/device_hardware/tracker-t1000-e.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/src/main/assets/device_hardware/unknown.svg b/app/src/main/assets/device_hardware/unknown.svg deleted file mode 100644 index 1d2cd87b7..000000000 --- a/app/src/main/assets/device_hardware/unknown.svg +++ /dev/null @@ -1,160 +0,0 @@ - - diff --git a/app/src/main/assets/device_hardware/wio-tracker-wm1110.svg b/app/src/main/assets/device_hardware/wio-tracker-wm1110.svg deleted file mode 100644 index 15ace5c5f..000000000 --- a/app/src/main/assets/device_hardware/wio-tracker-wm1110.svg +++ /dev/null @@ -1 +0,0 @@ -LoRaWI FILEDRESETGNSSBLE \ No newline at end of file diff --git a/app/src/main/assets/device_hardware/wm1110_dev_kit.svg b/app/src/main/assets/device_hardware/wm1110_dev_kit.svg deleted file mode 100644 index 94aefe308..000000000 --- a/app/src/main/assets/device_hardware/wm1110_dev_kit.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/app/src/main/assets/firmware_releases.json b/app/src/main/assets/firmware_releases.json new file mode 100644 index 000000000..9169f422b --- /dev/null +++ b/app/src/main/assets/firmware_releases.json @@ -0,0 +1,198 @@ +{ + "releases": { + "stable": [ + { + "id": "v2.6.4.b89355f", + "title": "Meshtastic Firmware 2.6.4.b89355f Beta", + "page_url": "https://github.com/meshtastic/firmware/releases/tag/v2.6.4.b89355f", + "zip_url": "https://github.com/meshtastic/firmware/releases/download/v2.6.4.b89355f/firmware-stm32-2.6.4.b89355f.zip", + "release_notes": "\u003E [!CAUTION] \r\n\u003E Updating from a previous version of firmware to 2.6, **will wipe** your device. Please remember to [backup your keys](https://meshtastic.org/docs/configuration/radio/security/#security-keys---backup-and-restore) and important [configurations](https://meshtastic.org/docs/software/python/cli/usage/#export-device-config-with---export-config) before proceeding!\r\n\r\n\u003E [!WARNING] \r\nFor Seeed Sensecap Indicator devices _stuck_ in bluetooth pairing mode, we recommend doing a full erase / flash.\r\n\r\n## ⚠️ Known issues:\r\nLegacy ESP32 devices such as T-LoRA V2 1.6 may experience more crashes on Wifi. This should be fixed in 2.6.5.\r\nT-Echos may start with backlight on by default. Fixed in 2.6.5\r\n\r\n## 🚀 Enhancements\r\n* CrowPanel e-Ink Updates for 4.2 and 2.9 inch by @markbirss in https://github.com/meshtastic/firmware/pull/6401\r\n* Update lora-Adafruit-RFM9x by @markbirss in https://github.com/meshtastic/firmware/pull/6402\r\n* Add Thinknode-M1 by @caveman99 in https://github.com/meshtastic/firmware/pull/6435\r\n* Portduino: Return CH341 Product String by @vidplace7 in https://github.com/meshtastic/firmware/pull/6436\r\n* UDP-multicast: error handling support by @Jorropo in https://github.com/meshtastic/firmware/pull/6433\r\n* Add ThinkNode M2 Support by @caveman99 in https://github.com/meshtastic/firmware/pull/6354\r\n* Try-fix ESP32 wifi disconnects by @thebentern in https://github.com/meshtastic/firmware/pull/6363\r\n* MUI: node list \u003C-\u003E map navigation by @mverch67 in https://github.com/meshtastic/firmware/pull/6456\r\n\r\n## 🐛 Bug fixes and maintenance\r\n* Fix: T-Watch-S3 has 8MB Flash by @vidplace7 in https://github.com/meshtastic/firmware/pull/6407\r\n* Fix USERPREFS_EVENT_MODE compile error by @vidplace7 in https://github.com/meshtastic/firmware/pull/6408\r\n* Add missing board definition for MESHLINK by @macvenez in https://github.com/meshtastic/firmware/pull/6404\r\n* FIX: SenseCAP Indicator sporadic touch crash by @mverch67 in https://github.com/meshtastic/firmware/pull/6432\r\n* Revert \"TCA8418 initial config + basic 3x4 keypad config\" by @thebentern in https://github.com/meshtastic/firmware/pull/6410\r\n* Speed up builds by referencing github zips for shallow checkouts by @caveman99 in https://github.com/meshtastic/firmware/pull/6441\r\n* Fix a couple of warnings by @caveman99 in https://github.com/meshtastic/firmware/pull/6445\r\n* Fix Bold and Inverted Displays to actually show Uptime by @Xaositek in https://github.com/meshtastic/firmware/pull/6413\r\n* Fix STM32 build by @thebentern in https://github.com/meshtastic/firmware/pull/6455\r\n\r\n\r\n**Full Changelog**: https://github.com/meshtastic/firmware/compare/v2.6.3.640e731...v2.6.4.b89355f" + }, + { + "id": "v2.5.20.4c97351", + "title": "Meshtastic Firmware 2.5.20.4c97351 Beta", + "page_url": "https://github.com/meshtastic/firmware/releases/tag/v2.5.20.4c97351", + "zip_url": "https://github.com/meshtastic/firmware/releases/download/v2.5.20.4c97351/firmware-stm32-2.5.20.4c97351.zip", + "release_notes": "\u003E [!IMPORTANT] \r\n\u003E Linux packages have been migrated from GitHub Releases to distro-specific build services.\r\n\u003E For additional information see: [Installing meshtasticd](https://meshtastic.org/docs/hardware/devices/linux-native-hardware/#installing-meshtasticd)\r\n\r\n## ⚠️ Known issues \r\n* We are cautiously optimistic that many of the intrinsic file system (LittleFS) issues on NRF52 based devices and instability should be resolved in this release. A [full flash erase](https://meshtastic.org/docs/getting-started/flashing-firmware/nrf52/nrf52-erase/) may be required if you are experiencing LFS assert issues.\r\n* Bluetooth was inadvertently disabled for T-Deck and T-Watch devices, preventing pairing with client apps. This issue will be resolved in the next alpha release after 2.5.21.\r\n\r\n## 🚀 Enhancements\r\n* Canned messages: allow GPIO0 with \"scan and select\" input by @todd-herbert in https://github.com/meshtastic/firmware/pull/5838\r\n* COPR: Switch from hook to `copr_cli` by @vidplace7 in https://github.com/meshtastic/firmware/pull/5864\r\n* Initiate magnetometer based compass calibration from button presses by @danwelch3 in https://github.com/meshtastic/firmware/pull/5553\r\n* Slight rework of CH341 HAL by @psiegl in https://github.com/meshtastic/firmware/pull/5848\r\n* Alert app messages should be treated as text by @thebentern in https://github.com/meshtastic/firmware/pull/5878\r\n* COPR: Switch to forked GitHub Action by @vidplace7 in https://github.com/meshtastic/firmware/pull/5871\r\n* Initial commit of a fuzzer for Meshtastic by @esev in https://github.com/meshtastic/firmware/pull/5790\r\n* Build docker images with other linux release channels by @vidplace7 in https://github.com/meshtastic/firmware/pull/5837\r\n* No focus on new messages if auto-carousel is off by @isseysandei in https://github.com/meshtastic/firmware/pull/5881\r\n* Create BananaPi-BPI-R4-sx1262.yaml by @markbirss in https://github.com/meshtastic/firmware/pull/5897\r\n* Update RAK2560 code by @caveman99 in https://github.com/meshtastic/firmware/pull/5844\r\n* Docker: tag intermediate containers by @vidplace7 in https://github.com/meshtastic/firmware/pull/5910\r\n* Debian: Switch OBS repo to `network:Meshtastic` by @vidplace7 in https://github.com/meshtastic/firmware/pull/5912\r\n* Docker: Switch tags to newline-seperated by @vidplace7 in https://github.com/meshtastic/firmware/pull/5919\r\n\r\n## 🐛 Bug fixes and maintenance\r\n\r\n* Changed GPS buad rate to 9600 by @SignalMedic in https://github.com/meshtastic/firmware/pull/5786\r\n* Fixed localization on bigger screens by @kyberpunk in https://github.com/meshtastic/firmware/pull/5695\r\n* Small fix: Reference COPR group correctly (with `@`) by @vidplace7 in https://github.com/meshtastic/firmware/pull/5872\r\n* Fix detection of lark weather station and add rain sensor by @caveman99 in https://github.com/meshtastic/firmware/pull/5874\r\n* Reboot before formatting LittleFS by @esev in https://github.com/meshtastic/firmware/pull/5900\r\n* Fix possible memory leak for `ROUTER_LATE` by @GUVWAF in https://github.com/meshtastic/firmware/pull/5901\r\n* Move OpenWRT configs to subdir by @vidplace7 in https://github.com/meshtastic/firmware/pull/5902\r\n* Add quotes around ${platformio.build_dir} to avoid invalid paths by @esev in https://github.com/meshtastic/firmware/pull/5906\r\n* NRF52 - Remove file totally before opening write by @thebentern in https://github.com/meshtastic/firmware/pull/5916\r\n* Peg NRF52 arduino to meshtastic fork with LFS bluetooth fix by @thebentern in https://github.com/meshtastic/firmware/pull/5924\r\n* TFT Cherrypick: WiFi.persistent(false) by @fifieldt in https://github.com/meshtastic/firmware/pull/5925\r\n\r\n## New Contributors\r\n* @danwelch3 made their first contribution in https://github.com/meshtastic/firmware/pull/5553\r\n* @SignalMedic made their first contribution in https://github.com/meshtastic/firmware/pull/5786\r\n\r\n**Full Changelog**: https://github.com/meshtastic/firmware/compare/v2.5.19.f9876cf...v2.5.20.4c97351" + }, + { + "id": "v2.5.18.89ebafc", + "title": "Meshtastic Firmware 2.5.18.89ebafc Beta", + "page_url": "https://github.com/meshtastic/firmware/releases/tag/v2.5.18.89ebafc", + "zip_url": "https://github.com/meshtastic/firmware/releases/download/v2.5.18.89ebafc/firmware-stm32-2.5.18.89ebafc.zip", + "release_notes": "## ⚠️ Known issues \r\n* The new `ROUTER_LATE` role has some known issues with delaying rebroadcasts beyond the desired window. It is recommended to avoid this role on this release version.\r\n* For NRF52 devices, there are additional fixes for filesystem corruption available in 2.5.20 onwards. If you have an NRF52-based device we recommend you select a later release.\r\n\r\n## 🚀 Enhancements\r\n* Synchronize test workflow packages with native by @esev in https://github.com/meshtastic/firmware/pull/5664\r\n* More accurately determine if MQTT uses the default server by @esev in https://github.com/meshtastic/firmware/pull/5663\r\n* Generate a coverage report for End to end tests by @esev in https://github.com/meshtastic/firmware/pull/5667\r\n* Include log messages in unit tests by @esev in https://github.com/meshtastic/firmware/pull/5666\r\n* Add czech oled localization by @kyberpunk in https://github.com/meshtastic/firmware/pull/5661\r\n* Meshtasticd-docker: simplify, add USB compose by @vidplace7 in https://github.com/meshtastic/firmware/pull/5662\r\n* Alpine Docker image (musl CI target) by @vidplace7 in https://github.com/meshtastic/firmware/pull/5659\r\n* Cherry-pick: device-ui persistency by @fifieldt in https://github.com/meshtastic/firmware/pull/5570\r\n* Add packet length to printPacket() by @jp-bennett in https://github.com/meshtastic/firmware/pull/5672\r\n* Enable the autoconf settings for MPR121 based keyboards by @aussieklutz in https://github.com/meshtastic/firmware/pull/5680\r\n\r\n## 🐛 Bug fixes & maintenance\r\n* Unset received SNR/RSSI values upon receiving packet via MQTT by @GUVWAF in https://github.com/meshtastic/firmware/pull/5668\r\n* Fix for nrf52 lfs assert boot loop by @tavdog in https://github.com/meshtastic/firmware/pull/5670\r\n* Remove remaining \\n from log lines. by @fifieldt in https://github.com/meshtastic/firmware/pull/5675\r\n* TFT branch - minor cherry picks by @fifieldt in https://github.com/meshtastic/firmware/pull/5676\r\n* Cherry-pick: Mesh-tab by @fifieldt in https://github.com/meshtastic/firmware/pull/5674\r\n* Fix RP2040 crash issue #5665. by @Mictronics in https://github.com/meshtastic/firmware/pull/5678\r\n* Exclude health telemetry by macro by @thebentern in https://github.com/meshtastic/firmware/pull/5679\r\n* Add new ROUTER_LATE role by @erayd in https://github.com/meshtastic/firmware/pull/5528\r\n* More meshtab cherry-pick by @fifieldt in https://github.com/meshtastic/firmware/pull/5681\r\n* TFT branch synch grab-bag by @fifieldt in https://github.com/meshtastic/firmware/pull/5683\r\n* Minor TFT branch cherry-picks by @fifieldt in https://github.com/meshtastic/firmware/pull/5682\r\n\r\n## New Contributors\r\n* @kyberpunk made their first contribution in https://github.com/meshtastic/firmware/pull/5661\r\n* @erayd made their first contribution in https://github.com/meshtastic/firmware/pull/5528\r\n\r\n**Full Changelog**: https://github.com/meshtastic/firmware/compare/v2.5.17.b4b2fd6...v2.5.18.89ebafc" + }, + { + "id": "v2.5.15.79da236", + "title": "Meshtastic Firmware 2.5.15.79da236 Beta", + "page_url": "https://github.com/meshtastic/firmware/releases/tag/v2.5.15.79da236", + "zip_url": "https://github.com/meshtastic/firmware/releases/download/v2.5.15.79da236/firmware-esp32c3-2.5.15.79da236.zip", + "release_notes": "## 🚀 Enhancements\r\n* Support for the ClimateGuard RadSens Geiger-Muller tube by @jake-b in https://github.com/meshtastic/firmware/pull/5425\r\n* Enable MQTT with TLS on RPi picow by @tomasdubec in https://github.com/meshtastic/firmware/pull/5442\r\n* Don't powersave on Wifi by @thebentern in https://github.com/meshtastic/firmware/pull/5443\r\n\r\n\r\n## 🐛 Bug fixes and maintenance\r\n* Fixes https://github.com/meshtastic/firmware/issues/5434 by @caveman99 in https://github.com/meshtastic/firmware/pull/5435\r\n* Fix memory leaks by adding missing `free()` calls before early returns in `MQTT::onReceive` by @CTassisF in https://github.com/meshtastic/firmware/pull/5439\r\n* Clean up some inline functions by @thebentern in https://github.com/meshtastic/firmware/pull/5454\r\n* Use isWithinTimespanMs to avoid refererence to NodeDb instance inside of NodeDb by @thebentern in https://github.com/meshtastic/firmware/pull/5453\r\n* Fixes CORS for meshtasticd to allow use of clients on other origins by @liamcottle in https://github.com/meshtastic/firmware/pull/5463\r\n* Remove ATECC crypto chip placeholder code by @thebentern in https://github.com/meshtastic/firmware/pull/5461\r\n* GPS.h cleanups round 3. by @charlieh0tel in https://github.com/meshtastic/firmware/pull/5447\r\n* Fix ukrainian fonts by @panaceya in https://github.com/meshtastic/firmware/pull/5468\r\n* Disable lightsleep for indicator by @Wvirgil123 in https://github.com/meshtastic/firmware/pull/5470\r\n* Warnings and log cleanup by @thebentern in https://github.com/meshtastic/firmware/pull/5472\r\n* Revert \"Seems like the last DIY board that's not \"extra\"\" by @thebentern in https://github.com/meshtastic/firmware/pull/5446\r\n* Removing 1.0 legacy boards from releases and completely removing Heltec wireless capsule from support by @thebentern in https://github.com/meshtastic/firmware/pull/5436\r\n* A second round of cleanup on GPS.h by @charlieh0tel in https://github.com/meshtastic/firmware/pull/5433\r\n* Actually gunzip all the files when building a .deb by @jp-bennett in https://github.com/meshtastic/firmware/pull/5449\r\n* Cleanup i2c scan logs and macro to save some bytes and remain consistent by @thebentern in https://github.com/meshtastic/firmware/pull/5455\r\n\r\n## New Contributors\r\n* @jake-b made their first contribution in https://github.com/meshtastic/firmware/pull/5425\r\n* @CTassisF made their first contribution in https://github.com/meshtastic/firmware/pull/5439\r\n* @tomasdubec made their first contribution in https://github.com/meshtastic/firmware/pull/5442\r\n* @liamcottle made their first contribution in https://github.com/meshtastic/firmware/pull/5463\r\n\r\n**Full Changelog**: https://github.com/meshtastic/firmware/compare/v2.5.14.f2ee0df...v2.5.15.79da236" + }, + { + "id": "v2.5.14.f2ee0df", + "title": "Meshtastic Firmware 2.5.14.f2ee0df Beta", + "page_url": "https://github.com/meshtastic/firmware/releases/tag/v2.5.14.f2ee0df", + "zip_url": "https://github.com/meshtastic/firmware/releases/download/v2.5.14.f2ee0df/firmware-stm32-2.5.14.f2ee0df.zip", + "release_notes": "\u003E [!IMPORTANT] \r\n\u003E When we initially released the 2.5 version of the firmware, [we added a new bit `OkToMqtt` to packets to express the intent of users to opt-in to their packets being uplinked to an MQTT broker](https://meshtastic.org/docs/configuration/radio/lora/#ok-to-mqtt\r\n). \r\n\u003E\r\n\u003EPrior to this, uplinking of packets was just implicit fact, which was not fair to users wishing to remain off of any public brokers, maps, etc. However, in order to not immediately begin dumping all of the traffic from previous firmware versions from going to MQTT, we allowed for a grace period to transition folks to the newer 2.5.X firmware, where they can now opt-in, or remain off (by default). This grace period has concluded. The firmware will now enforce that the `OkToMqtt` bit is both present and opted into before uplinking any packets to MQTT. \r\n\r\n## 🚀 Enhancements \r\n* Minimize time between channel scan and actual transmit by @GUVWAF in https://github.com/meshtastic/firmware/pull/5383\r\n* Allows all 3 PKI keys to be added to userPrefs.h (#4969) and a tool. by @gjelsoe in https://github.com/meshtastic/firmware/pull/5368\r\n* Check for OkToMqtt flag presence before uplinking to MQTT by @thebentern in https://github.com/meshtastic/firmware/pull/5413\r\n* Telemetry can respond to want-response for LocalStats variant by @thebentern in https://github.com/meshtastic/firmware/pull/5414\r\n* Add canned message and keyboard in indicator board by @Dylanliacc in https://github.com/meshtastic/firmware/pull/5410\r\n* Add smiley emoji by @jcyrio in https://github.com/meshtastic/firmware/pull/5391\r\n* Enable trace route function on rak wismeshtap platform by @DanielCao0 in https://github.com/meshtastic/firmware/pull/5389\r\n* Add GPS in indicator board by @Dylanliacc in https://github.com/meshtastic/firmware/pull/5411\r\n* /api/v1/fromradio: add OPTIONS handler for CORS. by @cpatulea in https://github.com/meshtastic/firmware/pull/5386\r\n* Create a specific hw_model for WisMesh Tap by @thebentern in https://github.com/meshtastic/firmware/pull/5400\r\n\r\n## 🐛 Bug fixes and maintenance\r\n* Make heart emoji usable by @jcyrio in https://github.com/meshtastic/firmware/pull/5403\r\n* Fix RTC time injection and consolidate position logic by @thebentern in https://github.com/meshtastic/firmware/pull/5396\r\n* Update arduino-pico core to fix sporadic hangs by @GUVWAF in https://github.com/meshtastic/firmware/pull/5406\r\n* Update platform-raspberrypi also by @GUVWAF in https://github.com/meshtastic/firmware/pull/5407\r\n* --web added to device-install(.sh/.bat) by @gjelsoe in https://github.com/meshtastic/firmware/pull/5405\r\n* Fixed NMEA sentence issue in CalTopo as well as bug with no printing all of the nodes by @thebentern in https://github.com/meshtastic/firmware/pull/5412\r\n* --web littlefswebui-* typo fix by @gjelsoe in https://github.com/meshtastic/firmware/pull/5416\r\n* Temporarily disable MDNS when MQTT is enabled on RP2040 by @GUVWAF in https://github.com/meshtastic/firmware/pull/5418\r\n* Seems like the last DIY board that's not \"extra\" by @jp-bennett in https://github.com/meshtastic/firmware/pull/5420\r\n* Cherry pick tdeck fixes by @thebentern in https://github.com/meshtastic/firmware/pull/5422\r\n* Update build-native.sh by @madeofstown in https://github.com/meshtastic/firmware/pull/5415\r\n* Cleans up visibility in GPS.h by @charlieh0tel in https://github.com/meshtastic/firmware/pull/5426\r\n* Fix admin key loading from userPrefs.h by @Mictronics in https://github.com/meshtastic/firmware/pull/5417\r\n* Try to detect dfrobot station to tell it apart from an ublox gps. by @caveman99 in https://github.com/meshtastic/firmware/pull/5393\r\n* Remove BMA-423 and STK8X by default by @thebentern in https://github.com/meshtastic/firmware/pull/5429\r\n\r\n## New Contributors\r\n* @cpatulea made their first contribution in https://github.com/meshtastic/firmware/pull/5386\r\n\r\n**Full Changelog**: https://github.com/meshtastic/firmware/compare/v2.5.13.1a06f88...v2.5.14.f2ee0df" + }, + { + "id": "v2.5.13.1a06f88", + "title": "Meshtastic Firmware 2.5.13.1a06f88 Beta", + "page_url": "https://github.com/meshtastic/firmware/releases/tag/v2.5.13.1a06f88", + "zip_url": "https://github.com/meshtastic/firmware/releases/download/v2.5.13.1a06f88/firmware-esp32c6-2.5.13.1a06f88.zip", + "release_notes": "\u003E [!WARNING]\r\n\u003E ### We are making the Web UI on ESP32 optional going forward: [the full details](https://github.com/meshtastic/firmware/discussions/5381).\r\n\u003E This is a re-cut release of 2.5.13. If you performed an erase and install of `2.5.13.295278b` on an ESP32 based device and experienced panic and reboot on saving to the filesystem, performing a fresh install of this release should resolve the issue.\r\n\r\n## 🚀 Enhancements\r\n* Add setting to transmit NeighborInfo over LoRa by @GUVWAF in https://github.com/meshtastic/firmware/pull/5286\r\n* Fix non-primary channel usage for non-PKC packets by @GUVWAF in https://github.com/meshtastic/firmware/pull/5287\r\n* Remove scary warning about full NodeDB by @fifieldt in https://github.com/meshtastic/firmware/pull/5292\r\n* Pin library versions in platform.io by @jp-bennett in https://github.com/meshtastic/firmware/pull/5293\r\n* Update dependency versions by @fifieldt in https://github.com/meshtastic/firmware/pull/5299\r\n* Exclude some niche modules by default and populate exclude_modules by @thebentern in https://github.com/meshtastic/firmware/pull/5300\r\n* Rak10701 (rak wismeshtap) optimization by @DanielCao0 in https://github.com/meshtastic/firmware/pull/5280\r\n* Coerce minimum neighborinfo interval on startup by @thebentern in https://github.com/meshtastic/firmware/pull/5314\r\n* Add back some details to the PhoneAPI logs by @thebentern in https://github.com/meshtastic/firmware/pull/5313\r\n* Radiolib update by @caveman99 in https://github.com/meshtastic/firmware/pull/5246\r\n* Fix sending duplicate packets to PhoneAPI/MQTT by @GUVWAF in https://github.com/meshtastic/firmware/pull/5315\r\n* Don't send to public channel by @gjelsoe in https://github.com/meshtastic/firmware/pull/5310\r\n* Portduino packaging: Move meshtastic/web out of `/usr/share/doc` by @vidplace7 in https://github.com/meshtastic/firmware/pull/5323\r\n* Reduce the flash usage of wismeshtap platform by @DanielCao0 in https://github.com/meshtastic/firmware/pull/5322\r\n* Add support for ignoring nodes with `is_ignored` field in NodeInfo by @mdesmedt in https://github.com/meshtastic/firmware/pull/5319\r\n* RP2040: Update core; add mDNS support by @GUVWAF in https://github.com/meshtastic/firmware/pull/5355\r\n\r\n## 🐛 Bug fixes\r\n* Fix memory leak in MQTT by @GUVWAF in https://github.com/meshtastic/firmware/pull/5311\r\n* Don't attempt to save NodeDB on low-batt shutdown to prevent FS corruption by @thebentern in https://github.com/meshtastic/firmware/pull/5312\r\n* Fix syntax error with package builds by @fifieldt in https://github.com/meshtastic/firmware/pull/5302\r\n* Package file move - include dotfiles by @fifieldt in https://github.com/meshtastic/firmware/pull/5303\r\n* Fix another heap leak by @GUVWAF in https://github.com/meshtastic/firmware/pull/5328\r\n* Handle repeated packet after potentially canceling previous Tx by @GUVWAF in https://github.com/meshtastic/firmware/pull/5330\r\n* Read voltage during init fixes #5276 by @Blake-Latchford in https://github.com/meshtastic/firmware/pull/5332\r\n* Only allow 30 seconds minimum for power.on_battery_shutdown_after_secs by @thebentern in https://github.com/meshtastic/firmware/pull/5337\r\n* Decrease max nodes for NRF52 to 80 as workaround to prevent FS blowouts by @thebentern in https://github.com/meshtastic/firmware/pull/5338\r\n* Revert \"Decrease max nodes for NRF52 to 80 as workaround to prevent FS blowouts\" by @thebentern in https://github.com/meshtastic/firmware/pull/5340\r\n* Remove log spam when reading INA sensor. by @Mictronics in https://github.com/meshtastic/firmware/pull/5345\r\n* Migrate NRF52 devices max nodes down to 80 for now to prevent file system blowouts by @thebentern in https://github.com/meshtastic/firmware/pull/5346\r\n* Adds fixed GPS, BUTTON_PIN and BLE code to userPrefs.h by @gjelsoe in https://github.com/meshtastic/firmware/pull/5341\r\n* Add sudo to apt-get commands for Raspbian Build by @fifieldt in https://github.com/meshtastic/firmware/pull/5364\r\n* Typo fix in build_raspbian.yml by @fifieldt in https://github.com/meshtastic/firmware/pull/5365\r\n* Bug fixed in ExternalNotificationModule by @gjelsoe in https://github.com/meshtastic/firmware/pull/5375\r\n* Cleanup static files from bad Web UI bundle on 2.5.13 release by @thebentern in https://github.com/meshtastic/firmware/pull/5376\r\n\r\n## New Contributors\r\n* @mdesmedt made their first contribution in https://github.com/meshtastic/firmware/pull/5319\r\n* @Blake-Latchford made their first contribution in https://github.com/meshtastic/firmware/pull/5332\r\n\r\n**Full Changelog**: https://github.com/meshtastic/firmware/compare/v2.5.12.aa184e6...v2.5.13.1a06f88" + }, + { + "id": "v2.5.11.8e2a3e5", + "title": "Meshtastic Firmware 2.5.11.8e2a3e5 Beta", + "page_url": "https://github.com/meshtastic/firmware/releases/tag/v2.5.11.8e2a3e5", + "zip_url": "https://github.com/meshtastic/firmware/releases/download/v2.5.11.8e2a3e5/firmware-stm32-2.5.11.8e2a3e5.zip", + "release_notes": "## ⚠️ Known issues \r\n* In some cases, connected apps may show duplicate received packets. This issue will be fixed in version 2.5.13.\r\n\r\n## 🚀 Enhancements \r\n* PIO_ENV by @caveman99 in https://github.com/meshtastic/firmware/pull/5239\r\n* Spell check all Code by @Technologyman00 in https://github.com/meshtastic/firmware/pull/5228\r\n* Improve ACK logic for responses and repeated packets by @GUVWAF in https://github.com/meshtastic/firmware/pull/5232\r\n* Musl compatibility by @vidplace7 in https://github.com/meshtastic/firmware/pull/5219\r\n* Disable automatic NodeInfo request when NodeDB is full by @GUVWAF in https://github.com/meshtastic/firmware/pull/5255\r\n* Exclude preferred routing roles from nodeinfo interrogation behavior by @thebentern in https://github.com/meshtastic/firmware/pull/5242\r\n\r\n## 🐛 Bug fixes and maintenance\r\n* Fix displays showing \"GPS Not Present\" until first lock by @fifieldt in https://github.com/meshtastic/firmware/pull/5229\r\n* LR1110 - remove old comment referring to non-existent function. by @fifieldt in https://github.com/meshtastic/firmware/pull/5233\r\n* Log cleanups by @fifieldt in https://github.com/meshtastic/firmware/pull/5135\r\n* Fix cppcheck HIGH error by @fifieldt in https://github.com/meshtastic/firmware/pull/5250\r\n* More configs by @jp-bennett in https://github.com/meshtastic/firmware/pull/5253\r\n* Pass#2: Lots more savings in logs and string reduction surgery by @thebentern in https://github.com/meshtastic/firmware/pull/5251\r\n* Release no-LoRa packet after sending to phone by @GUVWAF in https://github.com/meshtastic/firmware/pull/5254\r\n* More reduction by @thebentern in https://github.com/meshtastic/firmware/pull/5256\r\n* Fix display of more Unicode symbols by @timo-mart in https://github.com/meshtastic/firmware/pull/5252\r\n\r\n## New Contributors\r\n* @timo-mart made their first contribution in https://github.com/meshtastic/firmware/pull/5252\r\n\r\n**Full Changelog**: https://github.com/meshtastic/firmware/compare/v2.5.10.0fc5c9b...v2.5.11.8e2a3e5" + }, + { + "id": "v2.5.9.936260f", + "title": "Meshtastic Firmware 2.5.9.936260f Beta", + "page_url": "https://github.com/meshtastic/firmware/releases/tag/v2.5.9.936260f", + "zip_url": "https://github.com/meshtastic/firmware/releases/download/v2.5.9.936260f/firmware-stm32-2.5.9.936260f.zip", + "release_notes": "## ⚠️ Known issues \r\n* Enabling NeighborInfo module can cause device crashes #5235\r\n\r\n## 🚀 Enhancements\r\n* Default rebroadcast mode for Router and Repeater to ignore problematic portnums by @thebentern in https://github.com/meshtastic/firmware/pull/5178\r\n* Added PA1616S GPS module by @Megaceryle-alcyon in https://github.com/meshtastic/firmware/pull/5157\r\n* Icarus - Custom PCB by @Babyyoda777 in https://github.com/meshtastic/firmware/pull/5155\r\n* Native config.d by @jp-bennett in https://github.com/meshtastic/firmware/pull/5165\r\n\r\n## 🐛 Bug fixes & maintenance\r\n* Fix missing includes by @mverch67 in https://github.com/meshtastic/firmware/pull/5138\r\n* Update variant.h fix sx1280 power by @markbirss in https://github.com/meshtastic/firmware/pull/5140\r\n* T1000-E Peripherals by @caveman99 in https://github.com/meshtastic/firmware/pull/5141\r\n* Cherry-picks by @jp-bennett in https://github.com/meshtastic/firmware/pull/5166\r\n* Cherry-pick: diy mesh-tab initial files by @fifieldt in https://github.com/meshtastic/firmware/pull/5169\r\n* Cherry-pick: unphone support by @fifieldt in https://github.com/meshtastic/firmware/pull/5174\r\n* Cherry-pick: fix nrf builds by @fifieldt in https://github.com/meshtastic/firmware/pull/5172\r\n* Cherry-pick bin/config-dist.yml from TFT-GUI-Work by @fifieldt in https://github.com/meshtastic/firmware/pull/5168\r\n* Fix long lock-times by @spiffysec in https://github.com/meshtastic/firmware/pull/5160\r\n* De-duplicate Ambient LED management code by @fifieldt in https://github.com/meshtastic/firmware/pull/5156\r\n* De-duplicate log-level determination by @fifieldt in https://github.com/meshtastic/firmware/pull/5148\r\n* Remove unused AXP debug code by @fifieldt in https://github.com/meshtastic/firmware/pull/5149\r\n* Fix tracker build by @caveman99 in https://github.com/meshtastic/firmware/pull/5151\r\n\r\n\r\n## New Contributors\r\n* @Babyyoda777 made their first contribution in https://github.com/meshtastic/firmware/pull/5155\r\n* @spiffysec made their first contribution in https://github.com/meshtastic/firmware/pull/5160\r\n* @Megaceryle-alcyon made their first contribution in https://github.com/meshtastic/firmware/pull/5157\r\n\r\n**Full Changelog**: https://github.com/meshtastic/firmware/compare/v2.5.8.6485f03...v2.5.9.936260f" + }, + { + "id": "v2.5.8.6485f03", + "title": "Meshtastic Firmware 2.5.8.6485f03 Beta", + "page_url": "https://github.com/meshtastic/firmware/releases/tag/v2.5.8.6485f03", + "zip_url": "https://github.com/meshtastic/firmware/releases/download/v2.5.8.6485f03/firmware-stm32-2.5.8.6485f03.zip", + "release_notes": "## ⚠️ Known issues \r\n* Enabling NeighborInfo module can cause device crashes #5235\r\n\r\n## 🚀 Enhancements\r\n* Coerce minimum telemetry interval of 30 minutes on defaults and make new default interval one hour by @thebentern in https://github.com/meshtastic/firmware/pull/5086\r\n* Add buzzer feedback on GPS toggle by @Technologyman00 in https://github.com/meshtastic/firmware/pull/5090\r\n* Add `-p` flag by @madeofstown in https://github.com/meshtastic/firmware/pull/5093\r\n* Initial NODENUM_BROADCAST_NO_LORA implementation with NeighborInfo module by @thebentern in https://github.com/meshtastic/firmware/pull/5087\r\n* Move 115200 baud GNSS probe earlier by @thebentern in https://github.com/meshtastic/firmware/pull/5101\r\n* MPR121 Touch IC Based Keypad Input Module by @aussieklutz in https://github.com/meshtastic/firmware/pull/5103\r\n* Add RFC 3927 IP address space to private IP checks by @rbrtio in https://github.com/meshtastic/firmware/pull/5115\r\n* Update meshtasticd.service by @yNosGR in https://github.com/meshtastic/firmware/pull/5118\r\n* Add Configurable UPLINK_ENABLED and DOWNLINK_ENABLED in userPrefs.h by @panaceya in https://github.com/meshtastic/firmware/pull/5120\r\n* Add device unique id by @thebentern in https://github.com/meshtastic/firmware/pull/5092\r\n* Account for port number in MQTT server by @JohnathonMohr in https://github.com/meshtastic/firmware/pull/5084\r\n\r\n## 🐛 Bug fixes & maintenance\r\n* Revert \"Permanently engage !CTRL\" by @caveman99 in https://github.com/meshtastic/firmware/pull/5095\r\n* Fix GPS_DEBUG output by @fifieldt in https://github.com/meshtastic/firmware/pull/5100\r\n* Wide_Lora uses 12 symbols to be compatible with SX1280 by @caveman99 in https://github.com/meshtastic/firmware/pull/5112\r\n* Fix rebroadcasting encrypted packets when `KNOWN_ONLY`/`LOCAL_ONLY` is used by @GUVWAF in https://github.com/meshtastic/firmware/pull/5109\r\n\r\n\r\n## New Contributors\r\n* @Technologyman00 made their first contribution in https://github.com/meshtastic/firmware/pull/5090\r\n* @madeofstown made their first contribution in https://github.com/meshtastic/firmware/pull/5093\r\n* @aussieklutz made their first contribution in https://github.com/meshtastic/firmware/pull/5103\r\n* @rbrtio made their first contribution in https://github.com/meshtastic/firmware/pull/5115\r\n* @yNosGR made their first contribution in https://github.com/meshtastic/firmware/pull/5118\r\n\r\n**Full Changelog**: https://github.com/meshtastic/firmware/compare/v2.5.7.f77c87d...v2.5.8.6485f03" + }, + { + "id": "v2.5.7.f77c87d", + "title": "Meshtastic Firmware 2.5.7.f77c87d Beta", + "page_url": "https://github.com/meshtastic/firmware/releases/tag/v2.5.7.f77c87d", + "zip_url": "https://github.com/meshtastic/firmware/releases/download/v2.5.7.f77c87d/firmware-stm32-2.5.7.f77c87d.zip", + "release_notes": "## Enhancements\r\n* Remove waypoint and text message frames on NodeDB reset as well by @thebentern in https://github.com/meshtastic/firmware/pull/5029\r\n* Fix SH1107 - Set Geometry 128x128 by @markbirss in https://github.com/meshtastic/firmware/pull/5033\r\n* Implement rebroadcast mode NONE by @thebentern in https://github.com/meshtastic/firmware/pull/5040\r\n* Remove newline from logging statements. by @caveman99 in https://github.com/meshtastic/firmware/pull/5022\r\n* [Board]: Support for M5Stack CoreS3 (Part 1: radio) by @lboue in https://github.com/meshtastic/firmware/pull/5049\r\n* Add in RF95 support to Pro-micro DIY by @Nestpebble in https://github.com/meshtastic/firmware/pull/5055\r\n* Drop oem.proto support in favor of userprefs by @caveman99 in https://github.com/meshtastic/firmware/pull/5061\r\n* Ws85 updates : set want_ack, high_priority, add temperature. by @tavdog in https://github.com/meshtastic/firmware/pull/5052\r\n* Add MQTT exception for private IP address server by @JohnathonMohr in https://github.com/meshtastic/firmware/pull/5072\r\n* Ensure the MQTT address is an IPv4 before determining it's private by @JohnathonMohr in https://github.com/meshtastic/firmware/pull/5081\r\n\r\n## Bug fixes\r\n* Remove waypoint and text message frames on NodeDB reset as well by @thebentern in https://github.com/meshtastic/firmware/pull/5029\r\n* Retain `fixed_position` during reset-nodedb by @andrekir in https://github.com/meshtastic/firmware/pull/5067\r\n* Fix incorrect va_start calls by @jepler in https://github.com/meshtastic/firmware/pull/5076\r\n* Permanently engage !CTRL by @caveman99 in https://github.com/meshtastic/firmware/pull/5036\r\n\r\n\r\n## New Contributors\r\n* @jepler made their first contribution in https://github.com/meshtastic/firmware/pull/5076\r\n* @JohnathonMohr made their first contribution in https://github.com/meshtastic/firmware/pull/5072\r\n\r\n**Full Changelog**: https://github.com/meshtastic/firmware/compare/v2.5.6.d55c08d...v2.5.7.f77c87d" + }, + { + "id": "v2.5.6.d55c08d", + "title": "Meshtastic Firmware 2.5.6.d55c08d Beta", + "page_url": "https://github.com/meshtastic/firmware/releases/tag/v2.5.6.d55c08d", + "zip_url": "https://github.com/meshtastic/firmware/releases/download/v2.5.6.d55c08d/firmware-stm32-2.5.6.d55c08d.zip", + "release_notes": "\u003E [!WARNING]\r\n\u003E This is a re-cut release of 2.5.6. If you performed an erase and install of 2.5.6.ad8747d on an ESP32 based device and experienced boot issues. Performing a fresh install of this release should resolve the issue.\r\n\r\n## Enhancements\r\n* UserPrefs - Preconfigure up to 3 channels, GPS Mode by @medentem in https://github.com/meshtastic/firmware/pull/4930\r\n* Start of generating json manifest of macros in userPrefs.h by @thebentern in https://github.com/meshtastic/firmware/pull/4946\r\n* Coalesce duplicated method GetTimeSinceMeshPacket by @fifieldt in https://github.com/meshtastic/firmware/pull/4968\r\n* Which Module wants a UI Frame? by @fifieldt in https://github.com/meshtastic/firmware/pull/4967\r\n* Upgrade nanopb by @thebentern in https://github.com/meshtastic/firmware/pull/4973\r\n* Add RAK4631 Ethernet Gateway with working JSON output to MQTT by @beegee-tokyo in https://github.com/meshtastic/firmware/pull/4661\r\n* Preliminary Othernet Dreamcatcher Support by @caveman99 in https://github.com/meshtastic/firmware/pull/4933\r\n* Toggle Bluetooth with Fn+b shortcut by @HarukiToreda in https://github.com/meshtastic/firmware/pull/4977\r\n* Add health telemetry module by @fifieldt @thebentern in https://github.com/meshtastic/firmware/pull/4927\r\n* First version of a DeepSleep state for the RP2040 by @TheMalkavien in https://github.com/meshtastic/firmware/pull/4976\r\n* Add frequencies for Philippines by @fifieldt in https://github.com/meshtastic/firmware/pull/4951\r\n* Set TZ config from string if unset by @jp-bennett in https://github.com/meshtastic/firmware/pull/4979\r\n* Switch Environment Telemetry to use UnitConversions by @fifieldt in https://github.com/meshtastic/firmware/pull/4972\r\n\r\n## Bug fixes and maintenance\r\n* Remove unused Jlink monitoring files by @fifieldt in https://github.com/meshtastic/firmware/pull/4953\r\n* Retire PPR Boards by @fifieldt in https://github.com/meshtastic/firmware/pull/4956\r\n* Retire lora-relay boards by @fifieldt in https://github.com/meshtastic/firmware/pull/4957\r\n* Remove support for pca10056-rc-clock by @fifieldt in https://github.com/meshtastic/firmware/pull/4955\r\n* Remove unused headers by @fifieldt in https://github.com/meshtastic/firmware/pull/4954\r\n* Remove has_rx * on installDefaultDeviceState by @thebentern in https://github.com/meshtastic/firmware/pull/4982\r\n* Fix storage of admin key when installing default config. by @Mictronics in https://github.com/meshtastic/firmware/pull/4995\r\n* On T114 do no wake into loader instead of application. by @jhps in https://github.com/meshtastic/firmware/pull/4997\r\n* Ignore packets coming from the broadcast address by @GUVWAF in https://github.com/meshtastic/firmware/pull/4998\r\n* Possibly forward PKC DMs over MQTT by @jp-bennett in https://github.com/meshtastic/firmware/pull/5012\r\n* Fixes critical error rendering before screen thread is running by @thebentern in https://github.com/meshtastic/firmware/pull/5024\r\n* Uplink DMs not to us if MQTT encryption enabled by @GUVWAF in https://github.com/meshtastic/firmware/pull/5025\r\n\r\n## New Contributors\r\n* @medentem made their first contribution in https://github.com/meshtastic/firmware/pull/4930\r\n\r\n**Full Changelog**: https://github.com/meshtastic/firmware/compare/v2.5.5.e182ae7...v2.5.6.d55c08d" + }, + { + "id": "v2.5.5.e182ae7", + "title": "Meshtastic Firmware 2.5.5.e182ae7 Beta", + "page_url": "https://github.com/meshtastic/firmware/releases/tag/v2.5.5.e182ae7", + "zip_url": "https://github.com/meshtastic/firmware/releases/download/v2.5.5.e182ae7/firmware-stm32-2.5.5.e182ae7.zip", + "release_notes": "\u003E [!WARNING]\r\n\u003E This release does not come bundled with the web client interface due to a transient issue with the build pipeline. If that is an important feature for your use case, please consider either grabbing a later release or rolling back to 2.5.4.\r\n\r\n## Enhancements \r\n* Save a couple of bytes by @caveman99 in https://github.com/meshtastic/firmware/pull/4922\r\n* Consolidate and shrink down the re-used strings in logs by @thebentern in https://github.com/meshtastic/firmware/pull/4907\r\n* Userprefs prefix macros for clarity and consistency by @thebentern in https://github.com/meshtastic/firmware/pull/4923\r\n* Add a Userprefs Timezone String, to be replaced in the web flasher by @jp-bennett in https://github.com/meshtastic/firmware/pull/4938\r\n* Add `rxDupe`, `txRelay` and `txRelayCanceled` to LocalStats by @GUVWAF in https://github.com/meshtastic/firmware/pull/4936\r\n* Leave the build epoch commented and uncomment when CI runs by @thebentern in https://github.com/meshtastic/firmware/pull/4943\r\n* Add Panel_ILI9342 to TFTDisplay.cpp by @lboue in https://github.com/meshtastic/firmware/pull/4822\r\n\r\n## Bug fixes\r\n* Enabling Ve pin on T114 by @HarukiToreda in https://github.com/meshtastic/firmware/pull/4940\r\n* CleanupNeighbors() time difference fix by @gitbisector in https://github.com/meshtastic/firmware/pull/4941\r\n* Don't use a static decleration in a header file by @jp-bennett in https://github.com/meshtastic/firmware/pull/4944\r\n* Move ifndef to fix test by @jp-bennett in https://github.com/meshtastic/firmware/pull/4950\r\n* Remove ancient .gitignore lines by @fifieldt in https://github.com/meshtastic/firmware/pull/4952\r\n* Adjust dimensions for Canned Message popup screen by @todd-herbert in https://github.com/meshtastic/firmware/pull/4924\r\n\r\n## New Contributors\r\n* @lboue made their first contribution in https://github.com/meshtastic/firmware/pull/4822\r\n\r\n**Full Changelog**: https://github.com/meshtastic/firmware/compare/v2.5.4.8d288d5...v2.5.5.e182ae7" + }, + { + "id": "v2.5.4.8d288d5", + "title": "Meshtastic Firmware 2.5.4.8d288d5 Beta", + "page_url": "https://github.com/meshtastic/firmware/releases/tag/v2.5.4.8d288d5", + "zip_url": "https://github.com/meshtastic/firmware/releases/download/v2.5.4.8d288d5/firmware-2.5.4.8d288d5.zip", + "release_notes": "## Enhancements\r\n* Comment on PR with build artifacts link by @scruplelesswizard in https://github.com/meshtastic/firmware/pull/4896\r\n* Return queue status on rate limit throttling by @thebentern in https://github.com/meshtastic/firmware/pull/4901\r\n* Get accelerometerThread running from AdminModule. by @gjelsoe in https://github.com/meshtastic/firmware/pull/4886\r\n* Construct StoreForwardModule for Portduino as well by @GUVWAF in https://github.com/meshtastic/firmware/pull/4903\r\n* Update INA3221 to 1.0.1 by @KodinLanewave in https://github.com/meshtastic/firmware/pull/4877\r\n* Update radiolib to 7.0.1 by @caveman99 in https://github.com/meshtastic/firmware/pull/4905\r\n* Allow for better target level Radiolib exclude plumbing by @thebentern in https://github.com/meshtastic/firmware/pull/4906\r\n\r\n## Bug fixes\r\n* Fix: Not being able to stop Ext. Notification nagging for screenless devices by @thebentern in https://github.com/meshtastic/firmware/pull/4899\r\n* When importing config, keep Bluetooth on and defer rebooting until co… by @dahanc in https://github.com/meshtastic/firmware/pull/4898\r\n* Fix duplicate PR comments by @scruplelesswizard in https://github.com/meshtastic/firmware/pull/4908\r\n* Radiolib 7.0.2 by @caveman99 in https://github.com/meshtastic/firmware/pull/4915\r\n* Regenerate public key on boot, to avoid accidental mismatch. by @jp-bennett in https://github.com/meshtastic/firmware/pull/4916\r\n* Fix #4911 : Partially rework some code to remove warnings about potential non-aligned memory accesses by @TheMalkavien in https://github.com/meshtastic/firmware/pull/4912\r\n\r\n**Full Changelog**: https://github.com/meshtastic/firmware/compare/v2.5.3.a70d5ee...v2.5.4.8d288d5" + } + ], + "alpha": [ + { + "id": "v2.6.6.54c1423", + "title": "Meshtastic Firmware 2.6.6.54c1423 Alpha", + "page_url": "https://github.com/meshtastic/firmware/releases/tag/v2.6.6.54c1423", + "zip_url": "https://github.com/meshtastic/firmware/releases/download/v2.6.6.54c1423/firmware-stm32-2.6.6.54c1423.zip", + "release_notes": "## 🚀 Enhancements\r\n* DIY v1/v1_1 add TCXO_OPTIONAL make it so that the firmware can try both TCXO and XTAL by @Andrik45719 in https://github.com/meshtastic/firmware/pull/6534\r\n* InkHUD support for LilyGo T3S3 E-Paper by @todd-herbert in https://github.com/meshtastic/firmware/pull/6503\r\n* Feat: Add Electronic Cats variant for Catsniffer by @JahazielLem in https://github.com/meshtastic/firmware/pull/6483\r\n* Add generic thread module by @tavdog in https://github.com/meshtastic/firmware/pull/5484\r\n* Add Meshtastic Linux desktop metadata by @vidplace7 in https://github.com/meshtastic/firmware/pull/6568\r\n* Add new hardware: Heltec MeshPocket by @Heltec-Aaron-Lee in https://github.com/meshtastic/firmware/pull/6533\r\n* Switch to actually maintained thingsboard pubsubclient by @thebentern in https://github.com/meshtastic/firmware/pull/5204\r\n* Make startup screen show the short ID by @Heltec-Aaron-Lee in https://github.com/meshtastic/firmware/pull/6591\r\n* Update platformio.ini to exclude unused modules from t1000-e by @benkyd in https://github.com/meshtastic/firmware/pull/6584\r\n* Debian: use native-tft compile target by @vidplace7 in https://github.com/meshtastic/firmware/pull/6580\r\n* Create lora-piggystick-lr1121.yaml by @markbirss in https://github.com/meshtastic/firmware/pull/6600\r\n* Add TFT docker builds (for CI) by @vidplace7 in https://github.com/meshtastic/firmware/pull/6614\r\n* FlatHub: bump metainfo.xml on release by @ThatKalle in https://github.com/meshtastic/firmware/pull/6578\r\n\r\n## 🐛 Bug fixes and enhancements\r\n* Fix Ublox GPS for Heltec T114 by @todd-herbert in https://github.com/meshtastic/firmware/pull/6497\r\n* Portduino: Set C standard to 17 by @vidplace7 in https://github.com/meshtastic/firmware/pull/6561\r\n* Fix: Correct underlying cause of T-Watch not functioning when set to a 16MB filesystem by @Kealper in https://github.com/meshtastic/firmware/pull/6563\r\n* Trunk fixes for heltec mesh pocket. by @fifieldt in https://github.com/meshtastic/firmware/pull/6588\r\n* Fix T-Echo display light blink on LoRa TX by @todd-herbert in https://github.com/meshtastic/firmware/pull/6590\r\n* Fix: set upload_speed for tlora_v1_3 & tlora_v2_1_16 by @MayNiklas in https://github.com/meshtastic/firmware/pull/6595\r\n* Fix tlora v1 uploadspeed by @MayNiklas in https://github.com/meshtastic/firmware/pull/6601\r\n* Fix uninitialised memory read (adminModule) by @benkyd in https://github.com/meshtastic/firmware/pull/6605\r\n* Add support for Seeed solar panel by @Dylanliacc in https://github.com/meshtastic/firmware/pull/6597\r\n* Fix compiler error in PowerFSM when WiFi is excluded by @benkyd in https://github.com/meshtastic/firmware/pull/6603\r\n* Crowpanel support by @caveman99 in https://github.com/meshtastic/firmware/pull/6355\r\n* Lib Update by @caveman99 in https://github.com/meshtastic/firmware/pull/6510\r\n* Fix crash when clearing NRF52 BLE bonds by @todd-herbert in https://github.com/meshtastic/firmware/pull/6609\r\n* Docker: Fix arg passthrough by @vidplace7 in https://github.com/meshtastic/firmware/pull/6623\r\n* RPM: Build native-tft target by @vidplace7 in https://github.com/meshtastic/firmware/pull/6613\r\n* Docker alpine: Add config templates by @vidplace7 in https://github.com/meshtastic/firmware/pull/6631\r\n* Appdata.xml: Add date to all releases by @vidplace7 in https://github.com/meshtastic/firmware/pull/6632\r\n* Rak13800 Ethernet works on rak11310 too by @Nivek-domo in https://github.com/meshtastic/firmware/pull/6622\r\n* Build and deploy event firmwares by @vidplace7 in https://github.com/meshtastic/firmware/pull/6628\r\n* Publish firmware all together by @vidplace7 in https://github.com/meshtastic/firmware/pull/6642\r\n* Fix: SenseCAP Indicator: remove buzzer definition by @mverch67 in https://github.com/meshtastic/firmware/pull/6652\r\n* Correct a typing error in InkHUD display driver by @todd-herbert in https://github.com/meshtastic/firmware/pull/6651\r\n* Fix preamble detected IRQ flag by @GUVWAF in https://github.com/meshtastic/firmware/pull/6653\r\n* Update meshtastic-device-ui digest to 189ed6c by @renovate in https://github.com/meshtastic/firmware/pull/6657\r\n* Fix building WiPhone variant by @todd-herbert in https://github.com/meshtastic/firmware/pull/6664\r\n* Downgrade web to 2.5.4 by @vidplace7 in https://github.com/meshtastic/firmware/pull/6669\r\n\r\n## New Contributors\r\n* @renovate made their first contribution in https://github.com/meshtastic/firmware/pull/6545\r\n* @JahazielLem made their first contribution in https://github.com/meshtastic/firmware/pull/6483\r\n* @MayNiklas made their first contribution in https://github.com/meshtastic/firmware/pull/6595\r\n* @benkyd made their first contribution in https://github.com/meshtastic/firmware/pull/6584\r\n* @Nivek-domo made their first contribution in https://github.com/meshtastic/firmware/pull/6622\r\n\r\n**Full Changelog**: https://github.com/meshtastic/firmware/compare/v2.6.5.fc3d9f2...v2.6.6.54c1423" + }, + { + "id": "v2.6.5.fc3d9f2", + "title": "Meshtastic Firmware 2.6.5.fc3d9f2 Alpha", + "page_url": "https://github.com/meshtastic/firmware/releases/tag/v2.6.5.fc3d9f2", + "zip_url": "https://github.com/meshtastic/firmware/releases/download/v2.6.5.fc3d9f2/firmware-stm32-2.6.5.fc3d9f2.zip", + "release_notes": "\u003E [!CAUTION] \r\n\u003E Updating from a previous version of firmware to 2.6, **will wipe** your device. Please remember to [backup your keys](https://meshtastic.org/docs/configuration/radio/security/#security-keys---backup-and-restore) and important [configurations](https://meshtastic.org/docs/software/python/cli/usage/#export-device-config-with---export-config) before proceeding!\r\n\r\n## 🚀 Enhancements\r\n* Update library deps and nrf Toolchain by @caveman99 in https://github.com/meshtastic/firmware/pull/6450\r\n* Update to handle ws80 serial data as well by @tavdog in https://github.com/meshtastic/firmware/pull/6440\r\n* Add a static_assert to verify assumption about NodeInfoLite size by @jasonbcox in https://github.com/meshtastic/firmware/pull/6428\r\n* meshtasticd: CH341 / HAT+ Auto Configuration by @vidplace7 in https://github.com/meshtastic/firmware/pull/6446\r\n* More toggles for InkHUD menu by @todd-herbert in https://github.com/meshtastic/firmware/pull/6469\r\n* Add InkHUD driver for WeAct Studio 4.2\" display module by @todd-herbert in https://github.com/meshtastic/firmware/pull/6384\r\n* Added initial support for Texas Instruments LP5562 by @CypressXt in https://github.com/meshtastic/firmware/pull/6381\r\n* meshtasticd: Set available.d dir in yaml by @vidplace7 in https://github.com/meshtastic/firmware/pull/6481\r\n* Disable bluetooth config on rp2040, portduino (for now), and stm32 by @thebentern in https://github.com/meshtastic/firmware/pull/6465\r\n* meshtasticd: Add FrequencyLabs MeshAdv-Mini Hat by @vidplace7 in https://github.com/meshtastic/firmware/pull/6458\r\n* Initial InkHUD support for Elecrow ThinkNode M1 by @todd-herbert in https://github.com/meshtastic/firmware/pull/6473\r\n* Add support for Quectel-L96, a MT3333 module by @ke6zfi in https://github.com/meshtastic/firmware/pull/6498\r\n* Update OLED library, fix nRF build of SH1107 by @caveman99 in https://github.com/meshtastic/firmware/pull/6489\r\n* Disable network config for non-eth_gateway nrf52 and non-W RP2040 targets by @thebentern in https://github.com/meshtastic/firmware/pull/6462\r\n* Honor user button remapping within InkHUD by @todd-herbert in https://github.com/meshtastic/firmware/pull/6400\r\n* Improve PKC unit test coverage by @jasonbcox in https://github.com/meshtastic/firmware/pull/6485\r\n* TCA8418 initial config + basic 3x4 keypad config by @Nasimovy in https://github.com/meshtastic/firmware/pull/6422\r\n* MUI: update device-ui commit reference by @mverch67 in https://github.com/meshtastic/firmware/pull/6526\r\n\r\n## 🐛 Bug fixes & maintenance\r\n* Fix: Update xiao_ble E22-900M30S regulatory gain to 7 dB by @ndoo in https://github.com/meshtastic/firmware/pull/6466\r\n* Update ScreenFonts.h fix CrowPanel 5.79 Font by @markbirss in https://github.com/meshtastic/firmware/pull/6412\r\n* Added 'bluetooth' as a connectivity option for the LilyGo T-Watch-S3.… by @PlantDaddy in https://github.com/meshtastic/firmware/pull/6470* Try-fix some import of configuration inconsistencies by @thebentern in https://github.com/meshtastic/firmware/pull/6364\r\n* Fix: T-Echo frontlight on at boot when using OLED UI by @todd-herbert in https://github.com/meshtastic/firmware/pull/6474\r\n* MUI unPhone-tft: fix defaults (BT, power save, and MUI cache size) by @mverch67 in https://github.com/meshtastic/firmware/pull/6477\r\n* Fixes #6315 by @RCGV1 in https://github.com/meshtastic/firmware/pull/6475\r\n* Reinstate M1 Backlight by @caveman99 in https://github.com/meshtastic/firmware/pull/6484\r\n* Remove Very_Long_Slow by @rcarteraz in https://github.com/meshtastic/firmware/pull/6486\r\n* Revert \"Try-fix ESP32 wifi disconnects\" by @thebentern in https://github.com/meshtastic/firmware/pull/6493\r\n* InkHUD: ad-hoc ping using the menu by @todd-herbert in https://github.com/meshtastic/firmware/pull/6492\r\n* Remove duplicate HAS_LP5562 introduced in #6422 by @Nasimovy in https://github.com/meshtastic/firmware/pull/6494\r\n* Fix for PSRAM detection on ESP32-S3R8 and t-beam by @Nasimovy in https://github.com/meshtastic/firmware/pull/6504\r\n* Fix several features of M1 and M2 (i know what the 7 is now ...) by @caveman99 in https://github.com/meshtastic/firmware/pull/6507\r\n* Update platformio.ini fix build-flags ${esp32s3_base.build_flags} by @markbirss in https://github.com/meshtastic/firmware/pull/6512\r\n* inkhud doesn't have a button thread by @caveman99 in https://github.com/meshtastic/firmware/pull/6513\r\n* Fix device-specific logic in install script by @epall in https://github.com/meshtastic/firmware/pull/6508\r\n* Update web, use centrally defined version by @vidplace7 in https://github.com/meshtastic/firmware/pull/6500\r\n* Minor adjustment of blink codes and 'unstick' the M2 button. by @caveman99 in https://github.com/meshtastic/firmware/pull/6521\r\n* chore: update ubx.h by @eltociear in https://github.com/meshtastic/firmware/pull/6522\r\n* meshtasticd docker: Support webui by @vidplace7 in https://github.com/meshtastic/firmware/pull/6482\r\n* remove checkov from trunk config by @fifieldt in https://github.com/meshtastic/firmware/pull/6532\r\n* Send UDP packet even if it's encrypted by @GUVWAF in https://github.com/meshtastic/firmware/pull/6524\r\n\r\n## New Contributors\r\n* @jasonbcox made their first contribution in https://github.com/meshtastic/firmware/pull/6428\r\n* @PlantDaddy made their first contribution in https://github.com/meshtastic/firmware/pull/6470\r\n* @CypressXt made their first contribution in https://github.com/meshtastic/firmware/pull/6381\r\n* @ke6zfi made their first contribution in https://github.com/meshtastic/firmware/pull/6498\r\n* @epall made their first contribution in https://github.com/meshtastic/firmware/pull/6508\r\n\r\n**Full Changelog**: https://github.com/meshtastic/firmware/compare/v2.6.4.b89355f...v2.6.5.fc3d9f2" + }, + { + "id": "v2.6.2.31c0e8f", + "title": "Meshtastic Firmware 2.6.2.31c0e8f Alpha", + "page_url": "https://github.com/meshtastic/firmware/releases/tag/v2.6.2.31c0e8f", + "zip_url": "https://github.com/meshtastic/firmware/releases/download/v2.6.2.31c0e8f/firmware-stm32-2.6.2.31c0e8f.zip", + "release_notes": "\u003E [!CAUTION] \r\n\u003E Updating from a previous version of firmware to 2.6, **will wipe** your device. Please remember to [backup your keys](https://meshtastic.org/docs/configuration/radio/security/#security-keys---backup-and-restore) and important [configurations](https://meshtastic.org/docs/software/python/cli/usage/#export-device-config-with---export-config) before proceeding!\r\n\r\n\u003E [!WARNING] \r\nAdditionally, this release allocates more storage space on a number of ESP32 targets. Updating one of these devices flashed with previous versions of meshtastic may result in unexpected behavior and we recommend doing a full erase / flash to be safe.\r\n\r\n**Affected 8MB and 16MB devices:**\r\n\r\n- **Heltec:** LoRa v3, Tracker, Wireless Stick Lite v3, Wireless Paper, Vision Master\r\n- **Lilygo:** T-Beam S3 Supreme, T-Watch S3\r\n- **Seeed:** Xiao-S3\r\n- **B&Q:** Station G2\r\n\r\n## ⚠️ Known issues\r\nThis release may will cause issues with T-Watch S3 devices which have 8MB flash #6406\r\n\r\n## 🚀 Enhancements\r\n* Don't allow is_managed without any valid admin_keys by @cdanis in https://github.com/meshtastic/firmware/pull/6310\r\n* E-ink partial refresh limitation removed for free text screen by @HarukiToreda in https://github.com/meshtastic/firmware/pull/6201\r\n* Send UDP packets to multicast address rather than broadcast address by @Jorropo in https://github.com/meshtastic/firmware/pull/6331\r\n* Simplify MAX_NUM_NODES, increase limit on large-flash targets. by @vidplace7 in https://github.com/meshtastic/firmware/pull/6311\r\n* Add packages to devcontainer for build native-tft by @ThatKalle in https://github.com/meshtastic/firmware/pull/6299\r\n* Mainline tlora v3 by @caveman99 in https://github.com/meshtastic/firmware/pull/6322\r\n* Update Seeed-xiao-nrf52840-kit board defination by @Dylanliacc in https://github.com/meshtastic/firmware/pull/6318\r\n* Support WiFi OTA by @mskvortsov in https://github.com/meshtastic/firmware/pull/6352\r\n* Add UDP multicast support on linux. by @Jorropo in https://github.com/meshtastic/firmware/pull/6342\r\n* RP2xx0: Add UDP Multicast support by @vidplace7 in https://github.com/meshtastic/firmware/pull/6327\r\n* Pass pointer to UDP multicast packet to protobuf decoder by @Jorropo in https://github.com/meshtastic/firmware/pull/6333\r\n* Meshtasticd: Add MeshToad - USB 1W 'MeshStick' by @vidplace7 in https://github.com/meshtastic/firmware/pull/6339\r\n\r\n## 🐛 Bug fixes and maintenance\r\n* Windows script lineendings by @ThatKalle in https://github.com/meshtastic/firmware/pull/6289\r\n* MUI: fix packet queue full by @mverch67 in https://github.com/meshtastic/firmware/pull/6292\r\n* Fix KR920's Tx power limitation by @qkdxorjs1002 in https://github.com/meshtastic/firmware/pull/6307\r\n* New device: Lilygo T-Eth-Elite by @caveman99 in https://github.com/meshtastic/firmware/pull/6321\r\n* Pass pointer to UDP multicast packet to protobuf decoder by @Jorropo in https://github.com/meshtastic/firmware/pull/6333\r\n* Device-install/update: fix esptool --port by @ThatKalle in https://github.com/meshtastic/firmware/pull/6341\r\n* Fixed UF2 generation problem when sys.executable path has spaces in it ( platformio-custom.py ) by @rbreesems in https://github.com/meshtastic/firmware/pull/6346\r\n* Added bounds checking to memcpy and use memory-safe strlcpy by @raulperdomo in https://github.com/meshtastic/firmware/pull/6351\r\n\r\n## New Contributors\r\n* @qkdxorjs1002 made their first contribution in https://github.com/meshtastic/firmware/pull/6307\r\n* @rbreesems made their first contribution in https://github.com/meshtastic/firmware/pull/6346\r\n* @raulperdomo made their first contribution in https://github.com/meshtastic/firmware/pull/6351\r\n\r\n**Full Changelog**: https://github.com/meshtastic/firmware/compare/v2.6.0.f7afa9a...v2.6.2.31c0e8f" + }, + { + "id": "v2.6.1.7c3edde", + "title": "Meshtastic Firmware 2.6.1.7c3edde Alpha", + "page_url": "https://github.com/meshtastic/firmware/releases/tag/v2.6.1.7c3edde", + "zip_url": "https://github.com/meshtastic/firmware/releases/download/v2.6.1.7c3edde/firmware-stm32-2.6.1.7c3edde.zip", + "release_notes": "\u003E [!CAUTION] \r\n\u003E Updating from a previous version of firmware to 2.6, **will wipe** your device. Please remember to [backup your keys](https://meshtastic.org/docs/configuration/radio/security/#security-keys---backup-and-restore) and important [configurations](https://meshtastic.org/docs/software/python/cli/usage/#export-device-config-with---export-config) before proceeding!\r\n\r\n\r\n\r\n## 🚀 Enhancements\r\n\r\n### [Big 2.6 changes!](https://meshtastic.org/blog/meshtastic-2-6-preview/)\r\n- Meshtastic UI\r\n- Next-hop Routing Protocol for DMs\r\n- Optimized LoRa Slot-Time Calculation\r\n- InkHUD\r\n- Meshtastic over LAN (ESP32 Wifi UDP experimental support)\r\n- Improved Device State File Management\r\n- Add rain data from ws85 by @tavdog in https://github.com/meshtastic/firmware/pull/6242\r\n- Add some minor additional options to userPrefs.jsonc by @karchf in https://github.com/meshtastic/firmware/pull/6137\r\n- Switch pio_deps to `native-tft` for flatpak by @vidplace7 in https://github.com/meshtastic/firmware/pull/6187\r\n- Only request NodeInfo/Position from everyone on fresh install by @GUVWAF in https://github.com/meshtastic/firmware/pull/6184\r\n- Create lora-starter-edition-sx1262-i2c.yaml and lora-ws-raspberry-pi-pico-to-rpi-adapter.yaml by @markbirss in https://github.com/meshtastic/firmware/pull/6162\r\n- Create lora-raxda-rock2f-starter-edition-hat.yaml by @markbirss in https://github.com/meshtastic/firmware/pull/6192\r\n- Enable external (UART) GPS support on Seeed WM1110 tracker dev board by @thebentern in https://github.com/meshtastic/firmware/pull/6189\r\n- Changes for 2.6 device_install by @gjelsoe in https://github.com/meshtastic/firmware/pull/6206\r\n- Consume device-ui as a pio library by @vidplace7 in https://github.com/meshtastic/firmware/pull/6193\r\n- Add support for seeed_xiao_nrf52840_kit by @Dylanliacc in https://github.com/meshtastic/firmware/pull/6231\r\n- Environment: add DPS310 high-accuracy barometer by @cdanis in https://github.com/meshtastic/firmware/pull/6237\r\n- Update platformio.ini for 4.2 and 2.9 CrowPanel ESP32-S3 epaper and point GxEPD2 to meshtastic branch by @markbirss in https://github.com/meshtastic/firmware/pull/6245\r\n- Ebyte E77 (STM32) DevKit support by @vidplace7 in https://github.com/meshtastic/firmware/pull/6255\r\n- Add detection support for LTR390UV Sensor by @fifieldt in https://github.com/meshtastic/firmware/pull/6009\r\n- NodeInfo request: don't bother if too far away by @cdanis in https://github.com/meshtastic/firmware/pull/6260\r\n- MUI: exFat support for SD by @mverch67 in https://github.com/meshtastic/firmware/pull/6279\r\n\r\n## 🐛 Bug fixes and maintenance\r\n- Fix trunk debt by @vidplace7 in https://github.com/meshtastic/firmware/pull/6149\r\n- Cast user pref strings. by @Mictronics in https://github.com/meshtastic/firmware/pull/6123\r\n- More trunk junk / remove old workflows by @vidplace7 in https://github.com/meshtastic/firmware/pull/6153\r\n- DevContainers: Include meshtasticd dependencies by @rickmark in https://github.com/meshtastic/firmware/pull/5699\r\n- RAK11310: Update to last building platform package and possibly fix for #5361 by @Mictronics in https://github.com/meshtastic/firmware/pull/6202\r\n- RAK11310 support for RAK12002 RTC added. by @Mictronics in https://github.com/meshtastic/firmware/pull/6210\r\n- Only call GPS Probe commands once per family by @fifieldt in https://github.com/meshtastic/firmware/pull/6114\r\n- Enable GPS functionality for RAK4631_eth_gw variant by @mandreko in https://github.com/meshtastic/firmware/pull/6229\r\n- RAK11310 Fix build with latest Arduino framework by @Mictronics in https://github.com/meshtastic/firmware/pull/6227\r\n- EBYTE E22-400Mxx SX126X_DIO3_TCXO_VOLTAGE fix by @Andrik45719 in https://github.com/meshtastic/firmware/pull/6232\r\n- InkHUD refactoring by @todd-herbert in https://github.com/meshtastic/firmware/pull/6216\r\n- Add initial support for CrowPanel ESP32 5.79” E-paper HMI by @markbirss in https://github.com/meshtastic/firmware/pull/6233\r\n- [Task]: 2.6 device-install scripts by @ThatKalle in https://github.com/meshtastic/firmware/pull/6248\r\n- I2C: 0x45 can also be an SHT35, not just an OPT3001 by @cdanis in https://github.com/meshtastic/firmware/pull/6249\r\n- Flag semgrep to not run on self-hosted by @fifieldt in https://github.com/meshtastic/firmware/pull/6256\r\n- PlatformIO: Bump ArduinoThread / device-ui versions by @vidplace7 in https://github.com/meshtastic/firmware/pull/6271-\r\n- Fix excluded_modules metadata with InkHUD by @todd-herbert in https://github.com/meshtastic/firmware/pull/6272\r\n- Update device-install scripts by @ThatKalle in https://github.com/meshtastic/firmware/pull/6267\r\n\r\n## New Contributors\r\n- @karchf made their first contribution in https://github.com/meshtastic/firmware/pull/6137\r\n- @rickmark made their first contribution in https://github.com/meshtastic/firmware/pull/5699\r\n- @mandreko made their first contribution in https://github.com/meshtastic/firmware/pull/6229\r\n- @cdanis made their first contribution in https://github.com/meshtastic/firmware/pull/6237\r\n- @Andrik45719 made their first contribution in https://github.com/meshtastic/firmware/pull/6232\r\n\r\n**Full Changelog**: https://github.com/meshtastic/firmware/compare/v2.5.23.bf958ed...v2.6.1.7c3edde" + }, + { + "id": "v2.6.0.f7afa9a", + "title": "Meshtastic Firmware 2.6.0.f7afa9a Technical Preview", + "page_url": "https://github.com/meshtastic/firmware/releases/tag/v2.6.0.f7afa9a", + "zip_url": "https://github.com/meshtastic/firmware/releases/download/v2.6.0.f7afa9a/firmware-stm32-2.6.0.f7afa9a.zip", + "release_notes": "## [Meshtastic 2.6 Preview: MUI and Next-Hop Routing are here!](https://meshtastic.org/blog/meshtastic-2-6-preview/)\r\n\r\n**Full Changelog**: https://github.com/meshtastic/firmware/compare/v2.5.23.bf958ed...v2.6.0.f7afa9a" + }, + { + "id": "v2.5.23.bf958ed", + "title": "Meshtastic Firmware 2.5.23.bf958ed Alpha", + "page_url": "https://github.com/meshtastic/firmware/releases/tag/v2.5.23.bf958ed", + "zip_url": "https://github.com/meshtastic/firmware/releases/download/v2.5.23.bf958ed/firmware-stm32-2.5.23.bf958ed.zip", + "release_notes": "## 🚀 Enhancements\r\n* Add XIAO nRF52840 + Wio SX1262 DIY Variant by @porkcube in https://github.com/meshtastic/firmware/pull/5976\r\n* Allow NeighborInfo on non-default frequency slot by @GUVWAF in https://github.com/meshtastic/firmware/pull/6061\r\n* Assigning SDA/SCL so it actually works 8| by @porkcube in https://github.com/meshtastic/firmware/pull/6065\r\n* Reject invalid configuration for the default MQTT server by @esev in https://github.com/meshtastic/firmware/pull/6066\r\n* Add support for new NRF52 board, MeshLink by @ponzano in https://github.com/meshtastic/firmware/pull/5736\r\n* Validate MQTT config by testing a connection by @esev in https://github.com/meshtastic/firmware/pull/6076\r\n* Add missing traceroute fields to serialized JSON output by @noahhaon in https://github.com/meshtastic/firmware/pull/6087\r\n* Trunk: Annotate PRs and Auto-Upgrade by @vidplace7 in https://github.com/meshtastic/firmware/pull/6091\r\n* Dependencies: minor version updates by @fifieldt in https://github.com/meshtastic/firmware/pull/6045\r\n* Add Pico2W variant including Wifi support. by @Mictronics in https://github.com/meshtastic/firmware/pull/6062\r\n* Feat: added BMP-390 support to the BMP-3xx sensors by @rostekus in https://github.com/meshtastic/firmware/pull/6103\r\n\r\n## 🐛 Bug fixes and maintenance\r\n* Consider the MQTT TLS remote IP when checking for a private IP by @esev in https://github.com/meshtastic/firmware/pull/6058\r\n* Fix MQTT over TLS crash loop by @esev in https://github.com/meshtastic/firmware/pull/6057\r\n* Expose INA219 measurement as battery voltage for Seeed Xiao ESP32S3 by @syssi in https://github.com/meshtastic/firmware/pull/6070\r\n* Chore: update unishox2.h by @eltociear in https://github.com/meshtastic/firmware/pull/6092\r\n* Fix STM32WL TCXO setting; enable logs and modules by @GUVWAF in https://github.com/meshtastic/firmware/pull/6063\r\n* Update Readme by @rcarteraz in https://github.com/meshtastic/firmware/pull/6088\r\n* PIO: Cleanup dependency naming by @vidplace7 in https://github.com/meshtastic/firmware/pull/6090\r\n* Move variant-specific lines back to variant by @fifieldt in https://github.com/meshtastic/firmware/pull/6044\r\n* Ignore and disallow multi-hop traceroutes destined to broadcast address by @GUVWAF in https://github.com/meshtastic/firmware/pull/6109\r\n* Fix PowerTelemetry initialization by @GUVWAF in https://github.com/meshtastic/firmware/pull/6106\r\n* Perhaps fix TXCO reports on pro-micro by @thebentern in https://github.com/meshtastic/firmware/pull/6110\r\n* meshtasticd deb: Build armv6-compatible binary by @vidplace7 in https://github.com/meshtastic/firmware/pull/6104\r\n* GPS Factory Reset no longer needed. by @fifieldt in https://github.com/meshtastic/firmware/pull/6116\r\n* Reduce some log levels. by @fifieldt in https://github.com/meshtastic/firmware/pull/6127\r\n* Debian: Ensure deps exist for changelog bump by @vidplace7 in https://github.com/meshtastic/firmware/pull/6145\r\n* Trunk: userPrefs trailing commas begone! by @vidplace7 in https://github.com/meshtastic/firmware/pull/6038\r\n* Typo in Bandit button LEDs by @gjelsoe in https://github.com/meshtastic/firmware/pull/6053\r\n\r\n\r\n## New Contributors\r\n* @porkcube made their first contribution in https://github.com/meshtastic/firmware/pull/5976\r\n* @ponzano made their first contribution in https://github.com/meshtastic/firmware/pull/5736\r\n* @noahhaon made their first contribution in https://github.com/meshtastic/firmware/pull/6087\r\n* @eltociear made their first contribution in https://github.com/meshtastic/firmware/pull/6092\r\n* @syssi made their first contribution in https://github.com/meshtastic/firmware/pull/6070\r\n* @rostekus made their first contribution in https://github.com/meshtastic/firmware/pull/6103\r\n\r\n**Full Changelog**: https://github.com/meshtastic/firmware/compare/v2.5.22.d1fa27d...v2.5.23.bf958ed" + }, + { + "id": "v2.5.22.d1fa27d", + "title": "Meshtastic Firmware 2.5.22.d1fa27d Alpha", + "page_url": "https://github.com/meshtastic/firmware/releases/tag/v2.5.22.d1fa27d", + "zip_url": "https://github.com/meshtastic/firmware/releases/download/v2.5.22.d1fa27d/firmware-stm32-2.5.22.d1fa27d.zip", + "release_notes": " ## ⚠️ Known issues \r\n* PowerTelemetry reporting is broken in this release. This issue will be resolved in the next release.\r\n\r\n## 🚀 Enhancements\r\n* Change nonce logging to DEBUG instead of Info by @lizTheDeveloper in https://github.com/meshtastic/firmware/pull/6001\r\n* T1000-E hardware updates and GPS positioning accuracy optimization by @Dylanliacc in https://github.com/meshtastic/firmware/pull/6003\r\n* Improve UTF-8 string handling in JSONValue by @ChangYanChu in https://github.com/meshtastic/firmware/pull/6011\r\n* meshtasticd flatpak: Include pio deps with release by @vidplace7 in https://github.com/meshtastic/firmware/pull/6025\r\n* Add support for 12- and 24-hour clock, Minor Settings Frame Adjustment by @Xaositek in https://github.com/meshtastic/firmware/pull/5988\r\n* Added custom OCV array values for T1000-E to improve percentage estimates by @nwilde1590 in https://github.com/meshtastic/firmware/pull/6031\r\n\r\n## 🐛 Bug fixes\r\n* Update protobufs and classes by @github-actions in https://github.com/meshtastic/firmware/pull/6027\r\n* meshtasticd: include `.hidden` (.git) dirs in pio-deps by @vidplace7 in https://github.com/meshtastic/firmware/pull/6028\r\n* Small fix: don't junk the zip for pio-deps by @vidplace7 in https://github.com/meshtastic/firmware/pull/6029\r\n* Fix T-Deck/T-Watch no BT by @mverch67 in https://github.com/meshtastic/firmware/pull/5998\r\n* Corrected some misinformation by @NomDeTom in https://github.com/meshtastic/firmware/pull/5995\r\n* meshtasticd: Fix web download location by @vidplace7 in https://github.com/meshtastic/firmware/pull/5993\r\n\r\n\r\n## New Contributors\r\n* @lizTheDeveloper made their first contribution in https://github.com/meshtastic/firmware/pull/6001\r\n* @ChangYanChu made their first contribution in https://github.com/meshtastic/firmware/pull/6011\r\n* @nwilde1590 made their first contribution in https://github.com/meshtastic/firmware/pull/6031\r\n\r\n**Full Changelog**: https://github.com/meshtastic/firmware/compare/v2.5.21.447533a...v2.5.22.d1fa27d" + }, + { + "id": "v2.5.21.447533a", + "title": "Meshtastic Firmware 2.5.21.447533a Alpha", + "page_url": "https://github.com/meshtastic/firmware/releases/tag/v2.5.21.447533a", + "zip_url": "https://github.com/meshtastic/firmware/releases/download/v2.5.21.447533a/firmware-esp32c3-2.5.21.447533a.zip", + "release_notes": "\u003E [!IMPORTANT] \r\n\u003E Linux packages have been migrated from GitHub Releases to distro-specific build services.\r\n\u003E For additional information see: [Installing meshtasticd](https://meshtastic.org/docs/hardware/devices/linux-native-hardware/#installing-meshtasticd)\r\n\r\n\r\n ## ⚠️ Known issues \r\n * For NRF52 devices which have been upgraded through the 2.5.X versions, a [full flash erase](https://meshtastic.org/docs/getting-started/flashing-firmware/nrf52/nrf52-erase/) is recommended to fully remediate any lingering LFS assert issues.\r\n* Bluetooth was inadvertently disabled for T-Deck and T-Watch devices, preventing pairing with client apps. This issue will be resolved in the next alpha release after 2.5.21.\r\n* PowerTelemetry reporting is broken in this release. This issue will be resolved in the next release after 2.5.22.\r\n\r\n## 🚀 Enhancements\r\n* Rate limit position replies to three minutes by @GUVWAF in https://github.com/meshtastic/firmware/pull/5932\r\n* Space out periodic broadcasts of modules automatically by @GUVWAF in https://github.com/meshtastic/firmware/pull/5931\r\n* Oem logo by @caveman99 in https://github.com/meshtastic/firmware/pull/5939\r\n* Portduino: Allow limiting TX Power from yaml by @vidplace7 in https://github.com/meshtastic/firmware/pull/5954\r\n* Portduino: Set Web SSL Cert / Key paths from yaml by @vidplace7 in https://github.com/meshtastic/firmware/pull/5961\r\n* Add bearing to other node on device screen in text by @Woutvstk in https://github.com/meshtastic/firmware/pull/5968\r\n* Don't rate-limit position requests for Lost and Found role by @GUVWAF in https://github.com/meshtastic/firmware/pull/5981\r\n* E80 promicro update by @NomDeTom in https://github.com/meshtastic/firmware/pull/5967\r\n\r\n## 🐛 Bug fixes and maintenance\r\n* Revert \"No focus on new messages if auto-carousel is off\" by @thebentern in https://github.com/meshtastic/firmware/pull/5936\r\n* Clean up some legacy macro definitions by @caveman99 in https://github.com/meshtastic/firmware/pull/5983\r\n* meshtasticd-debian: Remove existing deb builds by @vidplace7 in https://github.com/meshtastic/firmware/pull/5792\r\n* Fix: TCXO_OPTIONAL featuring SenseCAP Indicator (V1/V2) by @mverch67 in https://github.com/meshtastic/firmware/pull/5948\r\n* Add missing build_unflags by @krant in https://github.com/meshtastic/firmware/pull/5941\r\n* Fix INA226 Sensor Voltage Readings by @fifieldt in https://github.com/meshtastic/firmware/pull/5972\r\n* Fix off-by-one error with log writes by @fifieldt in https://github.com/meshtastic/firmware/pull/5959\r\n* Fixes #5766 Updated MQTT privateCidrRanges to add Tailscale by @Xaositek in https://github.com/meshtastic/firmware/pull/5957\r\n* Remove unused usages of #include \u003Ciostream\u003E to save Flash by @Stary2001 in https://github.com/meshtastic/firmware/pull/5978\r\n* Fix negative decimal value detection in userPrefs by @thebentern in https://github.com/meshtastic/firmware/pull/5963\r\n\r\n## New Contributors\r\n* @krant made their first contribution in https://github.com/meshtastic/firmware/pull/5941\r\n* @Xaositek made their first contribution in https://github.com/meshtastic/firmware/pull/5957\r\n* @Stary2001 made their first contribution in https://github.com/meshtastic/firmware/pull/5978\r\n\r\n**Full Changelog**: https://github.com/meshtastic/firmware/compare/v2.5.20.4c97351...v2.5.21.447533a" + }, + { + "id": "v2.5.17.b4b2fd6", + "title": "Meshtastic Firmware 2.5.17.b4b2fd6 Alpha", + "page_url": "https://github.com/meshtastic/firmware/releases/tag/v2.5.17.b4b2fd6", + "zip_url": "https://github.com/meshtastic/firmware/releases/download/v2.5.17.b4b2fd6/firmware-stm32-2.5.17.b4b2fd6.zip", + "release_notes": "## 🚀 Enhancements\r\n* Update OpenWRT_One_mikroBUS_sx1262.yaml by @markbirss in https://github.com/meshtastic/firmware/pull/5544\r\n* Add portduino-buildroot variant by @vidplace7 in https://github.com/meshtastic/firmware/pull/5540\r\n* Portduino-buildroot: Define C++ standard by @vidplace7 in https://github.com/meshtastic/firmware/pull/5547\r\n* DIO3_TCXO_VOLTAGE in config.yaml can now take an exact voltage by @jp-bennett in https://github.com/meshtastic/firmware/pull/5558\r\n* Support TLORA_V3.0 by @caveman99 in https://github.com/meshtastic/firmware/pull/5563\r\n* Create OpenWRT-One-mikroBUS-LR-IOT-CLICK.yaml by @markbirss in https://github.com/meshtastic/firmware/pull/5564\r\n* Add new endpoint to retrieve node info by @andrepcg in https://github.com/meshtastic/firmware/pull/5557\r\n* Add screen detection function by @Heltec-Aaron-Lee in https://github.com/meshtastic/firmware/pull/5533\r\n* Based default Node Names on NodeNum, rather than MAC address by @fifieldt in https://github.com/meshtastic/firmware/pull/5576\r\n* Define BUTTON_PIN as -1 for RP2040-lora by @fifieldt in https://github.com/meshtastic/firmware/pull/5574\r\n* StoreForward: (tapback) reply support by @GUVWAF in https://github.com/meshtastic/firmware/pull/5585\r\n* Added support for the LR1121 radio to the NRF52 Pro-Micro by @Nestpebble in https://github.com/meshtastic/firmware/pull/5515\r\n* Added product url by @WatskeBart in https://github.com/meshtastic/firmware/pull/5594\r\n* [T-Deck] Fixed the issue that some devices may experience low voltage… by @lewisxhe in https://github.com/meshtastic/firmware/pull/5607\r\n* Remove unnecessary memcpy for PKI crypto by @esev in https://github.com/meshtastic/firmware/pull/5608\r\n* Use IPAddress.fromString in MQTT.cpp for parsing private IPs by @esev in https://github.com/meshtastic/firmware/pull/5621\r\n* Use encoded ServiceEnvelope in mqttQueue by @esev in https://github.com/meshtastic/firmware/pull/5619\r\n* Ch341 by @jp-bennett in https://github.com/meshtastic/firmware/pull/5474\r\n* Add detection code for INA226 by @fifieldt in https://github.com/meshtastic/firmware/pull/5605\r\n* Check if MQTT remote IP is private by @esev in https://github.com/meshtastic/firmware/pull/5627\r\n\r\n## 🐛 Bug fixes and maintenance\r\n* Portduino-buildroot: Remove `pkg-config` optional libs by @vidplace7 in https://github.com/meshtastic/firmware/pull/5573\r\n* Portduino: Move meshtasticd/web out of /usr/share/doc/ by @vidplace7 in https://github.com/meshtastic/firmware/pull/5548\r\n* Portduino: fix transitional symlinks for /usr/share/doc/ by @vidplace7 in https://github.com/meshtastic/firmware/pull/5550\r\n* Cherry-pick: Windows Support - Trunk and Platformio (#5397) by @fifieldt in https://github.com/meshtastic/firmware/pull/5518\r\n* Synch minor changes from TFT branch by @fifieldt in https://github.com/meshtastic/firmware/pull/5520\r\n* Refactor MQTT::onReceive to reduce if/else nesting by @esev in https://github.com/meshtastic/firmware/pull/5592\r\n* Let RangeTest Module (RX) use Phone position if there's no GPS by @fifieldt in https://github.com/meshtastic/firmware/pull/5623\r\n* Separate host:port before checking for private IP by @esev in https://github.com/meshtastic/firmware/pull/5630\r\n* Clean up some straggler NRF52 json by @thebentern in https://github.com/meshtastic/firmware/pull/5628\r\n* Fix omission of AQ metrics by @thebentern in https://github.com/meshtastic/firmware/pull/5584\r\n* tlora_v2_1_16: Unset BUTTON_PIN and BUTTON_NEED_PULLUP by @ndoo in https://github.com/meshtastic/firmware/pull/5535\r\n* Fix detection for some RadSens hardware versions by @jake-b in https://github.com/meshtastic/firmware/pull/5542\r\n* Initialize dmac array to nulls by @jp-bennett in https://github.com/meshtastic/firmware/pull/5538\r\n* Portduino: fix setting `hwId` via argument by @GUVWAF in https://github.com/meshtastic/firmware/pull/5565\r\n* Add nugget and nibble boards for 38c3 by @caveman99 in https://github.com/meshtastic/firmware/pull/5609\r\n* Fix: Add libusb to dockerfile for ch341 by @thebentern in https://github.com/meshtastic/firmware/pull/5641\r\n* Portduino: specify C++ standard and link pthread by @GUVWAF in https://github.com/meshtastic/firmware/pull/5642\r\n* Separate host:port before checking for private IP (x2) by @esev in https://github.com/meshtastic/firmware/pull/5643\r\n* Update Femtofox configs by @noon92 in https://github.com/meshtastic/firmware/pull/5646\r\n* Detect charging status by measuring current flow with configured INA219 battery sensor by @nebman in https://github.com/meshtastic/firmware/pull/5271\r\n* Add NXP_SE050 detection by @jp-bennett in https://github.com/meshtastic/firmware/pull/5651\r\n* Check if MQTT remote IP is private by @esev in https://github.com/meshtastic/firmware/pull/5647\r\n* LIS3DH (WisMesh Pocket) - Honor Wake On Tap Or Motion by @fifieldt in https://github.com/meshtastic/firmware/pull/5625\r\n\r\n## New Contributors\r\n* @andrepcg made their first contribution in https://github.com/meshtastic/firmware/pull/5557\r\n* @WatskeBart made their first contribution in https://github.com/meshtastic/firmware/pull/5594\r\n* @esev made their first contribution in https://github.com/meshtastic/firmware/pull/5592\r\n* @nebman made their first contribution in https://github.com/meshtastic/firmware/pull/5271\r\n\r\n**Full Changelog**: https://github.com/meshtastic/firmware/compare/v2.5.16.f81d3b0...v2.5.17.b4b2fd6" + }, + { + "id": "v2.5.16.f81d3b0", + "title": "Meshtastic Firmware 2.5.16.f81d3b0 Alpha", + "page_url": "https://github.com/meshtastic/firmware/releases/tag/v2.5.16.f81d3b0", + "zip_url": "https://github.com/meshtastic/firmware/releases/download/v2.5.16.f81d3b0/firmware-rp2040-2.5.16.f81d3b0.zip", + "release_notes": "## 🚀 Enhancements\r\n* Adds libusb dev package to Raspbian build steps by @jp-bennett in https://github.com/meshtastic/firmware/pull/5480\r\n* Update arduino-pico core and remove mDNS restriction by @GUVWAF in https://github.com/meshtastic/firmware/pull/5483\r\n* Update xiao_esp32 fully support L76K by @Dylanliacc in https://github.com/meshtastic/firmware/pull/5488\r\n* Convert userprefs to a json file instead of header file which has to be included everywhere by @thebentern in https://github.com/meshtastic/firmware/pull/5471\r\n* SimRadio: clean-up and emulate collisions by @GUVWAF in https://github.com/meshtastic/firmware/pull/5487\r\n* add nodeId to nodeinfo update log lines and removed redundant nodeinfo update log line by @rbrtio in https://github.com/meshtastic/firmware/pull/5493\r\n* Refactor the macro definition of GPS initialization of GPSDEFAULTD_NOT_PRESENT and added seeeed Indicator to this sequence by @Dylanliacc in https://github.com/meshtastic/firmware/pull/5494\r\n* Extend Length of Source and Destination Node IDs Logged by @rbrtio in https://github.com/meshtastic/firmware/pull/5492\r\n* Added femtofox configs by @noon92 in https://github.com/meshtastic/firmware/pull/5477\r\n* [Add] LR1110, LR1120 and LR1121 to linux native Portduino by @markbirss in https://github.com/meshtastic/firmware/pull/5496\r\n* Add popular nrf52 pro micro to the builds by @thebentern in https://github.com/meshtastic/firmware/pull/5523\r\n* Add MACAddress to config.yaml by @jp-bennett in https://github.com/meshtastic/firmware/pull/5506\r\n* Configure Seeed Xiao S3 RX enable pin by @mgranberry in https://github.com/meshtastic/firmware/pull/5517\r\n* Add OpenWRT One config.d files by @markbirss in https://github.com/meshtastic/firmware/pull/5529\r\n\r\n## 🐛 Bug fixes and maintenance\r\n* Fix minor typos in package workflows by @jp-bennett in https://github.com/meshtastic/firmware/pull/5505\r\n* Don't use channel index for encrypted packet by @GUVWAF in https://github.com/meshtastic/firmware/pull/5509\r\n* Always Announce MDNS meshtastic service by @broglep in https://github.com/meshtastic/firmware/pull/5503\r\n* Cherry-pick: fix nodeDB erase loop when free mem returns invalid value (0, -1). by @fifieldt in https://github.com/meshtastic/firmware/pull/5519\r\n* Portduino fixes by @jp-bennett in https://github.com/meshtastic/firmware/pull/5479\r\n\r\n## New Contributors\r\n* @noon92 made their first contribution in https://github.com/meshtastic/firmware/pull/5477\r\n* @broglep made their first contribution in https://github.com/meshtastic/firmware/pull/5503\r\n* @mgranberry made their first contribution in https://github.com/meshtastic/firmware/pull/5517\r\n\r\n**Full Changelog**: https://github.com/meshtastic/firmware/compare/v2.5.15.79da236...v2.5.16.f81d3b0" + }, + { + "id": "v2.5.12.aa184e6", + "title": "Meshtastic Firmware 2.5.12.aa184e6 Alpha", + "page_url": "https://github.com/meshtastic/firmware/releases/tag/v2.5.12.aa184e6", + "zip_url": "https://github.com/meshtastic/firmware/releases/download/v2.5.12.aa184e6/firmware-stm32-2.5.12.aa184e6.zip", + "release_notes": "## ⚠️ Known issues \r\n* In some cases, connected apps may show duplicate received packets.\r\n\r\n## 🚀 Enhancements\r\n* uClibc compatibility by @vidplace7 in https://github.com/meshtastic/firmware/pull/5270\r\n* Smarter traffic scaling by @thebentern in https://github.com/meshtastic/firmware/pull/5264\r\n* Fix device flashing scripts so they work with esptool when it's installed via pipx by @jeremiah-k in https://github.com/meshtastic/firmware/pull/5269\r\n\r\n## 🐛 Bug fixes & maintenance\r\n* More log reductions. I'll probably stop now ;-) by @thebentern in https://github.com/meshtastic/firmware/pull/5263\r\n* Add exception for RTC to not strip time from position by @thebentern in https://github.com/meshtastic/firmware/pull/5262\r\n* Only PKC encrypt when packet originates from us by @GUVWAF in https://github.com/meshtastic/firmware/pull/5267\r\n* Fix wio-tracker-dev sensor scan by @caveman99 in https://github.com/meshtastic/firmware/pull/5274\r\n* Fixed compile error when using GPS_DEBUG by @macvenez in https://github.com/meshtastic/firmware/pull/5275\r\n* Copy the has_relative_humidity value to full telem packet from AHTX0 packet by @tavdog in https://github.com/meshtastic/firmware/pull/5277\r\n\r\n## New Contributors\r\n* @jeremiah-k made their first contribution in https://github.com/meshtastic/firmware/pull/5269\r\n* @macvenez made their first contribution in https://github.com/meshtastic/firmware/pull/5275\r\n\r\n**Full Changelog**: https://github.com/meshtastic/firmware/compare/v2.5.11.8e2a3e5...v2.5.12.aa184e6" + }, + { + "id": "v2.5.10.0fc5c9b", + "title": "Meshtastic Firmware 2.5.10.0fc5c9b Alpha", + "page_url": "https://github.com/meshtastic/firmware/releases/tag/v2.5.10.0fc5c9b", + "zip_url": "https://github.com/meshtastic/firmware/releases/download/v2.5.10.0fc5c9b/firmware-stm32-2.5.10.0fc5c9b.zip", + "release_notes": "## ⚠️ Known issues \r\n* Enabling NeighborInfo module can cause device crashes #5235\r\n* GPS reports as not present before first lock #5257 \r\n\r\n## 🚀 Enhancements\r\n* Added ADC control pin automatic logic switch function for Heltec LoRa 32 V3 by @Heltec-Aaron-Lee in https://github.com/meshtastic/firmware/pull/5196\r\n* Create CODE_OF_CONDUCT.md by @thebentern in https://github.com/meshtastic/firmware/pull/5225\r\n* Don't skip GPS serial speeds, and always land on GPS_BAUDRATE by @jp-bennett in https://github.com/meshtastic/firmware/pull/5195\r\n\r\n## 🐛 Bug fixes & maintenance\r\n* Fix: don't broadcast public keys if the user is licensed by @andrekir in https://github.com/meshtastic/firmware/pull/5190\r\n* Fix SerialModule handling received packet by @GUVWAF in https://github.com/meshtastic/firmware/pull/5206\r\n* Refactor getMacAddr function by @alexbegoon in https://github.com/meshtastic/firmware/pull/5208\r\n* Increase NimBLE stack size by @thebentern in https://github.com/meshtastic/firmware/pull/5202\r\n* Don't try to count non-lora transmissions into airtime (or attempt to decode) by @thebentern in https://github.com/meshtastic/firmware/pull/5215\r\n* Drop oldest packet from radio when queue is full by @GUVWAF in https://github.com/meshtastic/firmware/pull/5212\r\n* Fix \"Scan and Select\" input for Canned Messages by @todd-herbert in https://github.com/meshtastic/firmware/pull/5221\r\n* Remove assert in mesh-pb-constants.cpp by @jp-bennett in https://github.com/meshtastic/firmware/pull/5207\r\n* Optimize GPS Baud Rate cycle by @fifieldt in https://github.com/meshtastic/firmware/pull/5102\r\n\r\n## New Contributors\r\n* @alexbegoon made their first contribution in https://github.com/meshtastic/firmware/pull/5208\r\n\r\n**Full Changelog**: https://github.com/meshtastic/firmware/compare/v2.5.9.936260f...v2.5.10.0fc5c9b" + }, + { + "id": "v2.5.3.a70d5ee", + "title": "Meshtastic Firmware 2.5.3.a70d5ee Alpha", + "page_url": "https://github.com/meshtastic/firmware/releases/tag/v2.5.3.a70d5ee", + "zip_url": "https://github.com/meshtastic/firmware/releases/download/v2.5.3.a70d5ee/firmware-2.5.3.a70d5ee.zip", + "release_notes": "\u003E [!WARNING] \r\n\u003E With this release, there is a known issue that SX127x radios cannot receive any packets. It will be fixed in the next release.\r\n\r\n## Enhancements \r\n* Support for Seeed XIAO S3 Board by @Dylanliacc in https://github.com/meshtastic/firmware/pull/4850\r\n* Add a second delay() to get the unit tests running on Rak4631 by @jp-bennett in https://github.com/meshtastic/firmware/pull/4862\r\n* Add MAX17048 lipo fuel gauge by @dhskinner in https://github.com/meshtastic/firmware/pull/4851\r\n* Refactor AccelerometerThread.h by @dhskinner in https://github.com/meshtastic/firmware/pull/4831\r\n* Wrangle module frames with I2C keyboard by @todd-herbert in https://github.com/meshtastic/firmware/pull/4817\r\n* IS_ONE_OF macro to make long chains of conditions more concise and easy to follow by @thebentern in https://github.com/meshtastic/firmware/pull/4860\r\n* Create SECURITY.md by @thebentern in https://github.com/meshtastic/firmware/pull/4868\r\n* Encapsulate RadioLibInterface receive IRQ logic by @thebentern in https://github.com/meshtastic/firmware/pull/4866\r\n* Add pkc test by @jp-bennett in https://github.com/meshtastic/firmware/pull/4878\r\n* Add sx126x_ant_sw for Native by @jp-bennett in https://github.com/meshtastic/firmware/pull/4887\r\n* First stab at enabling store and forward for Native by @jp-bennett in https://github.com/meshtastic/firmware/pull/4891\r\n* Don't process RX when region unset by @caveman99 in https://github.com/meshtastic/firmware/pull/4895\r\n* Support T3S3 LR1121 variant by @caveman99 in https://github.com/meshtastic/firmware/pull/4869\r\n* First stab at ESP32-C6 support for TLora-C6 by @caveman99 in https://github.com/meshtastic/firmware/pull/4692\r\n\r\n## Bug fixes\r\n* Fix #4844 (Disable onboard buzzer on wakeup for some roles) by @caveman99 in https://github.com/meshtastic/firmware/pull/4859\r\n* Tbeams have no ADC by @caveman99 in https://github.com/meshtastic/firmware/pull/4871\r\n* DetectionSensor: more flexible triggering by @augustozanellato in https://github.com/meshtastic/firmware/pull/4780\r\n* Account for size of Envelope when allocating buffer. by @caveman99 in https://github.com/meshtastic/firmware/pull/4819\r\n* fix a lot of nuisances reported by cppcheck by @caveman99 in https://github.com/meshtastic/firmware/pull/4872\r\n* Update WaypointModule.cpp by @Szetya in https://github.com/meshtastic/firmware/pull/4870\r\n* Fix (some ?) memory alignment issues on the crypto part - resulting in crashes or strange behavior by @TheMalkavien in https://github.com/meshtastic/firmware/pull/4867\r\n* Update radiolib, fixes CRC bug on SX127x and improves LR11xx support by @caveman99 in https://github.com/meshtastic/firmware/pull/4880\r\n* Use delete[] to avoid leaking memory by @jp-bennett in https://github.com/meshtastic/firmware/pull/4883\r\n* Implement GPIO pin allowlist for Remote Hardware module by @Kealper in https://github.com/meshtastic/firmware/pull/4882\r\n* Ignore seen phoneapi packets by @thebentern in https://github.com/meshtastic/firmware/pull/4888\r\n* Only check hardsleep threshold if GPS softsleep is supported by @GUVWAF in https://github.com/meshtastic/firmware/pull/4893\r\n* Remove remote hardware from firmware release by @thebentern in https://github.com/meshtastic/firmware/pull/4890\r\n* Only log \"Setting DIO2 as RF switch\" when doing so and fix battery level by @dahanc in https://github.com/meshtastic/firmware/pull/4892\r\n* Potential fix for bad Rx performance on T1000-E by @GUVWAF in https://github.com/meshtastic/firmware/pull/4885\r\n\r\n## New Contributors\r\n* @TheMalkavien made their first contribution in https://github.com/meshtastic/firmware/pull/4867\r\n\r\n**Full Changelog**: https://github.com/meshtastic/firmware/compare/v2.5.2.771cb52...v2.5.3.a70d5ee" + }, + { + "id": "v2.5.2.771cb52", + "title": "Meshtastic Firmware 2.5.2.771cb52 Alpha", + "page_url": "https://github.com/meshtastic/firmware/releases/tag/v2.5.2.771cb52", + "zip_url": "https://github.com/meshtastic/firmware/releases/download/v2.5.2.771cb52/firmware-2.5.2.771cb52.zip", + "release_notes": "## Enhancements\r\n* Set title for protobufs update PR by @scruplelesswizard in https://github.com/meshtastic/firmware/pull/4792\r\n* Set title for version bump PRs by @scruplelesswizard in https://github.com/meshtastic/firmware/pull/4791\r\n* Enable Dependabot by @scruplelesswizard in https://github.com/meshtastic/firmware/pull/4790\r\n* Actions: Semgrep Images have moved from returntocorp to semgrep by @fifieldt in https://github.com/meshtastic/firmware/pull/4774\r\n* Update protobufs and classes by @github-actions in https://github.com/meshtastic/firmware/pull/4804\r\n* Heltec-wireless-bridge by @caveman99 in https://github.com/meshtastic/firmware/pull/4801\r\n* Update classes on protobufs update by @scruplelesswizard in https://github.com/meshtastic/firmware/pull/4805\r\n* [Board] DIY \"t-energy-s3_e22\" by @vidplace7 in https://github.com/meshtastic/firmware/pull/4782\r\n* Make Ublox code more readable by @fifieldt in https://github.com/meshtastic/firmware/pull/4727\r\n* I2C for Heltec Mesh Node T114 by @todd-herbert in https://github.com/meshtastic/firmware/pull/4745\r\n* Refactor and consolidate time window logic by @thebentern in https://github.com/meshtastic/firmware/pull/4826\r\n* Consolidate variant build steps by @scruplelesswizard in https://github.com/meshtastic/firmware/pull/4820\r\n\r\n# Bug fixes\r\n* Minor fix by @fifieldt in https://github.com/meshtastic/firmware/pull/4666\r\n* Update platform-native to pick up portduino crash fix by @jp-bennett in https://github.com/meshtastic/firmware/pull/4807\r\n* Rename message length headers and set payload max to 255 by @jp-bennett in https://github.com/meshtastic/firmware/pull/4827\r\n* Check for null before printing debug by @jp-bennett in https://github.com/meshtastic/firmware/pull/4835\r\n* Teardown bluetooth phoneAPI better and fix client notification issue by @thebentern in https://github.com/meshtastic/firmware/pull/4834\r\n* Fix RAK4631 accelerometer by @thebentern in https://github.com/meshtastic/firmware/pull/4837\r\n* Second Wire is PIN_WIRE1_SDA by @fifieldt in https://github.com/meshtastic/firmware/pull/4840\r\n* Build message in printBytes, to not spam BLE log by @jp-bennett in https://github.com/meshtastic/firmware/pull/4843\r\n* Syntax fix for github action by @fifieldt in https://github.com/meshtastic/firmware/pull/4846\r\n* Sed doesn't like newlines by @scruplelesswizard in https://github.com/meshtastic/firmware/pull/4847\r\n* Chomp trailing newline by @scruplelesswizard in https://github.com/meshtastic/firmware/pull/4848\r\n* Fix Ublox M10 Setup by @fifieldt in https://github.com/meshtastic/firmware/pull/4842\r\n* Remove old comments from main by @fifieldt in https://github.com/meshtastic/firmware/pull/4849\r\n* Fix deep-sleep for T-Beam by @todd-herbert in https://github.com/meshtastic/firmware/pull/4802\r\n\r\n## New Contributors\r\n* @scruplelesswizard made their first contribution in https://github.com/meshtastic/firmware/pull/4792\r\n* @dependabot made their first contribution in https://github.com/meshtastic/firmware/pull/4797\r\n* @vidplace7 made their first contribution in https://github.com/meshtastic/firmware/pull/4782\r\n\r\n**Full Changelog**: https://github.com/meshtastic/firmware/compare/v2.5.1.c13b44b...v2.5.2.771cb52" + } + ] + }, + "pullRequests": [] +} \ No newline at end of file diff --git a/app/src/main/java/com/geeksville/mesh/MyNodeInfo.kt b/app/src/main/java/com/geeksville/mesh/MyNodeInfo.kt index dec4bee54..41965a2ec 100644 --- a/app/src/main/java/com/geeksville/mesh/MyNodeInfo.kt +++ b/app/src/main/java/com/geeksville/mesh/MyNodeInfo.kt @@ -35,7 +35,8 @@ data class MyNodeInfo( val maxChannels: Int, val hasWifi: Boolean, val channelUtilization: Float, - val airUtilTx: Float + val airUtilTx: Float, + val deviceId: String?, ) : Parcelable { /** A human readable description of the software/hardware version */ val firmwareString: String get() = "$model $firmwareVersion" diff --git a/app/src/main/java/com/geeksville/mesh/database/Converters.kt b/app/src/main/java/com/geeksville/mesh/database/Converters.kt index d5cc3d09a..97ddf5d21 100644 --- a/app/src/main/java/com/geeksville/mesh/database/Converters.kt +++ b/app/src/main/java/com/geeksville/mesh/database/Converters.kt @@ -129,4 +129,20 @@ class Converters : Logging { fun metadataToBytes(value: MeshProtos.DeviceMetadata): ByteArray? { return value.toByteArray() } + + @TypeConverter + fun fromStringList(value: String?): List? { + if (value == null) { + return null + } + return Json.decodeFromString>(value) + } + + @TypeConverter + fun toStringList(list: List?): String? { + if (list == null) { + return null + } + return Json.encodeToString(list) + } } diff --git a/app/src/main/java/com/geeksville/mesh/database/DatabaseModule.kt b/app/src/main/java/com/geeksville/mesh/database/DatabaseModule.kt index 2e8626f0c..db0ba1251 100644 --- a/app/src/main/java/com/geeksville/mesh/database/DatabaseModule.kt +++ b/app/src/main/java/com/geeksville/mesh/database/DatabaseModule.kt @@ -18,6 +18,8 @@ package com.geeksville.mesh.database import android.app.Application +import com.geeksville.mesh.database.dao.DeviceHardwareDao +import com.geeksville.mesh.database.dao.FirmwareReleaseDao import com.geeksville.mesh.database.dao.MeshLogDao import com.geeksville.mesh.database.dao.NodeInfoDao import com.geeksville.mesh.database.dao.PacketDao @@ -55,4 +57,14 @@ class DatabaseModule { fun provideQuickChatActionDao(database: MeshtasticDatabase): QuickChatActionDao { return database.quickChatActionDao() } -} \ No newline at end of file + + @Provides + fun provideDeviceHardwareDao(database: MeshtasticDatabase): DeviceHardwareDao { + return database.deviceHardwareDao() + } + + @Provides + fun provideFirmwareReleaseDao(database: MeshtasticDatabase): FirmwareReleaseDao { + return database.firmwareReleaseDao() + } +} diff --git a/app/src/main/java/com/geeksville/mesh/database/MeshtasticDatabase.kt b/app/src/main/java/com/geeksville/mesh/database/MeshtasticDatabase.kt index 0578a5a0b..740f0711d 100644 --- a/app/src/main/java/com/geeksville/mesh/database/MeshtasticDatabase.kt +++ b/app/src/main/java/com/geeksville/mesh/database/MeshtasticDatabase.kt @@ -25,11 +25,15 @@ import androidx.room.Room import androidx.room.RoomDatabase import androidx.room.TypeConverters import androidx.room.migration.AutoMigrationSpec -import com.geeksville.mesh.database.dao.PacketDao +import com.geeksville.mesh.database.dao.DeviceHardwareDao +import com.geeksville.mesh.database.dao.FirmwareReleaseDao import com.geeksville.mesh.database.dao.MeshLogDao import com.geeksville.mesh.database.dao.NodeInfoDao +import com.geeksville.mesh.database.dao.PacketDao import com.geeksville.mesh.database.dao.QuickChatActionDao import com.geeksville.mesh.database.entity.ContactSettings +import com.geeksville.mesh.database.entity.DeviceHardwareEntity +import com.geeksville.mesh.database.entity.FirmwareReleaseEntity import com.geeksville.mesh.database.entity.MeshLog import com.geeksville.mesh.database.entity.MetadataEntity import com.geeksville.mesh.database.entity.MyNodeEntity @@ -48,6 +52,8 @@ import com.geeksville.mesh.database.entity.ReactionEntity QuickChatAction::class, ReactionEntity::class, MetadataEntity::class, + DeviceHardwareEntity::class, + FirmwareReleaseEntity::class, ], autoMigrations = [ AutoMigration(from = 3, to = 4), @@ -63,8 +69,9 @@ import com.geeksville.mesh.database.entity.ReactionEntity AutoMigration(from = 13, to = 14), AutoMigration(from = 14, to = 15), AutoMigration(from = 15, to = 16), + AutoMigration(from = 16, to = 17), ], - version = 16, + version = 17, exportSchema = true, ) @TypeConverters(Converters::class) @@ -73,6 +80,8 @@ abstract class MeshtasticDatabase : RoomDatabase() { abstract fun packetDao(): PacketDao abstract fun meshLogDao(): MeshLogDao abstract fun quickChatActionDao(): QuickChatActionDao + abstract fun deviceHardwareDao(): DeviceHardwareDao + abstract fun firmwareReleaseDao(): FirmwareReleaseDao companion object { fun getDatabase(context: Context): MeshtasticDatabase { @@ -82,7 +91,7 @@ abstract class MeshtasticDatabase : RoomDatabase() { MeshtasticDatabase::class.java, "meshtastic_database" ) - .fallbackToDestructiveMigration() + .fallbackToDestructiveMigration(false) .build() } } diff --git a/app/src/main/java/com/geeksville/mesh/database/dao/DeviceHardwareDao.kt b/app/src/main/java/com/geeksville/mesh/database/dao/DeviceHardwareDao.kt new file mode 100644 index 000000000..6650abadf --- /dev/null +++ b/app/src/main/java/com/geeksville/mesh/database/dao/DeviceHardwareDao.kt @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2025 Meshtastic LLC + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.geeksville.mesh.database.dao + +import androidx.room.Dao +import androidx.room.Insert +import androidx.room.OnConflictStrategy +import androidx.room.Query +import com.geeksville.mesh.database.entity.DeviceHardwareEntity + +@Dao +interface DeviceHardwareDao { + @Insert(onConflict = OnConflictStrategy.REPLACE) + suspend fun insert(deviceHardware: DeviceHardwareEntity) + + @Query("SELECT * FROM device_hardware WHERE hwModel = :hwModel") + suspend fun getByHwModel(hwModel: Int): DeviceHardwareEntity? + + @Query("DELETE FROM device_hardware") + suspend fun deleteAll() +} diff --git a/app/src/main/java/com/geeksville/mesh/database/dao/FirmwareReleaseDao.kt b/app/src/main/java/com/geeksville/mesh/database/dao/FirmwareReleaseDao.kt new file mode 100644 index 000000000..6576607c7 --- /dev/null +++ b/app/src/main/java/com/geeksville/mesh/database/dao/FirmwareReleaseDao.kt @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2025 Meshtastic LLC + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.geeksville.mesh.database.dao + +import androidx.room.Dao +import androidx.room.Insert +import androidx.room.OnConflictStrategy +import androidx.room.Query +import com.geeksville.mesh.database.entity.FirmwareReleaseEntity +import com.geeksville.mesh.database.entity.FirmwareReleaseType + +@Dao +interface FirmwareReleaseDao { + @Insert(onConflict = OnConflictStrategy.REPLACE) + suspend fun insert(firmwareReleaseEntity: FirmwareReleaseEntity) + + @Query("DELETE FROM firmware_release") + suspend fun deleteAll() + + @Query("SELECT * FROM firmware_release") + suspend fun getAllReleases(): List? + + @Query("SELECT * FROM firmware_release WHERE release_type = :releaseType") + suspend fun getReleasesByType(releaseType: FirmwareReleaseType): List? +} diff --git a/app/src/main/java/com/geeksville/mesh/database/entity/DeviceHardwareEntity.kt b/app/src/main/java/com/geeksville/mesh/database/entity/DeviceHardwareEntity.kt new file mode 100644 index 000000000..c00a63d22 --- /dev/null +++ b/app/src/main/java/com/geeksville/mesh/database/entity/DeviceHardwareEntity.kt @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2025 Meshtastic LLC + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.geeksville.mesh.database.entity + +import androidx.room.ColumnInfo +import androidx.room.Entity +import androidx.room.PrimaryKey +import com.geeksville.mesh.model.DeviceHardware +import com.geeksville.mesh.network.model.NetworkDeviceHardware +import kotlinx.serialization.Serializable + +@Serializable +@Entity(tableName = "device_hardware") +data class DeviceHardwareEntity( + @ColumnInfo(name = "actively_supported") val activelySupported: Boolean, + val architecture: String, + @ColumnInfo(name = "display_name") val displayName: String, + @ColumnInfo(name = "has_ink_hud") val hasInkHud: Boolean? = null, + @ColumnInfo(name = "has_mui") val hasMui: Boolean? = null, + @PrimaryKey val hwModel: Int, + @ColumnInfo(name = "hw_model_slug") val hwModelSlug: String, + val images: List?, + @ColumnInfo(name = "last_updated") val lastUpdated: Long = System.currentTimeMillis(), + @ColumnInfo(name = "partition_scheme") val partitionScheme: String? = null, + @ColumnInfo(name = "platformio_target") val platformioTarget: String, + @ColumnInfo(name = "requires_dfu") val requiresDfu: Boolean?, + @ColumnInfo(name = "support_level") val supportLevel: Int?, + val tags: List?, +) + +fun NetworkDeviceHardware.asEntity() = DeviceHardwareEntity( + activelySupported = activelySupported, + architecture = architecture, + displayName = displayName, + hasInkHud = hasInkHud, + hasMui = hasMui, + hwModel = hwModel, + hwModelSlug = hwModelSlug, + images = images, + lastUpdated = System.currentTimeMillis(), + partitionScheme = partitionScheme, + platformioTarget = platformioTarget, + requiresDfu = requiresDfu, + supportLevel = supportLevel, + tags = tags, +) + +fun DeviceHardwareEntity.asExternalModel() = DeviceHardware( + activelySupported = activelySupported, + architecture = architecture, + displayName = displayName, + hasInkHud = hasInkHud, + hasMui = hasMui, + hwModel = hwModel, + hwModelSlug = hwModelSlug, + images = images, + partitionScheme = partitionScheme, + platformioTarget = platformioTarget, + requiresDfu = requiresDfu, + supportLevel = supportLevel, + tags = tags, +) diff --git a/app/src/main/java/com/geeksville/mesh/database/entity/FirmwareReleaseEntity.kt b/app/src/main/java/com/geeksville/mesh/database/entity/FirmwareReleaseEntity.kt new file mode 100644 index 000000000..68a962eb2 --- /dev/null +++ b/app/src/main/java/com/geeksville/mesh/database/entity/FirmwareReleaseEntity.kt @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2025 Meshtastic LLC + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.geeksville.mesh.database.entity + +import androidx.room.ColumnInfo +import androidx.room.Entity +import androidx.room.PrimaryKey +import com.geeksville.mesh.network.model.NetworkFirmwareRelease +import kotlinx.serialization.Serializable + +@Serializable +@Entity(tableName = "firmware_release") +data class FirmwareReleaseEntity( + @PrimaryKey + @ColumnInfo(name = "id") + val id: String = "", + @ColumnInfo(name = "page_url") + val pageUrl: String = "", + @ColumnInfo(name = "release_notes") + val releaseNotes: String = "", + @ColumnInfo(name = "title") + val title: String = "", + @ColumnInfo(name = "zip_url") + val zipUrl: String = "", + @ColumnInfo(name = "last_updated") + val lastUpdated: Long = System.currentTimeMillis(), + @ColumnInfo(name = "release_type") + val releaseType: FirmwareReleaseType = FirmwareReleaseType.STABLE, +) + +fun NetworkFirmwareRelease.asEntity(releaseType: FirmwareReleaseType) = FirmwareReleaseEntity( + id = id, + pageUrl = pageUrl, + releaseNotes = releaseNotes, + title = title, + zipUrl = zipUrl, + lastUpdated = System.currentTimeMillis(), + releaseType = releaseType, +) + +fun FirmwareReleaseEntity.asExternalModel() = FirmwareRelease( + id = id, + pageUrl = pageUrl, + releaseNotes = releaseNotes, + title = title, + zipUrl = zipUrl, + lastUpdated = lastUpdated, + releaseType = releaseType, +) + +data class FirmwareRelease( + val id: String = "", + val pageUrl: String = "", + val releaseNotes: String = "", + val title: String = "", + val zipUrl: String = "", + val lastUpdated: Long = System.currentTimeMillis(), + val releaseType: FirmwareReleaseType = FirmwareReleaseType.STABLE, +) + +enum class FirmwareReleaseType { + STABLE, + ALPHA +} diff --git a/app/src/main/java/com/geeksville/mesh/database/entity/MyNodeEntity.kt b/app/src/main/java/com/geeksville/mesh/database/entity/MyNodeEntity.kt index 722187439..f6a99e037 100644 --- a/app/src/main/java/com/geeksville/mesh/database/entity/MyNodeEntity.kt +++ b/app/src/main/java/com/geeksville/mesh/database/entity/MyNodeEntity.kt @@ -34,6 +34,7 @@ data class MyNodeEntity( val minAppVersion: Int, val maxChannels: Int, val hasWifi: Boolean, + val deviceId: String? = "unknown", ) { /** A human readable description of the software/hardware version */ val firmwareString: String get() = "$model $firmwareVersion" @@ -52,5 +53,6 @@ data class MyNodeEntity( hasWifi = hasWifi, channelUtilization = 0f, airUtilTx = 0f, + deviceId = deviceId, ) } diff --git a/app/src/main/java/com/geeksville/mesh/model/MetricsViewModel.kt b/app/src/main/java/com/geeksville/mesh/model/MetricsViewModel.kt index 783390d81..58c7444b6 100644 --- a/app/src/main/java/com/geeksville/mesh/model/MetricsViewModel.kt +++ b/app/src/main/java/com/geeksville/mesh/model/MetricsViewModel.kt @@ -29,7 +29,6 @@ import androidx.lifecycle.viewModelScope import androidx.navigation.toRoute import com.geeksville.mesh.ConfigProtos.Config.DisplayConfig.DisplayUnits import com.geeksville.mesh.CoroutineDispatchers -import com.geeksville.mesh.MeshProtos.HardwareModel import com.geeksville.mesh.MeshProtos.MeshPacket import com.geeksville.mesh.MeshProtos.Position import com.geeksville.mesh.Portnums.PortNum @@ -37,9 +36,12 @@ import com.geeksville.mesh.R import com.geeksville.mesh.TelemetryProtos.Telemetry import com.geeksville.mesh.android.Logging import com.geeksville.mesh.database.MeshLogRepository +import com.geeksville.mesh.database.entity.FirmwareRelease import com.geeksville.mesh.database.entity.MeshLog import com.geeksville.mesh.model.map.CustomTileSource import com.geeksville.mesh.navigation.Route +import com.geeksville.mesh.repository.api.DeviceHardwareRepository +import com.geeksville.mesh.repository.api.FirmwareReleaseRepository import com.geeksville.mesh.repository.datastore.RadioConfigRepository import com.geeksville.mesh.service.ServiceAction import com.geeksville.mesh.ui.map.MAP_STYLE_ID @@ -56,11 +58,9 @@ import kotlinx.coroutines.flow.toList import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch import kotlinx.coroutines.withContext -import kotlinx.serialization.json.Json import java.io.BufferedWriter import java.io.FileNotFoundException import java.io.FileWriter -import java.io.IOException import java.text.SimpleDateFormat import java.util.Locale import java.util.concurrent.TimeUnit @@ -79,6 +79,9 @@ data class MetricsState( val tracerouteResults: List = emptyList(), val positionLogs: List = emptyList(), val deviceHardware: DeviceHardware? = null, + val isLocalDevice: Boolean = false, + val latestStableFirmware: FirmwareRelease? = null, + val latestAlphaFirmware: FirmwareRelease? = null, ) { fun hasDeviceMetrics() = deviceMetrics.isNotEmpty() fun hasSignalMetrics() = signalMetrics.isNotEmpty() @@ -188,6 +191,7 @@ private fun MeshPacket.toPosition(): Position? = if (!decoded.wantResponse) { null } +@Suppress("LongParameterList") @HiltViewModel class MetricsViewModel @Inject constructor( savedStateHandle: SavedStateHandle, @@ -195,6 +199,8 @@ class MetricsViewModel @Inject constructor( private val dispatchers: CoroutineDispatchers, private val meshLogRepository: MeshLogRepository, private val radioConfigRepository: RadioConfigRepository, + private val deviceHardwareRepository: DeviceHardwareRepository, + private val firmwareReleaseRepository: FirmwareReleaseRepository, private val preferences: SharedPreferences, ) : ViewModel(), Logging { private val destNum = savedStateHandle.toRoute().destNum @@ -229,25 +235,23 @@ class MetricsViewModel @Inject constructor( private val _timeFrame = MutableStateFlow(TimeFrame.TWENTY_FOUR_HOURS) val timeFrame: StateFlow = _timeFrame - private var deviceHardwareList: List = listOf() - init { destNum?.let { radioConfigRepository.nodeDBbyNum .mapLatest { nodes -> nodes[destNum] to nodes.keys.firstOrNull() } .distinctUntilChanged() .onEach { (node, ourNode) -> - _state.update { state -> state.copy(node = node, isLocal = destNum == ourNode) } - node?.user?.hwModel?.let { hwModel -> - val deviceHardware = getDeviceHardwareFromHardwareModel(hwModel) - deviceHardware?.let { - _state.update { state -> - state.copy(deviceHardware = it) - } - } + val deviceHardware = node?.user?.hwModel?.number?.let { + deviceHardwareRepository.getDeviceHardwareByModel(it) } - } - .launchIn(viewModelScope) + _state.update { state -> + state.copy( + node = node, + isLocal = destNum == ourNode, + deviceHardware = deviceHardware + ) + } + }.launchIn(viewModelScope) radioConfigRepository.deviceProfileFlow.onEach { profile -> val moduleConfig = profile.moduleConfig @@ -308,6 +312,18 @@ class MetricsViewModel @Inject constructor( } }.launchIn(viewModelScope) + firmwareReleaseRepository.stableRelease.onEach { latestStable -> + _state.update { state -> + state.copy(latestStableFirmware = latestStable) + } + }.launchIn(viewModelScope) + + firmwareReleaseRepository.alphaRelease.onEach { latestAlpha -> + _state.update { state -> + state.copy(latestAlphaFirmware = latestAlpha) + } + }.launchIn(viewModelScope) + debug("MetricsViewModel created") } } @@ -361,22 +377,4 @@ class MetricsViewModel @Inject constructor( errormsg("Can't write file error: ${ex.message}") } } - - private fun getDeviceHardwareFromHardwareModel( - hwModel: HardwareModel - ): DeviceHardware? { - if (deviceHardwareList.isEmpty()) { - try { - val json = - app.assets.open("device_hardware.json").bufferedReader().use { it.readText() } - deviceHardwareList = Json.decodeFromString>(json) - return deviceHardwareList.find { it.hwModel == hwModel.number } - } catch (ex: IOException) { - errormsg("Can't read device_hardware.json error: ${ex.message}") - } catch (ex: IllegalArgumentException) { - errormsg(ex.message.toString()) - } - } - return null - } } diff --git a/app/src/main/java/com/geeksville/mesh/repository/api/DeviceHardwareJsonDataSource.kt b/app/src/main/java/com/geeksville/mesh/repository/api/DeviceHardwareJsonDataSource.kt new file mode 100644 index 000000000..8d773b4d5 --- /dev/null +++ b/app/src/main/java/com/geeksville/mesh/repository/api/DeviceHardwareJsonDataSource.kt @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2025 Meshtastic LLC + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.geeksville.mesh.repository.api + +import android.app.Application +import com.geeksville.mesh.network.model.NetworkDeviceHardware +import kotlinx.serialization.ExperimentalSerializationApi +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.decodeFromStream +import javax.inject.Inject + +class DeviceHardwareJsonDataSource @Inject constructor( + private val application: Application, +) { + @OptIn(ExperimentalSerializationApi::class) + fun loadDeviceHardwareFromJsonAsset(): List { + val inputStream = application.assets.open("device_hardware.json") + return Json.decodeFromStream>(inputStream) + } +} diff --git a/app/src/main/java/com/geeksville/mesh/repository/api/DeviceHardwareLocalDataSource.kt b/app/src/main/java/com/geeksville/mesh/repository/api/DeviceHardwareLocalDataSource.kt new file mode 100644 index 000000000..10bf84652 --- /dev/null +++ b/app/src/main/java/com/geeksville/mesh/repository/api/DeviceHardwareLocalDataSource.kt @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2025 Meshtastic LLC + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.geeksville.mesh.repository.api + +import com.geeksville.mesh.database.dao.DeviceHardwareDao +import com.geeksville.mesh.database.entity.DeviceHardwareEntity +import com.geeksville.mesh.database.entity.asEntity +import com.geeksville.mesh.network.model.NetworkDeviceHardware +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import javax.inject.Inject + +class DeviceHardwareLocalDataSource @Inject constructor( + private val deviceHardwareDaoLazy: dagger.Lazy +) { + private val deviceHardwareDao by lazy { + deviceHardwareDaoLazy.get() + } + + suspend fun insertAllDeviceHardware(deviceHardware: List) = + withContext(Dispatchers.IO) { + deviceHardware.forEach { deviceHardware -> + deviceHardwareDao.insert(deviceHardware.asEntity()) + } + } + + suspend fun deleteAllDeviceHardware() = withContext(Dispatchers.IO) { + deviceHardwareDao.deleteAll() + } + + suspend fun getByHwModel(hwModel: Int): DeviceHardwareEntity? = withContext(Dispatchers.IO) { + deviceHardwareDao.getByHwModel(hwModel) + } +} diff --git a/app/src/main/java/com/geeksville/mesh/repository/api/DeviceHardwareRepository.kt b/app/src/main/java/com/geeksville/mesh/repository/api/DeviceHardwareRepository.kt new file mode 100644 index 000000000..ca1956106 --- /dev/null +++ b/app/src/main/java/com/geeksville/mesh/repository/api/DeviceHardwareRepository.kt @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2025 Meshtastic LLC + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.geeksville.mesh.repository.api + +import com.geeksville.mesh.android.BuildUtils.debug +import com.geeksville.mesh.android.BuildUtils.warn +import com.geeksville.mesh.database.entity.asExternalModel +import com.geeksville.mesh.model.DeviceHardware +import com.geeksville.mesh.network.DeviceHardwareRemoteDataSource +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import java.io.IOException +import javax.inject.Inject + +class DeviceHardwareRepository @Inject constructor( + private val apiDataSource: DeviceHardwareRemoteDataSource, + private val localDataSource: DeviceHardwareLocalDataSource, + private val jsonDataSource: DeviceHardwareJsonDataSource, +) { + + companion object { + // 1 day + private const val CACHE_EXPIRATION_TIME_MS = 24 * 60 * 60 * 1000L + } + + suspend fun getDeviceHardwareByModel(hwModel: Int, refresh: Boolean = false): DeviceHardware? { + return withContext(Dispatchers.IO) { + if (refresh) { + invalidateCache() + } else { + val cachedHardware = localDataSource.getByHwModel(hwModel) + if (cachedHardware != null && !isCacheExpired(cachedHardware.lastUpdated)) { + debug("Using recent cached device hardware") + val externalModel = cachedHardware.asExternalModel() + return@withContext externalModel + } + } + try { + debug("Fetching device hardware from server") + localDataSource.insertAllDeviceHardware(apiDataSource.getAllDeviceHardware()) + val cachedHardware = localDataSource.getByHwModel(hwModel) + val externalModel = cachedHardware?.asExternalModel() + return@withContext externalModel + } catch (e: IOException) { + warn("Failed to fetch device hardware from server: ${e.message}") + var cachedHardware = localDataSource.getByHwModel(hwModel) + if (cachedHardware != null) { + debug("Using stale cached device hardware") + return@withContext cachedHardware.asExternalModel() + } + debug("Loading and caching device hardware from local JSON asset") + localDataSource.insertAllDeviceHardware(jsonDataSource.loadDeviceHardwareFromJsonAsset()) + cachedHardware = localDataSource.getByHwModel(hwModel) + val externalModel = cachedHardware?.asExternalModel() + return@withContext externalModel + } + } + } + + suspend fun invalidateCache() { + localDataSource.deleteAllDeviceHardware() + } + + /** + * Check if the cache is expired + */ + private fun isCacheExpired(lastUpdated: Long): Boolean { + return System.currentTimeMillis() - lastUpdated > CACHE_EXPIRATION_TIME_MS + } +} diff --git a/app/src/main/java/com/geeksville/mesh/repository/api/FirmwareReleaseJsonDataSource.kt b/app/src/main/java/com/geeksville/mesh/repository/api/FirmwareReleaseJsonDataSource.kt new file mode 100644 index 000000000..96d4d019a --- /dev/null +++ b/app/src/main/java/com/geeksville/mesh/repository/api/FirmwareReleaseJsonDataSource.kt @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2025 Meshtastic LLC + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.geeksville.mesh.repository.api + +import android.app.Application +import com.geeksville.mesh.network.model.NetworkFirmwareReleases +import kotlinx.serialization.ExperimentalSerializationApi +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.decodeFromStream +import javax.inject.Inject + +class FirmwareReleaseJsonDataSource @Inject constructor( + private val application: Application, +) { + @OptIn(ExperimentalSerializationApi::class) + fun loadFirmwareReleaseFromJsonAsset(): NetworkFirmwareReleases { + val inputStream = application.assets.open("firmware_releases.json") + val result = inputStream.use { + Json.decodeFromStream(inputStream) + } + return result + } +} diff --git a/app/src/main/java/com/geeksville/mesh/repository/api/FirmwareReleaseLocalDataSource.kt b/app/src/main/java/com/geeksville/mesh/repository/api/FirmwareReleaseLocalDataSource.kt new file mode 100644 index 000000000..5094c6bbe --- /dev/null +++ b/app/src/main/java/com/geeksville/mesh/repository/api/FirmwareReleaseLocalDataSource.kt @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2025 Meshtastic LLC + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.geeksville.mesh.repository.api + +import com.geeksville.mesh.database.dao.FirmwareReleaseDao +import com.geeksville.mesh.database.entity.FirmwareReleaseEntity +import com.geeksville.mesh.database.entity.FirmwareReleaseType +import com.geeksville.mesh.database.entity.asEntity +import com.geeksville.mesh.network.model.NetworkFirmwareRelease +import dagger.Lazy +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import javax.inject.Inject + +class FirmwareReleaseLocalDataSource @Inject constructor( + private val firmwareReleaseDaoLazy: Lazy +) { + private val firmwareReleaseDao by lazy { + firmwareReleaseDaoLazy.get() + } + + suspend fun insertFirmwareReleases( + firmwareReleases: List, + releaseType: FirmwareReleaseType + ) = + withContext(Dispatchers.IO) { + firmwareReleases.forEach { firmwareRelease -> + firmwareReleaseDao.insert(firmwareRelease.asEntity(releaseType)) + } + } + + suspend fun deleteAllFirmwareReleases() = withContext(Dispatchers.IO) { + firmwareReleaseDao.deleteAll() + } + + suspend fun getLatestRelease(releaseType: FirmwareReleaseType): FirmwareReleaseEntity? = + withContext(Dispatchers.IO) { + val releases = firmwareReleaseDao.getReleasesByType(releaseType) + val latestRelease = + releases?.firstOrNull() + return@withContext latestRelease + } +} diff --git a/app/src/main/java/com/geeksville/mesh/repository/api/FirmwareReleaseRepository.kt b/app/src/main/java/com/geeksville/mesh/repository/api/FirmwareReleaseRepository.kt new file mode 100644 index 000000000..cd642b1d1 --- /dev/null +++ b/app/src/main/java/com/geeksville/mesh/repository/api/FirmwareReleaseRepository.kt @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2025 Meshtastic LLC + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.geeksville.mesh.repository.api + +import com.geeksville.mesh.android.BuildUtils.debug +import com.geeksville.mesh.android.BuildUtils.warn +import com.geeksville.mesh.database.entity.FirmwareRelease +import com.geeksville.mesh.database.entity.FirmwareReleaseType +import com.geeksville.mesh.database.entity.asExternalModel +import com.geeksville.mesh.network.FirmwareReleaseRemoteDataSource +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flow +import java.io.IOException +import javax.inject.Inject + +class FirmwareReleaseRepository @Inject constructor( + private val apiDataSource: FirmwareReleaseRemoteDataSource, + private val localDataSource: FirmwareReleaseLocalDataSource, + private val jsonDataSource: FirmwareReleaseJsonDataSource, +) { + + companion object { + // 1 hour + private const val CACHE_EXPIRATION_TIME_MS = 60 * 60 * 1000L + } + + val stableRelease: Flow = getLatestFirmware(FirmwareReleaseType.STABLE) + + val alphaRelease: Flow = getLatestFirmware(FirmwareReleaseType.ALPHA) + + private fun getLatestFirmware( + releaseType: FirmwareReleaseType, + refresh: Boolean = false + ): Flow = flow { + if (refresh) { + invalidateCache() + } else { + val cachedRelease = localDataSource.getLatestRelease(releaseType) + if (cachedRelease != null && !isCacheExpired(cachedRelease.lastUpdated)) { + debug("Using recent cached firmware release") + val externalModel = cachedRelease.asExternalModel() + emit(externalModel) + return@flow + } + } + try { + debug("Fetching firmware releases from server") + val networkFirmwareReleases = apiDataSource.getFirmwareReleases() + val releases = when (releaseType) { + FirmwareReleaseType.STABLE -> networkFirmwareReleases.releases.stable + FirmwareReleaseType.ALPHA -> networkFirmwareReleases.releases.alpha + } + localDataSource.insertFirmwareReleases( + releases, + releaseType + ) + val cachedRelease = localDataSource.getLatestRelease(releaseType) + val externalModel = cachedRelease?.asExternalModel() + emit(externalModel) + } catch (e: IOException) { + warn("Failed to fetch firmware releases from server: ${e.message}") + val jsonFirmwareReleases = jsonDataSource.loadFirmwareReleaseFromJsonAsset() + val releases = when (releaseType) { + FirmwareReleaseType.STABLE -> jsonFirmwareReleases.releases.stable + FirmwareReleaseType.ALPHA -> jsonFirmwareReleases.releases.alpha + } + localDataSource.insertFirmwareReleases( + releases, + releaseType + ) + val cachedRelease = localDataSource.getLatestRelease(releaseType) + val externalModel = cachedRelease?.asExternalModel() + emit(externalModel) + } + } + + suspend fun invalidateCache() { + localDataSource.deleteAllFirmwareReleases() + } + + /** + * Check if the cache is expired + */ + private fun isCacheExpired(lastUpdated: Long): Boolean { + return System.currentTimeMillis() - lastUpdated > CACHE_EXPIRATION_TIME_MS + } +} diff --git a/app/src/main/java/com/geeksville/mesh/service/MeshService.kt b/app/src/main/java/com/geeksville/mesh/service/MeshService.kt index 8f5ab983a..1cb9e727b 100644 --- a/app/src/main/java/com/geeksville/mesh/service/MeshService.kt +++ b/app/src/main/java/com/geeksville/mesh/service/MeshService.kt @@ -1604,6 +1604,7 @@ class MeshService : Service(), Logging { minAppVersion = minAppVersion, maxChannels = 8, hasWifi = metadata.hasWifi, + deviceId = deviceId.toStringUtf8(), ) } serviceScope.handledLaunch { diff --git a/app/src/main/java/com/geeksville/mesh/ui/NodeDetail.kt b/app/src/main/java/com/geeksville/mesh/ui/NodeDetail.kt index eb00668c4..660c8fdbc 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/NodeDetail.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/NodeDetail.kt @@ -57,11 +57,11 @@ import androidx.compose.material.icons.filled.Share import androidx.compose.material.icons.filled.SignalCellularAlt import androidx.compose.material.icons.filled.Speed import androidx.compose.material.icons.filled.Thermostat -import androidx.compose.material.icons.filled.Verified import androidx.compose.material.icons.filled.WaterDrop import androidx.compose.material.icons.filled.Work import androidx.compose.material.icons.outlined.Navigation import androidx.compose.material.icons.outlined.NoCell +import androidx.compose.material.icons.twotone.Verified import androidx.compose.material3.Card import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.Icon @@ -79,6 +79,7 @@ import androidx.compose.ui.draw.rotate import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.vectorResource @@ -90,7 +91,11 @@ import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle import coil3.compose.AsyncImage +import coil3.request.ErrorResult +import coil3.request.ImageRequest +import coil3.request.SuccessResult import com.geeksville.mesh.R +import com.geeksville.mesh.android.BuildUtils.debug import com.geeksville.mesh.model.DeviceHardware import com.geeksville.mesh.model.MetricsState import com.geeksville.mesh.model.MetricsViewModel @@ -207,6 +212,33 @@ private fun NodeDetailList( NodeDetailsContent(node) } } + node.metadata?.firmwareVersion?.let { firmwareVersion -> + item { + PreferenceCategory(stringResource(R.string.firmware)) { + val latestStableFirmware = metricsState.latestStableFirmware + val latestAlphaFirmware = metricsState.latestAlphaFirmware + NodeDetailRow( + label = "Installed", + icon = Icons.Default.Memory, + value = firmwareVersion.substringBeforeLast(".") + ) + latestStableFirmware?.let { stable -> + NodeDetailRow( + label = "Latest stable", + icon = Icons.Default.Memory, + value = stable.id.substringBeforeLast(".").replace("v", "") + ) + } + latestAlphaFirmware?.let { alpha -> + NodeDetailRow( + label = "Latest alpha", + icon = Icons.Default.Memory, + value = alpha.id.substringBeforeLast(".").replace("v", "") + ) + } + } + } + } item { DeviceActions( @@ -332,25 +364,19 @@ private fun DeviceDetailsContent( ), contentAlignment = Alignment.Center ) { - DeviceHardwareImage( - deviceHardware = deviceHardware, - modifier = Modifier - .size(100.dp) - ) + DeviceHardwareImage(deviceHardware, Modifier.fillMaxSize()) } NodeDetailRow( label = stringResource(R.string.hardware), icon = Icons.Default.Router, value = hwModelName ) - if (isSupported) { - NodeDetailRow( - label = stringResource(R.string.supported), - icon = Icons.Default.Verified, - value = "", - iconTint = Color.Green - ) - } + NodeDetailRow( + label = if (isSupported) stringResource(R.string.supported) else "Supported by Community", + icon = if (isSupported) Icons.TwoTone.Verified else ImageVector.vectorResource(R.drawable.unverified), + value = "", + iconTint = if (isSupported) Color.Green else Color.Red + ) } @Composable @@ -358,20 +384,37 @@ fun DeviceHardwareImage( deviceHardware: DeviceHardware, modifier: Modifier = Modifier, ) { - val hwImg = deviceHardware.images?.lastOrNull() - if (hwImg != null) { - val imageUrl = "file:///android_asset/device_hardware/$hwImg" - AsyncImage( - model = imageUrl, - contentScale = ContentScale.Inside, - contentDescription = deviceHardware.displayName, - placeholder = painterResource(R.drawable.hw_unknown), - error = painterResource(R.drawable.hw_unknown), - fallback = painterResource(R.drawable.hw_unknown), - modifier = modifier - .padding(16.dp) - ) + val hwImg = deviceHardware.images?.get(1) ?: deviceHardware.images?.get(0) ?: "unknown.svg" + val imageUrl = "https://flasher.meshtastic.org/img/devices/$hwImg" + val listener = object : ImageRequest.Listener { + override fun onStart(request: ImageRequest) { + super.onStart(request) + debug("Image request started") + } + + override fun onError(request: ImageRequest, result: ErrorResult) { + super.onError(request, result) + debug("Image request failed: ${result.throwable.message}") + } + + override fun onSuccess(request: ImageRequest, result: SuccessResult) { + super.onSuccess(request, result) + debug("Image request succeeded: ${result.dataSource.name}") + } } + AsyncImage( + model = ImageRequest.Builder(LocalContext.current) + .listener(listener) + .data(imageUrl) + .build(), + contentScale = ContentScale.Inside, + contentDescription = deviceHardware.displayName, + placeholder = painterResource(R.drawable.hw_unknown), + error = painterResource(R.drawable.hw_unknown), + fallback = painterResource(R.drawable.hw_unknown), + modifier = modifier + .padding(16.dp) + ) } @Suppress("LongMethod") @@ -435,13 +478,6 @@ private fun NodeDetailsContent( value = formatUptime(node.deviceMetrics.uptimeSeconds) ) } - if (node.metadata != null) { - NodeDetailRow( - label = stringResource(R.string.firmware_version), - icon = Icons.Default.Memory, - value = node.metadata.firmwareVersion.substringBeforeLast(".") - ) - } NodeDetailRow( label = stringResource(R.string.node_sort_last_heard), icon = Icons.Default.History, diff --git a/app/src/main/res/drawable/hw_unknown.xml b/app/src/main/res/drawable/hw_unknown.xml index e12d55def..e2df2cd56 100644 --- a/app/src/main/res/drawable/hw_unknown.xml +++ b/app/src/main/res/drawable/hw_unknown.xml @@ -1,138 +1,121 @@ + android:width="909.88dp" + android:height="546.86dp" + android:viewportWidth="909.88" + android:viewportHeight="546.86"> - - - - - - - + + + - - - - - - + android:fillColor="#4d4d4d" + android:strokeColor="#000000"/> + + + + diff --git a/app/src/main/res/drawable/unverified.xml b/app/src/main/res/drawable/unverified.xml new file mode 100644 index 000000000..2983be307 --- /dev/null +++ b/app/src/main/res/drawable/unverified.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index c1ec0d62c..e7dd6210a 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -628,4 +628,5 @@ Import Request Metadata Actions + Firmware diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 792128cdf..f334db8e7 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -33,11 +33,13 @@ material = "1.12.0" material3 = "1.3.2" mgrs = "2.1.3" navigation = "2.9.0" +okhttp = "4.12.0" org-eclipse-paho-client-mqttv3 = "1.2.5" osmbonuspack = "6.9.0" osmdroid-android = "6.1.14" protobuf-gradle-plugin = "0.9.5" protobuf-kotlin = "4.31.0" +retrofit = "2.11.0" room = "2.7.1" streamsupport-minifuture = "1.7.4" usb-serial-android = "3.9.0" @@ -57,6 +59,8 @@ appintro = { group = "com.github.AppIntro", name = "AppIntro", version.ref = "ap awesome-app-rating = { group = "com.suddenh4x.ratingdialog", name = "awesome-app-rating", version.ref = "awesome-app-rating" } cardview = { group = "androidx.cardview", name = "cardview", version.ref = "cardview" } coil = { group = "io.coil-kt.coil3", name = "coil-compose", version.ref = "coil" } +coil-network-core = { group = "io.coil-kt.coil3", name = "coil-network-core", version.ref = "coil" } +coil-network-okhttp = { group = "io.coil-kt.coil3", name = "coil-network-okhttp", version.ref = "coil" } coil-svg = { group = "io.coil-kt.coil3", name = "coil-svg", version.ref = "coil" } compose-material3 = { group = "androidx.compose.material3", name = "material3", version.ref = "material3" } compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "compose-bom" } @@ -106,6 +110,8 @@ material = { group = "com.google.android.material", name = "material", version.r mgrs = { group = "mil.nga", name = "mgrs", version.ref = "mgrs" } navigation-compose = { group = "androidx.navigation", name = "navigation-compose", version.ref = "navigation" } navigation-testing = { group = "androidx.navigation", name = "navigation-testing", version.ref = "navigation" } +okhttp3 = { group = "com.squareup.okhttp3", name = "okhttp", version.ref = "okhttp" } +okhttp3-logging-interceptor = { group = "com.squareup.okhttp3", name = "logging-interceptor", version.ref = "okhttp" } org-eclipse-paho-client-mqttv3 = { group = "org.eclipse.paho", name = "org.eclipse.paho.client.mqttv3", version.ref = "org-eclipse-paho-client-mqttv3" } osmbonuspack = { group = "com.github.MKergall", name = "osmbonuspack", version.ref = "osmbonuspack" } osmdroid-android = { group = "org.osmdroid", name = "osmdroid-android", version.ref = "osmdroid-android" } @@ -114,6 +120,8 @@ osmdroid-wms = { group = "org.osmdroid", name = "osmdroid-wms", version.ref = "o protobuf-gradle-plugin = { group = "com.google.protobuf", name = "protobuf-gradle-plugin", version.ref = "protobuf-gradle-plugin" } protobuf-kotlin = { group = "com.google.protobuf", name = "protobuf-kotlin", version.ref = "protobuf-kotlin" } protobuf-protoc = { group = "com.google.protobuf", name ="protoc", version.ref = "protobuf-kotlin" } +retrofit2 = { group = "com.squareup.retrofit2", name = "retrofit", version.ref = "retrofit" } +retrofit2-kotlin-serialization = { group = "com.squareup.retrofit2", name = "converter-kotlinx-serialization", version.ref = "retrofit" } room-compiler = { group = "androidx.room", name = "room-compiler", version.ref = "room" } room-ktx = { group = "androidx.room", name = "room-ktx", version.ref = "room" } room-runtime = { group = "androidx.room", name = "room-runtime", version.ref = "room" } @@ -163,11 +171,14 @@ osm = ["osmdroid-android", "osmdroid-wms", "osmbonuspack", "mgrs"] # Firebase firebase = ["firebase-analytics", "firebase-crashlytics"] -#Protobuf +# Protobuf protobuf = ["protobuf-kotlin"] +# retrofit +retrofit = ["retrofit2", "retrofit2-kotlin-serialization", "okhttp3", "okhttp3-logging-interceptor"] + # coil -coil = ["coil", "coil-svg"] +coil = ["coil", "coil-network-core", "coil-network-okhttp", "coil-svg"] [plugins] android-application = { id = "com.android.application" } @@ -178,6 +189,7 @@ hilt = { id = "com.google.dagger.hilt.android" } kotlin-android = { id = "org.jetbrains.kotlin.android" } kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" } kotlin-parcelize = { id = "org.jetbrains.kotlin.plugin.parcelize" } -kotlin-serialization = { id = "kotlinx-serialization" } +kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization" } protobuf = { id = "com.google.protobuf" } +android-library = { id = "com.android.library" } diff --git a/network/.gitignore b/network/.gitignore new file mode 100644 index 000000000..42afabfd2 --- /dev/null +++ b/network/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/network/build.gradle.kts b/network/build.gradle.kts new file mode 100644 index 000000000..58f6b7d61 --- /dev/null +++ b/network/build.gradle.kts @@ -0,0 +1,46 @@ +import org.jetbrains.kotlin.gradle.dsl.JvmTarget + +plugins { + alias(libs.plugins.android.library) + alias(libs.plugins.kotlin.android) + alias(libs.plugins.hilt) + alias(libs.plugins.devtools.ksp) + alias(libs.plugins.detekt) + id("kotlinx-serialization") +} + +android { + buildFeatures { + buildConfig = true + } + compileSdk = 35 + defaultConfig { + minSdk = 21 + } + + namespace = "com.geeksville.mesh.network" + compileOptions { + sourceCompatibility(JavaVersion.VERSION_17) + targetCompatibility(JavaVersion.VERSION_17) + } +} + +kotlin { + compilerOptions { + jvmTarget.set(JvmTarget.JVM_17) + } +} + +dependencies { + implementation(libs.bundles.hilt) + implementation(libs.bundles.retrofit) + implementation(libs.bundles.coil) + ksp(libs.hilt.compiler) + implementation(libs.kotlinx.serialization.json) + detektPlugins(libs.detekt.formatting) +} + +detekt { + config.setFrom("../config/detekt/detekt.yml") + baseline = file("../config/detekt/detekt-baseline.xml") +} diff --git a/network/src/main/AndroidManifest.xml b/network/src/main/AndroidManifest.xml new file mode 100644 index 000000000..a8800291f --- /dev/null +++ b/network/src/main/AndroidManifest.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/network/src/main/java/com/geeksville/mesh/network/DeviceHardwareRemoteDataSource.kt b/network/src/main/java/com/geeksville/mesh/network/DeviceHardwareRemoteDataSource.kt new file mode 100644 index 000000000..ca31ef9b8 --- /dev/null +++ b/network/src/main/java/com/geeksville/mesh/network/DeviceHardwareRemoteDataSource.kt @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2025 Meshtastic LLC + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.geeksville.mesh.network + +import com.geeksville.mesh.network.model.NetworkDeviceHardware +import com.geeksville.mesh.network.retrofit.ApiService +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import javax.inject.Inject + +class DeviceHardwareRemoteDataSource @Inject constructor( + private val apiService: ApiService, +) { + suspend fun getAllDeviceHardware(): List = withContext(Dispatchers.IO) { + apiService.getDeviceHardware().body() ?: emptyList() + } +} diff --git a/network/src/main/java/com/geeksville/mesh/network/FirmwareReleaseRemoteDataSource.kt b/network/src/main/java/com/geeksville/mesh/network/FirmwareReleaseRemoteDataSource.kt new file mode 100644 index 000000000..b5bae4138 --- /dev/null +++ b/network/src/main/java/com/geeksville/mesh/network/FirmwareReleaseRemoteDataSource.kt @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2025 Meshtastic LLC + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.geeksville.mesh.network + +import com.geeksville.mesh.network.model.NetworkFirmwareReleases +import com.geeksville.mesh.network.retrofit.ApiService +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import javax.inject.Inject + +class FirmwareReleaseRemoteDataSource @Inject constructor( + private val apiService: ApiService, +) { + suspend fun getFirmwareReleases(): NetworkFirmwareReleases = withContext(Dispatchers.IO) { + apiService.getFirmwareReleases().body() ?: NetworkFirmwareReleases() + } +} diff --git a/network/src/main/java/com/geeksville/mesh/network/di/ApiModule.kt b/network/src/main/java/com/geeksville/mesh/network/di/ApiModule.kt new file mode 100644 index 000000000..08bc01acf --- /dev/null +++ b/network/src/main/java/com/geeksville/mesh/network/di/ApiModule.kt @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2025 Meshtastic LLC + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.geeksville.mesh.network.di + +import android.content.Context +import coil3.ImageLoader +import coil3.disk.DiskCache +import coil3.memory.MemoryCache +import coil3.network.okhttp.OkHttpNetworkFetcherFactory +import coil3.request.crossfade +import coil3.svg.SvgDecoder +import coil3.util.DebugLogger +import coil3.util.Logger +import com.geeksville.mesh.network.BuildConfig +import com.geeksville.mesh.network.retrofit.ApiService +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.android.qualifiers.ApplicationContext +import dagger.hilt.components.SingletonComponent +import kotlinx.serialization.json.Json +import okhttp3.MediaType.Companion.toMediaType +import okhttp3.OkHttpClient +import okhttp3.logging.HttpLoggingInterceptor +import retrofit2.Retrofit +import retrofit2.converter.kotlinx.serialization.asConverterFactory +import javax.inject.Singleton + +private const val DISK_CACHE_PERCENT = 0.02 +private const val MEMORY_CACHE_PERCENT = 0.25 +@InstallIn(SingletonComponent::class) +@Module +class ApiModule { + @Provides + @Singleton + fun provideOkHttpClient(): OkHttpClient { + val loggingInterceptor = HttpLoggingInterceptor().apply { + if (BuildConfig.DEBUG) { + setLevel(HttpLoggingInterceptor.Level.BODY) + } + } + return OkHttpClient.Builder() + .addInterceptor(loggingInterceptor) + .build() + } + + @Provides + @Singleton + fun provideRetrofit( + okHttpClient: OkHttpClient + ): Retrofit { + return Retrofit.Builder() + .baseUrl("https://api.meshtastic.org/") // Replace with your base URL + .addConverterFactory( + Json.asConverterFactory( + "application/json; charset=UTF8".toMediaType() + ) + ) + .client(okHttpClient) + .build() + } + + @Provides + @Singleton + fun provideApiService(retrofit: Retrofit): ApiService { + return retrofit.create(ApiService::class.java) + } + + @Provides + @Singleton + fun imageLoader( + httpClient: OkHttpClient, + @ApplicationContext application: Context, + ): ImageLoader { + val sharedOkHttp = httpClient.newBuilder().build() + return ImageLoader.Builder(application) + .components { + add( + OkHttpNetworkFetcherFactory({ sharedOkHttp }) + ) + add(SvgDecoder.Factory()) + } + .memoryCache { + MemoryCache.Builder() + .maxSizePercent(application, MEMORY_CACHE_PERCENT) + .build() + } + .diskCache { + DiskCache.Builder() + .maxSizePercent(DISK_CACHE_PERCENT) + .build() + } + .logger(if (BuildConfig.DEBUG) DebugLogger(Logger.Level.Verbose) else null) + .crossfade(true) + .build() + } +} diff --git a/network/src/main/java/com/geeksville/mesh/network/model/NetworkDeviceHardware.kt b/network/src/main/java/com/geeksville/mesh/network/model/NetworkDeviceHardware.kt new file mode 100644 index 000000000..a78a49901 --- /dev/null +++ b/network/src/main/java/com/geeksville/mesh/network/model/NetworkDeviceHardware.kt @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2025 Meshtastic LLC + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.geeksville.mesh.network.model + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class NetworkDeviceHardware( + @SerialName("activelySupported") + val activelySupported: Boolean = false, + @SerialName("architecture") + val architecture: String = "", + @SerialName("displayName") + val displayName: String = "", + @SerialName("hasInkHud") + val hasInkHud: Boolean? = null, + @SerialName("hasMui") + val hasMui: Boolean? = null, + @SerialName("hwModel") + val hwModel: Int = 0, + @SerialName("hwModelSlug") + val hwModelSlug: String = "", + @SerialName("images") + val images: List? = null, + @SerialName("partitionScheme") + val partitionScheme: String? = null, + @SerialName("platformioTarget") + val platformioTarget: String = "", + @SerialName("requiresDfu") + val requiresDfu: Boolean? = null, + @SerialName("supportLevel") + val supportLevel: Int? = null, + @SerialName("tags") + val tags: List? = null +) diff --git a/network/src/main/java/com/geeksville/mesh/network/model/NetworkFirmwareRelease.kt b/network/src/main/java/com/geeksville/mesh/network/model/NetworkFirmwareRelease.kt new file mode 100644 index 000000000..7e9bac2c9 --- /dev/null +++ b/network/src/main/java/com/geeksville/mesh/network/model/NetworkFirmwareRelease.kt @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2025 Meshtastic LLC + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.geeksville.mesh.network.model + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class NetworkFirmwareRelease( + @SerialName("id") + val id: String = "", + @SerialName("page_url") + val pageUrl: String = "", + @SerialName("release_notes") + val releaseNotes: String = "", + @SerialName("title") + val title: String = "", + @SerialName("zip_url") + val zipUrl: String = "" +) + +@Serializable +data class Releases( + @SerialName("alpha") + val alpha: List = listOf(), + @SerialName("stable") + val stable: List = listOf() +) + +@Serializable +data class NetworkFirmwareReleases( + @SerialName("pullRequests") + val pullRequests: List = listOf(), + @SerialName("releases") + val releases: Releases = Releases() +) diff --git a/network/src/main/java/com/geeksville/mesh/network/retrofit/ApiService.kt b/network/src/main/java/com/geeksville/mesh/network/retrofit/ApiService.kt new file mode 100644 index 000000000..97c9c907b --- /dev/null +++ b/network/src/main/java/com/geeksville/mesh/network/retrofit/ApiService.kt @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2025 Meshtastic LLC + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.geeksville.mesh.network.retrofit + +import com.geeksville.mesh.network.model.NetworkDeviceHardware +import com.geeksville.mesh.network.model.NetworkFirmwareReleases +import retrofit2.Response +import retrofit2.http.GET +import retrofit2.http.Query + +interface ApiService { + @GET(".") + suspend fun checkDeviceRegistration(@Query("deviceId") deviceId: String): Response + + @GET("resource/deviceHardware") + suspend fun getDeviceHardware(): Response> + + @GET("/github/firmware/list") + suspend fun getFirmwareReleases(): Response +} diff --git a/settings.gradle b/settings.gradle index a5fd01fd2..4f6c8c362 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,2 +1,3 @@ include ':app' rootProject.name='Meshtastic Android' +include ':network'