Skip to content

Commit

Permalink
Added OpenKNX Toolbox library and WinForms test UI.
Browse files Browse the repository at this point in the history
  • Loading branch information
Andreas Breitschopp committed Jul 28, 2024
1 parent 81bd70b commit 0a4a90b
Show file tree
Hide file tree
Showing 26 changed files with 1,523 additions and 3 deletions.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,6 @@ bin/
Check.*
Check-Verify.*
release/*
debug/*
debug/*
.vs
*.user
2 changes: 1 addition & 1 deletion Extensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

namespace OpenKNXproducer
{
public static class ExtensionMethods
internal static class ExtensionMethods
{

public static string NodeAttr(this XmlNode iNode, string iAttributeName, string iDefault = "")
Expand Down
2 changes: 1 addition & 1 deletion KnxProdHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

namespace OpenKNXproducer
{
public static class KnxProdHelper
internal static class KnxProdHelper
{
struct EtsVersion
{
Expand Down
12 changes: 12 additions & 0 deletions OpenKNX.Toolbox.Lib/Data/OpenKnxData.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
namespace OpenKNX.Toolbox.Lib.Data
{
public class OpenKnxData
{
public List<OpenKnxProject> Projects { get; set; }

public OpenKnxData()
{
Projects = [];
}
}
}
26 changes: 26 additions & 0 deletions OpenKNX.Toolbox.Lib/Data/OpenKnxProject.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
namespace OpenKNX.Toolbox.Lib.Data
{
public class OpenKnxProject : IComparable
{
public long Id { get; set; }
public string Name { get; set; }
public List<OpenKnxRelease> Releases { get; set; }

public OpenKnxProject(long id, string name)
{
Id = id;
Name = name;
Releases = [];
}

public override string ToString()
{
return Name;
}

public int CompareTo(object? obj)
{
return string.Compare(ToString(), obj?.ToString(), StringComparison.CurrentCulture);
}
}
}
26 changes: 26 additions & 0 deletions OpenKNX.Toolbox.Lib/Data/OpenKnxRelease.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
namespace OpenKNX.Toolbox.Lib.Data
{
public class OpenKnxRelease : IComparable
{
public long Id { get; set; }
public string Name { get; set; }
public List<OpenKnxReleaseFile> Files { get; set; }

public OpenKnxRelease(long id, string name)
{
Id = id;
Name = name;
Files = [];
}

public override string ToString()
{
return Name;
}

public int CompareTo(object? obj)
{
return string.Compare(ToString(), obj?.ToString(), StringComparison.CurrentCulture);
}
}
}
26 changes: 26 additions & 0 deletions OpenKNX.Toolbox.Lib/Data/OpenKnxReleaseFile.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
namespace OpenKNX.Toolbox.Lib.Data
{
public class OpenKnxReleaseFile : IComparable
{
public long Id { get; set; }
public string Name { get; set; }
public string DownloadUrl { get; set; }

public OpenKnxReleaseFile(long id, string name, string downloadUrl)
{
Id = id;
Name = name;
DownloadUrl = downloadUrl;
}

public override string ToString()
{
return Name;
}

public int CompareTo(object? obj)
{
return string.Compare(ToString(), obj?.ToString(), StringComparison.CurrentCulture);
}
}
}
16 changes: 16 additions & 0 deletions OpenKNX.Toolbox.Lib/Data/ReleaseContent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
namespace OpenKNX.Toolbox.Lib.Data
{
public class ReleaseContent
{
public string AppName { get; set; }
public string AppXmlFilePath { get; set; }
public List<ReleaseContentFirmware> Firmwares { get; set; }

public ReleaseContent(string appName, string appXmlFilePath)
{
AppName = appName;
AppXmlFilePath = appXmlFilePath;
Firmwares = [];
}
}
}
19 changes: 19 additions & 0 deletions OpenKNX.Toolbox.Lib/Data/ReleaseContentFirmware.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
namespace OpenKNX.Toolbox.Lib.Data
{
public class ReleaseContentFirmware
{
public string Name { get; set; }
public string FilePathUf2 { get; set; }

public ReleaseContentFirmware(string name, string filePathUf2)
{
Name = name;
FilePathUf2 = filePathUf2;
}

public override string ToString()
{
return Name;
}
}
}
130 changes: 130 additions & 0 deletions OpenKNX.Toolbox.Lib/GitHubAccess.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
using System.Text.Json;
using Octokit;
using OpenKNX.Toolbox.Lib.Data;

namespace OpenKNX.Toolbox.Lib
{
public static class GitHubAccess
{
private const string OPEN_KNX_ORG = "OpenKNX";
private const string OPEN_KNX_REPO_DEFAULT_START = "OAM-";
private const string OPEN_KNX_DATA_FILE_NAME = "OpenKNX.Toolbox.DataCache.json";

private static List<string> repositoryWhitelist = new List<string>()
{
"SOM-UP",
"GW-REG1-Dali",
"SEN-UP1-8xTH",
"BEM-GardenControl"
};

/// <summary>
/// Checks if a "OpenKnxData.json" file is present and not older than one day, otherwise download OpenKNX data from GitHub.
/// </summary>
/// <param name="dataDirectory">The directory to store the data file.</param>
/// <returns>Returns a "OpenKnxData" object in case of success.</returns>
public static async Task<OpenKnxData?> GetOpenKnxData(string dataDirectory)
{
var dataFilePath = Path.Combine(dataDirectory, OPEN_KNX_DATA_FILE_NAME);
if (File.Exists(dataFilePath))
{
if (File.GetLastWriteTimeUtc(dataFilePath) > DateTime.UtcNow.AddDays(-1))
{
using (var fileStream = new FileStream(dataFilePath, System.IO.FileMode.Open))
return await JsonSerializer.DeserializeAsync<OpenKnxData>(fileStream);
}
}

var openKnxData = new OpenKnxData();
openKnxData.Projects = await GetOpenKnxProjects();
openKnxData.Projects.Sort();

using (var fileStream = new FileStream(dataFilePath, System.IO.FileMode.Create))
await JsonSerializer.SerializeAsync(fileStream, openKnxData);

return openKnxData;
}

/// <summary>
/// Load OpenKNX projects data from GitHub.
/// </summary>
/// <returns>The OpenKNX projects list.</returns>
private static async Task<List<OpenKnxProject>> GetOpenKnxProjects()
{
var openKnxProjects = new List<OpenKnxProject>();
var client = new GitHubClient(new ProductHeaderValue(OPEN_KNX_ORG));

var repositories = await client.Repository.GetAllForOrg(OPEN_KNX_ORG);
foreach (var repository in repositories)
{
if (!repository.Name.StartsWith(OPEN_KNX_REPO_DEFAULT_START) &&
!repositoryWhitelist.Contains(repository.Name))
continue;

var openKnxProject = new OpenKnxProject(repository.Id, repository.Name);

var releases = await client.Repository.Release.GetAll(repository.Id);
foreach (var release in releases)
{
if (string.IsNullOrEmpty(release.Name))
continue;

var openKnxRelease = new OpenKnxRelease(release.Id, release.Name);

foreach (var asset in release.Assets)
{
if (!asset.Name.ToLower().EndsWith(".zip"))
continue;

openKnxRelease.Files.Add(new OpenKnxReleaseFile(asset.Id, asset.Name, asset.BrowserDownloadUrl));
}

if (openKnxRelease.Files.Count > 0)
{
openKnxRelease.Files.Sort();
openKnxProject.Releases.Add(openKnxRelease);
}
}

if (openKnxProject.Releases.Count > 0)
{
openKnxProject.Releases.Sort((a, b) => b.CompareTo(a));
openKnxProjects.Add(openKnxProject);
}
}

return openKnxProjects;
}

/// <summary>
/// Downloads a release ZIP file from GitHub.
/// </summary>
/// <param name="releaseFile">The "OpenKnxReleaseFile" object containing the download URL.</param>
/// <returns>The file path where the downloaded ZIP is stored.</returns>
/// <exception cref="FileNotFoundException"></exception>
public static async Task<string> DownloadReleaseFile(OpenKnxReleaseFile releaseFile)
{
using (var client = new HttpClient())
{
var response = await client.GetAsync(releaseFile.DownloadUrl);
if (response.IsSuccessStatusCode)
{
var contentStream = await response.Content.ReadAsStreamAsync();
var targetPath = Path.Combine(TempData.Instance.GetTempPath(), releaseFile.Name);
var fileStream = new FileStream(targetPath, System.IO.FileMode.Create);
await contentStream.CopyToAsync(fileStream).ContinueWith(
(copyTask) =>
{
fileStream.Close();
});

return targetPath;
}
else
{
throw new FileNotFoundException();
}
}
}
}
}
24 changes: 24 additions & 0 deletions OpenKNX.Toolbox.Lib/KnxProdBuilder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using System.Text.RegularExpressions;
using OpenKNXproducer;

namespace OpenKNX.Toolbox.Lib
{
public static class KnxProdBuilder
{
/// <summary>
/// Generates a KNXprod file.
/// </summary>
/// <param name="xmlFilePath">The path to the XML file the KNXprod will be generated from.</param>
/// <param name="knxprodOutputPath">The output path of the generated KNXprod file.</param>
/// <returns>True, if success, False otherwise.</returns>
public static bool BuildKnxProd(string xmlFilePath, string knxprodOutputPath)
{
var workingDir = KnxProdHelper.GetAbsWorkingDir(xmlFilePath);
var xml = File.ReadAllText(xmlFilePath);
var rs = new Regex("xmlns=\"(http:\\/\\/knx\\.org\\/xml\\/project\\/[0-9]{1,2})\"");
var match = rs.Match(xml);
var etsPath = KnxProdHelper.FindEtsPath(match.Groups[1].Value);
return KnxProdHelper.ExportKnxprod(etsPath, workingDir, knxprodOutputPath, xmlFilePath, Path.GetFileName(xmlFilePath).Replace(".xml", ".baggages"), null, false, false) == 0;
}
}
}
22 changes: 22 additions & 0 deletions OpenKNX.Toolbox.Lib/OpenKNX.Toolbox.Lib.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Octokit" Version="13.0.1" />
</ItemGroup>

<ItemGroup>
<Compile Include="../Extensions.cs"/>
<Compile Include="../KnxProdHelper.cs"/>
<Compile Include="../Signing/ApplicationSigner.cs" Link="Signing/ApplicationSigner.cs"/>
<Compile Include="../Signing/CatalogIdPatcher.cs" Link="Signing/CatalogIdPatcher.cs"/>
<Compile Include="../Signing/HardwareSigner.cs" Link="Signing/HardwareSigner.cs"/>
<Compile Include="../Signing/XmlSigner.cs" Link="Signing/XmlSigner.cs"/>
</ItemGroup>

</Project>
41 changes: 41 additions & 0 deletions OpenKNX.Toolbox.Lib/ReleaseContentHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
using System.Text.RegularExpressions;
using OpenKNX.Toolbox.Lib.Data;

namespace OpenKNX.Toolbox.Lib
{
public static class ReleaseContentHelper
{
/// <summary>
/// Reads the "content.xml" file from a release.
/// </summary>
/// <param name="releaseDirectory">The release directory containing a "data\content.xml" file.</param>
/// <returns>Returns a "ReleaseContent" object.</returns>
public static ReleaseContent GetReleaseContent(string releaseDirectory)
{
var contentXmlPath = Path.Combine(releaseDirectory, "data", "content.xml");
var contentXml = File.ReadAllText(contentXmlPath);

var rs = new Regex("<ETSapp Name=\"(.*)\" XmlFile=\"(.*)\" \\/>");
var match = rs.Match(contentXml);
var appName = match.Groups[1].Value;
var appXmlFileName = Path.Combine(Path.GetDirectoryName(contentXmlPath), match.Groups[2].Value);

var appXmlFilePath = Path.Combine(releaseDirectory, "data", appXmlFileName);
var releaseContent = new ReleaseContent(appName, appXmlFilePath);

rs = new Regex("<Product Name=\"(.*)\" Firmware=\"(.*)\" Processor=\"(.*)\" \\/>");
foreach (Match rsMatch in rs.Matches(contentXml))
{
if (rsMatch.Groups[3].Value != "RP2040")
continue;

var firmwareName = rsMatch.Groups[1].Value;
var filePathUf2 = Path.Combine(releaseDirectory, "data", rsMatch.Groups[2].Value);
var firmware = new ReleaseContentFirmware(firmwareName, filePathUf2);
releaseContent.Firmwares.Add(firmware);
}

return releaseContent;
}
}
}
Loading

0 comments on commit 0a4a90b

Please sign in to comment.