diff --git a/openHAB.Core.Client.csproj b/openHAB.Core.Client.csproj new file mode 100644 index 00000000..8fcc514f --- /dev/null +++ b/openHAB.Core.Client.csproj @@ -0,0 +1,19 @@ + + + netstandard2.0 + 11.0 + true + annotations + true + $(DefineConstants);EXPERIMENTAL + https://pkgs.dev.azure.com/azure-sdk/public/_packaging/azure-sdk-for-net/nuget/v3/index.json + + + + + + + + + + diff --git a/src/openHAB.Common/openHAB.Common.csproj b/src/openHAB.Common/openHAB.Common.csproj index edcfab1c..bf581cc9 100644 --- a/src/openHAB.Common/openHAB.Common.csproj +++ b/src/openHAB.Common/openHAB.Common.csproj @@ -8,7 +8,7 @@ - - + + diff --git a/src/openHAB.Core.Client/AutoNumberToStringConverter.cs b/src/openHAB.Core.Client/AutoNumberToStringConverter.cs new file mode 100644 index 00000000..62df6465 --- /dev/null +++ b/src/openHAB.Core.Client/AutoNumberToStringConverter.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.Json.Serialization; +using System.Text.Json; +using System.Threading.Tasks; + +namespace openHAB.Core.Client +{ + public class AutoNumberToStringConverter : JsonConverter + { + public override bool CanConvert(Type typeToConvert) + { + return typeof(string) == typeToConvert; + } + + public override object Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType == JsonTokenType.Number) + { + return reader.TryGetInt64(out long l) ? + l.ToString() : + reader.GetDouble().ToString(); + } + + if (reader.TokenType == JsonTokenType.String) + { + return reader.GetString(); + } + + using (JsonDocument document = JsonDocument.ParseValue(ref reader)) + { + return document.RootElement.Clone().ToString(); + } + } + + public override void Write(Utf8JsonWriter writer, object value, JsonSerializerOptions options) + { + writer.WriteStringValue(value.ToString()); + } + } +} diff --git a/src/openHAB.Core.Client/Connection/ConnectionService.cs b/src/openHAB.Core.Client/Connection/ConnectionService.cs index dd184c3b..8d50565c 100644 --- a/src/openHAB.Core.Client/Connection/ConnectionService.cs +++ b/src/openHAB.Core.Client/Connection/ConnectionService.cs @@ -1,11 +1,12 @@ using System; using System.Net.Http; +using System.Text.Json; +using System.Text.Json.Serialization; using System.Text.RegularExpressions; using System.Threading.Tasks; using CommunityToolkit.Mvvm.Messaging; using CommunityToolkit.WinUI.Helpers; using Microsoft.Extensions.Logging; -using Newtonsoft.Json; using openHAB.Common; using openHAB.Core.Client.Common; using openHAB.Core.Client.Connection.Contracts; @@ -160,8 +161,9 @@ public async Task> GetOpenHABServerInfo(Models.Co string responseBody = await result.Content.ReadAsStringAsync(); - APIInfo apiInfo = JsonConvert.DeserializeObject(responseBody); - if (apiInfo.Version < 4) + APIInfo apiInfo = JsonSerializer.Deserialize(responseBody); + + if (int.TryParse(apiInfo.Version, out int apiVersion) && apiVersion < 4) { serverInfo.Version = OpenHABVersion.Two; return new HttpResponseResult(serverInfo, result.StatusCode); diff --git a/src/openHAB.Core.Client/Contracts/IOpenHABClient.cs b/src/openHAB.Core.Client/Contracts/IOpenHABClient.cs index 2150eed3..b1d0ce99 100644 --- a/src/openHAB.Core.Client/Contracts/IOpenHABClient.cs +++ b/src/openHAB.Core.Client/Contracts/IOpenHABClient.cs @@ -23,7 +23,7 @@ public interface IOpenHABClient /// /// Name of the item. /// openHab item object. - Task GetItemByName(string itemName); + Task GetItemByName(string itemName); /// /// Loads all the sitemaps. @@ -31,14 +31,14 @@ public interface IOpenHABClient /// The version of OpenHAB running on the server. /// Filters for sitemap list. /// A list of sitemaps. - Task> LoadSitemaps(OpenHABVersion version, List> filters); + Task> LoadSitemaps(OpenHABVersion version, List> filters); /// Loads the items from sitemap. /// The sitemap link. /// The openHab server version. /// Returns loaded sitemap - Task> LoadItemsFromSitemap(string sitemapLink, OpenHABVersion version); + Task> LoadItemsFromSitemap(string sitemapLink, OpenHABVersion version); /// /// Sends a command to an item. @@ -46,7 +46,7 @@ public interface IOpenHABClient /// The item. /// The Command. /// Operation result if the command was successful or not. - Task> SendCommand(OpenHABItem item, string command); + Task> SendCommand(Item item, string command); /// /// Reset the connection to the OpenHAB server after changing the settings in the App. @@ -61,6 +61,6 @@ public interface IOpenHABClient /// Starts listening to server events. /// void StartItemUpdates(System.Threading.CancellationToken token); - Task GetSitemap(string sitemapLink, OpenHABVersion version); + Task GetSitemap(string sitemapLink, OpenHABVersion version); } } diff --git a/src/openHAB.Core.Client/Messages/TriggerCommandMessage.cs b/src/openHAB.Core.Client/Messages/TriggerCommandMessage.cs index eecf42a4..f653fefa 100644 --- a/src/openHAB.Core.Client/Messages/TriggerCommandMessage.cs +++ b/src/openHAB.Core.Client/Messages/TriggerCommandMessage.cs @@ -13,7 +13,7 @@ public class TriggerCommandMessage /// /// The OpenHAB item that triggered the command. /// The command that was triggered. - public TriggerCommandMessage(OpenHABItem item, string command) + public TriggerCommandMessage(Item item, string command) { Id = Guid.NewGuid(); Item = item; @@ -40,7 +40,7 @@ public Guid Id /// /// Gets or sets the OpenHAB item that triggered the command. /// - public OpenHABItem Item + public Item Item { get; set; diff --git a/src/openHAB.Core.Client/Models/APIInfo.cs b/src/openHAB.Core.Client/Models/APIInfo.cs index c9055e7f..d915a0f0 100644 --- a/src/openHAB.Core.Client/Models/APIInfo.cs +++ b/src/openHAB.Core.Client/Models/APIInfo.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using Newtonsoft.Json; +using System.Text.Json.Serialization; namespace openHAB.Core.Client.Models { @@ -10,15 +10,15 @@ public class APIInfo { /// Gets or sets the version. /// The version. - [JsonProperty("version")] - public int Version + [JsonPropertyName("version")] + public string Version { get; set; } /// Gets or sets the locale. /// The locale. - [JsonProperty("locale")] + [JsonPropertyName("locale")] public string Locale { get; set; @@ -26,7 +26,7 @@ public string Locale /// Gets or sets the measurement system. /// The measurement system. - [JsonProperty("measurementSystem")] + [JsonPropertyName("measurementSystem")] public string MeasurementSystem { get; set; @@ -34,7 +34,7 @@ public string MeasurementSystem /// Gets or sets the runtime information. /// The runtime information. - [JsonProperty("runtimeInfo")] + [JsonPropertyName("runtimeInfo")] public RuntimeInfo RuntimeInfo { get; set; @@ -42,7 +42,7 @@ public RuntimeInfo RuntimeInfo /// Gets or sets the links. /// The links. - [JsonProperty("links")] + [JsonPropertyName("links")] public List Links { get; set; diff --git a/src/openHAB.Core.Client/Models/OpenHABCommandDescription.cs b/src/openHAB.Core.Client/Models/CommandDescription.cs similarity index 63% rename from src/openHAB.Core.Client/Models/OpenHABCommandDescription.cs rename to src/openHAB.Core.Client/Models/CommandDescription.cs index 43cd6926..c1bbbf46 100644 --- a/src/openHAB.Core.Client/Models/OpenHABCommandDescription.cs +++ b/src/openHAB.Core.Client/Models/CommandDescription.cs @@ -5,16 +5,16 @@ namespace openHAB.Core.Client.Models /// /// A mapping for an OpenHAB Widget. /// - public class OpenHABCommandDescription + public class CommandDescription { /// /// Gets or sets the CommandOptions. /// - public ICollection CommandOptions { get; set; } + public ICollection CommandOptions { get; set; } - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// The command options. - public OpenHABCommandDescription(ICollection commandOptions) + public CommandDescription(ICollection commandOptions) { CommandOptions = commandOptions; } diff --git a/src/openHAB.Core.Client/Models/OpenHABCommandOptions.cs b/src/openHAB.Core.Client/Models/CommandOptions.cs similarity index 76% rename from src/openHAB.Core.Client/Models/OpenHABCommandOptions.cs rename to src/openHAB.Core.Client/Models/CommandOptions.cs index 90d4ea59..fb4ad0b3 100644 --- a/src/openHAB.Core.Client/Models/OpenHABCommandOptions.cs +++ b/src/openHAB.Core.Client/Models/CommandOptions.cs @@ -3,7 +3,7 @@ namespace openHAB.Core.Client.Models /// /// A CommandOptions for commandDescription. /// - public class OpenHABCommandOptions + public class CommandOptions { /// /// Gets or sets the Command of the mapping. @@ -16,11 +16,11 @@ public class OpenHABCommandOptions public string Label { get; set; } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// A command. /// A label. - public OpenHABCommandOptions(string command, string label) + public CommandOptions(string command, string label) { Command = command; Label = label; diff --git a/src/openHAB.Core.Client/Models/OpenHABItem.cs b/src/openHAB.Core.Client/Models/Item.cs similarity index 90% rename from src/openHAB.Core.Client/Models/OpenHABItem.cs rename to src/openHAB.Core.Client/Models/Item.cs index b5f22c20..355b4b68 100644 --- a/src/openHAB.Core.Client/Models/OpenHABItem.cs +++ b/src/openHAB.Core.Client/Models/Item.cs @@ -1,10 +1,10 @@ using System; using System.Globalization; +using System.Text.Json; using System.Text.RegularExpressions; using System.Xml.Linq; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Messaging; -using Newtonsoft.Json; using openHAB.Core.Client.Messages; namespace openHAB.Core.Client.Models @@ -12,7 +12,7 @@ namespace openHAB.Core.Client.Models /// /// A class that represents an OpenHAB item. /// - public class OpenHABItem : ObservableObject + public class Item : ObservableObject { private string _state; private string _type; @@ -106,15 +106,15 @@ public string Link /// Gets or sets the CommandDescription of the OpenHAB item. /// /// - public OpenHABCommandDescription CommandDescription + public CommandDescription CommandDescription { get; set; } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// - public OpenHABItem() + public Item() { StrongReferenceMessenger.Default.Register(this, HandleUpdateItemMessage); } @@ -130,21 +130,21 @@ private async void HandleUpdateItemMessage(object recipient, UpdateItemMessage m } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// The XML from the OpenHAB server that represents this OpenHAB item. - public OpenHABItem(XElement startNode) + public Item(XElement startNode) { ParseNode(startNode); } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// The JSON from the OpenHAB server that represents this OpenHAB item. - public OpenHABItem(string jsonObject) + public Item(string jsonObject) { - var item = JsonConvert.DeserializeObject(jsonObject); + Item item = JsonSerializer.Deserialize(jsonObject); Name = item.Name; Type = item.Type; GroupType = item.GroupType; diff --git a/src/openHAB.Core.Client/Models/Link.cs b/src/openHAB.Core.Client/Models/Link.cs index cff4c741..4defe6a5 100644 --- a/src/openHAB.Core.Client/Models/Link.cs +++ b/src/openHAB.Core.Client/Models/Link.cs @@ -1,5 +1,5 @@ using System; -using Newtonsoft.Json; +using System.Text.Json.Serialization; namespace openHAB.Core.Client.Models { @@ -8,7 +8,7 @@ public partial class Link { /// Gets or sets the type. /// The type. - [JsonProperty("type")] + [JsonPropertyName("type")] public string Type { get; set; @@ -16,7 +16,7 @@ public string Type /// Gets or sets the URL. /// The URL. - [JsonProperty("url")] + [JsonPropertyName("url")] public Uri Url { get; set; diff --git a/src/openHAB.Core.Client/Models/OpenHABSitemap.cs b/src/openHAB.Core.Client/Models/OpenHABSitemap.cs deleted file mode 100644 index d902c3f3..00000000 --- a/src/openHAB.Core.Client/Models/OpenHABSitemap.cs +++ /dev/null @@ -1,107 +0,0 @@ -using System.Collections.Generic; -using System.Xml.Linq; - -namespace openHAB.Core.Client.Models -{ - /// - /// A class that represents an OpenHAB sitemap. - /// - public class OpenHABSitemap - { - /// - /// Initializes a new instance of the class. - /// - public OpenHABSitemap() - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The XML from the OpenHAB server that represents this OpenHAB item. - public OpenHABSitemap(XElement startNode) - { - ParseNode(startNode); - } - - /// - /// Gets or sets the name of the OpenHAB sitemap. - /// - public string Name - { - get; set; - } - - /// - /// Gets or sets the label of the OpenHAB sitemap. - /// - public string Label - { - get; set; - } - - /// - /// Gets or sets the link of the OpenHAB sitemap. - /// - public string Link - { - get; set; - } - - /// - /// Gets or sets the icon of the OpenHAB sitemap. - /// - public string Icon - { - get; set; - } - - /// - /// Gets or sets the url of the OpenHAB sitemap. - /// - public string HomepageLink - { - get; set; - } - - /// - /// Gets or sets a value indicating whether the sitemap is a leaf. - /// - public bool Leaf - { - get; set; - } - - /// - /// Gets or sets the title of the sitemap. - /// - public string Title - { - get; set; - } - - /// - /// Gets or sets a collection of widgets of the OpenHAB sitemap. - /// - public ICollection Widgets - { - get; - set; - } - - private void ParseNode(XElement startNode) - { - if (startNode.HasElements) - { - Name = startNode.Element("name")?.Value; - Label = startNode.Element("label")?.Value; - Link = startNode.Element("link")?.Value; - Icon = startNode.Element("icon")?.Value; - - var homePage = startNode.Element("homepage"); - HomepageLink = homePage?.Element("link")?.Value; - Leaf = homePage?.Element("leaf")?.Value == "true"; - } - } - } -} diff --git a/src/openHAB.Core.Client/Models/Page.cs b/src/openHAB.Core.Client/Models/Page.cs new file mode 100644 index 00000000..42e97692 --- /dev/null +++ b/src/openHAB.Core.Client/Models/Page.cs @@ -0,0 +1,88 @@ +using System.Text.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Text.Json.Serialization; + +namespace openHAB.Core.Client.Models +{ + /// + /// Represents a page in the openHAB application. + /// + public class Page + { + /// + /// Gets or sets the ID of the page. + /// + [JsonPropertyName("id")] + public string Id + { + get; set; + } + + /// + /// Gets or sets the title of the page. + /// + [JsonPropertyName("title")] + public string Title + { + get; set; + } + + /// + /// Gets or sets the icon of the page. + /// + [JsonPropertyName("icon")] + public string Icon + { + get; set; + } + + /// + /// Gets or sets the link of the page. + /// + [JsonPropertyName("link")] + public string Link + { + get; set; + } + + /// + /// Gets or sets the parent page ID. + /// + [JsonPropertyName("parent")] + public string Parent + { + get; set; + } + + /// + /// Gets or sets a value indicating whether the page is a leaf page. + /// + [JsonPropertyName("leaf")] + public bool Leaf + { + get; set; + } + + /// + /// Gets or sets a value indicating whether the page has a timeout. + /// + [JsonPropertyName("timeout")] + public bool Timeout + { + get; set; + } + + /// + /// Gets or sets the list of widgets on the page. + /// + [JsonPropertyName("widgets")] + public List Widgets + { + get; set; + } + } +} diff --git a/src/openHAB.Core.Client/Models/RuntimeInfo.cs b/src/openHAB.Core.Client/Models/RuntimeInfo.cs index 083316cc..b7a5029c 100644 --- a/src/openHAB.Core.Client/Models/RuntimeInfo.cs +++ b/src/openHAB.Core.Client/Models/RuntimeInfo.cs @@ -1,4 +1,6 @@ -using Newtonsoft.Json; + + +using System.Text.Json.Serialization; namespace openHAB.Core.Client.Models { @@ -7,7 +9,7 @@ public partial class RuntimeInfo { /// Gets or sets the server version. /// The version. - [JsonProperty("version")] + [JsonPropertyName("version")] public string Version { get; set; @@ -15,7 +17,7 @@ public string Version /// Gets or sets the build version string. /// The build string. - [JsonProperty("buildString")] + [JsonPropertyName("buildString")] public string BuildString { get; set; diff --git a/src/openHAB.Core.Client/Models/Sitemap.cs b/src/openHAB.Core.Client/Models/Sitemap.cs new file mode 100644 index 00000000..b902bd7d --- /dev/null +++ b/src/openHAB.Core.Client/Models/Sitemap.cs @@ -0,0 +1,56 @@ +using System.Text.Json.Serialization; + +namespace openHAB.Core.Client.Models +{ + + /// + /// Represents an OpenHAB sitemap. + /// + public class Sitemap + { + /// + /// Gets or sets the name of the sitemap. + /// + [JsonPropertyName("name")] + public string Name + { + get; set; + } + + /// + /// Gets or sets the icon of the sitemap. + /// + [JsonPropertyName("icon")] + public string Icon + { + get; set; + } + + /// + /// Gets or sets the label of the sitemap. + /// + [JsonPropertyName("label")] + public string Label + { + get; set; + } + + /// + /// Gets or sets the link of the sitemap. + /// + [JsonPropertyName("link")] + public string Link + { + get; set; + } + + /// + /// Gets or sets the homepage of the sitemap. + /// + [JsonPropertyName("homepage")] + public Page Homepage + { + get; set; + } + } +} diff --git a/src/openHAB.Core.Client/Models/OpenHABWidget.cs b/src/openHAB.Core.Client/Models/Widget.cs similarity index 67% rename from src/openHAB.Core.Client/Models/OpenHABWidget.cs rename to src/openHAB.Core.Client/Models/Widget.cs index 774ac2e1..6e1a4fd4 100644 --- a/src/openHAB.Core.Client/Models/OpenHABWidget.cs +++ b/src/openHAB.Core.Client/Models/Widget.cs @@ -2,43 +2,93 @@ using System.Collections.Generic; using System.ComponentModel; using System.Runtime.CompilerServices; -using Newtonsoft.Json; +using System.Text.Json.Serialization; namespace openHAB.Core.Client.Models { /// /// A class that represents an OpenHAB widget. /// - public class OpenHABWidget : INotifyPropertyChanged, IEquatable + public class Widget : INotifyPropertyChanged, IEquatable { private string _icon; private string _label; + /// + /// Initializes a new instance of the class. + /// + public Widget() + { + Children = new List(); + } + /// Occurs when a property value changes. /// public event PropertyChangedEventHandler PropertyChanged; /// - /// Called when [property changed]. + /// Gets or sets the Children of the OpenHAB widget. /// - /// Name of the property. - protected void OnPropertyChanged([CallerMemberName] string propertyName = null) + [JsonPropertyName("widgets")] + public ICollection Children { - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + get; set; } /// - /// Initializes a new instance of the class. + /// Gets or sets the Encoding of the OpenHAB widget. /// - public OpenHABWidget() + [JsonPropertyName("encoding")] + public string Encoding { - Children = new List(); + get; set; + } + + [JsonPropertyName("forceAsItem")] + public bool ForceAsItem + { + get; set; } /// - /// Gets or sets the ID of the OpenHAB widget. + /// Gets or sets the Height of the OpenHAB widget. /// - public string WidgetId + [JsonPropertyName("height")] + public int Height + { + get; set; + } + + /// + /// Gets or sets the Icon of the OpenHAB widget. + /// + [JsonPropertyName("icon")] + public string Icon + { + get => _icon ?? string.Empty; + set => _icon = value; + } + + /// + /// Gets or sets the IconColor of the OpenHAB widget. + /// + [JsonPropertyName("iconcolor")] + public string IconColor + { + get; set; + } + + [JsonPropertyName("inputHint")] + public string InputHint + { + get; set; + } + + /// + /// Gets or sets the Item of the OpenHAB widget. + /// + [JsonPropertyName("item")] + public Item Item { get; set; } @@ -46,6 +96,7 @@ public string WidgetId /// /// Gets or sets the Label of the OpenHAB widget. /// + [JsonPropertyName("label")] public string Label { get => _label; @@ -71,221 +122,207 @@ public string Label } /// - /// Gets or sets the Value of the widget. + /// Gets or sets the LabelColor of the OpenHAB widget. /// - public string Value + [JsonPropertyName("labelcolor")] + public string LabelColor { get; set; } - /// - /// Gets or sets the Icon of the OpenHAB widget. - /// - public string Icon + [JsonPropertyName("labelSource")] + public string LabelSource { - get => _icon ?? string.Empty; - set => _icon = value; + get; set; } - /// - /// Gets or sets the Type of the OpenHAB widget. - /// - public string Type + [JsonPropertyName("legend")] + public bool Legend { get; set; } /// - /// Gets or sets the Url of the OpenHAB widget. + /// Gets or sets the linked page when available. /// - public string Url + [JsonPropertyName("linkedPage")] + public Page LinkedPage { get; set; } /// - /// Gets or sets the Period of the OpenHAB widget. + /// Gets or sets the Mapping of the OpenHAB widget. /// - public string Period + [JsonPropertyName("mappings")] + public ICollection Mappings { get; set; } - /// - /// Gets or sets the Service of the OpenHAB widget. - /// - public string Service + [JsonPropertyName("maxValue")] + public float MaxValue { get; set; } - /// - /// Gets or sets the MinValue of the OpenHAB widget. - /// + [JsonPropertyName("minValue")] public float MinValue { get; set; } - /// - /// Gets or sets the MaxValue of the OpenHAB widget. - /// - public float MaxValue + [JsonPropertyName("name")] + public string Name { get; set; } /// - /// Gets or sets the Step of the OpenHAB widget. + /// Gets or sets the Parent of the OpenHAB widget. /// - public float Step + public Widget Parent { get; set; } - /// - /// Gets or sets the Refresh of the OpenHAB widget. - /// - public int Refresh + [JsonPropertyName("pattern")] + public string Pattern { get; set; } - /// - /// Gets or sets the Height of the OpenHAB widget. - /// - public int Height + [JsonPropertyName("period")] + public string Period { get; set; } - /// - /// Gets or sets the State of the OpenHAB widget. - /// - public string State + [JsonPropertyName("refresh")] + public float Refresh { get; set; } - /// - /// Gets or sets the IconColor of the OpenHAB widget. - /// - public string IconColor + [JsonPropertyName("sendFrequency")] + public float SendFrequency { get; set; } - /// - /// Gets or sets the LabelColor of the OpenHAB widget. - /// - public string LabelColor + [JsonPropertyName("service")] + public string Service { get; set; } - /// - /// Gets or sets the ValueColor of the OpenHAB widget. - /// - public string ValueColor + [JsonPropertyName("state")] + public string State { get; set; } - /// - /// Gets or sets the Encoding of the OpenHAB widget. - /// - public string Encoding + [JsonPropertyName("staticIcon")] + public bool StaticIcon { get; set; } - /// - /// Gets or sets the Item of the OpenHAB widget. - /// - public OpenHABItem Item + [JsonPropertyName("step")] + public float Step { get; set; } - /// - /// Gets or sets the Parent of the OpenHAB widget. - /// - public OpenHABWidget Parent + [JsonPropertyName("switchSupport")] + public bool SwitchSupport { get; set; } - /// - /// Gets or sets the Children of the OpenHAB widget. - /// - [JsonProperty(PropertyName = "widgets")] - public ICollection Children + [JsonPropertyName("type")] + public string Type + { + get; set; + } + + [JsonPropertyName("unit")] + public string Unit + { + get; set; + } + + [JsonPropertyName("url")] + public string Url { get; set; } /// - /// Gets or sets the Mapping of the OpenHAB widget. + /// Gets or sets the Value of the widget. /// - public ICollection Mappings + public string Value { get; set; } /// - /// Gets or sets the linked page when available. + /// Gets or sets the ValueColor of the OpenHAB widget. /// - public OpenHABSitemap LinkedPage + [JsonPropertyName("valuecolor")] + public string ValueColor { get; set; } - /// Gets or sets a value indicating whether this is visibility. - /// - /// true if visibility; otherwise, false. + [JsonPropertyName("visibility")] public bool Visibility { - get; - set; + get; set; } - #region IEquatable Implementation - - /// - public override int GetHashCode() + [JsonPropertyName("widgetId")] + public string WidgetId { - return WidgetId.GetHashCode(); + get; set; } - /// - public override bool Equals(object obj) + [JsonPropertyName("yAxisDecimalPattern")] + public string YAxisDecimalPattern { - OpenHABWidget widget = (OpenHABWidget)obj; - - if (widget == null) - { - return false; - } + get; set; + } - return Equals(widget); + /// + /// Called when [property changed]. + /// + /// Name of the property. + protected void OnPropertyChanged([CallerMemberName] string propertyName = null) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } - /// - public bool Equals(OpenHABWidget other) + #region IEquatable Implementation + + /// Implements the operator !=. + /// The widget1. + /// The widget2. + /// The result of the operator. + public static bool operator !=(Widget widget1, Widget widget2) { - if (string.IsNullOrEmpty(WidgetId) || ReferenceEquals(other, null)) + if (ReferenceEquals(widget1, null)) { return false; } - return WidgetId.CompareTo(other.WidgetId) == 0; + return !widget1.Equals(widget2); } /// Implements the operator ==. /// The widget1. /// The widget2. /// The result of the operator. - public static bool operator ==(OpenHABWidget widget1, OpenHABWidget widget2) + public static bool operator ==(Widget widget1, Widget widget2) { if (ReferenceEquals(widget1, null)) { @@ -295,20 +332,36 @@ public bool Equals(OpenHABWidget other) return widget1.Equals(widget2); } - /// Implements the operator !=. - /// The widget1. - /// The widget2. - /// The result of the operator. - public static bool operator !=(OpenHABWidget widget1, OpenHABWidget widget2) + /// + public override bool Equals(object obj) { - if (ReferenceEquals(widget1, null)) + Widget widget = (Widget)obj; + + if (widget == null) { return false; } - return !widget1.Equals(widget2); + return Equals(widget); + } + + /// + public bool Equals(Widget other) + { + if (string.IsNullOrEmpty(WidgetId) || ReferenceEquals(other, null)) + { + return false; + } + + return WidgetId.CompareTo(other.WidgetId) == 0; + } + + /// + public override int GetHashCode() + { + return WidgetId.GetHashCode(); } - #endregion + #endregion IEquatable Implementation } -} +} \ No newline at end of file diff --git a/src/openHAB.Core.Client/Models/OpenHABWidgetMapping.cs b/src/openHAB.Core.Client/Models/WidgetMapping.cs similarity index 76% rename from src/openHAB.Core.Client/Models/OpenHABWidgetMapping.cs rename to src/openHAB.Core.Client/Models/WidgetMapping.cs index bb1df45c..b5a18467 100644 --- a/src/openHAB.Core.Client/Models/OpenHABWidgetMapping.cs +++ b/src/openHAB.Core.Client/Models/WidgetMapping.cs @@ -3,7 +3,7 @@ namespace openHAB.Core.Client.Models /// /// A mapping for an OpenHAB Widget. /// - public class OpenHABWidgetMapping + public class WidgetMapping { /// /// Gets or sets the Command of the mapping. @@ -16,11 +16,11 @@ public class OpenHABWidgetMapping public string Label { get; set; } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// A command. /// A label. - public OpenHABWidgetMapping(string command, string label) + public WidgetMapping(string command, string label) { Command = command; Label = label; diff --git a/src/openHAB.Core.Client/OpenHABClient.cs b/src/openHAB.Core.Client/OpenHABClient.cs index 20420463..aa05e7af 100644 --- a/src/openHAB.Core.Client/OpenHABClient.cs +++ b/src/openHAB.Core.Client/OpenHABClient.cs @@ -1,13 +1,5 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Net.Http; -using System.Threading.Tasks; using CommunityToolkit.Mvvm.Messaging; using Microsoft.Extensions.Logging; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; using openHAB.Core.Client.Common; using openHAB.Core.Client.Connection.Contracts; using openHAB.Core.Client.Contracts; @@ -15,6 +7,14 @@ using openHAB.Core.Client.Event.Contracts; using openHAB.Core.Client.Messages; using openHAB.Core.Client.Models; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net.Http; +using System.Text.Json; +using System.Text.Json.Serialization; +using System.Threading.Tasks; namespace openHAB.Core.Client { @@ -60,7 +60,7 @@ public async Task> GetOpenHABServerInfo() } /// - public async Task> LoadItemsFromSitemap(string sitemapLink, OpenHABVersion version) + public async Task> LoadItemsFromSitemap(string sitemapLink, OpenHABVersion version) { try { @@ -75,22 +75,11 @@ public async Task> LoadItemsFromSitemap(string sitema string resultString = await result.Content.ReadAsStringAsync().ConfigureAwait(false); - ICollection items = null; + ICollection items = null; if (version == OpenHABVersion.Two || version == OpenHABVersion.Three || version == OpenHABVersion.Four) { - JObject jsonObject = JObject.Parse(resultString); - - string content = string.Empty; - if (jsonObject["homepage"] == null) - { - content = jsonObject["widgets"].ToString(); - } - else - { - content = jsonObject["homepage"]["widgets"].ToString(); - } - - items = JsonConvert.DeserializeObject>(content); + Sitemap sitemap = JsonSerializer.Deserialize(resultString); + items = sitemap.Homepage.Widgets; } else { @@ -115,7 +104,7 @@ public async Task> LoadItemsFromSitemap(string sitema } } - public async Task GetSitemap(string sitemapLink, OpenHABVersion version) + public async Task GetSitemap(string sitemapLink, OpenHABVersion version) { try { @@ -130,11 +119,16 @@ public async Task GetSitemap(string sitemapLink, OpenHABVersion string resultString = await result.Content.ReadAsStringAsync().ConfigureAwait(false); - OpenHABSitemap sitemap = null; + Sitemap sitemap = null; if (version == OpenHABVersion.Two || version == OpenHABVersion.Three || version == OpenHABVersion.Four) { - JObject jsonObject = JObject.Parse(resultString); - sitemap = JsonConvert.DeserializeObject(jsonObject["homepage"].ToString()); + JsonSerializerOptions serializerOptions = new JsonSerializerOptions + { + PropertyNameCaseInsensitive = true, + NumberHandling = JsonNumberHandling.AllowReadingFromString, + }; + + sitemap = JsonSerializer.Deserialize(resultString, serializerOptions); } else { @@ -161,7 +155,7 @@ public async Task GetSitemap(string sitemapLink, OpenHABVersion /// - public async Task GetItemByName(string itemName) + public async Task GetItemByName(string itemName) { try { @@ -177,7 +171,7 @@ public async Task GetItemByName(string itemName) } string resultString = await result.Content.ReadAsStringAsync().ConfigureAwait(false); - OpenHABItem item = JsonConvert.DeserializeObject(resultString); + Item item = JsonSerializer.Deserialize(resultString); _logger.LogInformation($"Loaded item '{itemName}' from server"); @@ -196,7 +190,7 @@ public async Task GetItemByName(string itemName) } /// - public async Task> LoadSitemaps(OpenHABVersion version, List> filters) + public async Task> LoadSitemaps(OpenHABVersion version, List> filters) { try { @@ -211,11 +205,11 @@ public async Task> LoadSitemaps(OpenHABVersion versi string resultString = await result.Content.ReadAsStringAsync().ConfigureAwait(false); - List sitemaps = JsonConvert.DeserializeObject>(resultString); + List sitemaps = JsonSerializer.Deserialize>(resultString); if (sitemaps == null) { _logger.LogError($"Failed to load sitemaps from server"); - return new List(); + return new List(); } _logger.LogInformation($"Loaded '{sitemaps.Count}' sitemaps from server"); @@ -256,7 +250,7 @@ public async Task ResetConnection(Connection.Models.Connection localConnec } /// - public async Task> SendCommand(OpenHABItem item, string command) + public async Task> SendCommand(Item item, string command) { try { diff --git a/src/openHAB.Core.Client/Schema/openhab-schema.json b/src/openHAB.Core.Client/Schema/openhab-schema.json new file mode 100644 index 00000000..a577f5a0 --- /dev/null +++ b/src/openHAB.Core.Client/Schema/openhab-schema.json @@ -0,0 +1,10150 @@ +{ + "openapi": "3.0.1", + "info": { + "title": "openHAB REST API", + "contact": { + "name": "openHAB", + "url": "https://www.openhab.org/docs/" + }, + "version": "6" + }, + "servers": [ + { + "url": "https://home.myopenhab.org/rest/" + } + ], + "paths": { + "/module-types": { + "get": { + "tags": [ + "module-types" + ], + "summary": "Get all available module types.", + "operationId": "getModuleTypes", + "parameters": [ + { + "name": "Accept-Language", + "in": "header", + "description": "language", + "schema": { + "type": "string" + } + }, + { + "name": "tags", + "in": "query", + "description": "tags for filtering", + "schema": { + "type": "string" + } + }, + { + "name": "type", + "in": "query", + "description": "filtering by action, condition or trigger", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ModuleTypeDTO" + } + } + } + } + } + } + } + }, + "/module-types/{moduleTypeUID}": { + "get": { + "tags": [ + "module-types" + ], + "summary": "Gets a module type corresponding to the given UID.", + "operationId": "getModuleTypeById", + "parameters": [ + { + "name": "Accept-Language", + "in": "header", + "description": "language", + "schema": { + "type": "string" + } + }, + { + "name": "moduleTypeUID", + "in": "path", + "description": "moduleTypeUID", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModuleTypeDTO" + } + } + } + }, + "404": { + "description": "Module Type corresponding to the given UID does not found." + } + } + } + }, + "/rules": { + "get": { + "tags": [ + "rules" + ], + "summary": "Get available rules, optionally filtered by tags and/or prefix.", + "operationId": "getRules", + "parameters": [ + { + "name": "prefix", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "tags", + "in": "query", + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + { + "name": "summary", + "in": "query", + "description": "summary fields only", + "schema": { + "type": "boolean" + } + }, + { + "name": "staticDataOnly", + "in": "query", + "description": "provides a cacheable list of values not expected to change regularly and honors the If-Modified-Since header, all other parameters are ignored", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/EnrichedRuleDTO" + } + } + } + } + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + }, + "post": { + "tags": [ + "rules" + ], + "summary": "Creates a rule.", + "operationId": "createRule", + "requestBody": { + "description": "rule data", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RuleDTO" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Created", + "headers": { + "Location": { + "description": "Newly created Rule", + "style": "simple", + "schema": { + "type": "string" + } + } + } + }, + "400": { + "description": "Creation of the rule is refused. Missing required parameter." + }, + "409": { + "description": "Creation of the rule is refused. Rule with the same UID already exists." + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + } + }, + "/rules/{ruleUID}/enable": { + "post": { + "tags": [ + "rules" + ], + "summary": "Sets the rule enabled status.", + "operationId": "enableRule", + "parameters": [ + { + "name": "ruleUID", + "in": "path", + "description": "ruleUID", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "description": "enable", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK" + }, + "404": { + "description": "Rule corresponding to the given UID does not found." + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + } + }, + "/rules/{ruleUID}/actions": { + "get": { + "tags": [ + "rules" + ], + "summary": "Gets the rule actions.", + "operationId": "getRuleActions", + "parameters": [ + { + "name": "ruleUID", + "in": "path", + "description": "ruleUID", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ActionDTO" + } + } + } + } + }, + "404": { + "description": "Rule corresponding to the given UID does not found." + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + } + }, + "/rules/{ruleUID}": { + "get": { + "tags": [ + "rules" + ], + "summary": "Gets the rule corresponding to the given UID.", + "operationId": "getRuleById", + "parameters": [ + { + "name": "ruleUID", + "in": "path", + "description": "ruleUID", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EnrichedRuleDTO" + } + } + } + }, + "404": { + "description": "Rule not found" + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + }, + "put": { + "tags": [ + "rules" + ], + "summary": "Updates an existing rule corresponding to the given UID.", + "operationId": "updateRule", + "parameters": [ + { + "name": "ruleUID", + "in": "path", + "description": "ruleUID", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "description": "rule data", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RuleDTO" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK" + }, + "404": { + "description": "Rule corresponding to the given UID does not found." + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + }, + "delete": { + "tags": [ + "rules" + ], + "summary": "Removes an existing rule corresponding to the given UID.", + "operationId": "deleteRule", + "parameters": [ + { + "name": "ruleUID", + "in": "path", + "description": "ruleUID", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + }, + "404": { + "description": "Rule corresponding to the given UID does not found." + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + } + }, + "/rules/{ruleUID}/conditions": { + "get": { + "tags": [ + "rules" + ], + "summary": "Gets the rule conditions.", + "operationId": "getRuleConditions", + "parameters": [ + { + "name": "ruleUID", + "in": "path", + "description": "ruleUID", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ConditionDTO" + } + } + } + } + }, + "404": { + "description": "Rule corresponding to the given UID does not found." + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + } + }, + "/rules/{ruleUID}/config": { + "get": { + "tags": [ + "rules" + ], + "summary": "Gets the rule configuration values.", + "operationId": "getRuleConfiguration", + "parameters": [ + { + "name": "ruleUID", + "in": "path", + "description": "ruleUID", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + } + }, + "404": { + "description": "Rule corresponding to the given UID does not found." + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + }, + "put": { + "tags": [ + "rules" + ], + "summary": "Sets the rule configuration values.", + "operationId": "updateRuleConfiguration", + "parameters": [ + { + "name": "ruleUID", + "in": "path", + "description": "ruleUID", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "description": "config", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": { + "type": "object" + } + } + } + } + }, + "responses": { + "200": { + "description": "OK" + }, + "404": { + "description": "Rule corresponding to the given UID does not found." + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + } + }, + "/rules/{ruleUID}/{moduleCategory}/{id}": { + "get": { + "tags": [ + "rules" + ], + "summary": "Gets the rule's module corresponding to the given Category and ID.", + "operationId": "getRuleModuleById", + "parameters": [ + { + "name": "ruleUID", + "in": "path", + "description": "ruleUID", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "moduleCategory", + "in": "path", + "description": "moduleCategory", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "id", + "in": "path", + "description": "id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModuleDTO" + } + } + } + }, + "404": { + "description": "Rule corresponding to the given UID does not found or does not have a module with such Category and ID." + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + } + }, + "/rules/{ruleUID}/{moduleCategory}/{id}/config": { + "get": { + "tags": [ + "rules" + ], + "summary": "Gets the module's configuration.", + "operationId": "getRuleModuleConfig", + "parameters": [ + { + "name": "ruleUID", + "in": "path", + "description": "ruleUID", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "moduleCategory", + "in": "path", + "description": "moduleCategory", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "id", + "in": "path", + "description": "id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + } + }, + "404": { + "description": "Rule corresponding to the given UID does not found or does not have a module with such Category and ID." + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + } + }, + "/rules/{ruleUID}/{moduleCategory}/{id}/config/{param}": { + "get": { + "tags": [ + "rules" + ], + "summary": "Gets the module's configuration parameter.", + "operationId": "getRuleModuleConfigParameter", + "parameters": [ + { + "name": "ruleUID", + "in": "path", + "description": "ruleUID", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "moduleCategory", + "in": "path", + "description": "moduleCategory", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "id", + "in": "path", + "description": "id", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "param", + "in": "path", + "description": "param", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + }, + "404": { + "description": "Rule corresponding to the given UID does not found or does not have a module with such Category and ID." + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + }, + "put": { + "tags": [ + "rules" + ], + "summary": "Sets the module's configuration parameter value.", + "operationId": "setRuleModuleConfigParameter", + "parameters": [ + { + "name": "ruleUID", + "in": "path", + "description": "ruleUID", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "moduleCategory", + "in": "path", + "description": "moduleCategory", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "id", + "in": "path", + "description": "id", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "param", + "in": "path", + "description": "param", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "description": "value", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK" + }, + "404": { + "description": "Rule corresponding to the given UID does not found or does not have a module with such Category and ID." + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + } + }, + "/rules/{ruleUID}/triggers": { + "get": { + "tags": [ + "rules" + ], + "summary": "Gets the rule triggers.", + "operationId": "getRuleTriggers", + "parameters": [ + { + "name": "ruleUID", + "in": "path", + "description": "ruleUID", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TriggerDTO" + } + } + } + } + }, + "404": { + "description": "Rule corresponding to the given UID does not found." + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + } + }, + "/rules/{ruleUID}/runnow": { + "post": { + "tags": [ + "rules" + ], + "summary": "Executes actions of the rule.", + "operationId": "runRuleNow_1", + "parameters": [ + { + "name": "ruleUID", + "in": "path", + "description": "ruleUID", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "description": "the context for running this rule", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": { + "type": "object" + } + } + } + } + }, + "responses": { + "200": { + "description": "OK" + }, + "404": { + "description": "Rule corresponding to the given UID does not found." + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + } + }, + "/rules/schedule/simulations": { + "get": { + "tags": [ + "rules" + ], + "summary": "Simulates the executions of rules filtered by tag 'Schedule' within the given times.", + "operationId": "getScheduleRuleSimulations", + "parameters": [ + { + "name": "from", + "in": "query", + "description": "Start time of the simulated rule executions. Will default to the current time. [yyyy-MM-dd'T'HH:mm:ss.SSSZ]", + "schema": { + "type": "string" + } + }, + { + "name": "until", + "in": "query", + "description": "End time of the simulated rule executions. Will default to 30 days after the start time. Must be less than 180 days after the given start time. [yyyy-MM-dd'T'HH:mm:ss.SSSZ]", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RuleExecution" + } + } + } + } + }, + "400": { + "description": "The max. simulation duration of 180 days is exceeded." + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + } + }, + "/templates": { + "get": { + "tags": [ + "templates" + ], + "summary": "Get all available templates.", + "operationId": "getTemplates", + "parameters": [ + { + "name": "Accept-Language", + "in": "header", + "description": "language", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Template" + } + } + } + } + } + } + } + }, + "/templates/{templateUID}": { + "get": { + "tags": [ + "templates" + ], + "summary": "Gets a template corresponding to the given UID.", + "operationId": "getTemplateById", + "parameters": [ + { + "name": "Accept-Language", + "in": "header", + "description": "language", + "schema": { + "type": "string" + } + }, + { + "name": "templateUID", + "in": "path", + "description": "templateUID", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Template" + } + } + } + }, + "404": { + "description": "Template corresponding to the given UID does not found." + } + } + } + }, + "/actions/{thingUID}/{actionUid}": { + "post": { + "tags": [ + "actions" + ], + "summary": "Executes a thing action.", + "operationId": "executeThingAction", + "parameters": [ + { + "name": "thingUID", + "in": "path", + "description": "thingUID", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "actionUid", + "in": "path", + "description": "action type UID (including scope, separated by '.')", + "required": true, + "schema": { + "pattern": "[a-zA-Z0-9]+\\.[a-zA-Z0-9]+", + "type": "string" + } + }, + { + "name": "Accept-Language", + "in": "header", + "description": "language", + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "description": "action inputs as map (parameter name as key / argument as value)", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": { + "type": "object" + } + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + } + }, + "404": { + "description": "Action not found" + }, + "500": { + "description": "Creation of action handler or execution failed" + } + } + } + }, + "/actions/{thingUID}": { + "get": { + "tags": [ + "actions" + ], + "summary": "Get all available actions for provided thing UID", + "operationId": "getAvailableActionsForThing", + "parameters": [ + { + "name": "thingUID", + "in": "path", + "description": "thingUID", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "Accept-Language", + "in": "header", + "description": "language", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "uniqueItems": true, + "type": "array", + "items": { + "$ref": "#/components/schemas/ThingActionDTO" + } + } + } + } + }, + "204": { + "description": "No actions found." + } + } + } + }, + "/uuid": { + "get": { + "tags": [ + "uuid" + ], + "summary": "A unified unique id.", + "operationId": "getUUID", + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/audio/defaultsink": { + "get": { + "tags": [ + "audio" + ], + "summary": "Get the default sink if defined or the first available sink.", + "operationId": "getAudioDefaultSink", + "parameters": [ + { + "name": "Accept-Language", + "in": "header", + "description": "language", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AudioSinkDTO" + } + } + } + }, + "404": { + "description": "Sink not found" + } + } + } + }, + "/audio/defaultsource": { + "get": { + "tags": [ + "audio" + ], + "summary": "Get the default source if defined or the first available source.", + "operationId": "getAudioDefaultSource", + "parameters": [ + { + "name": "Accept-Language", + "in": "header", + "description": "language", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AudioSourceDTO" + } + } + } + }, + "404": { + "description": "Source not found" + } + } + } + }, + "/audio/sinks": { + "get": { + "tags": [ + "audio" + ], + "summary": "Get the list of all sinks.", + "operationId": "getAudioSinks", + "parameters": [ + { + "name": "Accept-Language", + "in": "header", + "description": "language", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AudioSinkDTO" + } + } + } + } + } + } + } + }, + "/audio/sources": { + "get": { + "tags": [ + "audio" + ], + "summary": "Get the list of all sources.", + "operationId": "getAudioSources", + "parameters": [ + { + "name": "Accept-Language", + "in": "header", + "description": "language", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AudioSourceDTO" + } + } + } + } + } + } + } + }, + "/auth/logout": { + "post": { + "tags": [ + "auth" + ], + "summary": "Delete the session associated with a refresh token.", + "operationId": "deleteSession", + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "type": "object", + "properties": { + "refresh_token": { + "type": "string" + }, + "id": { + "type": "string" + } + } + } + } + } + }, + "responses": { + "200": { + "description": "OK" + }, + "401": { + "description": "User is not authenticated" + }, + "404": { + "description": "User or refresh token not found" + } + } + } + }, + "/auth/apitokens": { + "get": { + "tags": [ + "auth" + ], + "summary": "List the API tokens associated to the authenticated user.", + "operationId": "getApiTokens", + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/UserApiTokenDTO" + } + } + } + } + }, + "401": { + "description": "User is not authenticated" + }, + "404": { + "description": "User not found" + } + } + } + }, + "/auth/sessions": { + "get": { + "tags": [ + "auth" + ], + "summary": "List the sessions associated to the authenticated user.", + "operationId": "getSessionsForCurrentUser", + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/UserSessionDTO" + } + } + } + } + }, + "401": { + "description": "User is not authenticated" + }, + "404": { + "description": "User not found" + } + } + } + }, + "/auth/token": { + "post": { + "tags": [ + "auth" + ], + "summary": "Get access and refresh tokens.", + "operationId": "getOAuthToken", + "parameters": [ + { + "name": "useCookie", + "in": "query", + "schema": { + "type": "boolean" + } + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "type": "object", + "properties": { + "grant_type": { + "type": "string" + }, + "code": { + "type": "string" + }, + "redirect_uri": { + "type": "string" + }, + "client_id": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "code_verifier": { + "type": "string" + } + } + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TokenResponseDTO" + } + } + } + }, + "400": { + "description": "Invalid request parameters" + } + } + } + }, + "/auth/apitokens/{name}": { + "delete": { + "tags": [ + "auth" + ], + "summary": "Revoke a specified API token associated to the authenticated user.", + "operationId": "removeApiToken", + "parameters": [ + { + "name": "name", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + }, + "401": { + "description": "User is not authenticated" + }, + "404": { + "description": "User or API token not found" + } + } + } + }, + "/addons": { + "get": { + "tags": [ + "addons" + ], + "summary": "Get all add-ons.", + "operationId": "getAddons", + "parameters": [ + { + "name": "Accept-Language", + "in": "header", + "description": "language", + "schema": { + "type": "string" + } + }, + { + "name": "serviceId", + "in": "query", + "description": "service ID", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Addon" + } + } + } + } + }, + "404": { + "description": "Service not found" + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + } + }, + "/addons/{addonId}": { + "get": { + "tags": [ + "addons" + ], + "summary": "Get add-on with given ID.", + "operationId": "getAddonById", + "parameters": [ + { + "name": "Accept-Language", + "in": "header", + "description": "language", + "schema": { + "type": "string" + } + }, + { + "name": "addonId", + "in": "path", + "description": "addon ID", + "required": true, + "schema": { + "pattern": "[a-zA-Z_0-9-:]+", + "type": "string" + } + }, + { + "name": "serviceId", + "in": "query", + "description": "service ID", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Addon" + } + } + } + }, + "404": { + "description": "Not found" + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + } + }, + "/addons/{addonId}/config": { + "get": { + "tags": [ + "addons" + ], + "summary": "Get add-on configuration for given add-on ID.", + "operationId": "getAddonConfiguration", + "parameters": [ + { + "name": "addonId", + "in": "path", + "description": "addon ID", + "required": true, + "schema": { + "pattern": "[a-zA-Z_0-9-:]+", + "type": "string" + } + }, + { + "name": "serviceId", + "in": "query", + "description": "service ID", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + } + }, + "404": { + "description": "Add-on does not exist" + }, + "500": { + "description": "Configuration can not be read due to internal error" + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + }, + "put": { + "tags": [ + "addons" + ], + "summary": "Updates an add-on configuration for given ID and returns the old configuration.", + "operationId": "updateAddonConfiguration", + "parameters": [ + { + "name": "addonId", + "in": "path", + "description": "Add-on id", + "required": true, + "schema": { + "pattern": "[a-zA-Z_0-9-:]+", + "type": "string" + } + }, + { + "name": "serviceId", + "in": "query", + "description": "service ID", + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": { + "type": "object" + } + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + } + }, + "204": { + "description": "No old configuration" + }, + "404": { + "description": "Add-on does not exist" + }, + "500": { + "description": "Configuration can not be updated due to internal error" + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + } + }, + "/addons/services": { + "get": { + "tags": [ + "addons" + ], + "summary": "Get all add-on types.", + "operationId": "getAddonTypes", + "parameters": [ + { + "name": "Accept-Language", + "in": "header", + "description": "language", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AddonType" + } + } + } + } + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + } + }, + "/addons/suggestions": { + "get": { + "tags": [ + "addons" + ], + "summary": "Get suggested add-ons to be installed.", + "operationId": "getSuggestedAddons", + "parameters": [ + { + "name": "Accept-Language", + "in": "header", + "description": "language", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Addon" + } + } + } + } + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + } + }, + "/addons/types": { + "get": { + "tags": [ + "addons" + ], + "summary": "Get add-on services.", + "operationId": "getAddonServices", + "parameters": [ + { + "name": "Accept-Language", + "in": "header", + "description": "language", + "schema": { + "type": "string" + } + }, + { + "name": "serviceId", + "in": "query", + "description": "service ID", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AddonType" + } + } + } + } + }, + "404": { + "description": "Service not found" + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + } + }, + "/addons/{addonId}/install": { + "post": { + "tags": [ + "addons" + ], + "summary": "Installs the add-on with the given ID.", + "operationId": "installAddonById", + "parameters": [ + { + "name": "addonId", + "in": "path", + "description": "addon ID", + "required": true, + "schema": { + "pattern": "[a-zA-Z_0-9-:]+", + "type": "string" + } + }, + { + "name": "serviceId", + "in": "query", + "description": "service ID", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + }, + "404": { + "description": "Not found" + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + } + }, + "/addons/url/{url}/install": { + "post": { + "tags": [ + "addons" + ], + "summary": "Installs the add-on from the given URL.", + "operationId": "installAddonFromURL", + "parameters": [ + { + "name": "url", + "in": "path", + "description": "addon install URL", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "The given URL is malformed or not valid." + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + } + }, + "/addons/{addonId}/uninstall": { + "post": { + "tags": [ + "addons" + ], + "summary": "Uninstalls the add-on with the given ID.", + "operationId": "uninstallAddon", + "parameters": [ + { + "name": "addonId", + "in": "path", + "description": "addon ID", + "required": true, + "schema": { + "pattern": "[a-zA-Z_0-9-:]+", + "type": "string" + } + }, + { + "name": "serviceId", + "in": "query", + "description": "service ID", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + }, + "404": { + "description": "Not found" + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + } + }, + "/channel-types": { + "get": { + "tags": [ + "channel-types" + ], + "summary": "Gets all available channel types.", + "operationId": "getChannelTypes", + "parameters": [ + { + "name": "Accept-Language", + "in": "header", + "description": "language", + "schema": { + "type": "string" + } + }, + { + "name": "prefixes", + "in": "query", + "description": "filter UIDs by prefix (multiple comma-separated prefixes allowed, for example: 'system,mqtt')", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "uniqueItems": true, + "type": "array", + "items": { + "$ref": "#/components/schemas/ChannelTypeDTO" + } + } + } + } + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + } + }, + "/channel-types/{channelTypeUID}": { + "get": { + "tags": [ + "channel-types" + ], + "summary": "Gets channel type by UID.", + "operationId": "getChannelTypeByUID", + "parameters": [ + { + "name": "channelTypeUID", + "in": "path", + "description": "channelTypeUID", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "Accept-Language", + "in": "header", + "description": "language", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Channel type with provided channelTypeUID does not exist.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ChannelTypeDTO" + } + } + } + }, + "404": { + "description": "No content" + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + } + }, + "/channel-types/{channelTypeUID}/linkableItemTypes": { + "get": { + "tags": [ + "channel-types" + ], + "summary": "Gets the item types the given trigger channel type UID can be linked to.", + "operationId": "getLinkableItemTypesByChannelTypeUID", + "parameters": [ + { + "name": "channelTypeUID", + "in": "path", + "description": "channelTypeUID", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "uniqueItems": true, + "type": "array", + "items": { + "type": "string" + } + } + } + } + }, + "204": { + "description": "No content: channel type has no linkable items or is no trigger channel." + }, + "404": { + "description": "Given channel type UID not found." + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + } + }, + "/config-descriptions": { + "get": { + "tags": [ + "config-descriptions" + ], + "summary": "Gets all available config descriptions.", + "operationId": "getConfigDescriptions", + "parameters": [ + { + "name": "Accept-Language", + "in": "header", + "description": "language", + "schema": { + "type": "string" + } + }, + { + "name": "scheme", + "in": "query", + "description": "scheme filter", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ConfigDescriptionDTO" + } + } + } + } + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + } + }, + "/config-descriptions/{uri}": { + "get": { + "tags": [ + "config-descriptions" + ], + "summary": "Gets a config description by URI.", + "operationId": "getConfigDescriptionByURI", + "parameters": [ + { + "name": "Accept-Language", + "in": "header", + "description": "language", + "schema": { + "type": "string" + } + }, + { + "name": "uri", + "in": "path", + "description": "uri", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ConfigDescriptionDTO" + } + } + } + }, + "400": { + "description": "Invalid URI syntax" + }, + "404": { + "description": "Not found" + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + } + }, + "/discovery": { + "get": { + "tags": [ + "discovery" + ], + "summary": "Gets all bindings that support discovery.", + "operationId": "getBindingsWithDiscoverySupport", + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "uniqueItems": true, + "type": "array", + "items": { + "type": "string" + } + } + } + } + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + } + }, + "/discovery/bindings/{bindingId}/scan": { + "post": { + "tags": [ + "discovery" + ], + "summary": "Starts asynchronous discovery process for a binding and returns the timeout in seconds of the discovery operation.", + "operationId": "scan", + "parameters": [ + { + "name": "bindingId", + "in": "path", + "description": "bindingId", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "type": "integer", + "format": "int32" + } + } + } + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + } + }, + "/inbox/{thingUID}/approve": { + "post": { + "tags": [ + "inbox" + ], + "summary": "Approves the discovery result by adding the thing to the registry.", + "operationId": "approveInboxItemById", + "parameters": [ + { + "name": "Accept-Language", + "in": "header", + "description": "language", + "schema": { + "type": "string" + } + }, + { + "name": "thingUID", + "in": "path", + "description": "thingUID", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "newThingId", + "in": "query", + "description": "new thing ID", + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "description": "thing label", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + }, + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Invalid new thing ID." + }, + "404": { + "description": "Thing unable to be approved." + }, + "409": { + "description": "No binding found that supports this thing." + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + } + }, + "/inbox/{thingUID}": { + "delete": { + "tags": [ + "inbox" + ], + "summary": "Removes the discovery result from the inbox.", + "operationId": "removeItemFromInbox", + "parameters": [ + { + "name": "thingUID", + "in": "path", + "description": "thingUID", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + }, + "404": { + "description": "Discovery result not found in the inbox." + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + } + }, + "/inbox": { + "get": { + "tags": [ + "inbox" + ], + "summary": "Get all discovered things.", + "operationId": "getDiscoveredInboxItems", + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DiscoveryResultDTO" + } + } + } + } + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + } + }, + "/inbox/{thingUID}/ignore": { + "post": { + "tags": [ + "inbox" + ], + "summary": "Flags a discovery result as ignored for further processing.", + "operationId": "flagInboxItemAsIgnored", + "parameters": [ + { + "name": "thingUID", + "in": "path", + "description": "thingUID", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + } + }, + "/inbox/{thingUID}/unignore": { + "post": { + "tags": [ + "inbox" + ], + "summary": "Removes ignore flag from a discovery result.", + "operationId": "removeIgnoreFlagOnInboxItem", + "parameters": [ + { + "name": "thingUID", + "in": "path", + "description": "thingUID", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + } + }, + "/items/{itemName}/members/{memberItemName}": { + "put": { + "tags": [ + "items" + ], + "summary": "Adds a new member to a group item.", + "operationId": "addMemberToGroupItem", + "parameters": [ + { + "name": "itemName", + "in": "path", + "description": "item name", + "required": true, + "schema": { + "pattern": "[a-zA-Z_0-9]+", + "type": "string" + } + }, + { + "name": "memberItemName", + "in": "path", + "description": "member item name", + "required": true, + "schema": { + "pattern": "[a-zA-Z_0-9]+", + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + }, + "404": { + "description": "Item or member item not found or item is not of type group item." + }, + "405": { + "description": "Member item is not editable." + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + }, + "delete": { + "tags": [ + "items" + ], + "summary": "Removes an existing member from a group item.", + "operationId": "removeMemberFromGroupItem", + "parameters": [ + { + "name": "itemName", + "in": "path", + "description": "item name", + "required": true, + "schema": { + "pattern": "[a-zA-Z_0-9]+", + "type": "string" + } + }, + { + "name": "memberItemName", + "in": "path", + "description": "member item name", + "required": true, + "schema": { + "pattern": "[a-zA-Z_0-9]+", + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + }, + "404": { + "description": "Item or member item not found or item is not of type group item." + }, + "405": { + "description": "Member item is not editable." + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + } + }, + "/items/{itemname}/metadata/{namespace}": { + "put": { + "tags": [ + "items" + ], + "summary": "Adds metadata to an item.", + "operationId": "addMetadataToItem", + "parameters": [ + { + "name": "itemname", + "in": "path", + "description": "item name", + "required": true, + "schema": { + "pattern": "[a-zA-Z_0-9]+", + "type": "string" + } + }, + { + "name": "namespace", + "in": "path", + "description": "namespace", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "description": "metadata", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MetadataDTO" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK" + }, + "201": { + "description": "Created" + }, + "400": { + "description": "Metadata value empty." + }, + "404": { + "description": "Item not found." + }, + "405": { + "description": "Metadata not editable." + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + }, + "delete": { + "tags": [ + "items" + ], + "summary": "Removes metadata from an item.", + "operationId": "removeMetadataFromItem", + "parameters": [ + { + "name": "itemname", + "in": "path", + "description": "item name", + "required": true, + "schema": { + "pattern": "[a-zA-Z_0-9]+", + "type": "string" + } + }, + { + "name": "namespace", + "in": "path", + "description": "namespace", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + }, + "404": { + "description": "Item not found." + }, + "405": { + "description": "Meta data not editable." + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + } + }, + "/items/{itemname}/tags/{tag}": { + "put": { + "tags": [ + "items" + ], + "summary": "Adds a tag to an item.", + "operationId": "addTagToItem", + "parameters": [ + { + "name": "itemname", + "in": "path", + "description": "item name", + "required": true, + "schema": { + "pattern": "[a-zA-Z_0-9]+", + "type": "string" + } + }, + { + "name": "tag", + "in": "path", + "description": "tag", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + }, + "404": { + "description": "Item not found." + }, + "405": { + "description": "Item not editable." + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + }, + "delete": { + "tags": [ + "items" + ], + "summary": "Removes a tag from an item.", + "operationId": "removeTagFromItem", + "parameters": [ + { + "name": "itemname", + "in": "path", + "description": "item name", + "required": true, + "schema": { + "pattern": "[a-zA-Z_0-9]+", + "type": "string" + } + }, + { + "name": "tag", + "in": "path", + "description": "tag", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + }, + "404": { + "description": "Item not found." + }, + "405": { + "description": "Item not editable." + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + } + }, + "/items/{itemname}": { + "get": { + "tags": [ + "items" + ], + "summary": "Gets a single item.", + "operationId": "getItemByName", + "parameters": [ + { + "name": "Accept-Language", + "in": "header", + "description": "language", + "schema": { + "type": "string" + } + }, + { + "name": "metadata", + "in": "query", + "description": "metadata selector - a comma separated list or a regular expression (returns all if no value given)", + "schema": { + "type": "string", + "default": ".*" + } + }, + { + "name": "recursive", + "in": "query", + "description": "get member items if the item is a group item", + "schema": { + "type": "boolean", + "default": true + } + }, + { + "name": "itemname", + "in": "path", + "description": "item name", + "required": true, + "schema": { + "pattern": "[a-zA-Z_0-9]+", + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EnrichedItemDTO" + } + } + } + }, + "404": { + "description": "Item not found" + } + } + }, + "put": { + "tags": [ + "items" + ], + "summary": "Adds a new item to the registry or updates the existing item.", + "operationId": "addOrUpdateItemInRegistry", + "parameters": [ + { + "name": "Accept-Language", + "in": "header", + "description": "language", + "schema": { + "type": "string" + } + }, + { + "name": "itemname", + "in": "path", + "description": "item name", + "required": true, + "schema": { + "pattern": "[a-zA-Z_0-9]+", + "type": "string" + } + } + ], + "requestBody": { + "description": "item data", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GroupItemDTO" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EnrichedItemDTO" + } + } + } + }, + "201": { + "description": "Item created." + }, + "400": { + "description": "Payload invalid." + }, + "404": { + "description": "Item not found or name in path invalid." + }, + "405": { + "description": "Item not editable." + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + }, + "post": { + "tags": [ + "items" + ], + "summary": "Sends a command to an item.", + "operationId": "sendItemCommand", + "parameters": [ + { + "name": "itemname", + "in": "path", + "description": "item name", + "required": true, + "schema": { + "pattern": "[a-zA-Z_0-9]+", + "type": "string" + } + } + ], + "requestBody": { + "description": "valid item command (e.g. ON, OFF, UP, DOWN, REFRESH)", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Item command null" + }, + "404": { + "description": "Item not found" + } + } + }, + "delete": { + "tags": [ + "items" + ], + "summary": "Removes an item from the registry.", + "operationId": "removeItemFromRegistry", + "parameters": [ + { + "name": "itemname", + "in": "path", + "description": "item name", + "required": true, + "schema": { + "pattern": "[a-zA-Z_0-9]+", + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + }, + "404": { + "description": "Item not found or item is not editable." + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + } + }, + "/items": { + "get": { + "tags": [ + "items" + ], + "summary": "Get all available items.", + "operationId": "getItems", + "parameters": [ + { + "name": "Accept-Language", + "in": "header", + "description": "language", + "schema": { + "type": "string" + } + }, + { + "name": "type", + "in": "query", + "description": "item type filter", + "schema": { + "type": "string" + } + }, + { + "name": "tags", + "in": "query", + "description": "item tag filter", + "schema": { + "type": "string" + } + }, + { + "name": "metadata", + "in": "query", + "description": "metadata selector - a comma separated list or a regular expression (returns all if no value given)", + "schema": { + "type": "string", + "default": ".*" + } + }, + { + "name": "recursive", + "in": "query", + "description": "get member items recursively", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "name": "fields", + "in": "query", + "description": "limit output to the given fields (comma separated)", + "schema": { + "type": "string" + } + }, + { + "name": "staticDataOnly", + "in": "query", + "description": "provides a cacheable list of values not expected to change regularly and checks the If-Modified-Since header, all other parameters are ignored except \"metadata\"", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/EnrichedItemDTO" + } + } + } + } + } + } + }, + "put": { + "tags": [ + "items" + ], + "summary": "Adds a list of items to the registry or updates the existing items.", + "operationId": "addOrUpdateItemsInRegistry", + "requestBody": { + "description": "array of item data", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/GroupItemDTO" + } + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + } + }, + "400": { + "description": "Payload is invalid." + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + } + }, + "/items/{itemname}/state": { + "get": { + "tags": [ + "items" + ], + "summary": "Gets the state of an item.", + "operationId": "getItemState_1", + "parameters": [ + { + "name": "itemname", + "in": "path", + "description": "item name", + "required": true, + "schema": { + "pattern": "[a-zA-Z_0-9]+", + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + }, + "404": { + "description": "Item not found" + } + } + }, + "put": { + "tags": [ + "items" + ], + "summary": "Updates the state of an item.", + "operationId": "updateItemState", + "parameters": [ + { + "name": "Accept-Language", + "in": "header", + "description": "language", + "schema": { + "type": "string" + } + }, + { + "name": "itemname", + "in": "path", + "description": "item name", + "required": true, + "schema": { + "pattern": "[a-zA-Z_0-9]+", + "type": "string" + } + } + ], + "requestBody": { + "description": "valid item state (e.g. ON, OFF)", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + }, + "required": true + }, + "responses": { + "202": { + "description": "Accepted" + }, + "400": { + "description": "Item state null" + }, + "404": { + "description": "Item not found" + } + } + } + }, + "/items/{itemname}/metadata/namespaces": { + "get": { + "tags": [ + "items" + ], + "summary": "Gets the namespace of an item.", + "operationId": "getItemNamespaces", + "parameters": [ + { + "name": "itemname", + "in": "path", + "description": "item name", + "required": true, + "schema": { + "pattern": "[a-zA-Z_0-9]+", + "type": "string" + } + }, + { + "name": "Accept-Language", + "in": "header", + "description": "language", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + } + }, + "404": { + "description": "Item not found" + } + } + } + }, + "/items/{itemName}/semantic/{semanticClass}": { + "get": { + "tags": [ + "items" + ], + "summary": "Gets the item which defines the requested semantics of an item.", + "operationId": "getSemanticItem", + "parameters": [ + { + "name": "Accept-Language", + "in": "header", + "description": "language", + "schema": { + "type": "string" + } + }, + { + "name": "itemName", + "in": "path", + "description": "item name", + "required": true, + "schema": { + "pattern": "\\w+", + "type": "string" + } + }, + { + "name": "semanticClass", + "in": "path", + "description": "semantic class", + "required": true, + "schema": { + "pattern": "\\w+", + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + }, + "404": { + "description": "Item not found" + } + } + } + }, + "/items/metadata/purge": { + "post": { + "tags": [ + "items" + ], + "summary": "Remove unused/orphaned metadata.", + "operationId": "purgeDatabase", + "responses": { + "200": { + "description": "OK" + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + } + }, + "/links": { + "get": { + "tags": [ + "links" + ], + "summary": "Gets all available links.", + "operationId": "getItemLinks", + "parameters": [ + { + "name": "channelUID", + "in": "query", + "description": "filter by channel UID", + "schema": { + "type": "string" + } + }, + { + "name": "itemName", + "in": "query", + "description": "filter by item name", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/EnrichedItemChannelLinkDTO" + } + } + } + } + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + } + }, + "/links/{itemName}/{channelUID}": { + "get": { + "tags": [ + "links" + ], + "summary": "Retrieves an individual link.", + "operationId": "getItemLink", + "parameters": [ + { + "name": "itemName", + "in": "path", + "description": "item name", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "channelUID", + "in": "path", + "description": "channel UID", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EnrichedItemChannelLinkDTO" + } + } + } + }, + "404": { + "description": "Content does not match the path" + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + }, + "put": { + "tags": [ + "links" + ], + "summary": "Links an item to a channel.", + "operationId": "linkItemToChannel", + "parameters": [ + { + "name": "itemName", + "in": "path", + "description": "itemName", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "channelUID", + "in": "path", + "description": "channelUID", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "description": "link data", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ItemChannelLinkDTO" + } + } + } + }, + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Content does not match the path" + }, + "405": { + "description": "Link is not editable" + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + }, + "delete": { + "tags": [ + "links" + ], + "summary": "Unlinks an item from a channel.", + "operationId": "unlinkItemFromChannel", + "parameters": [ + { + "name": "itemName", + "in": "path", + "description": "itemName", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "channelUID", + "in": "path", + "description": "channelUID", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + }, + "404": { + "description": "Link not found." + }, + "405": { + "description": "Link not editable." + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + } + }, + "/links/purge": { + "post": { + "tags": [ + "links" + ], + "summary": "Remove unused/orphaned links.", + "operationId": "purgeDatabase_1", + "responses": { + "200": { + "description": "OK" + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + } + }, + "/links/{object}": { + "delete": { + "tags": [ + "links" + ], + "summary": "Delete all links that refer to an item or thing.", + "operationId": "removeAllLinksForObject", + "parameters": [ + { + "name": "object", + "in": "path", + "description": "item name or thing UID", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + } + }, + "/persistence/{serviceId}": { + "get": { + "tags": [ + "persistence" + ], + "summary": "Gets a persistence service configuration.", + "operationId": "getPersistenceServiceConfiguration", + "parameters": [ + { + "name": "serviceId", + "in": "path", + "description": "Id of the persistence service.", + "required": true, + "schema": { + "pattern": "[a-zA-Z0-9]+", + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PersistenceServiceConfigurationDTO" + } + } + } + }, + "404": { + "description": "Service configuration not found." + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + }, + "put": { + "tags": [ + "persistence" + ], + "summary": "Sets a persistence service configuration.", + "operationId": "putPersistenceServiceConfiguration", + "parameters": [ + { + "name": "serviceId", + "in": "path", + "description": "Id of the persistence service.", + "required": true, + "schema": { + "pattern": "[a-zA-Z0-9]+", + "type": "string" + } + } + ], + "requestBody": { + "description": "service configuration", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PersistenceServiceConfigurationDTO" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PersistenceServiceConfigurationDTO" + } + } + } + }, + "201": { + "description": "PersistenceServiceConfiguration created." + }, + "400": { + "description": "Payload invalid." + }, + "405": { + "description": "PersistenceServiceConfiguration not editable." + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + }, + "delete": { + "tags": [ + "persistence" + ], + "summary": "Deletes a persistence service configuration.", + "operationId": "deletePersistenceServiceConfiguration", + "parameters": [ + { + "name": "serviceId", + "in": "path", + "description": "Id of the persistence service.", + "required": true, + "schema": { + "pattern": "[a-zA-Z0-9]+", + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + }, + "404": { + "description": "Persistence service configuration not found." + }, + "405": { + "description": "Persistence service configuration not editable." + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + } + }, + "/persistence/items/{itemname}": { + "get": { + "tags": [ + "persistence" + ], + "summary": "Gets item persistence data from the persistence service.", + "operationId": "getItemDataFromPersistenceService", + "parameters": [ + { + "name": "serviceId", + "in": "query", + "description": "Id of the persistence service. If not provided the default service will be used", + "schema": { + "type": "string" + } + }, + { + "name": "itemname", + "in": "path", + "description": "The item name", + "required": true, + "schema": { + "pattern": "[a-zA-Z_0-9]+", + "type": "string" + } + }, + { + "name": "starttime", + "in": "query", + "description": "Start time of the data to return. Will default to 1 day before endtime. [yyyy-MM-dd'T'HH:mm:ss.SSSZ]", + "schema": { + "type": "string" + } + }, + { + "name": "endtime", + "in": "query", + "description": "End time of the data to return. Will default to current time. [yyyy-MM-dd'T'HH:mm:ss.SSSZ]", + "schema": { + "type": "string" + } + }, + { + "name": "page", + "in": "query", + "description": "Page number of data to return. This parameter will enable paging.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "pagelength", + "in": "query", + "description": "The length of each page.", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "boundary", + "in": "query", + "description": "Gets one value before and after the requested period.", + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ItemHistoryDTO" + } + } + } + }, + "404": { + "description": "Unknown Item or persistence service" + } + } + }, + "put": { + "tags": [ + "persistence" + ], + "summary": "Stores item persistence data into the persistence service.", + "operationId": "storeItemDataInPersistenceService", + "parameters": [ + { + "name": "serviceId", + "in": "query", + "description": "Id of the persistence service. If not provided the default service will be used", + "schema": { + "type": "string" + } + }, + { + "name": "itemname", + "in": "path", + "description": "The item name.", + "required": true, + "schema": { + "pattern": "[a-zA-Z_0-9]+", + "type": "string" + } + }, + { + "name": "time", + "in": "query", + "description": "Time of the data to be stored. Will default to current time. [yyyy-MM-dd'T'HH:mm:ss.SSSZ]", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "state", + "in": "query", + "description": "The state to store.", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + }, + "404": { + "description": "Unknown Item or persistence service" + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + }, + "delete": { + "tags": [ + "persistence" + ], + "summary": "Deletes item persistence data from a specific persistence service in a given time range.", + "operationId": "deleteItemFromPersistenceService", + "parameters": [ + { + "name": "serviceId", + "in": "query", + "description": "Id of the persistence service.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "itemname", + "in": "path", + "description": "The item name.", + "required": true, + "schema": { + "pattern": "[a-zA-Z_0-9]+", + "type": "string" + } + }, + { + "name": "starttime", + "in": "query", + "description": "Start of the time range to be deleted. [yyyy-MM-dd'T'HH:mm:ss.SSSZ]", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "endtime", + "in": "query", + "description": "End of the time range to be deleted. [yyyy-MM-dd'T'HH:mm:ss.SSSZ]", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + }, + "400": { + "description": "Invalid filter parameters" + }, + "404": { + "description": "Unknown persistence service" + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + } + }, + "/persistence/items": { + "get": { + "tags": [ + "persistence" + ], + "summary": "Gets a list of items available via a specific persistence service.", + "operationId": "getItemsForPersistenceService", + "parameters": [ + { + "name": "serviceId", + "in": "query", + "description": "Id of the persistence service. If not provided the default service will be used", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "uniqueItems": true, + "type": "array", + "items": { + "$ref": "#/components/schemas/PersistenceItemInfo" + } + } + } + } + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + } + }, + "/persistence": { + "get": { + "tags": [ + "persistence" + ], + "summary": "Gets a list of persistence services.", + "operationId": "getPersistenceServices", + "parameters": [ + { + "name": "Accept-Language", + "in": "header", + "description": "language", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PersistenceServiceDTO" + } + } + } + } + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + } + }, + "/profile-types": { + "get": { + "tags": [ + "profile-types" + ], + "summary": "Gets all available profile types.", + "operationId": "getProfileTypes", + "parameters": [ + { + "name": "Accept-Language", + "in": "header", + "description": "language", + "schema": { + "type": "string" + } + }, + { + "name": "channelTypeUID", + "in": "query", + "description": "channel type filter", + "schema": { + "type": "string" + } + }, + { + "name": "itemType", + "in": "query", + "description": "item type filter", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "uniqueItems": true, + "type": "array", + "items": { + "$ref": "#/components/schemas/ProfileTypeDTO" + } + } + } + } + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + } + }, + "/services/{serviceId}/config": { + "get": { + "tags": [ + "services" + ], + "summary": "Get service configuration for given service ID.", + "operationId": "getServiceConfig", + "parameters": [ + { + "name": "serviceId", + "in": "path", + "description": "service ID", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + } + }, + "500": { + "description": "Configuration can not be read due to internal error" + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + }, + "put": { + "tags": [ + "services" + ], + "summary": "Updates a service configuration for given service ID and returns the old configuration.", + "operationId": "updateServiceConfig", + "parameters": [ + { + "name": "Accept-Language", + "in": "header", + "description": "language", + "schema": { + "type": "string" + } + }, + { + "name": "serviceId", + "in": "path", + "description": "service ID", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": { + "type": "object" + } + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + } + }, + "204": { + "description": "No old configuration" + }, + "500": { + "description": "Configuration can not be updated due to internal error" + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + }, + "delete": { + "tags": [ + "services" + ], + "summary": "Deletes a service configuration for given service ID and returns the old configuration.", + "operationId": "deleteServiceConfig", + "parameters": [ + { + "name": "serviceId", + "in": "path", + "description": "service ID", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + } + }, + "204": { + "description": "No old configuration" + }, + "500": { + "description": "Configuration can not be deleted due to internal error" + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + } + }, + "/services": { + "get": { + "tags": [ + "services" + ], + "summary": "Get all configurable services.", + "operationId": "getServices", + "parameters": [ + { + "name": "Accept-Language", + "in": "header", + "description": "language", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ConfigurableServiceDTO" + } + } + } + } + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + } + }, + "/services/{serviceId}": { + "get": { + "tags": [ + "services" + ], + "summary": "Get configurable service for given service ID.", + "operationId": "getServicesById", + "parameters": [ + { + "name": "Accept-Language", + "in": "header", + "description": "language", + "schema": { + "type": "string" + } + }, + { + "name": "serviceId", + "in": "path", + "description": "service ID", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ConfigurableServiceDTO" + } + } + } + }, + "404": { + "description": "Not found" + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + } + }, + "/services/{serviceId}/contexts": { + "get": { + "tags": [ + "services" + ], + "summary": "Get existing multiple context service configurations for the given factory PID.", + "operationId": "getServiceContext", + "parameters": [ + { + "name": "Accept-Language", + "in": "header", + "description": "language", + "schema": { + "type": "string" + } + }, + { + "name": "serviceId", + "in": "path", + "description": "service ID", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ConfigurableServiceDTO" + } + } + } + } + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + } + }, + "/tags": { + "get": { + "tags": [ + "tags" + ], + "summary": "Get all available semantic tags.", + "operationId": "getSemanticTags", + "parameters": [ + { + "name": "Accept-Language", + "in": "header", + "description": "language", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/EnrichedSemanticTagDTO" + } + } + } + } + } + } + }, + "post": { + "tags": [ + "tags" + ], + "summary": "Creates a new semantic tag and adds it to the registry.", + "operationId": "createSemanticTag", + "parameters": [ + { + "name": "Accept-Language", + "in": "header", + "description": "language", + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "description": "tag data", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EnrichedSemanticTagDTO" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EnrichedSemanticTagDTO" + } + } + } + }, + "400": { + "description": "The tag identifier is invalid or the tag label is missing." + }, + "409": { + "description": "A tag with the same identifier already exists." + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + } + }, + "/tags/{tagId}": { + "get": { + "tags": [ + "tags" + ], + "summary": "Gets a semantic tag and its sub tags.", + "operationId": "getSemanticTagAndSubTags", + "parameters": [ + { + "name": "Accept-Language", + "in": "header", + "description": "language", + "schema": { + "type": "string" + } + }, + { + "name": "tagId", + "in": "path", + "description": "tag id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/EnrichedSemanticTagDTO" + } + } + } + } + }, + "404": { + "description": "Semantic tag not found." + } + } + }, + "put": { + "tags": [ + "tags" + ], + "summary": "Updates a semantic tag.", + "operationId": "updateSemanticTag", + "parameters": [ + { + "name": "Accept-Language", + "in": "header", + "description": "language", + "schema": { + "type": "string" + } + }, + { + "name": "tagId", + "in": "path", + "description": "tag id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "description": "tag data", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EnrichedSemanticTagDTO" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EnrichedSemanticTagDTO" + } + } + } + }, + "404": { + "description": "Semantic tag not found." + }, + "405": { + "description": "Semantic tag not editable." + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + }, + "delete": { + "tags": [ + "tags" + ], + "summary": "Removes a semantic tag and its sub tags from the registry.", + "operationId": "removeSemanticTag", + "parameters": [ + { + "name": "Accept-Language", + "in": "header", + "description": "language", + "schema": { + "type": "string" + } + }, + { + "name": "tagId", + "in": "path", + "description": "tag id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK, was deleted." + }, + "404": { + "description": "Semantic tag not found." + }, + "405": { + "description": "Semantic tag not removable." + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + } + }, + "/things": { + "get": { + "tags": [ + "things" + ], + "summary": "Get all available things.", + "operationId": "getThings", + "parameters": [ + { + "name": "Accept-Language", + "in": "header", + "description": "language", + "schema": { + "type": "string" + } + }, + { + "name": "summary", + "in": "query", + "description": "summary fields only", + "schema": { + "type": "boolean" + } + }, + { + "name": "staticDataOnly", + "in": "query", + "description": "provides a cacheable list of values not expected to change regularly and checks the If-Modified-Since header", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "uniqueItems": true, + "type": "array", + "items": { + "$ref": "#/components/schemas/EnrichedThingDTO" + } + } + } + } + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + }, + "post": { + "tags": [ + "things" + ], + "summary": "Creates a new thing and adds it to the registry.", + "operationId": "createThingInRegistry", + "parameters": [ + { + "name": "Accept-Language", + "in": "header", + "description": "language", + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "description": "thing data", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ThingDTO" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EnrichedThingDTO" + } + } + } + }, + "400": { + "description": "A uid must be provided, if no binding can create a thing of this type." + }, + "409": { + "description": "A thing with the same uid already exists." + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + } + }, + "/things/{thingUID}": { + "get": { + "tags": [ + "things" + ], + "summary": "Gets thing by UID.", + "operationId": "getThingById", + "parameters": [ + { + "name": "Accept-Language", + "in": "header", + "description": "language", + "schema": { + "type": "string" + } + }, + { + "name": "thingUID", + "in": "path", + "description": "thingUID", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EnrichedThingDTO" + } + } + } + }, + "404": { + "description": "Thing not found." + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + }, + "put": { + "tags": [ + "things" + ], + "summary": "Updates a thing.", + "operationId": "updateThing", + "parameters": [ + { + "name": "Accept-Language", + "in": "header", + "description": "language", + "schema": { + "type": "string" + } + }, + { + "name": "thingUID", + "in": "path", + "description": "thingUID", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "description": "thing", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ThingDTO" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EnrichedThingDTO" + } + } + } + }, + "404": { + "description": "Thing not found." + }, + "409": { + "description": "Thing could not be updated as it is not editable." + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + }, + "delete": { + "tags": [ + "things" + ], + "summary": "Removes a thing from the registry. Set 'force' to __true__ if you want the thing to be removed immediately.", + "operationId": "removeThingById", + "parameters": [ + { + "name": "Accept-Language", + "in": "header", + "description": "language", + "schema": { + "type": "string" + } + }, + { + "name": "thingUID", + "in": "path", + "description": "thingUID", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "force", + "in": "query", + "description": "force", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "responses": { + "200": { + "description": "OK, was deleted." + }, + "202": { + "description": "ACCEPTED for asynchronous deletion." + }, + "404": { + "description": "Thing not found." + }, + "409": { + "description": "Thing could not be deleted because it's not editable." + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + } + }, + "/things/{thingUID}/config/status": { + "get": { + "tags": [ + "things" + ], + "summary": "Gets thing config status.", + "operationId": "getThingConfigStatus", + "parameters": [ + { + "name": "Accept-Language", + "in": "header", + "description": "language", + "schema": { + "type": "string" + } + }, + { + "name": "thingUID", + "in": "path", + "description": "thing", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ConfigStatusMessage" + } + } + } + } + }, + "404": { + "description": "Thing not found." + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + } + }, + "/things/{thingUID}/firmware/status": { + "get": { + "tags": [ + "things" + ], + "summary": "Gets thing's firmware status.", + "operationId": "getThingFirmwareStatus", + "parameters": [ + { + "name": "Accept-Language", + "in": "header", + "description": "language", + "schema": { + "type": "string" + } + }, + { + "name": "thingUID", + "in": "path", + "description": "thing", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FirmwareStatusDTO" + } + } + } + }, + "204": { + "description": "No firmware status provided by this Thing." + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + } + }, + "/things/{thingUID}/firmwares": { + "get": { + "tags": [ + "things" + ], + "summary": "Get all available firmwares for provided thing UID", + "operationId": "getAvailableFirmwaresForThing", + "parameters": [ + { + "name": "thingUID", + "in": "path", + "description": "thingUID", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "Accept-Language", + "in": "header", + "description": "language", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "uniqueItems": true, + "type": "array", + "items": { + "$ref": "#/components/schemas/FirmwareDTO" + } + } + } + } + }, + "204": { + "description": "No firmwares found." + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + } + }, + "/things/{thingUID}/status": { + "get": { + "tags": [ + "things" + ], + "summary": "Gets thing status.", + "operationId": "getThingStatus", + "parameters": [ + { + "name": "Accept-Language", + "in": "header", + "description": "language", + "schema": { + "type": "string" + } + }, + { + "name": "thingUID", + "in": "path", + "description": "thing", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ThingStatusInfo" + } + } + } + }, + "404": { + "description": "Thing not found." + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + } + }, + "/things/{thingUID}/enable": { + "put": { + "tags": [ + "things" + ], + "summary": "Sets the thing enabled status.", + "operationId": "enableThing", + "parameters": [ + { + "name": "Accept-Language", + "in": "header", + "description": "language", + "schema": { + "type": "string" + } + }, + { + "name": "thingUID", + "in": "path", + "description": "thing", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "description": "enabled", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EnrichedThingDTO" + } + } + } + }, + "404": { + "description": "Thing not found." + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + } + }, + "/things/{thingUID}/config": { + "put": { + "tags": [ + "things" + ], + "summary": "Updates thing's configuration.", + "operationId": "updateThingConfig", + "parameters": [ + { + "name": "Accept-Language", + "in": "header", + "description": "language", + "schema": { + "type": "string" + } + }, + { + "name": "thingUID", + "in": "path", + "description": "thing", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "description": "configuration parameters", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": { + "type": "object" + } + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EnrichedThingDTO" + } + } + } + }, + "400": { + "description": "Configuration of the thing is not valid." + }, + "404": { + "description": "Thing not found" + }, + "409": { + "description": "Thing could not be updated as it is not editable." + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + } + }, + "/things/{thingUID}/firmware/{firmwareVersion}": { + "put": { + "tags": [ + "things" + ], + "summary": "Update thing firmware.", + "operationId": "updateThingFirmware", + "parameters": [ + { + "name": "Accept-Language", + "in": "header", + "description": "language", + "schema": { + "type": "string" + } + }, + { + "name": "thingUID", + "in": "path", + "description": "thing", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "firmwareVersion", + "in": "path", + "description": "version", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Firmware update preconditions not satisfied." + }, + "404": { + "description": "Thing not found." + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + } + }, + "/thing-types": { + "get": { + "tags": [ + "thing-types" + ], + "summary": "Gets all available thing types without config description, channels and properties.", + "operationId": "getThingTypes", + "parameters": [ + { + "name": "Accept-Language", + "in": "header", + "description": "language", + "schema": { + "type": "string" + } + }, + { + "name": "bindingId", + "in": "query", + "description": "filter by binding Id", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "uniqueItems": true, + "type": "array", + "items": { + "$ref": "#/components/schemas/StrippedThingTypeDTO" + } + } + } + } + } + } + } + }, + "/thing-types/{thingTypeUID}": { + "get": { + "tags": [ + "thing-types" + ], + "summary": "Gets thing type by UID.", + "operationId": "getThingTypeById", + "parameters": [ + { + "name": "thingTypeUID", + "in": "path", + "description": "thingTypeUID", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "Accept-Language", + "in": "header", + "description": "language", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Thing type with provided thingTypeUID does not exist.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ThingTypeDTO" + } + } + } + }, + "404": { + "description": "No content" + } + } + } + }, + "/": { + "get": { + "tags": [ + "root" + ], + "summary": "Gets information about the runtime, the API version and links to resources.", + "operationId": "getRoot", + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RootBean" + } + } + } + } + } + } + }, + "/systeminfo": { + "get": { + "tags": [ + "systeminfo" + ], + "summary": "Gets information about the system.", + "operationId": "getSystemInformation", + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SystemInfoBean" + } + } + } + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + } + }, + "/systeminfo/uom": { + "get": { + "tags": [ + "systeminfo" + ], + "summary": "Get all supported dimensions and their system units.", + "operationId": "getUoMInformation", + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UoMInfoBean" + } + } + } + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + } + }, + "/sitemaps/events/subscribe": { + "post": { + "tags": [ + "sitemaps" + ], + "summary": "Creates a sitemap event subscription.", + "operationId": "createSitemapEventSubscription", + "responses": { + "201": { + "description": "Subscription created." + }, + "503": { + "description": "Subscriptions limit reached." + } + } + } + }, + "/sitemaps/{sitemapname}/{pageid}": { + "get": { + "tags": [ + "sitemaps" + ], + "summary": "Polls the data for a sitemap.", + "operationId": "pollDataForSitemap", + "parameters": [ + { + "name": "Accept-Language", + "in": "header", + "description": "language", + "schema": { + "type": "string" + } + }, + { + "name": "sitemapname", + "in": "path", + "description": "sitemap name", + "required": true, + "schema": { + "pattern": "[a-zA-Z_0-9]+", + "type": "string" + } + }, + { + "name": "pageid", + "in": "path", + "description": "page id", + "required": true, + "schema": { + "pattern": "[a-zA-Z_0-9]+", + "type": "string" + } + }, + { + "name": "subscriptionid", + "in": "query", + "description": "subscriptionid", + "schema": { + "type": "string" + } + }, + { + "name": "includeHidden", + "in": "query", + "description": "include hidden widgets", + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PageDTO" + } + } + } + }, + "400": { + "description": "Invalid subscription id has been provided." + }, + "404": { + "description": "Sitemap with requested name does not exist or page does not exist, or page refers to a non-linkable widget" + } + } + } + }, + "/sitemaps/{sitemapname}": { + "get": { + "tags": [ + "sitemaps" + ], + "summary": "Get sitemap by name.", + "operationId": "getSitemapByName", + "parameters": [ + { + "name": "Accept-Language", + "in": "header", + "description": "language", + "schema": { + "type": "string" + } + }, + { + "name": "sitemapname", + "in": "path", + "description": "sitemap name", + "required": true, + "schema": { + "pattern": "[a-zA-Z_0-9]+", + "type": "string" + } + }, + { + "name": "type", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "jsoncallback", + "in": "query", + "schema": { + "type": "string", + "default": "callback" + } + }, + { + "name": "includeHidden", + "in": "query", + "description": "include hidden widgets", + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SitemapDTO" + } + } + } + } + } + } + }, + "/sitemaps/events/{subscriptionid}": { + "get": { + "tags": [ + "sitemaps" + ], + "summary": "Get sitemap events.", + "operationId": "getSitemapEvents", + "parameters": [ + { + "name": "subscriptionid", + "in": "path", + "description": "subscription id", + "required": true, + "schema": { + "pattern": "[a-zA-Z_0-9-]+", + "type": "string" + } + }, + { + "name": "sitemap", + "in": "query", + "description": "sitemap name", + "schema": { + "type": "string" + } + }, + { + "name": "pageid", + "in": "query", + "description": "page id", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Page not linked to the subscription." + }, + "404": { + "description": "Subscription not found." + } + } + } + }, + "/sitemaps": { + "get": { + "tags": [ + "sitemaps" + ], + "summary": "Get all available sitemaps.", + "operationId": "getSitemaps", + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SitemapDTO" + } + } + } + } + } + } + } + }, + "/events/states": { + "get": { + "tags": [ + "events" + ], + "summary": "Initiates a new item state tracker connection", + "operationId": "initNewStateTacker", + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/events": { + "get": { + "tags": [ + "events" + ], + "summary": "Get all events.", + "operationId": "getEvents", + "parameters": [ + { + "name": "topics", + "in": "query", + "description": "topics", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Topic is empty or contains invalid characters" + } + } + } + }, + "/events/states/{connectionId}": { + "post": { + "tags": [ + "events" + ], + "summary": "Changes the list of items a SSE connection will receive state updates to.", + "operationId": "updateItemListForStateUpdates", + "parameters": [ + { + "name": "connectionId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "description": "items", + "content": { + "application/json": { + "schema": { + "uniqueItems": true, + "type": "array", + "items": { + "type": "string" + } + } + } + } + }, + "responses": { + "200": { + "description": "OK" + }, + "404": { + "description": "Unknown connectionId" + } + } + } + }, + "/transformations/{uid}": { + "get": { + "tags": [ + "transformations" + ], + "summary": "Get a single transformation", + "operationId": "getTransformation", + "parameters": [ + { + "name": "uid", + "in": "path", + "description": "Transformation UID", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Transformation" + } + } + } + }, + "404": { + "description": "Not found" + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + }, + "put": { + "tags": [ + "transformations" + ], + "summary": "Put a single transformation", + "operationId": "putTransformation", + "parameters": [ + { + "name": "uid", + "in": "path", + "description": "Transformation UID", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "description": "transformation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TransformationDTO" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request (content missing or invalid)" + }, + "405": { + "description": "Transformation not editable" + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + }, + "delete": { + "tags": [ + "transformations" + ], + "summary": "Get a single transformation", + "operationId": "deleteTransformation", + "parameters": [ + { + "name": "uid", + "in": "path", + "description": "Transformation UID", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + }, + "404": { + "description": "UID not found" + }, + "405": { + "description": "Transformation not editable" + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + } + }, + "/transformations/services": { + "get": { + "tags": [ + "transformations" + ], + "summary": "Get all transformation services", + "operationId": "getTransformationServices", + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + } + }, + "/transformations": { + "get": { + "tags": [ + "transformations" + ], + "summary": "Get a list of all transformations", + "operationId": "getTransformations", + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TransformationDTO" + } + } + } + } + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + } + }, + "/ui/components/{namespace}": { + "get": { + "tags": [ + "ui" + ], + "summary": "Get all registered UI components in the specified namespace.", + "operationId": "getRegisteredUIComponentsInNamespace", + "parameters": [ + { + "name": "namespace", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "summary", + "in": "query", + "description": "summary fields only", + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RootUIComponent" + } + } + } + } + } + } + }, + "post": { + "tags": [ + "ui" + ], + "summary": "Add a UI component in the specified namespace.", + "operationId": "addUIComponentToNamespace", + "parameters": [ + { + "name": "namespace", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RootUIComponent" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RootUIComponent" + } + } + } + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + } + }, + "/ui/components/{namespace}/{componentUID}": { + "get": { + "tags": [ + "ui" + ], + "summary": "Get a specific UI component in the specified namespace.", + "operationId": "getUIComponentInNamespace", + "parameters": [ + { + "name": "namespace", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "componentUID", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RootUIComponent" + } + } + } + }, + "404": { + "description": "Component not found" + } + } + }, + "put": { + "tags": [ + "ui" + ], + "summary": "Update a specific UI component in the specified namespace.", + "operationId": "updateUIComponentInNamespace", + "parameters": [ + { + "name": "namespace", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "componentUID", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RootUIComponent" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RootUIComponent" + } + } + } + }, + "404": { + "description": "Component not found" + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + }, + "delete": { + "tags": [ + "ui" + ], + "summary": "Remove a specific UI component in the specified namespace.", + "operationId": "removeUIComponentFromNamespace", + "parameters": [ + { + "name": "namespace", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "componentUID", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + }, + "404": { + "description": "Component not found" + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + } + }, + "/ui/tiles": { + "get": { + "tags": [ + "ui" + ], + "summary": "Get all registered UI tiles.", + "operationId": "getUITiles", + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TileDTO" + } + } + } + } + } + } + } + }, + "/voice/defaultvoice": { + "get": { + "tags": [ + "voice" + ], + "summary": "Gets the default voice.", + "operationId": "getDefaultVoice", + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoiceDTO" + } + } + } + }, + "404": { + "description": "No default voice was found." + } + } + } + }, + "/voice/interpreters/{id}": { + "get": { + "tags": [ + "voice" + ], + "summary": "Gets a single interpreter.", + "operationId": "getVoiceInterpreterByUID", + "parameters": [ + { + "name": "Accept-Language", + "in": "header", + "description": "language", + "schema": { + "type": "string" + } + }, + { + "name": "id", + "in": "path", + "description": "interpreter id", + "required": true, + "schema": { + "pattern": "[a-zA-Z_0-9]+", + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/HumanLanguageInterpreterDTO" + } + } + } + } + }, + "404": { + "description": "Interpreter not found" + } + } + } + }, + "/voice/interpreters": { + "get": { + "tags": [ + "voice" + ], + "summary": "Get the list of all interpreters.", + "operationId": "getVoiceInterpreters", + "parameters": [ + { + "name": "Accept-Language", + "in": "header", + "description": "language", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/HumanLanguageInterpreterDTO" + } + } + } + } + } + } + }, + "post": { + "tags": [ + "voice" + ], + "summary": "Sends a text to the default human language interpreter.", + "operationId": "interpretTextByDefaultInterpreter", + "parameters": [ + { + "name": "Accept-Language", + "in": "header", + "description": "language", + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "description": "text to interpret", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "interpretation exception occurs" + }, + "404": { + "description": "No human language interpreter was found." + } + } + } + }, + "/voice/voices": { + "get": { + "tags": [ + "voice" + ], + "summary": "Get the list of all voices.", + "operationId": "getVoices", + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/VoiceDTO" + } + } + } + } + } + } + } + }, + "/voice/interpreters/{ids}": { + "post": { + "tags": [ + "voice" + ], + "summary": "Sends a text to a given human language interpreter(s).", + "operationId": "interpretText", + "parameters": [ + { + "name": "Accept-Language", + "in": "header", + "description": "language", + "schema": { + "type": "string" + } + }, + { + "name": "ids", + "in": "path", + "description": "comma separated list of interpreter ids", + "required": true, + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + ], + "requestBody": { + "description": "text to interpret", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "interpretation exception occurs" + }, + "404": { + "description": "No human language interpreter was found." + } + } + } + }, + "/voice/listenandanswer": { + "post": { + "tags": [ + "voice" + ], + "summary": "Executes a simple dialog sequence without keyword spotting for a given audio source.", + "operationId": "listenAndAnswer", + "parameters": [ + { + "name": "Accept-Language", + "in": "header", + "description": "language", + "schema": { + "type": "string" + } + }, + { + "name": "sourceId", + "in": "query", + "description": "source ID", + "schema": { + "type": "string" + } + }, + { + "name": "sttId", + "in": "query", + "description": "Speech-to-Text ID", + "schema": { + "type": "string" + } + }, + { + "name": "ttsId", + "in": "query", + "description": "Text-to-Speech ID", + "schema": { + "type": "string" + } + }, + { + "name": "voiceId", + "in": "query", + "description": "voice ID", + "schema": { + "type": "string" + } + }, + { + "name": "hliIds", + "in": "query", + "description": "interpreter IDs", + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + { + "name": "sinkId", + "in": "query", + "description": "audio sink ID", + "schema": { + "type": "string" + } + }, + { + "name": "listeningItem", + "in": "query", + "description": "listening item", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Services are missing or language is not supported by services or dialog processing is already started for the audio source." + }, + "404": { + "description": "One of the given ids is wrong." + } + } + } + }, + "/voice/say": { + "post": { + "tags": [ + "voice" + ], + "summary": "Speaks a given text with a given voice through the given audio sink.", + "operationId": "textToSpeech", + "parameters": [ + { + "name": "voiceid", + "in": "query", + "description": "voice id", + "schema": { + "type": "string" + } + }, + { + "name": "sinkid", + "in": "query", + "description": "audio sink id", + "schema": { + "type": "string" + } + }, + { + "name": "volume", + "in": "query", + "description": "volume level", + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "description": "text to speak", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/voice/dialog/start": { + "post": { + "tags": [ + "voice" + ], + "summary": "Start dialog processing for a given audio source.", + "operationId": "startDialog", + "parameters": [ + { + "name": "Accept-Language", + "in": "header", + "description": "language", + "schema": { + "type": "string" + } + }, + { + "name": "sourceId", + "in": "query", + "description": "source ID", + "schema": { + "type": "string" + } + }, + { + "name": "ksId", + "in": "query", + "description": "keywork spotter ID", + "schema": { + "type": "string" + } + }, + { + "name": "sttId", + "in": "query", + "description": "Speech-to-Text ID", + "schema": { + "type": "string" + } + }, + { + "name": "ttsId", + "in": "query", + "description": "Text-to-Speech ID", + "schema": { + "type": "string" + } + }, + { + "name": "voiceId", + "in": "query", + "description": "voice ID", + "schema": { + "type": "string" + } + }, + { + "name": "hliIds", + "in": "query", + "description": "comma separated list of interpreter IDs", + "schema": { + "type": "string" + } + }, + { + "name": "sinkId", + "in": "query", + "description": "audio sink ID", + "schema": { + "type": "string" + } + }, + { + "name": "keyword", + "in": "query", + "description": "keyword", + "schema": { + "type": "string" + } + }, + { + "name": "listeningItem", + "in": "query", + "description": "listening item", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Services are missing or language is not supported by services or dialog processing is already started for the audio source." + }, + "404": { + "description": "One of the given ids is wrong." + } + } + } + }, + "/voice/dialog/stop": { + "post": { + "tags": [ + "voice" + ], + "summary": "Stop dialog processing for a given audio source.", + "operationId": "stopDialog", + "parameters": [ + { + "name": "sourceId", + "in": "query", + "description": "source ID", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "No dialog processing is started for the audio source." + }, + "404": { + "description": "No audio source was found." + } + } + } + }, + "/logging/{loggerName}": { + "get": { + "tags": [ + "logging" + ], + "summary": "Get a single logger.", + "operationId": "getLogger", + "parameters": [ + { + "name": "loggerName", + "in": "path", + "description": "logger name", + "required": true, + "schema": { + "pattern": "[a-zA-Z0-9.]+", + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LoggerInfo" + } + } + } + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + }, + "put": { + "tags": [ + "logging" + ], + "summary": "Modify or add logger", + "operationId": "putLogger", + "parameters": [ + { + "name": "loggerName", + "in": "path", + "description": "logger name", + "required": true, + "schema": { + "pattern": "[a-zA-Z0-9.]+", + "type": "string" + } + } + ], + "requestBody": { + "description": "logger", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LoggerInfo" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Payload is invalid." + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + }, + "delete": { + "tags": [ + "logging" + ], + "summary": "Remove a single logger.", + "operationId": "removeLogger", + "parameters": [ + { + "name": "loggerName", + "in": "path", + "description": "logger name", + "required": true, + "schema": { + "pattern": "[a-zA-Z0-9.]+", + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + } + }, + "/logging": { + "get": { + "tags": [ + "logging" + ], + "summary": "Get all loggers", + "operationId": "getLogger_1", + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LoggerBean" + } + } + } + } + }, + "security": [ + { + "oauth2": [ + "admin" + ] + } + ] + } + }, + "/iconsets": { + "get": { + "tags": [ + "iconsets" + ], + "summary": "Gets all icon sets.", + "operationId": "getIconSets", + "parameters": [ + { + "name": "Accept-Language", + "in": "header", + "description": "language", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/IconSet" + } + } + } + } + } + } + } + }, + "/habot/chat": { + "post": { + "tags": [ + "habot" + ], + "summary": "Send a query to HABot to interpret.", + "operationId": "chat", + "requestBody": { + "description": "human language query", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ChatReply" + } + } + } + }, + "500": { + "description": "An interpretation error occurred" + } + } + } + }, + "/habot/compat/cards": { + "post": { + "tags": [ + "habot" + ], + "summary": "Creates a new card in the card deck (compatibility endpoint).", + "operationId": "createCard", + "requestBody": { + "description": "card", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "The card was created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Card" + } + } + } + }, + "500": { + "description": "An error occured" + } + } + } + }, + "/habot/cards": { + "get": { + "tags": [ + "habot" + ], + "summary": "Gets all cards of the card deck.", + "operationId": "getAllCards", + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Card" + } + } + } + } + }, + "500": { + "description": "An error occured" + } + } + }, + "post": { + "tags": [ + "habot" + ], + "summary": "Creates a new card in the card deck.", + "operationId": "createCard_1", + "requestBody": { + "description": "card", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Card" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "The card was created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Card" + } + } + } + }, + "500": { + "description": "An error occured" + } + } + } + }, + "/habot/cards/{cardUID}": { + "get": { + "tags": [ + "habot" + ], + "summary": "Gets a card from the card deck by its UID.", + "operationId": "getCardByUid", + "parameters": [ + { + "name": "cardUID", + "in": "path", + "description": "cardUID", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Card" + } + } + } + }, + "404": { + "description": "The card with the provided UID doesn't exist" + }, + "500": { + "description": "An error occured" + } + } + }, + "put": { + "tags": [ + "habot" + ], + "summary": "Updates a card in the card deck.", + "operationId": "updateCard_1", + "parameters": [ + { + "name": "cardUID", + "in": "path", + "description": "cardUID", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "description": "card", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Card" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "The card was updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Card" + } + } + } + }, + "500": { + "description": "An error occured" + } + } + }, + "delete": { + "tags": [ + "habot" + ], + "summary": "Deletes a card from the card deck.", + "operationId": "deleteCard", + "parameters": [ + { + "name": "cardUID", + "in": "path", + "description": "cardUID", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "The card was deleted" + }, + "500": { + "description": "An error occured" + } + } + } + }, + "/habot/compat/cards/{cardUID}/delete": { + "post": { + "tags": [ + "habot" + ], + "summary": "Deletes a card from the card deck (compatibility endpoint).", + "operationId": "deleteCardPost", + "parameters": [ + { + "name": "cardUID", + "in": "path", + "description": "cardUID", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "The card was updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Card" + } + } + } + }, + "500": { + "description": "An error occured" + } + } + } + }, + "/habot/attributes": { + "get": { + "tags": [ + "habot" + ], + "summary": "Gets all item named attributes.", + "operationId": "getAttributes", + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ChatReply" + } + } + } + }, + "500": { + "description": "An error occurred" + } + } + } + }, + "/habot/greet": { + "get": { + "tags": [ + "habot" + ], + "summary": "Retrieves a first greeting message from the bot in the specified or configured language.", + "operationId": "greet", + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ChatReply" + } + } + } + }, + "500": { + "description": "There is no support for the configured language" + } + } + } + }, + "/habot/cards/recent": { + "get": { + "tags": [ + "habot" + ], + "summary": "Gets the most recent cards from the card deck", + "operationId": "recentCards", + "parameters": [ + { + "name": "skip", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "count", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "The most recent cards", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Card" + } + } + } + } + }, + "500": { + "description": "An error occured" + } + } + } + }, + "/habot/cards/{cardUID}/bookmark": { + "put": { + "tags": [ + "habot" + ], + "summary": "Sets a bookmark on a card.", + "operationId": "setCardBookmark", + "parameters": [ + { + "name": "cardUID", + "in": "path", + "description": "cardUID", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + }, + "404": { + "description": "The card with the provided UID doesn't exist" + }, + "500": { + "description": "An error occured" + } + } + }, + "delete": { + "tags": [ + "habot" + ], + "summary": "Removes the bookmark on a card.", + "operationId": "unsetCardBookmark", + "parameters": [ + { + "name": "cardUID", + "in": "path", + "description": "cardUID", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + }, + "404": { + "description": "The card with the provided UID doesn't exist" + }, + "500": { + "description": "An error occured" + } + } + } + }, + "/habot/compat/cards/{cardUID}/unbookmark": { + "post": { + "tags": [ + "habot" + ], + "summary": "Removes the bookmark on a card (compatibility endpoint).", + "operationId": "unsetCardBookmarkCompat", + "parameters": [ + { + "name": "cardUID", + "in": "path", + "description": "cardUID", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + }, + "404": { + "description": "The card with the provided UID doesn't exist" + }, + "500": { + "description": "An error occured" + } + } + } + }, + "/habot/compat/cards/{cardUID}": { + "post": { + "tags": [ + "habot" + ], + "summary": "Updates a card in the card deck (compatibility endpoint).", + "operationId": "updateCard", + "parameters": [ + { + "name": "cardUID", + "in": "path", + "description": "cardUID", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "description": "card", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "The card was updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Card" + } + } + } + }, + "500": { + "description": "An error occured" + } + } + } + }, + "/habot/cards/{cardUID}/timestamp": { + "put": { + "tags": [ + "habot" + ], + "summary": "Updates the timestamp on a card to the current time", + "operationId": "updateCardTimestamp", + "parameters": [ + { + "name": "cardUID", + "in": "path", + "description": "cardUID", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + }, + "404": { + "description": "The card with the provided UID doesn't exist" + }, + "500": { + "description": "An error occured" + } + } + } + }, + "/habot/notifications/vapid": { + "get": { + "tags": [ + "habot" + ], + "summary": "Gets or generates the public VAPID key used for push notifications.", + "operationId": "webPushConfig", + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + } + }, + "500": { + "description": "An error occured" + } + } + } + }, + "/habot/notifications/subscribe": { + "post": { + "tags": [ + "habot" + ], + "summary": "Subscribes a new client for push notifications.", + "operationId": "webPushSubscribe", + "requestBody": { + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + }, + "responses": { + "200": { + "description": "OK" + }, + "500": { + "description": "An error occured" + } + } + } + } + }, + "components": { + "schemas": { + "ConfigDescriptionParameterDTO": { + "type": "object", + "properties": { + "context": { + "type": "string" + }, + "defaultValue": { + "type": "string" + }, + "description": { + "type": "string" + }, + "label": { + "type": "string" + }, + "name": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "type": { + "type": "string", + "enum": [ + "TEXT", + "INTEGER", + "DECIMAL", + "BOOLEAN" + ] + }, + "min": { + "type": "number" + }, + "max": { + "type": "number" + }, + "stepsize": { + "type": "number" + }, + "pattern": { + "type": "string" + }, + "readOnly": { + "type": "boolean" + }, + "multiple": { + "type": "boolean" + }, + "multipleLimit": { + "type": "integer", + "format": "int32" + }, + "groupName": { + "type": "string" + }, + "advanced": { + "type": "boolean" + }, + "verify": { + "type": "boolean" + }, + "limitToOptions": { + "type": "boolean" + }, + "unit": { + "type": "string" + }, + "unitLabel": { + "type": "string" + }, + "options": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ParameterOptionDTO" + } + }, + "filterCriteria": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FilterCriteriaDTO" + } + } + } + }, + "FilterCriteriaDTO": { + "type": "object", + "properties": { + "value": { + "type": "string" + }, + "name": { + "type": "string" + } + } + }, + "ModuleTypeDTO": { + "type": "object", + "properties": { + "uid": { + "type": "string" + }, + "visibility": { + "type": "string", + "enum": [ + "VISIBLE", + "HIDDEN", + "EXPERT" + ] + }, + "tags": { + "uniqueItems": true, + "type": "array", + "items": { + "type": "string" + } + }, + "label": { + "type": "string" + }, + "description": { + "type": "string" + }, + "configDescriptions": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ConfigDescriptionParameterDTO" + } + } + } + }, + "ParameterOptionDTO": { + "type": "object", + "properties": { + "label": { + "type": "string" + }, + "value": { + "type": "string" + } + } + }, + "ActionDTO": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "description": { + "type": "string" + }, + "configuration": { + "type": "object", + "additionalProperties": { + "type": "object" + } + }, + "type": { + "type": "string" + }, + "inputs": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + } + }, + "ConditionDTO": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "description": { + "type": "string" + }, + "configuration": { + "type": "object", + "additionalProperties": { + "type": "object" + } + }, + "type": { + "type": "string" + }, + "inputs": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + } + }, + "RuleDTO": { + "type": "object", + "properties": { + "triggers": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TriggerDTO" + } + }, + "conditions": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ConditionDTO" + } + }, + "actions": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ActionDTO" + } + }, + "configuration": { + "type": "object", + "additionalProperties": { + "type": "object" + } + }, + "configDescriptions": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ConfigDescriptionParameterDTO" + } + }, + "templateUID": { + "type": "string" + }, + "uid": { + "type": "string" + }, + "name": { + "type": "string" + }, + "tags": { + "uniqueItems": true, + "type": "array", + "items": { + "type": "string" + } + }, + "visibility": { + "type": "string", + "enum": [ + "VISIBLE", + "HIDDEN", + "EXPERT" + ] + }, + "description": { + "type": "string" + } + } + }, + "TriggerDTO": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "description": { + "type": "string" + }, + "configuration": { + "type": "object", + "additionalProperties": { + "type": "object" + } + }, + "type": { + "type": "string" + } + } + }, + "EnrichedRuleDTO": { + "type": "object", + "properties": { + "triggers": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TriggerDTO" + } + }, + "conditions": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ConditionDTO" + } + }, + "actions": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ActionDTO" + } + }, + "configuration": { + "type": "object", + "additionalProperties": { + "type": "object" + } + }, + "configDescriptions": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ConfigDescriptionParameterDTO" + } + }, + "templateUID": { + "type": "string" + }, + "uid": { + "type": "string" + }, + "name": { + "type": "string" + }, + "tags": { + "uniqueItems": true, + "type": "array", + "items": { + "type": "string" + } + }, + "visibility": { + "type": "string", + "enum": [ + "VISIBLE", + "HIDDEN", + "EXPERT" + ] + }, + "description": { + "type": "string" + }, + "status": { + "$ref": "#/components/schemas/RuleStatusInfo" + }, + "editable": { + "type": "boolean" + } + } + }, + "RuleStatusInfo": { + "type": "object", + "properties": { + "status": { + "type": "string", + "enum": [ + "UNINITIALIZED", + "INITIALIZING", + "IDLE", + "RUNNING" + ] + }, + "statusDetail": { + "type": "string", + "enum": [ + "NONE", + "HANDLER_MISSING_ERROR", + "HANDLER_INITIALIZING_ERROR", + "CONFIGURATION_ERROR", + "TEMPLATE_MISSING_ERROR", + "INVALID_RULE", + "DISABLED" + ] + }, + "description": { + "type": "string" + } + } + }, + "ModuleDTO": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "description": { + "type": "string" + }, + "configuration": { + "type": "object", + "additionalProperties": { + "type": "object" + } + }, + "type": { + "type": "string" + } + } + }, + "Action": { + "type": "object", + "properties": { + "inputs": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "description": { + "type": "string" + }, + "label": { + "type": "string" + }, + "typeUID": { + "type": "string" + }, + "configuration": { + "$ref": "#/components/schemas/Configuration" + }, + "id": { + "type": "string" + } + } + }, + "Condition": { + "type": "object", + "properties": { + "inputs": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "description": { + "type": "string" + }, + "label": { + "type": "string" + }, + "typeUID": { + "type": "string" + }, + "configuration": { + "$ref": "#/components/schemas/Configuration" + }, + "id": { + "type": "string" + } + } + }, + "ConfigDescriptionParameter": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "TEXT", + "INTEGER", + "DECIMAL", + "BOOLEAN" + ] + }, + "groupName": { + "type": "string" + }, + "pattern": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "readOnly": { + "type": "boolean" + }, + "multiple": { + "type": "boolean" + }, + "multipleLimit": { + "type": "integer", + "format": "int32" + }, + "unit": { + "type": "string" + }, + "unitLabel": { + "type": "string" + }, + "context": { + "type": "string" + }, + "label": { + "type": "string" + }, + "description": { + "type": "string" + }, + "options": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ParameterOption" + } + }, + "filterCriteria": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FilterCriteria" + } + }, + "limitToOptions": { + "type": "boolean" + }, + "advanced": { + "type": "boolean" + }, + "minimum": { + "type": "number" + }, + "maximum": { + "type": "number" + }, + "stepSize": { + "type": "number" + }, + "verifyable": { + "type": "boolean" + }, + "default": { + "type": "string" + } + } + }, + "Configuration": { + "type": "object", + "properties": { + "properties": { + "type": "object", + "additionalProperties": { + "type": "object" + } + } + } + }, + "FilterCriteria": { + "type": "object", + "properties": { + "value": { + "type": "string" + }, + "name": { + "type": "string" + } + } + }, + "Module": { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "label": { + "type": "string" + }, + "typeUID": { + "type": "string" + }, + "configuration": { + "$ref": "#/components/schemas/Configuration" + }, + "id": { + "type": "string" + } + } + }, + "ParameterOption": { + "type": "object", + "properties": { + "label": { + "type": "string" + }, + "value": { + "type": "string" + } + } + }, + "Rule": { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "templateUID": { + "type": "string" + }, + "triggers": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Trigger" + } + }, + "configurationDescriptions": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ConfigDescriptionParameter" + } + }, + "tags": { + "uniqueItems": true, + "type": "array", + "items": { + "type": "string" + } + }, + "uid": { + "type": "string" + }, + "visibility": { + "type": "string", + "enum": [ + "VISIBLE", + "HIDDEN", + "EXPERT" + ] + }, + "configuration": { + "$ref": "#/components/schemas/Configuration" + }, + "modules": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Module" + } + }, + "conditions": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Condition" + } + }, + "name": { + "type": "string" + }, + "actions": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Action" + } + } + } + }, + "RuleExecution": { + "type": "object", + "properties": { + "date": { + "type": "string", + "format": "date-time" + }, + "rule": { + "$ref": "#/components/schemas/Rule" + } + } + }, + "Trigger": { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "label": { + "type": "string" + }, + "typeUID": { + "type": "string" + }, + "configuration": { + "$ref": "#/components/schemas/Configuration" + }, + "id": { + "type": "string" + } + } + }, + "Template": { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "label": { + "type": "string" + }, + "tags": { + "uniqueItems": true, + "type": "array", + "items": { + "type": "string" + } + }, + "uid": { + "type": "string" + }, + "visibility": { + "type": "string", + "enum": [ + "VISIBLE", + "HIDDEN", + "EXPERT" + ] + } + } + }, + "Input": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "type": { + "type": "string" + }, + "label": { + "type": "string" + }, + "description": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "tags": { + "uniqueItems": true, + "type": "array", + "items": { + "type": "string" + } + }, + "reference": { + "type": "string" + }, + "defaultValue": { + "type": "string" + } + } + }, + "Output": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "type": { + "type": "string" + }, + "tags": { + "uniqueItems": true, + "type": "array", + "items": { + "type": "string" + } + }, + "label": { + "type": "string" + }, + "description": { + "type": "string" + }, + "reference": { + "type": "string" + }, + "defaultValue": { + "type": "string" + } + } + }, + "ThingActionDTO": { + "type": "object", + "properties": { + "actionUid": { + "type": "string" + }, + "label": { + "type": "string" + }, + "description": { + "type": "string" + }, + "inputs": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Input" + } + }, + "outputs": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Output" + } + } + } + }, + "AudioSinkDTO": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "label": { + "type": "string" + } + } + }, + "AudioSourceDTO": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "label": { + "type": "string" + } + } + }, + "UserApiTokenDTO": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "createdTime": { + "type": "string", + "format": "date-time" + }, + "scope": { + "type": "string" + } + } + }, + "UserSessionDTO": { + "type": "object", + "properties": { + "sessionId": { + "type": "string" + }, + "createdTime": { + "type": "string", + "format": "date-time" + }, + "lastRefreshTime": { + "type": "string", + "format": "date-time" + }, + "clientId": { + "type": "string" + }, + "scope": { + "type": "string" + } + } + }, + "TokenResponseDTO": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "expires_in": { + "type": "integer", + "format": "int32" + }, + "refresh_token": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "user": { + "$ref": "#/components/schemas/UserDTO" + } + } + }, + "UserDTO": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "roles": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "Addon": { + "type": "object", + "properties": { + "uid": { + "type": "string" + }, + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "version": { + "type": "string" + }, + "maturity": { + "type": "string" + }, + "compatible": { + "type": "boolean" + }, + "contentType": { + "type": "string" + }, + "link": { + "type": "string" + }, + "author": { + "type": "string" + }, + "verifiedAuthor": { + "type": "boolean" + }, + "installed": { + "type": "boolean" + }, + "type": { + "type": "string" + }, + "description": { + "type": "string" + }, + "detailedDescription": { + "type": "string" + }, + "configDescriptionURI": { + "type": "string" + }, + "keywords": { + "type": "string" + }, + "countries": { + "type": "array", + "items": { + "type": "string" + } + }, + "license": { + "type": "string" + }, + "connection": { + "type": "string" + }, + "backgroundColor": { + "type": "string" + }, + "imageLink": { + "type": "string" + }, + "properties": { + "type": "object", + "additionalProperties": { + "type": "object" + } + }, + "loggerPackages": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "AddonType": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "label": { + "type": "string" + } + } + }, + "ChannelTypeDTO": { + "type": "object", + "properties": { + "parameters": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ConfigDescriptionParameterDTO" + } + }, + "parameterGroups": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ConfigDescriptionParameterGroupDTO" + } + }, + "description": { + "type": "string" + }, + "label": { + "type": "string" + }, + "category": { + "type": "string" + }, + "itemType": { + "type": "string" + }, + "kind": { + "type": "string" + }, + "stateDescription": { + "$ref": "#/components/schemas/StateDescription" + }, + "tags": { + "uniqueItems": true, + "type": "array", + "items": { + "type": "string" + } + }, + "UID": { + "type": "string" + }, + "advanced": { + "type": "boolean" + }, + "commandDescription": { + "$ref": "#/components/schemas/CommandDescription" + } + } + }, + "CommandDescription": { + "type": "object", + "properties": { + "commandOptions": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CommandOption" + } + } + } + }, + "CommandOption": { + "type": "object", + "properties": { + "command": { + "type": "string" + }, + "label": { + "type": "string" + } + } + }, + "ConfigDescriptionParameterGroupDTO": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "context": { + "type": "string" + }, + "advanced": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "description": { + "type": "string" + } + } + }, + "StateDescription": { + "type": "object", + "properties": { + "minimum": { + "type": "number" + }, + "maximum": { + "type": "number" + }, + "step": { + "type": "number" + }, + "pattern": { + "type": "string" + }, + "readOnly": { + "type": "boolean" + }, + "options": { + "type": "array", + "items": { + "$ref": "#/components/schemas/StateOption" + } + } + } + }, + "StateOption": { + "type": "object", + "properties": { + "value": { + "type": "string" + }, + "label": { + "type": "string" + } + } + }, + "ConfigDescriptionDTO": { + "type": "object", + "properties": { + "uri": { + "type": "string" + }, + "parameters": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ConfigDescriptionParameterDTO" + } + }, + "parameterGroups": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ConfigDescriptionParameterGroupDTO" + } + } + } + }, + "DiscoveryResultDTO": { + "type": "object", + "properties": { + "bridgeUID": { + "type": "string" + }, + "flag": { + "type": "string", + "enum": [ + "NEW", + "IGNORED" + ] + }, + "label": { + "type": "string" + }, + "properties": { + "type": "object", + "additionalProperties": { + "type": "object" + } + }, + "representationProperty": { + "type": "string" + }, + "thingUID": { + "type": "string" + }, + "thingTypeUID": { + "type": "string" + } + } + }, + "MetadataDTO": { + "type": "object", + "properties": { + "value": { + "type": "string" + }, + "config": { + "type": "object", + "additionalProperties": { + "type": "object" + } + } + } + }, + "EnrichedItemDTO": { + "type": "object", + "properties": { + "type": { + "type": "string" + }, + "name": { + "type": "string" + }, + "label": { + "type": "string" + }, + "category": { + "type": "string" + }, + "tags": { + "uniqueItems": true, + "type": "array", + "items": { + "type": "string" + } + }, + "groupNames": { + "type": "array", + "items": { + "type": "string" + } + }, + "link": { + "type": "string" + }, + "state": { + "type": "string" + }, + "transformedState": { + "type": "string" + }, + "stateDescription": { + "$ref": "#/components/schemas/StateDescription" + }, + "unitSymbol": { + "type": "string" + }, + "commandDescription": { + "$ref": "#/components/schemas/CommandDescription" + }, + "metadata": { + "type": "object", + "additionalProperties": { + "type": "object" + } + }, + "editable": { + "type": "boolean" + } + } + }, + "GroupFunctionDTO": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "params": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "GroupItemDTO": { + "type": "object", + "properties": { + "type": { + "type": "string" + }, + "name": { + "type": "string" + }, + "label": { + "type": "string" + }, + "category": { + "type": "string" + }, + "tags": { + "uniqueItems": true, + "type": "array", + "items": { + "type": "string" + } + }, + "groupNames": { + "type": "array", + "items": { + "type": "string" + } + }, + "groupType": { + "type": "string" + }, + "function": { + "$ref": "#/components/schemas/GroupFunctionDTO" + } + } + }, + "EnrichedItemChannelLinkDTO": { + "type": "object", + "properties": { + "itemName": { + "type": "string" + }, + "channelUID": { + "type": "string" + }, + "configuration": { + "type": "object", + "additionalProperties": { + "type": "object" + } + }, + "editable": { + "type": "boolean" + } + } + }, + "ItemChannelLinkDTO": { + "type": "object", + "properties": { + "itemName": { + "type": "string" + }, + "channelUID": { + "type": "string" + }, + "configuration": { + "type": "object", + "additionalProperties": { + "type": "object" + } + } + } + }, + "HistoryDataBean": { + "type": "object", + "properties": { + "time": { + "type": "integer", + "format": "int64" + }, + "state": { + "type": "string" + } + } + }, + "ItemHistoryDTO": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "totalrecords": { + "type": "string" + }, + "datapoints": { + "type": "string" + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/HistoryDataBean" + } + } + } + }, + "PersistenceCronStrategyDTO": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "cronExpression": { + "type": "string" + } + } + }, + "PersistenceFilterDTO": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "number" + }, + "relative": { + "type": "boolean" + }, + "unit": { + "type": "string" + }, + "lower": { + "type": "number" + }, + "upper": { + "type": "number" + }, + "values": { + "type": "array", + "items": { + "type": "string" + } + }, + "inverted": { + "type": "boolean" + } + } + }, + "PersistenceItemConfigurationDTO": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "type": "string" + } + }, + "strategies": { + "type": "array", + "items": { + "type": "string" + } + }, + "filters": { + "type": "array", + "items": { + "type": "string" + } + }, + "alias": { + "type": "string" + } + } + }, + "PersistenceServiceConfigurationDTO": { + "type": "object", + "properties": { + "serviceId": { + "type": "string" + }, + "configs": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PersistenceItemConfigurationDTO" + } + }, + "defaults": { + "type": "array", + "items": { + "type": "string" + } + }, + "cronStrategies": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PersistenceCronStrategyDTO" + } + }, + "thresholdFilters": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PersistenceFilterDTO" + } + }, + "timeFilters": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PersistenceFilterDTO" + } + }, + "equalsFilters": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PersistenceFilterDTO" + } + }, + "includeFilters": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PersistenceFilterDTO" + } + }, + "editable": { + "type": "boolean" + } + } + }, + "PersistenceItemInfo": { + "type": "object", + "properties": { + "earliest": { + "type": "string", + "format": "date-time" + }, + "latest": { + "type": "string", + "format": "date-time" + }, + "count": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string" + } + } + }, + "PersistenceServiceDTO": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "type": { + "type": "string" + } + } + }, + "ProfileTypeDTO": { + "type": "object", + "properties": { + "uid": { + "type": "string" + }, + "label": { + "type": "string" + }, + "kind": { + "type": "string" + }, + "supportedItemTypes": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "ConfigurableServiceDTO": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "category": { + "type": "string" + }, + "configDescriptionURI": { + "type": "string" + }, + "multiple": { + "type": "boolean" + } + } + }, + "EnrichedSemanticTagDTO": { + "type": "object" + }, + "EnrichedChannelDTO": { + "type": "object", + "properties": { + "uid": { + "type": "string" + }, + "id": { + "type": "string" + }, + "channelTypeUID": { + "type": "string" + }, + "itemType": { + "type": "string" + }, + "kind": { + "type": "string" + }, + "label": { + "type": "string" + }, + "description": { + "type": "string" + }, + "defaultTags": { + "uniqueItems": true, + "type": "array", + "items": { + "type": "string" + } + }, + "properties": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "configuration": { + "type": "object", + "additionalProperties": { + "type": "object" + } + }, + "autoUpdatePolicy": { + "type": "string" + }, + "linkedItems": { + "uniqueItems": true, + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "EnrichedThingDTO": { + "type": "object", + "properties": { + "label": { + "type": "string" + }, + "bridgeUID": { + "type": "string" + }, + "configuration": { + "type": "object", + "additionalProperties": { + "type": "object" + } + }, + "properties": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "UID": { + "type": "string" + }, + "thingTypeUID": { + "type": "string" + }, + "location": { + "type": "string" + }, + "channels": { + "type": "array", + "items": { + "$ref": "#/components/schemas/EnrichedChannelDTO" + } + }, + "statusInfo": { + "$ref": "#/components/schemas/ThingStatusInfo" + }, + "firmwareStatus": { + "$ref": "#/components/schemas/FirmwareStatusDTO" + }, + "editable": { + "type": "boolean" + } + } + }, + "FirmwareStatusDTO": { + "type": "object", + "properties": { + "status": { + "type": "string" + }, + "updatableVersion": { + "type": "string" + } + } + }, + "ThingStatusInfo": { + "type": "object", + "properties": { + "status": { + "type": "string", + "enum": [ + "UNINITIALIZED", + "INITIALIZING", + "UNKNOWN", + "ONLINE", + "OFFLINE", + "REMOVING", + "REMOVED" + ] + }, + "statusDetail": { + "type": "string", + "enum": [ + "NONE", + "NOT_YET_READY", + "HANDLER_MISSING_ERROR", + "HANDLER_REGISTERING_ERROR", + "HANDLER_INITIALIZING_ERROR", + "HANDLER_CONFIGURATION_PENDING", + "CONFIGURATION_PENDING", + "COMMUNICATION_ERROR", + "CONFIGURATION_ERROR", + "BRIDGE_OFFLINE", + "FIRMWARE_UPDATING", + "DUTY_CYCLE", + "BRIDGE_UNINITIALIZED", + "GONE", + "DISABLED" + ] + }, + "description": { + "type": "string" + } + } + }, + "ChannelDTO": { + "type": "object", + "properties": { + "uid": { + "type": "string" + }, + "id": { + "type": "string" + }, + "channelTypeUID": { + "type": "string" + }, + "itemType": { + "type": "string" + }, + "kind": { + "type": "string" + }, + "label": { + "type": "string" + }, + "description": { + "type": "string" + }, + "defaultTags": { + "uniqueItems": true, + "type": "array", + "items": { + "type": "string" + } + }, + "properties": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "configuration": { + "type": "object", + "additionalProperties": { + "type": "object" + } + }, + "autoUpdatePolicy": { + "type": "string" + } + } + }, + "ThingDTO": { + "type": "object", + "properties": { + "label": { + "type": "string" + }, + "bridgeUID": { + "type": "string" + }, + "configuration": { + "type": "object", + "additionalProperties": { + "type": "object" + } + }, + "properties": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "UID": { + "type": "string" + }, + "thingTypeUID": { + "type": "string" + }, + "location": { + "type": "string" + }, + "channels": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ChannelDTO" + } + } + } + }, + "ConfigStatusMessage": { + "type": "object", + "properties": { + "parameterName": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "INFORMATION", + "WARNING", + "ERROR", + "PENDING" + ] + }, + "message": { + "type": "string" + }, + "statusCode": { + "type": "integer", + "format": "int32" + } + } + }, + "FirmwareDTO": { + "type": "object", + "properties": { + "thingTypeUID": { + "type": "string" + }, + "vendor": { + "type": "string" + }, + "model": { + "type": "string" + }, + "modelRestricted": { + "type": "boolean" + }, + "description": { + "type": "string" + }, + "version": { + "type": "string" + }, + "changelog": { + "type": "string" + }, + "prerequisiteVersion": { + "type": "string" + } + } + }, + "StrippedThingTypeDTO": { + "type": "object", + "properties": { + "UID": { + "type": "string" + }, + "label": { + "type": "string" + }, + "description": { + "type": "string" + }, + "category": { + "type": "string" + }, + "listed": { + "type": "boolean" + }, + "supportedBridgeTypeUIDs": { + "type": "array", + "items": { + "type": "string" + } + }, + "bridge": { + "type": "boolean" + } + } + }, + "ChannelDefinitionDTO": { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "tags": { + "uniqueItems": true, + "type": "array", + "items": { + "type": "string" + } + }, + "properties": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "category": { + "type": "string" + }, + "stateDescription": { + "$ref": "#/components/schemas/StateDescription" + }, + "advanced": { + "type": "boolean" + }, + "typeUID": { + "type": "string" + } + } + }, + "ChannelGroupDefinitionDTO": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "description": { + "type": "string" + }, + "label": { + "type": "string" + }, + "channels": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ChannelDefinitionDTO" + } + } + } + }, + "ThingTypeDTO": { + "type": "object", + "properties": { + "UID": { + "type": "string" + }, + "label": { + "type": "string" + }, + "description": { + "type": "string" + }, + "category": { + "type": "string" + }, + "listed": { + "type": "boolean" + }, + "supportedBridgeTypeUIDs": { + "type": "array", + "items": { + "type": "string" + } + }, + "bridge": { + "type": "boolean" + }, + "channels": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ChannelDefinitionDTO" + } + }, + "channelGroups": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ChannelGroupDefinitionDTO" + } + }, + "configParameters": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ConfigDescriptionParameterDTO" + } + }, + "parameterGroups": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ConfigDescriptionParameterGroupDTO" + } + }, + "properties": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "extensibleChannelTypeIds": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "Links": { + "type": "object", + "properties": { + "type": { + "type": "string" + }, + "url": { + "type": "string" + } + } + }, + "RootBean": { + "type": "object", + "properties": { + "version": { + "type": "string" + }, + "locale": { + "type": "string" + }, + "measurementSystem": { + "type": "string" + }, + "runtimeInfo": { + "$ref": "#/components/schemas/RuntimeInfo" + }, + "links": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Links" + } + } + } + }, + "RuntimeInfo": { + "type": "object", + "properties": { + "version": { + "type": "string" + }, + "buildString": { + "type": "string" + } + } + }, + "SystemInfo": { + "type": "object", + "properties": { + "configFolder": { + "type": "string" + }, + "userdataFolder": { + "type": "string" + }, + "logFolder": { + "type": "string" + }, + "javaVersion": { + "type": "string" + }, + "javaVendor": { + "type": "string" + }, + "javaVendorVersion": { + "type": "string" + }, + "osName": { + "type": "string" + }, + "osVersion": { + "type": "string" + }, + "osArchitecture": { + "type": "string" + }, + "availableProcessors": { + "type": "integer", + "format": "int32" + }, + "freeMemory": { + "type": "integer", + "format": "int64" + }, + "totalMemory": { + "type": "integer", + "format": "int64" + }, + "uptime": { + "type": "integer", + "format": "int64" + }, + "startLevel": { + "type": "integer", + "format": "int32" + } + } + }, + "SystemInfoBean": { + "type": "object", + "properties": { + "systemInfo": { + "$ref": "#/components/schemas/SystemInfo" + } + } + }, + "DimensionInfo": { + "type": "object", + "properties": { + "dimension": { + "type": "string" + }, + "systemUnit": { + "type": "string" + } + } + }, + "UoMInfo": { + "type": "object", + "properties": { + "dimensions": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DimensionInfo" + } + } + } + }, + "UoMInfoBean": { + "type": "object", + "properties": { + "uomInfo": { + "$ref": "#/components/schemas/UoMInfo" + } + } + }, + "MappingDTO": { + "type": "object", + "properties": { + "row": { + "type": "integer", + "format": "int32" + }, + "column": { + "type": "integer", + "format": "int32" + }, + "command": { + "type": "string" + }, + "label": { + "type": "string" + }, + "icon": { + "type": "string" + } + } + }, + "PageDTO": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "title": { + "type": "string" + }, + "icon": { + "type": "string" + }, + "link": { + "type": "string" + }, + "parent": { + "$ref": "#/components/schemas/PageDTO" + }, + "leaf": { + "type": "boolean" + }, + "timeout": { + "type": "boolean" + }, + "widgets": { + "type": "array", + "items": { + "$ref": "#/components/schemas/WidgetDTO" + } + } + } + }, + "WidgetDTO": { + "type": "object", + "properties": { + "widgetId": { + "type": "string" + }, + "type": { + "type": "string" + }, + "name": { + "type": "string" + }, + "visibility": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "labelSource": { + "type": "string" + }, + "icon": { + "type": "string" + }, + "staticIcon": { + "type": "boolean" + }, + "labelcolor": { + "type": "string" + }, + "valuecolor": { + "type": "string" + }, + "iconcolor": { + "type": "string" + }, + "pattern": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "mappings": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MappingDTO" + } + }, + "switchSupport": { + "type": "boolean" + }, + "sendFrequency": { + "type": "integer", + "format": "int32" + }, + "refresh": { + "type": "integer", + "format": "int32" + }, + "height": { + "type": "integer", + "format": "int32" + }, + "minValue": { + "type": "number" + }, + "maxValue": { + "type": "number" + }, + "step": { + "type": "number" + }, + "inputHint": { + "type": "string" + }, + "url": { + "type": "string" + }, + "encoding": { + "type": "string" + }, + "service": { + "type": "string" + }, + "period": { + "type": "string" + }, + "yAxisDecimalPattern": { + "type": "string" + }, + "legend": { + "type": "boolean" + }, + "forceAsItem": { + "type": "boolean" + }, + "state": { + "type": "string" + }, + "item": { + "$ref": "#/components/schemas/EnrichedItemDTO" + }, + "linkedPage": { + "$ref": "#/components/schemas/PageDTO" + } + } + }, + "SitemapDTO": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "icon": { + "type": "string" + }, + "label": { + "type": "string" + }, + "link": { + "type": "string" + }, + "homepage": { + "$ref": "#/components/schemas/PageDTO" + } + } + }, + "Transformation": { + "type": "object", + "properties": { + "uid": { + "type": "string" + }, + "label": { + "type": "string" + }, + "type": { + "type": "string" + }, + "configuration": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + } + }, + "TransformationDTO": { + "type": "object", + "properties": { + "uid": { + "type": "string" + }, + "label": { + "type": "string" + }, + "type": { + "type": "string" + }, + "configuration": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "editable": { + "type": "boolean" + } + } + }, + "RootUIComponent": { + "type": "object", + "properties": { + "component": { + "type": "string" + }, + "config": { + "type": "object", + "additionalProperties": { + "type": "object" + } + }, + "slots": { + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "$ref": "#/components/schemas/UIComponent" + } + } + }, + "uid": { + "type": "string" + }, + "tags": { + "uniqueItems": true, + "type": "array", + "items": { + "type": "string" + } + }, + "props": { + "$ref": "#/components/schemas/ConfigDescriptionDTO" + }, + "timestamp": { + "type": "string", + "format": "date-time" + }, + "type": { + "type": "string" + } + } + }, + "UIComponent": { + "type": "object", + "properties": { + "component": { + "type": "string" + }, + "config": { + "type": "object", + "additionalProperties": { + "type": "object" + } + }, + "type": { + "type": "string" + } + } + }, + "TileDTO": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "url": { + "type": "string" + }, + "overlay": { + "type": "string" + }, + "imageUrl": { + "type": "string" + } + } + }, + "VoiceDTO": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "locale": { + "type": "string" + } + } + }, + "HumanLanguageInterpreterDTO": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "locales": { + "uniqueItems": true, + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "LoggerInfo": { + "type": "object", + "properties": { + "loggerName": { + "type": "string" + }, + "level": { + "type": "string" + } + } + }, + "LoggerBean": { + "type": "object", + "properties": { + "loggers": { + "type": "array", + "items": { + "$ref": "#/components/schemas/LoggerInfo" + } + } + } + }, + "IconSet": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "description": { + "type": "string" + }, + "formats": { + "uniqueItems": true, + "type": "array", + "items": { + "type": "string", + "enum": [ + "PNG", + "SVG" + ] + } + } + } + }, + "Card": { + "type": "object", + "properties": { + "config": { + "type": "object", + "additionalProperties": { + "type": "object" + } + }, + "slots": { + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Component" + } + } + }, + "uid": { + "type": "string" + }, + "title": { + "type": "string" + }, + "subtitle": { + "type": "string" + }, + "tags": { + "uniqueItems": true, + "type": "array", + "items": { + "type": "string" + } + }, + "bookmarked": { + "type": "boolean" + }, + "notReuseableInChat": { + "type": "boolean" + }, + "addToDeckDenied": { + "type": "boolean" + }, + "ephemeral": { + "type": "boolean" + }, + "timestamp": { + "type": "string", + "format": "date-time" + }, + "objectAttributes": { + "uniqueItems": true, + "type": "array", + "items": { + "type": "string" + } + }, + "locationAttributes": { + "uniqueItems": true, + "type": "array", + "items": { + "type": "string" + } + }, + "bookmark": { + "type": "boolean", + "writeOnly": true + }, + "name": { + "type": "string" + } + } + }, + "ChatReply": { + "type": "object", + "properties": { + "language": { + "type": "string" + }, + "query": { + "type": "string" + }, + "answer": { + "type": "string" + }, + "hint": { + "type": "string" + }, + "intent": { + "$ref": "#/components/schemas/Intent" + }, + "matchedItemNames": { + "type": "array", + "items": { + "type": "string" + } + }, + "card": { + "$ref": "#/components/schemas/Card" + }, + "matchedItems": { + "type": "array", + "writeOnly": true, + "items": { + "type": "string" + } + } + } + }, + "Component": { + "type": "object", + "properties": { + "config": { + "type": "object", + "additionalProperties": { + "type": "object" + } + }, + "name": { + "type": "string" + } + } + }, + "Intent": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "entities": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + } + } + }, + "securitySchemes": { + "oauth2": { + "type": "oauth2", + "flows": { + "authorizationCode": { + "authorizationUrl": "/auth/authorize", + "tokenUrl": "/rest/auth/token", + "scopes": { + "admin": "Administration operations" + } + } + } + } + } + } +} \ No newline at end of file diff --git a/src/openHAB.Core.Client/openHAB.Core.Client.csproj b/src/openHAB.Core.Client/openHAB.Core.Client.csproj index f810132e..4552f333 100644 --- a/src/openHAB.Core.Client/openHAB.Core.Client.csproj +++ b/src/openHAB.Core.Client/openHAB.Core.Client.csproj @@ -13,13 +13,15 @@ 10.0.18362.0 $(MSBuildProjectName.Replace(" ", "_")) + + + - - - - + + + 8.0.0 runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/openHAB.Core/Messages/SitemapChanged.cs b/src/openHAB.Core/Messages/SitemapChanged.cs index c9ac4175..68a3bbcf 100644 --- a/src/openHAB.Core/Messages/SitemapChanged.cs +++ b/src/openHAB.Core/Messages/SitemapChanged.cs @@ -7,12 +7,12 @@ namespace openHAB.Core.Messages public class SitemapChanged { - public SitemapChanged(OpenHABSitemap sitemap) + public SitemapChanged(Sitemap sitemap) { sitemap = sitemap; } - public OpenHABSitemap Sitemap + public Sitemap Sitemap { get; private set; diff --git a/src/openHAB.Core/Notification/NotificationManager.cs b/src/openHAB.Core/Notification/NotificationManager.cs index 9f7159ac..49a5621e 100644 --- a/src/openHAB.Core/Notification/NotificationManager.cs +++ b/src/openHAB.Core/Notification/NotificationManager.cs @@ -29,7 +29,7 @@ public NotificationManager(IItemManager itemStateManager, IIconCaching iconCachi { StrongReferenceMessenger.Default.Register(this, HandleUpdateItemMessage); _itemManager = itemStateManager; - _iconFormat = settings.UseSVGIcons ? "svg" : "png"; + _iconFormat = settings.UseSVGIcons ? "svg" : "svg"; _settingsService = settingsService; _iconCaching = iconCaching; } @@ -45,7 +45,7 @@ private async void HandleUpdateItemMessage(object receipts, ItemStateChangedMess string itemName = obj.ItemName; string itemImage = string.Empty; string itemPath = string.Empty; - if (_itemManager.TryGetItem(obj.ItemName, out OpenHABItem item)) + if (_itemManager.TryGetItem(obj.ItemName, out Item item)) { itemName = item?.Label ?? "NA"; string state = item?.State ?? "ON"; diff --git a/src/openHAB.Core/Openhab.Core.csproj b/src/openHAB.Core/Openhab.Core.csproj index 70ab02e1..31c53749 100644 --- a/src/openHAB.Core/Openhab.Core.csproj +++ b/src/openHAB.Core/Openhab.Core.csproj @@ -30,7 +30,7 @@ - 1.4.231219000 + 1.5.240311000 13.0.3 @@ -46,7 +46,7 @@ all - + diff --git a/src/openHAB.Core/Services/Contracts/IItemManager.cs b/src/openHAB.Core/Services/Contracts/IItemManager.cs index 0455dbbe..2b648844 100644 --- a/src/openHAB.Core/Services/Contracts/IItemManager.cs +++ b/src/openHAB.Core/Services/Contracts/IItemManager.cs @@ -12,6 +12,6 @@ public interface IItemManager /// /// Is true if the item was found in the dictionary or was successfully downloaded from openHAB server, otherwise false. /// - bool TryGetItem(string itemName, out OpenHABItem item); + bool TryGetItem(string itemName, out Item item); } } \ No newline at end of file diff --git a/src/openHAB.Core/Services/IconCaching.cs b/src/openHAB.Core/Services/IconCaching.cs index 14157c69..f9d054fa 100644 --- a/src/openHAB.Core/Services/IconCaching.cs +++ b/src/openHAB.Core/Services/IconCaching.cs @@ -55,13 +55,13 @@ public async Task ResolveIconPath(string icon, string state, string icon OpenHABVersion openHABVersion = _settingsService.ServerVersion; string iconUrl = openHABVersion == OpenHABVersion.Two || openHABVersion == OpenHABVersion.Three || openHABVersion == OpenHABVersion.Four ? - $"{serverUrl}icon/{icon}?state={state}&format={iconFormat}" : + $"{serverUrl}icon/{icon}?state={state}&format={iconFormat}&anyFormat=true&iconset=classic" : $"{serverUrl}images/{icon}.png"; try { - Match iconName = Regex.Match(iconUrl, "icon/[0-9a-zA-Z]*", RegexOptions.None, TimeSpan.FromMilliseconds(100)); - Match iconState = Regex.Match(iconUrl, "state=[0-9a-zA-Z=]*", RegexOptions.None, TimeSpan.FromMilliseconds(100)); + Match iconName = Regex.Match(iconUrl, "icon/[0-9a-zA-Z]*", RegexOptions.None, TimeSpan.FromMilliseconds(1000)); + Match iconState = Regex.Match(iconUrl, "state=[0-9a-zA-Z=]*", RegexOptions.None, TimeSpan.FromMilliseconds(1000)); if (!iconName.Success) { @@ -73,14 +73,8 @@ public async Task ResolveIconPath(string icon, string state, string icon throw new ServiceException("Can not resolve icon state from url"); } - if (!iconState.Success) - { - throw new ServiceException("Can not resolve icon state from url"); - } - DirectoryInfo iconDirectory = EnsureIconCacheFolder(); - //string iconFileName = $"{iconName.Value.Replace("icon/", string.Empty)}{iconState.Value.Replace("state=", string.Empty)}.{iconFormat}"; string iconFileName = $"{iconName.Value.Replace("icon/", string.Empty)}.{iconFormat}"; string iconFilePath = Path.Combine(iconDirectory.FullName, iconFileName).Replace("NULL", string.Empty); diff --git a/src/openHAB.Core/Services/ItemManager.cs b/src/openHAB.Core/Services/ItemManager.cs index 49c5644d..cbbe510c 100644 --- a/src/openHAB.Core/Services/ItemManager.cs +++ b/src/openHAB.Core/Services/ItemManager.cs @@ -9,18 +9,18 @@ namespace openHAB.Core.Services /// public class ItemManager : IItemManager { - private readonly Dictionary _nameToStateDictionary; + private readonly Dictionary _nameToStateDictionary; private IOpenHABClient _openHABClient; /// Initializes a new instance of the class. public ItemManager(IOpenHABClient openHABClient) { - _nameToStateDictionary = new Dictionary(); + _nameToStateDictionary = new Dictionary(); _openHABClient = openHABClient; } /// - public bool TryGetItem(string itemName, out OpenHABItem item) + public bool TryGetItem(string itemName, out Item item) { if (!_nameToStateDictionary.TryGetValue(itemName, out item)) { diff --git a/src/openHAB.Core/Services/SitemapService.cs b/src/openHAB.Core/Services/SitemapService.cs index 4d22e6c4..fcc648cc 100644 --- a/src/openHAB.Core/Services/SitemapService.cs +++ b/src/openHAB.Core/Services/SitemapService.cs @@ -41,8 +41,8 @@ public SitemapService(ISettingsService settingsService, IOpenHABClient openHABCl /// Gets the sitemap by URL. /// /// The sitemap URL. - /// The object representing the sitemap. - public async Task GetSitemapByUrlAsync(string sitemapUrl) + /// The object representing the sitemap. + public async Task GetSitemapByUrlAsync(string sitemapUrl) { try { @@ -53,7 +53,7 @@ public async Task GetSitemapByUrlAsync(string sitemapUrl) } _settingsService.ServerVersion = _serverInfo.Version; - OpenHABSitemap sitemap = await _openHABClient.GetSitemap(sitemapUrl, _serverInfo.Version).ConfigureAwait(false); + Sitemap sitemap = await _openHABClient.GetSitemap(sitemapUrl, _serverInfo.Version).ConfigureAwait(false); return sitemap; } catch (OpenHABException ex) @@ -74,8 +74,8 @@ public async Task GetSitemapByUrlAsync(string sitemapUrl) /// Gets the list of sitemaps. /// /// The cancellation token for the load operation. - /// The list of objects representing the sitemaps. - public async Task> GetSitemapsAsync(CancellationToken loadCancellationToken) + /// The list of objects representing the sitemaps. + public async Task> GetSitemapsAsync(CancellationToken loadCancellationToken) { try { @@ -91,20 +91,20 @@ public async Task> GetSitemapsAsync(CancellationToken loadC return null; } - Func defaultSitemapFilter = (sitemap) => + Func defaultSitemapFilter = (sitemap) => { return !sitemap.Name.Equals("_default", StringComparison.InvariantCultureIgnoreCase); }; Settings settings = _settingsService.Load(); - List> filters = new List>(); + List> filters = new List>(); if (!settings.ShowDefaultSitemap) { filters.Add(defaultSitemapFilter); } - ICollection sitemaps = await _openHABClient.LoadSitemaps(_serverInfo.Version, filters).ConfigureAwait(false); - return new List(sitemaps); + ICollection sitemaps = await _openHABClient.LoadSitemaps(_serverInfo.Version, filters).ConfigureAwait(false); + return new List(sitemaps); } catch (OpenHABException ex) { @@ -124,10 +124,10 @@ public async Task> GetSitemapsAsync(CancellationToken loadC /// Loads the items from a sitemap. /// /// The sitemap model. - /// The collection of objects representing the items. - public async Task> LoadItemsFromSitemapAsync(OpenHABSitemap model) + /// The collection of objects representing the items. + public async Task> LoadItemsFromSitemapAsync(Sitemap model) { - ICollection widgetModels = await _openHABClient.LoadItemsFromSitemap(model.Link, _serverInfo.Version).ConfigureAwait(false); + ICollection widgetModels = await _openHABClient.LoadItemsFromSitemap(model.Link, _serverInfo.Version).ConfigureAwait(false); return widgetModels; } @@ -137,7 +137,7 @@ public async Task> LoadItemsFromSitemapAsync(OpenHABS /// The item to send the command to. /// The command to send. /// The object representing the result of the command. - public async Task> SendItemCommand(OpenHABItem item, string command) + public async Task> SendItemCommand(Item item, string command) { HttpResponseResult result = await _openHABClient.SendCommand(item, command).ConfigureAwait(false); return result; diff --git a/src/openHAB.Windows/Controls/FrameWidget.xaml.cs b/src/openHAB.Windows/Controls/FrameWidget.xaml.cs index cda305f3..79a91e3b 100644 --- a/src/openHAB.Windows/Controls/FrameWidget.xaml.cs +++ b/src/openHAB.Windows/Controls/FrameWidget.xaml.cs @@ -1,8 +1,7 @@ using CommunityToolkit.Mvvm.Messaging; using Microsoft.UI.Xaml.Controls; -using openHAB.Core.Client.Models; -using openHAB.Core.Messages; -using openHAB.Core.Model; +using openHAB.Windows.Messages; +using openHAB.Windows.ViewModel; namespace openHAB.Windows.Controls { @@ -21,7 +20,13 @@ public FrameWidget() private void OnItemClick(object sender, ItemClickEventArgs e) { - StrongReferenceMessenger.Default.Send(new WidgetClickedMessage(e.ClickedItem as OpenHABWidget)); + WidgetViewModel viewModel = e.ClickedItem as WidgetViewModel; + if (viewModel == null) + { + return; + } + + StrongReferenceMessenger.Default.Send(new WidgetClickedMessage(viewModel)); } internal override void SetState() diff --git a/src/openHAB.Windows/Controls/PageLinkWidget.xaml b/src/openHAB.Windows/Controls/PageLinkWidget.xaml index 28abca1f..eb678619 100644 --- a/src/openHAB.Windows/Controls/PageLinkWidget.xaml +++ b/src/openHAB.Windows/Controls/PageLinkWidget.xaml @@ -9,11 +9,6 @@ d:DesignWidth="400" mc:Ignorable="d" Visibility="{x:Bind Widget.Visibility}"> - - - - - @@ -24,8 +19,7 @@ VerticalAlignment="Center" IconPath="{x:Bind Widget.IconPath, Mode=OneWay}" LabelText="{x:Bind Widget.Label, Mode=OneWay}" - LabelForeground="{x:Bind Widget.LabelColor, Mode=OneWay}"/> - + LabelForeground="{x:Bind Widget.LabelColor, Mode=OneWay}" /> - - + ((OpenHABWidgetMapping)x).Command == Widget.Item.State); + var currentItem = SectionsList?.Items?.SingleOrDefault(x => ((WidgetMapping)x).Command == Widget.Item.State); ContentPresenter presenter = SectionsList?.ContainerFromItem(currentItem) as Microsoft.UI.Xaml.Controls.ContentPresenter; if (presenter != null && presenter.FindChild(typeof(ToggleButton)) is ToggleButton toggleButton) diff --git a/src/openHAB.Windows/Controls/SelectionWidget.xaml.cs b/src/openHAB.Windows/Controls/SelectionWidget.xaml.cs index 27684356..3c64e502 100644 --- a/src/openHAB.Windows/Controls/SelectionWidget.xaml.cs +++ b/src/openHAB.Windows/Controls/SelectionWidget.xaml.cs @@ -34,7 +34,7 @@ private void SelectionWidget_Loaded(object sender, global::Microsoft.UI.Xaml.Rou selectionMappings = new System.Collections.Generic.List(); if (Widget?.Item.CommandDescription?.CommandOptions?.Count > 0) { - foreach (OpenHABCommandOptions option in Widget.Item.CommandDescription.CommandOptions) + foreach (CommandOptions option in Widget.Item.CommandDescription.CommandOptions) { SelectionMapping mapping = new SelectionMapping(option.Command, option.Label); selectionMappings.Add(mapping); @@ -43,7 +43,7 @@ private void SelectionWidget_Loaded(object sender, global::Microsoft.UI.Xaml.Rou if (Widget?.Mappings.Count > 0) { - foreach (OpenHABWidgetMapping option in Widget.Mappings) + foreach (WidgetMapping option in Widget.Mappings) { SelectionMapping mapping = new SelectionMapping(option.Command, option.Label); selectionMappings.Add(mapping); diff --git a/src/openHAB.Windows/Controls/SetpointWidget.xaml b/src/openHAB.Windows/Controls/SetpointWidget.xaml index 2a38b0e5..10bf369a 100644 --- a/src/openHAB.Windows/Controls/SetpointWidget.xaml +++ b/src/openHAB.Windows/Controls/SetpointWidget.xaml @@ -6,10 +6,9 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" d:DesignHeight="150" d:DesignWidth="300" - mc:Ignorable="d" + mc:Ignorable="d" Loaded="SetPointWidget_Loaded" Visibility="{x:Bind Widget.Visibility}"> - @@ -19,9 +18,6 @@ IconPath="{x:Bind Widget.IconPath, Mode=OneWay}" LabelForeground="{x:Bind Widget.LabelColor, Mode=OneWay}" LabelText="{x:Bind Widget.Label, Mode=OneWay}" /> - - - - + - + x:Name="comboBox" + HorizontalAlignment="Stretch" + FontSize="16" + Foreground="{x:Bind Widget.ValueColor, Mode=OneWay}" + Width="Auto" + VerticalAlignment="Stretch" /> + - - + + - - - - - - - diff --git a/src/openHAB.Windows/Converters/MenuItemTemplateSelector.cs b/src/openHAB.Windows/Converters/MenuItemTemplateSelector.cs index 28d01720..b5c6d996 100644 --- a/src/openHAB.Windows/Converters/MenuItemTemplateSelector.cs +++ b/src/openHAB.Windows/Converters/MenuItemTemplateSelector.cs @@ -27,7 +27,7 @@ public DataTemplate DefaultItemTemlate /// protected override DataTemplate SelectTemplateCore(object item) { - OpenHABSitemap sitemapMenuItem = item as OpenHABSitemap; + Sitemap sitemapMenuItem = item as Sitemap; if (sitemapMenuItem != null) { diff --git a/src/openHAB.Windows/Converters/ObjectToSitemapConverter.cs b/src/openHAB.Windows/Converters/ObjectToSitemapConverter.cs index b78a9169..721c7dbf 100644 --- a/src/openHAB.Windows/Converters/ObjectToSitemapConverter.cs +++ b/src/openHAB.Windows/Converters/ObjectToSitemapConverter.cs @@ -13,13 +13,13 @@ public class ObjectToSitemapConverter : IValueConverter /// public object Convert(object value, Type targetType, object parameter, string language) { - return value as OpenHABSitemap; + return value as Sitemap; } /// public object ConvertBack(object value, Type targetType, object parameter, string language) { - return value as OpenHABSitemap; + return value as Sitemap; } } } diff --git a/src/openHAB.Windows/Converters/WidgetTemplateSelector.cs b/src/openHAB.Windows/Converters/WidgetTemplateSelector.cs index e4c2935b..34c31963 100644 --- a/src/openHAB.Windows/Converters/WidgetTemplateSelector.cs +++ b/src/openHAB.Windows/Converters/WidgetTemplateSelector.cs @@ -24,7 +24,7 @@ protected override DataTemplate SelectTemplateCore(object item, DependencyObject return null; } - var itemType = GetItemViewType(widget); + WidgetTypeEnum itemType = GetItemViewType(widget); switch (itemType) { case WidgetTypeEnum.ColorPicker: diff --git a/src/openHAB.Windows/MainWindow.xaml b/src/openHAB.Windows/MainWindow.xaml index 10672a12..9a427ce9 100644 --- a/src/openHAB.Windows/MainWindow.xaml +++ b/src/openHAB.Windows/MainWindow.xaml @@ -65,7 +65,7 @@ - + - + @@ -132,7 +132,7 @@ - + @@ -160,6 +160,7 @@ + + Grid.Row="2" + Margin="10"> (new WigetNavigation(null, widget, EventTriggerSource.Breadcrumb)); + WidgetViewModel widget = args.Item as WidgetViewModel; + if (widget == null) + { + _logger.LogWarning("Breadcrumb item is not a widget."); + return; + } + + StrongReferenceMessenger.Default.Send(new WidgetNavigationMessage(null, widget, EventTriggerSource.Breadcrumb)); } private async Task ShowErrorMessage(object recipient, ConnectionErrorMessage message) @@ -143,7 +149,7 @@ private void SitemapNavigation_SelectionChanged( else { sender.AlwaysShowHeader = true; - OpenHABSitemap sitemap = args.SelectedItem as OpenHABSitemap; + Sitemap sitemap = args.SelectedItem as Sitemap; if (sitemap != null) { ContentFrame.Navigate(typeof(SitemapPage), sitemap.Link); @@ -153,7 +159,7 @@ private void SitemapNavigation_SelectionChanged( private void SitemapTextBlock_Tapped(object sender, Microsoft.UI.Xaml.Input.TappedRoutedEventArgs e) { - StrongReferenceMessenger.Default.Send(new WigetNavigation(null, null, EventTriggerSource.Root)); + StrongReferenceMessenger.Default.Send(new WidgetNavigationMessage(null, null, EventTriggerSource.Root)); } } } diff --git a/src/openHAB.Core/Messages/WidgetClickedMessage.cs b/src/openHAB.Windows/Messages/WidgetClickedMessage.cs similarity index 73% rename from src/openHAB.Core/Messages/WidgetClickedMessage.cs rename to src/openHAB.Windows/Messages/WidgetClickedMessage.cs index d5bcf6fa..7bd7c07f 100644 --- a/src/openHAB.Core/Messages/WidgetClickedMessage.cs +++ b/src/openHAB.Windows/Messages/WidgetClickedMessage.cs @@ -1,7 +1,8 @@ using openHAB.Core.Client.Models; using openHAB.Core.Model; +using openHAB.Windows.ViewModel; -namespace openHAB.Core.Messages +namespace openHAB.Windows.Messages { /// /// A message that fires whenever a widget is clicked on a sitemap. @@ -11,13 +12,16 @@ public class WidgetClickedMessage /// /// Gets or sets the Widget property. /// - public OpenHABWidget Widget { get; set; } + public WidgetViewModel Widget + { + get; set; + } /// /// Initializes a new instance of the class. /// /// The widget that was clicked. - public WidgetClickedMessage(OpenHABWidget widget) + public WidgetClickedMessage(WidgetViewModel widget) { Widget = widget; } diff --git a/src/openHAB.Core/Messages/WigetNavigation.cs b/src/openHAB.Windows/Messages/WidgetNavigationMessage.cs similarity index 54% rename from src/openHAB.Core/Messages/WigetNavigation.cs rename to src/openHAB.Windows/Messages/WidgetNavigationMessage.cs index 697c3532..e9a938f3 100644 --- a/src/openHAB.Core/Messages/WigetNavigation.cs +++ b/src/openHAB.Windows/Messages/WidgetNavigationMessage.cs @@ -1,20 +1,20 @@ using openHAB.Core.Client.Models; -using openHAB.Core.Model; -using Windows.Media.PlayTo; +using openHAB.Core.Messages; +using openHAB.Windows.ViewModel; -namespace openHAB.Core.Messages +namespace openHAB.Windows.Messages { /// /// Represents a navigation between two OpenHAB widgets. /// - public class WigetNavigation + public class WidgetNavigationMessage { /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// The origin widget. /// The target widget. - public WigetNavigation(OpenHABWidget originWidget, OpenHABWidget targetWidget, EventTriggerSource trigger) + public WidgetNavigationMessage(WidgetViewModel originWidget, WidgetViewModel targetWidget, EventTriggerSource trigger) { OriginWidget = originWidget; TargetWidget = targetWidget; @@ -24,16 +24,25 @@ public WigetNavigation(OpenHABWidget originWidget, OpenHABWidget targetWidget, E /// /// Gets or sets the trigger source. /// - public EventTriggerSource Trigger { get; set; } + public EventTriggerSource Trigger + { + get; set; + } /// /// Gets or sets the origin widget. /// - public OpenHABWidget OriginWidget { get; set; } + public WidgetViewModel OriginWidget + { + get; set; + } /// /// Gets or sets the target widget. /// - public OpenHABWidget TargetWidget { get; set; } + public WidgetViewModel TargetWidget + { + get; set; + } } } diff --git a/src/openHAB.Core/Services/WidgetNavigationService.cs b/src/openHAB.Windows/Services/WidgetNavigationService.cs similarity index 72% rename from src/openHAB.Core/Services/WidgetNavigationService.cs rename to src/openHAB.Windows/Services/WidgetNavigationService.cs index a80934df..13dda3da 100644 --- a/src/openHAB.Core/Services/WidgetNavigationService.cs +++ b/src/openHAB.Windows/Services/WidgetNavigationService.cs @@ -1,16 +1,17 @@ using System.Collections.Generic; using System.Linq; using openHAB.Core.Client.Models; +using openHAB.Windows.ViewModel; -namespace openHAB.Core.Services +namespace openHAB.Windows.Services { /// - /// Service that keeps track of navigation between linkedpages. + /// Service that keeps track of navigation between linked pages. /// public static class WidgetNavigationService { - private static readonly Stack WidgetBackStack = new Stack(); - private static OpenHABWidget _currentWidget; + private static readonly Stack WidgetBackStack = new Stack(); + private static WidgetViewModel _currentWidget; /// /// Gets a value indicating whether there is a previous widget on the backstack. @@ -21,7 +22,7 @@ public static class WidgetNavigationService /// Navigates the backstack to the passed in target. /// /// The openHAB widget to navigate to. - public static void Navigate(OpenHABWidget target) + public static void Navigate(WidgetViewModel target) { if (target == _currentWidget) { @@ -35,8 +36,8 @@ public static void Navigate(OpenHABWidget target) /// /// Go back to the previous openHAB widget. /// - /// The previous visted widget. - public static OpenHABWidget GoBack() + /// The previous visited widget. + public static WidgetViewModel GoBack() { if (WidgetBackStack.Count == 0) { @@ -52,10 +53,10 @@ public static OpenHABWidget GoBack() /// /// Go back to the previous openHAB widget. /// - /// The previous visted widget. - public static OpenHABWidget GoBackToRoot() + /// The previous visited widget. + public static WidgetViewModel GoBackToRoot() { - OpenHABWidget widget = GoBack(); + WidgetViewModel widget = GoBack(); while (widget != null && widget.Parent != null) { widget = GoBack(); @@ -77,6 +78,6 @@ public static void ClearWidgetNavigation() /// Gets the navigated widgets. /// The widgets. - public static List Widgets => WidgetBackStack.Reverse().ToList(); + public static List Widgets => WidgetBackStack.Reverse().ToList(); } } diff --git a/src/openHAB.Windows/View/MainPage.xaml.cs b/src/openHAB.Windows/View/MainPage.xaml.cs index b75cc0af..08e404cd 100644 --- a/src/openHAB.Windows/View/MainPage.xaml.cs +++ b/src/openHAB.Windows/View/MainPage.xaml.cs @@ -17,7 +17,7 @@ namespace openHAB.Windows.View /// /// Startup page of the application. /// - public sealed partial class MainPage : Page + public sealed partial class MainPage : Microsoft.UI.Xaml.Controls.Page { /// @@ -27,7 +27,5 @@ public MainPage() { InitializeComponent(); } - - } } \ No newline at end of file diff --git a/src/openHAB.Windows/View/SitemapPage.xaml.cs b/src/openHAB.Windows/View/SitemapPage.xaml.cs index f761dbe2..1d7c37d2 100644 --- a/src/openHAB.Windows/View/SitemapPage.xaml.cs +++ b/src/openHAB.Windows/View/SitemapPage.xaml.cs @@ -6,6 +6,7 @@ using openHAB.Core.Client.Models; using openHAB.Core.Messages; using openHAB.Core.Services; +using openHAB.Windows.Messages; using openHAB.Windows.Services; using openHAB.Windows.ViewModel; @@ -14,7 +15,7 @@ namespace openHAB.Windows.View /// /// An empty page that can be used on its own or navigated to within a Frame. /// - public sealed partial class SitemapPage : Page + public sealed partial class SitemapPage : Microsoft.UI.Xaml.Controls.Page { private SitemapService _sitemapService; private SitemapViewModel _viewModel; @@ -60,8 +61,8 @@ protected async override void OnNavigatedTo(NavigationEventArgs e) StrongReferenceMessenger.Default.Send(new DataOperation(OperationState.Started)); - OpenHABSitemap sitemap = await _sitemapService.GetSitemapByUrlAsync(sitemapUrl); - _viewModel = new SitemapViewModel(sitemap); + Sitemap sitemap = await _sitemapService.GetSitemapByUrlAsync(sitemapUrl); + _viewModel = await SitemapViewModel.CreateAsync(sitemap); DispatcherQueue dispatcherQueue = DispatcherQueue.GetForCurrentThread(); await dispatcherQueue.EnqueueAsync(async () => @@ -81,7 +82,7 @@ private void MasterListView_OnItemClick(object sender, ItemClickEventArgs e) return; } - StrongReferenceMessenger.Default.Send(new WidgetClickedMessage(widgetViewModel.Model)); + StrongReferenceMessenger.Default.Send(new WidgetClickedMessage(widgetViewModel)); } private void OnSitemapChangedEvent(SitemapChanged message) diff --git a/src/openHAB.Windows/ViewModel/MainViewModel.cs b/src/openHAB.Windows/ViewModel/MainViewModel.cs index 986cf6f4..6dff7696 100644 --- a/src/openHAB.Windows/ViewModel/MainViewModel.cs +++ b/src/openHAB.Windows/ViewModel/MainViewModel.cs @@ -1,9 +1,3 @@ -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; using CommunityToolkit.Mvvm.Messaging; using CommunityToolkit.WinUI; using Microsoft.Extensions.Logging; @@ -15,6 +9,14 @@ using openHAB.Core.Model; using openHAB.Core.Services; using openHAB.Core.Services.Contracts; +using openHAB.Windows.Messages; +using openHAB.Windows.Services; +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; namespace openHAB.Windows.ViewModel { @@ -28,11 +30,11 @@ public class MainViewModel : ViewModelBase private readonly ILogger _logger; private readonly SitemapService _sitemapManager; - private ObservableCollection _breadcrumbItems; + private ObservableCollection _breadcrumbItems; private bool _isDataLoading; private object _selectedMenuItem; - private OpenHABSitemap _selectedSitemap; - private ObservableCollection _sitemaps; + private Sitemap _selectedSitemap; + private ObservableCollection _sitemaps; /// /// Initializes a new instance of the class. @@ -47,13 +49,13 @@ public MainViewModel(IOpenHABClient openHABClient, ISettingsService settingsServ _openHABClient = openHABClient; _settingsService = settingsService; - _breadcrumbItems = new ObservableCollection(); + _breadcrumbItems = new ObservableCollection(); _sitemapManager = sitemapManager; StrongReferenceMessenger.Default.Register(this, async (obj, operation) => await DataOperationStateAsync(operation)); - StrongReferenceMessenger.Default.Register(this, (obj, operation) + StrongReferenceMessenger.Default.Register(this, (obj, operation) => WidgetNavigatedEvent()); } @@ -61,7 +63,7 @@ public MainViewModel(IOpenHABClient openHABClient, ISettingsService settingsServ /// Gets or sets the items for the breadcrumb. /// /// The breadcrumb items. - public ObservableCollection BreadcrumbItems + public ObservableCollection BreadcrumbItems { get => _breadcrumbItems; set => Set(ref _breadcrumbItems, value); @@ -90,7 +92,7 @@ public object SelectedMenuItem set { - OpenHABSitemap sitemapInfo = value as OpenHABSitemap; + Sitemap sitemapInfo = value as Sitemap; if (sitemapInfo != null && SelectedSitemap != value) { SelectedSitemap = sitemapInfo; @@ -103,7 +105,7 @@ public object SelectedMenuItem /// /// Gets or sets the sitemap currently selected by the user. /// - public OpenHABSitemap SelectedSitemap + public Sitemap SelectedSitemap { get { @@ -112,6 +114,12 @@ public OpenHABSitemap SelectedSitemap set { + if (_selectedSitemap != value) + { + + StrongReferenceMessenger.Default.Unregister(this, value.Name); + } + if (Set(ref _selectedSitemap, value)) { if (_selectedSitemap != null) @@ -131,7 +139,7 @@ public OpenHABSitemap SelectedSitemap /// /// Gets or sets a collection of OpenHAB sitemaps. /// - public ObservableCollection Sitemaps + public ObservableCollection Sitemaps { get => _sitemaps; set => Set(ref _sitemaps, value); @@ -205,14 +213,14 @@ private async Task LoadData(CancellationToken loadCancellationToken) return; } - List sitemaps = await _sitemapManager.GetSitemapsAsync(loadCancellationToken); + List sitemaps = await _sitemapManager.GetSitemapsAsync(loadCancellationToken); if (sitemaps == null) { StrongReferenceMessenger.Default.Send(new FireInfoMessage(MessageType.NotConfigured)); return; } - Sitemaps = new ObservableCollection(sitemaps); + Sitemaps = new ObservableCollection(sitemaps); _openHABClient.StartItemUpdates(loadCancellationToken); SelectedSitemap = OpenLastOrDefaultSitemap(); @@ -233,7 +241,7 @@ private async Task LoadData(CancellationToken loadCancellationToken) } } - private OpenHABSitemap OpenLastOrDefaultSitemap() + private Sitemap OpenLastOrDefaultSitemap() { Settings settings = _settingsService.Load(); string sitemapName = settings.LastSitemap; @@ -245,7 +253,7 @@ private OpenHABSitemap OpenLastOrDefaultSitemap() return Sitemaps.FirstOrDefault(); } - OpenHABSitemap selectedSitemap = Sitemaps.FirstOrDefault(x => x.Name == sitemapName); + Sitemap selectedSitemap = Sitemaps.FirstOrDefault(x => x.Name == sitemapName); if (SelectedSitemap == null) { _logger.LogInformation($"Unable to find sitemap '{sitemapName}' -> Pick first entry from list"); diff --git a/src/openHAB.Windows/ViewModel/SitemapViewModel.cs b/src/openHAB.Windows/ViewModel/SitemapViewModel.cs index 9c361b06..eae47ad0 100644 --- a/src/openHAB.Windows/ViewModel/SitemapViewModel.cs +++ b/src/openHAB.Windows/ViewModel/SitemapViewModel.cs @@ -12,6 +12,7 @@ using openHAB.Core.Common; using openHAB.Core.Messages; using openHAB.Core.Services; +using openHAB.Windows.Messages; using openHAB.Windows.Services; namespace openHAB.Windows.ViewModel @@ -19,7 +20,7 @@ namespace openHAB.Windows.ViewModel /// /// ViewModel class for the sitemap view. /// - public class SitemapViewModel : ViewModelBase, IDisposable + public class SitemapViewModel : ViewModelBase, IDisposable { private readonly SitemapService _sitemapService; @@ -33,8 +34,8 @@ public class SitemapViewModel : ViewModelBase, IDisposable /// /// Initializes a new instance of the class. /// - public SitemapViewModel() - : base(new OpenHABSitemap()) + private SitemapViewModel() + : base(new Sitemap()) { } @@ -43,10 +44,9 @@ public SitemapViewModel() /// /// Model class for view model. /// openHAB Instance information. - public SitemapViewModel(OpenHABSitemap model) + private SitemapViewModel(Sitemap model, List widgetViewModels) : base(model) { - List widgetViewModels = GetWidgetViewModels(model.Widgets).Result; _widgets = new ObservableCollection(widgetViewModels ?? new List()); _sitemapService = DIService.Instance.GetService(); _currentWidgets = new ObservableCollection(); @@ -59,7 +59,8 @@ public SitemapViewModel(OpenHABSitemap model) return; } - await OnWidgetClickedAsync(new WidgetViewModel(msg.Widget)); + WidgetViewModel viewModel = msg.Widget; + await OnWidgetClickedAsync(viewModel); }); StrongReferenceMessenger.Default.Register(this, async (recipient, msg) @@ -68,7 +69,7 @@ public SitemapViewModel(OpenHABSitemap model) StrongReferenceMessenger.Default.Register(this, (obj, operation) => DataOperationState(operation)); - StrongReferenceMessenger.Default.Register(this, (recipient, msg) => + StrongReferenceMessenger.Default.Register(this, (recipient, msg) => { if (msg.Trigger == EventTriggerSource.Breadcrumb) { @@ -80,23 +81,10 @@ public SitemapViewModel(OpenHABSitemap model) } }); - SetWidgetsOnScreen(Widgets); + SetWidgetsOnScreenAsync(Widgets); } - private async Task> GetWidgetViewModels(ICollection widgets) - { - - List widgetViewModels = new List(); - foreach (OpenHABWidget widget in widgets) - { - WidgetViewModel viewModel = new WidgetViewModel(widget); - widgetViewModels.Add(viewModel); - } - - return widgetViewModels; - } - - #endregion + #endregion Constructors #region Properties @@ -172,14 +160,18 @@ public ObservableCollection Widgets } } - #endregion + #endregion Properties #region Reload Command private ActionCommand _reloadSitemapCommand; - /// Gets the command to reload sitemap and widget data. - /// The refresh command. + /// + /// Gets the command to reload sitemap and widget data. + /// + /// + /// The refresh command. + /// public ActionCommand ReloadSitemapCommand => _reloadSitemapCommand ?? (_reloadSitemapCommand = new ActionCommand(ExecuteReloadSitemapCommand, CanExecuteReloadSitemapCommand)); private bool CanExecuteReloadSitemapCommand(object arg) @@ -192,13 +184,44 @@ private async void ExecuteReloadSitemapCommand(object obj) await ReloadSitemap().ConfigureAwait(false); } - #endregion + private async Task ReloadSitemap() + { + CurrentWidgets?.Clear(); + StrongReferenceMessenger.Default.Send(new DataOperation(OperationState.Started)); + + if (SelectedWidget != null) + { + await LoadWidgetsAsync().ConfigureAwait(false); + WidgetViewModel widget = FindWidget(SelectedWidget.WidgetId, Widgets); + if (widget != null) + { + await OnWidgetClickedAsync(widget); + } + else + { + SelectedWidget = null; + WidgetNavigationService.ClearWidgetNavigation(); + } + } + else + { + await LoadWidgetsAsync().ConfigureAwait(false); + } + + StrongReferenceMessenger.Default.Send(new DataOperation(OperationState.Completed)); + ReloadSitemapCommand.InvokeCanExecuteChanged(null); + } + + #endregion Reload Command #region Navigate To Sitemap Root Command private bool _canExecuteReloadSitemap; private ActionCommand _navigateToSitemapRootCommand; + /// + /// Gets the command to navigate to the root of the sitemap. + /// public ActionCommand NavigateToSitemapRoot => _navigateToSitemapRootCommand ?? (_navigateToSitemapRootCommand = new ActionCommand(ExecuteNavigateToSitemapRootCommand, CanExecuteNavigateToSitemapRootCommand)); @@ -210,13 +233,25 @@ private bool CanExecuteNavigateToSitemapRootCommand(object arg) private void ExecuteNavigateToSitemapRootCommand(object obj) { WidgetNavigationService.ClearWidgetNavigation(); - SetWidgetsOnScreen(Widgets); + SetWidgetsOnScreenAsync(Widgets); SelectedWidget = null; - StrongReferenceMessenger.Default.Send(new WigetNavigation(SelectedWidget.Model, null, EventTriggerSource.Widget)); + StrongReferenceMessenger.Default.Send(new WidgetNavigationMessage(SelectedWidget, null, EventTriggerSource.Widget), Model.Name); } - #endregion + private static async Task> GetWidgetViewModels(ICollection widgets) + { + List widgetViewModels = new List(); + foreach (Widget widget in widgets) + { + WidgetViewModel viewModel = await WidgetViewModel.CreateAsync(widget).ConfigureAwait(false); + widgetViewModels.Add(viewModel); + } + + return widgetViewModels; + } + + #endregion Navigate To Sitemap Root Command #region Events @@ -227,6 +262,7 @@ private void DataOperationState(DataOperation operation) case OperationState.Started: _canExecuteReloadSitemap = true; break; + case OperationState.Completed: _canExecuteReloadSitemap = false; break; @@ -245,47 +281,54 @@ private async Task TriggerItemCommand(TriggerCommandMessage message) } } - #endregion + #endregion Events + + #region Factory + + /// + /// Creates a new instance of the class asynchronously. + /// + /// The OpenHABSitemap object. + /// A task that represents the asynchronous operation. The task result contains the created SitemapViewModel. + public static async Task CreateAsync(Sitemap sitemap) + { + if (sitemap.Homepage?.Widgets == null || + sitemap.Homepage.Widgets.Count == 0) + { + return new SitemapViewModel(sitemap, new List()); + } + + List widgetViewModels = await GetWidgetViewModels(sitemap.Homepage.Widgets).ConfigureAwait(false); + SitemapViewModel viewModel = new SitemapViewModel(sitemap, widgetViewModels); + + return viewModel; + } private async Task LoadWidgetsAsync() { this.Widgets = new ObservableCollection(); CurrentWidgets?.Clear(); - ICollection widgetModels = await _sitemapService.LoadItemsFromSitemapAsync(Model).ConfigureAwait(false); - widgetModels.ToList().ForEach(model => Widgets.Add(new WidgetViewModel(model))); + ICollection widgetModels = await _sitemapService.LoadItemsFromSitemapAsync(Model).ConfigureAwait(false); + Widgets = new ObservableCollection(ConvertWidgetToViewModel(widgetModels)); - SetWidgetsOnScreen(this.Widgets); + await SetWidgetsOnScreenAsync(this.Widgets); } - private async Task ReloadSitemap() + private List ConvertWidgetToViewModel(ICollection widgetModels) { - CurrentWidgets?.Clear(); - StrongReferenceMessenger.Default.Send(new DataOperation(OperationState.Started)); - - if (SelectedWidget != null) - { - await LoadWidgetsAsync().ConfigureAwait(false); - WidgetViewModel widget = FindWidget(SelectedWidget.WidgetId, Widgets); - if (widget != null) - { - await OnWidgetClickedAsync(widget); - } - else - { - SelectedWidget = null; - WidgetNavigationService.ClearWidgetNavigation(); - } - } - else + List widgetViewModels = new List(); + widgetModels.ToList().ForEach(async model => { - await LoadWidgetsAsync().ConfigureAwait(false); - } + WidgetViewModel viewModel = await WidgetViewModel.CreateAsync(model).ConfigureAwait(false); + widgetViewModels.Add(viewModel); + }); - StrongReferenceMessenger.Default.Send(new DataOperation(OperationState.Completed)); - ReloadSitemapCommand.InvokeCanExecuteChanged(null); + return widgetViewModels; } + #endregion Factory + #region Widget interaction private WidgetViewModel FindWidget(string widgetId, ICollection widgets) @@ -303,7 +346,7 @@ private WidgetViewModel FindWidget(string widgetId, ICollection return widget; } - ICollection childWidgets = widget.Type.CompareTo("Group") == 0 ? widget.LinkedPage?.Widgets : widget.Children; + ICollection childWidgets = widget.Type.CompareTo("Group") == 0 ? ConvertWidgetToViewModel(widget.LinkedPage?.Widgets) : widget.Children; openHABWidget = FindWidget(widgetId, childWidgets); if (openHABWidget != null) { @@ -316,7 +359,7 @@ private WidgetViewModel FindWidget(string widgetId, ICollection private async Task OnWidgetClickedAsync(WidgetViewModel widget) { - await App.DispatcherQueue.EnqueueAsync(() => + await App.DispatcherQueue.EnqueueAsync(async () => { WidgetViewModel lastWidget = SelectedWidget; SelectedWidget = widget; @@ -325,41 +368,51 @@ await App.DispatcherQueue.EnqueueAsync(() => return; } - WidgetNavigationService.Navigate(SelectedWidget.Model); - StrongReferenceMessenger.Default.Send(new WigetNavigation(lastWidget.Model, widget.Model, EventTriggerSource.Widget)); + WidgetNavigationService.Navigate(SelectedWidget); + StrongReferenceMessenger.Default.Send(new WidgetNavigationMessage(lastWidget, widget, EventTriggerSource.Widget)); - SetWidgetsOnScreen(SelectedWidget.LinkedPage.Widgets); + List widgets = ConvertWidgetToViewModel(SelectedWidget.LinkedPage.Widgets); + await SetWidgetsOnScreenAsync(widgets); }); } - private async void SetWidgetsOnScreen(ICollection widgets) + private async Task SetWidgetsOnScreenAsync(ICollection widgets) { await App.DispatcherQueue.EnqueueAsync(() => { - CurrentWidgets.Clear(); - CurrentWidgets.AddRange(widgets); + CurrentWidgets?.Clear(); + CurrentWidgets?.AddRange(widgets); }); } - private void WidgetGoBack(OpenHABWidget widget) + private async Task WidgetGoBack(WidgetViewModel widget) { + if (!WidgetNavigationService.CanGoBack) + { + return; + } + WidgetViewModel lastWidget = SelectedWidget; WidgetViewModel widgetFromStack = null; - while (widgetFromStack == null || widgetFromStack.WidgetId != widget.WidgetId) + while (widgetFromStack?.WidgetId != widget.WidgetId) { - widgetFromStack = new WidgetViewModel(WidgetNavigationService.GoBack()); + widgetFromStack = WidgetNavigationService.GoBack(); } SelectedWidget = widgetFromStack; - WidgetNavigationService.Navigate(SelectedWidget.Model); - StrongReferenceMessenger.Default.Send(new WigetNavigation(lastWidget.Model, SelectedWidget.Model, EventTriggerSource.Widget)); + WidgetNavigationService.Navigate(SelectedWidget); + StrongReferenceMessenger.Default.Send(new WidgetNavigationMessage(lastWidget, SelectedWidget, EventTriggerSource.Widget)); - SetWidgetsOnScreen(SelectedWidget.LinkedPage.Widgets); + List widgets = ConvertWidgetToViewModel(SelectedWidget.LinkedPage.Widgets); + await SetWidgetsOnScreenAsync(widgets); } - #endregion + + #endregion Widget interaction #region Dispose + + /// public void Dispose() { // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method @@ -376,18 +429,17 @@ protected virtual void Dispose(bool disposing) StrongReferenceMessenger.Default.Unregister(this); StrongReferenceMessenger.Default.Unregister(this); StrongReferenceMessenger.Default.Unregister(this); - StrongReferenceMessenger.Default.Unregister(this); + StrongReferenceMessenger.Default.Unregister(this, Model.Name); Widgets = null; CurrentWidgets = null; SelectedWidget = null; } - // TODO: free unmanaged resources (unmanaged objects) and override finalizer - // TODO: set large fields to null disposedValue = true; } } - #endregion + + #endregion Dispose } } \ No newline at end of file diff --git a/src/openHAB.Windows/ViewModel/WidgetViewModel.cs b/src/openHAB.Windows/ViewModel/WidgetViewModel.cs index e05bcb28..f2623093 100644 --- a/src/openHAB.Windows/ViewModel/WidgetViewModel.cs +++ b/src/openHAB.Windows/ViewModel/WidgetViewModel.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using System.Linq; +using System.Collections.ObjectModel; using System.Threading.Tasks; using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Markup; @@ -15,21 +15,18 @@ namespace openHAB.Windows.ViewModel /// /// Represents the view model for a widget in the openHAB application. /// - public class WidgetViewModel : ViewModelBase + public class WidgetViewModel : ViewModelBase { + private ObservableCollection _children; + private string _iconPath; /// /// Initializes a new instance of the class. /// /// The underlying model for the widget. - public WidgetViewModel(OpenHABWidget model) + private WidgetViewModel(Widget model) : base(model) { - List children = new List(); - Model.Children.ToList().ForEach(w => children.Add(new WidgetViewModel(w))); - Children = children; - - LinkedPage = Model.LinkedPage != null ? new SitemapViewModel(Model.LinkedPage) : null; - IconPath = "C:\\Users\\ChristophHofmann\\AppData\\Local\\openHAB\\icons\\radiator.png"; //CacheAndRetriveLocalIconPath(Model.Icon).Result; + Children = new ObservableCollection(); } #region Properties @@ -37,9 +34,18 @@ public WidgetViewModel(OpenHABWidget model) /// /// Gets the collection of child widgets. /// - public ICollection Children + public ObservableCollection Children { - get; internal set; + get => _children; + set => Set(ref _children, value); + } + + /// + /// Gets the encoding of the widget. + /// + public string Encoding + { + get => Model.Encoding; } /// @@ -55,13 +61,14 @@ public string Icon /// public string IconPath { - get; internal set; + get => _iconPath; + set => Set(ref _iconPath, value); } /// /// Gets the item associated with the widget. /// - public OpenHABItem Item + public Item Item { get => Model.Item; } @@ -90,7 +97,7 @@ public SolidColorBrush LabelColor /// /// Gets the linked page of the widget. /// - public SitemapViewModel LinkedPage + public Page LinkedPage { get; internal set; } @@ -98,7 +105,7 @@ public SitemapViewModel LinkedPage /// /// Gets the collection of mappings for the widget. /// - public ICollection Mappings + public ICollection Mappings { get => Model.Mappings; } @@ -119,6 +126,12 @@ public float MinValue get => Model.MinValue; } + public WidgetViewModel Parent + { + get; + internal set; + } + /// /// Gets the period for the widget. /// @@ -132,17 +145,12 @@ public string Period /// public int Refresh { - get => Model.Refresh; + get => (int)Model.Refresh; } /// - /// Gets the step value for the widget. + /// Gets or sets the state of the widget. /// - public float Step - { - get => Model.Step; - } - public string State { get => Model.State; @@ -158,6 +166,14 @@ public string State } } + /// + /// Gets the step value for the widget. + /// + public float Step + { + get => Model.Step; + } + /// /// Gets the type of the widget. /// @@ -204,6 +220,14 @@ public SolidColorBrush ValueColor } } + /// + /// Gets the visibility of the widget. + /// + public Visibility Visibility + { + get => Model.Visibility ? Visibility.Visible : Visibility.Collapsed; + } + /// /// Gets the ID of the widget. /// @@ -211,34 +235,63 @@ public string WidgetId { get => Model.WidgetId; } + #endregion + + #region Factory /// - /// Gets the visibility of the widget. + /// Creates a new instance of the class asynchronously. /// - public Visibility Visibility + /// The underlying model for the widget. + /// A task that represents the asynchronous operation. The task result contains the created . + public static async Task CreateAsync(Widget model) { - get => Model.Visibility ? Visibility.Visible : Visibility.Collapsed; + WidgetViewModel viewModel = new WidgetViewModel(model); + viewModel.LoadData(); + + return viewModel; } - public string Encoding + /// + /// Loads the data for the widget asynchronously. + /// + /// A task that represents the asynchronous operation. + private async Task LoadData() { - get => Model.Encoding; - } + if (!string.IsNullOrEmpty(Model.Icon)) + { + IconPath = await CacheAndRetrieveLocalIconPath(Model.Icon); + } - #endregion + if (Model.LinkedPage != null) + { + LinkedPage = Model.LinkedPage; + } - private async Task CacheAndRetriveLocalIconPath(string icon) + ObservableCollection widgets = new ObservableCollection(); + foreach (Widget w in Model.Children) + { + WidgetViewModel viewModel = await WidgetViewModel.CreateAsync(w); + widgets.Add(viewModel); + } + + Children = widgets; + } + + private async Task CacheAndRetrieveLocalIconPath(string icon) { IIconCaching iconCaching = DIService.Instance.GetService(); ISettingsService settingsService = DIService.Instance.GetService(); Settings setting = settingsService.Load(); - string iconFormat = setting.UseSVGIcons ? "svg" : "png"; + string iconFormat = setting.UseSVGIcons ? "svg" : "svg"; string path = await iconCaching.ResolveIconPath(icon, Model.State, iconFormat).ConfigureAwait(false); return path; } + #endregion + private Color ConvertColorCodeToColor(string value) { if (string.IsNullOrEmpty(value)) diff --git a/src/openHAB.Windows/openHAB.Windows.csproj b/src/openHAB.Windows/openHAB.Windows.csproj index c95991e8..2ee80e5e 100644 --- a/src/openHAB.Windows/openHAB.Windows.csproj +++ b/src/openHAB.Windows/openHAB.Windows.csproj @@ -57,8 +57,8 @@ - - + + 8.0.0 runtime; build; native; contentfiles; analyzers; buildtransitive @@ -70,7 +70,7 @@ - 1.4.231219000 + 1.5.240311000