Skip to content

Commit 322d24e

Browse files
authored
2.3 (#172)
2.3 Release
1 parent 3c98720 commit 322d24e

File tree

110 files changed

+2738
-2206
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

110 files changed

+2738
-2206
lines changed

README.md

+13
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ This addon enables easy Home Assistant backup creation and sync to OneDrive.
1010
- Syncs backups to OneDrive **(Personal Account only. OneDrive for business not currently supported)**
1111
- Additional File Sync to OneDrive
1212
- Supports standard backup retention / Generational backup mode
13+
- Retain backups indefinitely
1314
- Supports multiple Home Assistant instances
1415
- Supports Home Assistant Persistent Notifications
1516
- Supports Home Assistant Events
@@ -135,6 +136,9 @@ This allows you to specify a list of paths for the addon to sync to OneDrive so
135136
> * /share
136137
> * /media
137138
> * /addons
139+
> * /addon_configs
140+
> * /homeassistant
141+
138142

139143
**Example**:
140144

@@ -176,6 +180,10 @@ A random Guid is generated when you run your addon for the first time (not persi
176180
* Ignore Allowed Hours for File Sync Enabled Flag
177181
* Addon Version
178182
* Notify On Error Enabled Flag
183+
* Error Reporting Enabled Flag
184+
185+
### Enable Anonymous Error Reporting
186+
Sends anonymous error messages (with exceptions) to help identify issues with the addon
179187

180188
### Dark Mode
181189
Use Dark mode for Addon UI
@@ -185,6 +193,11 @@ The add-on has specific permissions to a single folder in your OneDrive known as
185193

186194
The App Folder for the add-on is mapped to : <kbd>**[onedriveroot]/Apps/hassio-onedrive-backup**</kbd>
187195

196+
## Retaining Backups Indefinitely (Prevent Deletion)
197+
You can choose to 'pin' specific backups so that they stop counting against the set backup quotas and are never deleted by the addon. This can be set individually for both local and OneDrive through
198+
dedicated buttons in the main Dashboard for each backup.
199+
> Note - As any 'retained' backup will not count towards your maximum backup quota you could for example, have a maximum of 3 local backups set but chose to retain 2 Local backups. The addon will ignore the retained backups for the quota and will store a maximum of 3 addtional local backups
200+
188201
## OneDrive free space Sensor
189202
The add-on creates a native Home Assistant Sensor entity <kbd>sensor.onedrivefreespace</kbd> that will show you the amount of free space in your OneDrive account.
190203

onedrive-backup/.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -235,3 +235,5 @@ record.auth*
235235
.NativeSettings
236236
.clientId
237237
settings.json
238+
additionalBackupData.json
239+
.*

onedrive-backup/CHANGELOG.md

+11
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,14 @@
1+
## v2.3 [Febuary 7th 2024]
2+
### 🆕 Added
3+
* Added ability to retain backups indefinitely
4+
* New details in overview page - Total backup sizes, next backup date
5+
* Updated folder support for File Sync - /homeassistant, /addon_configs
6+
* New optional Error reporting (opt in)
7+
* Upgraded core libraries (Azure.Identity, Microsoft.Graph, Bootstrap)
8+
### 🐞 Fixed
9+
* If not enough space is available in OneDrive, the addon will no longer attempt to upload the backup and fail repeatedly.
10+
* Addons in partial backups were only refreshed on addon start (if another addon was installed after the addon has started it would not appear in a partial backup)
11+
112
## v2.2.4 [November 10th 2023]
213
### 🐞 Fixed
314
* Allowed hours requires restart - Fixed a bug where changing the allowed hours wouldn't take effect until addon was restarted.

onedrive-backup/ConsoleLogger.cs

+7
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using onedrive_backup;
2+
using onedrive_backup.Telemetry;
23
using System;
34
using System.Collections.Generic;
45
using System.Linq;
@@ -17,6 +18,12 @@ public void LogError(string msg)
1718
WriteLog(LogLevel.Error, msg);
1819
}
1920

21+
public void LogError(string msg, Exception ex = null, TelemetryManager telemetryManager = null)
22+
{
23+
WriteLog(LogLevel.Error, msg);
24+
telemetryManager?.SendError(msg, ex);
25+
}
26+
2027
public void LogWarning(string msg)
2128
{
2229
WriteLog(LogLevel.Warning, msg);

onedrive-backup/Contracts/AddonOptions.cs

+4-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ namespace hassio_onedrive_backup.Contracts
99
{
1010
public class AddonOptions : IEqualityComparer<AddonOptions>
1111
{
12-
public const string AddonVersion = "2.2.4";
12+
public const string AddonVersion = "2.3";
1313

1414
public event Action OnOptionsChanged;
1515

@@ -86,6 +86,9 @@ public class AddonOptions : IEqualityComparer<AddonOptions>
8686
[JsonProperty("enable_anonymous_telemetry")]
8787
public bool EnableAnonymousTelemetry { get; set; } = false;
8888

89+
[JsonProperty("enable_anonymous_error_reporting")]
90+
public bool EnableAnonymousErrorReporting { get; set; } = false;
91+
8992
[JsonProperty("ignore_allowed_hours_for_file_sync")]
9093
public bool IgnoreAllowedHoursForFileSync { get; set; } = false;
9194

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
using Microsoft.Graph.Models;
2+
3+
namespace onedrive_backup.Contracts
4+
{
5+
public class BackupAdditionalData
6+
{
7+
public BackupAdditionalData()
8+
{
9+
Backups = new();
10+
}
11+
12+
public List<BackupData> Backups { get; set; }
13+
14+
public bool IsRetainedLocally(string slug)
15+
{
16+
var backup = Backups.FirstOrDefault(backupData => backupData.Slug == slug);
17+
return (backup != null && backup.RetainLocal);
18+
}
19+
20+
public bool IsRetainedOneDrive(string slug)
21+
{
22+
var backup = Backups.FirstOrDefault(backupData => backupData.Slug == slug);
23+
return (backup != null && backup.RetainOneDrive);
24+
}
25+
26+
public int PruneAdditionalBackupData(params string[] existingSlugs)
27+
{
28+
return Backups.RemoveAll(backup => !existingSlugs.Contains(backup.Slug));
29+
}
30+
31+
public void UpdateRetainLocally(string slug, bool retain)
32+
{
33+
var backup = GetOrCreateBackupData(slug);
34+
backup.RetainLocal = retain;
35+
}
36+
37+
public void UpdateRetainOneDrive(string slug, bool retain)
38+
{
39+
var backup = GetOrCreateBackupData(slug);
40+
backup.RetainOneDrive = retain;
41+
}
42+
43+
private BackupData GetOrCreateBackupData(string slug)
44+
{
45+
var backup = Backups.FirstOrDefault(backupData => backupData.Slug == slug);
46+
if (backup == null)
47+
{
48+
backup = new BackupData
49+
{
50+
Slug = slug
51+
};
52+
53+
Backups.Add(backup);
54+
}
55+
56+
return backup;
57+
}
58+
59+
public class BackupData
60+
{
61+
public string Slug { get; set; }
62+
63+
public bool RetainLocal { get; set; }
64+
65+
public bool RetainOneDrive { get; set; }
66+
}
67+
}
68+
}

onedrive-backup/Extensions/BackupExtensions.cs

+20-33
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ namespace onedrive_backup.Extensions
1212
{
1313
public static class BackupExtensions
1414
{
15-
public static BackupModel ToBackupModel(this Backup backup, HassContext hassContext)
15+
public static BackupModel ToBackupModel(this Backup backup, HassContext hassContext, BackupAdditionalData backupAdditionalData)
1616
{
1717
return new BackupModel
1818
{
@@ -24,11 +24,13 @@ public static BackupModel ToBackupModel(this Backup backup, HassContext hassCont
2424
IsProtected = backup.Protected,
2525
Location = BackupModel.BackupLocation.Local,
2626
Addons = backup.Content?.Addons?.Select(slug => new Addon { Slug = slug, Name = GetAddonNameFromSlug(hassContext.Addons, slug) }).ToList() ?? Enumerable.Empty<Addon>(),
27-
Folders = backup.Content?.Folders ?? Enumerable.Empty<string>()
27+
Folders = backup.Content?.Folders ?? Enumerable.Empty<string>(),
28+
RetainLocal = backupAdditionalData.IsRetainedLocally(backup.Slug),
29+
RetainOneDrive = backupAdditionalData.IsRetainedOneDrive(backup.Slug)
2830
};
2931
}
3032

31-
public static BackupModel ToBackupModel(this OnedriveBackup onedriveBackup, HassContext hassContext)
33+
public static BackupModel ToBackupModel(this OnedriveBackup onedriveBackup, HassContext hassContext, BackupAdditionalData backupAdditionalData)
3234
{
3335
return new BackupModel
3436
{
@@ -40,8 +42,10 @@ public static BackupModel ToBackupModel(this OnedriveBackup onedriveBackup, Hass
4042
IsProtected = onedriveBackup.IsProtected,
4143
Location = BackupModel.BackupLocation.OneDrive,
4244
Addons = onedriveBackup.Addons?.Select(slug => new Addon { Slug = slug, Name = GetAddonNameFromSlug(hassContext.Addons, slug) }) ?? Enumerable.Empty<Addon>(),
43-
Folders = onedriveBackup.Folders ?? Enumerable.Empty<string>()
44-
};
45+
Folders = onedriveBackup.Folders ?? Enumerable.Empty<string>(),
46+
RetainLocal = backupAdditionalData.IsRetainedLocally(onedriveBackup.Slug),
47+
RetainOneDrive = backupAdditionalData.IsRetainedOneDrive(onedriveBackup.Slug)
48+
};
4549
}
4650

4751
public static OnedriveBackup ToOneDriveBackup(this BackupModel backupModel)
@@ -118,15 +122,6 @@ public static IList<IBackup> GetWeeklyGenerations(this IEnumerable<IBackup> back
118122
{
119123
ret.Add(weeklyBackup);
120124
}
121-
//else
122-
//{
123-
// var weekCutoffDate = DateTimeHelper.GetStartDateByWeekAndYear(year, week, firstDayOfWeek);
124-
// var nextCandidateBackup = backups.OrderByDescending(b => b.BackupDate).FirstOrDefault(b => b.BackupDate <= weekCutoffDate);
125-
// if (nextCandidateBackup != null)
126-
// {
127-
// ret.Add(nextCandidateBackup);
128-
// }
129-
//}
130125
}
131126

132127
return ret.Distinct().ToList();
@@ -163,15 +158,6 @@ public static IList<IBackup> GetMonthlyGenerations(this IEnumerable<IBackup> bac
163158
{
164159
ret.Add(monthlyBackup);
165160
}
166-
// else
167-
// {
168-
// var cutoffDate = new DateTime(year, month, 1);
169-
// var nextCandidateBackup = backups.OrderByDescending(b => b.BackupDate).FirstOrDefault(b => b.BackupDate >= cutoffDate);
170-
// if (nextCandidateBackup != null)
171-
// {
172-
// ret.Add(nextCandidateBackup);
173-
// }
174-
//}
175161
}
176162

177163
return ret.Distinct().ToList();
@@ -200,21 +186,22 @@ public static IList<IBackup> GetYearlyGenerations(this IEnumerable<IBackup> back
200186
{
201187
ret.Add(yearlyBackup);
202188
}
203-
//else
204-
//{
205-
// var cutoffDate = new DateTime(currentYear, 1, 1);
206-
// var nextCandidateBackup = backups.OrderByDescending(b => b.BackupDate).FirstOrDefault(b => b.BackupDate >= cutoffDate);
207-
// if (nextCandidateBackup != null)
208-
// {
209-
// ret.Add(nextCandidateBackup);
210-
// }
211-
//}
212189
}
213190

214191
return ret.Distinct().ToList();
215192
}
216193

217-
private static string GetAddonNameFromSlug(IEnumerable<Addon> addons, string slug)
194+
public static bool IsRetainedLocally(this IBackup backup, BackupAdditionalData additionalData)
195+
{
196+
return additionalData.IsRetainedLocally(backup.Slug);
197+
}
198+
199+
public static bool IsRetainedOneDrive(this IBackup backup, BackupAdditionalData additionalData)
200+
{
201+
return additionalData.IsRetainedOneDrive(backup.Slug);
202+
}
203+
204+
private static string GetAddonNameFromSlug(IEnumerable<Addon> addons, string slug)
218205
{
219206
string name = addons.FirstOrDefault(addon => addon.Slug.Equals(slug, StringComparison.OrdinalIgnoreCase))?.Name;
220207
return name ?? string.Empty;

0 commit comments

Comments
 (0)