From 495ce74149606bd1375e028ddd3a5620f165d27d Mon Sep 17 00:00:00 2001 From: Ryan Wagoner Date: Wed, 2 Nov 2022 18:09:33 -0400 Subject: [PATCH] 1.1.14 - Improve MQTT unit, output and flag capabilities --- OmniLinkBridge/Extensions.cs | 36 +--------- OmniLinkBridge/Global.cs | 1 + OmniLinkBridge/MQTT/Extensions.cs | 65 +++++++++++++++++ .../MQTT/{ => HomeAssistant}/Alarm.cs | 2 +- .../MQTT/{ => HomeAssistant}/BinarySensor.cs | 2 +- .../MQTT/{ => HomeAssistant}/Climate.cs | 2 +- .../MQTT/{ => HomeAssistant}/Device.cs | 2 +- .../{ => HomeAssistant}/DeviceRegistry.cs | 2 +- .../MQTT/{ => HomeAssistant}/Light.cs | 2 +- OmniLinkBridge/MQTT/HomeAssistant/Number.cs | 18 +++++ .../MQTT/{ => HomeAssistant}/Sensor.cs | 2 +- .../MQTT/{ => HomeAssistant}/Switch.cs | 2 +- OmniLinkBridge/MQTT/MappingExtensions.cs | 16 +++++ OmniLinkBridge/MQTT/MessageProcessor.cs | 15 ++-- OmniLinkBridge/MQTT/Number.cs | 12 ---- OmniLinkBridge/MQTT/OverrideUnit.cs | 7 ++ OmniLinkBridge/MQTT/OverrideZone.cs | 4 +- .../MQTT/{ => Parser}/AlarmCommands.cs | 2 +- .../MQTT/{ => Parser}/AreaCommands.cs | 2 +- .../MQTT/{ => Parser}/CommandTypes.cs | 2 +- .../MQTT/{ => Parser}/MessageCommands.cs | 2 +- OmniLinkBridge/MQTT/{ => Parser}/Topic.cs | 4 +- .../MQTT/{ => Parser}/UnitCommands.cs | 2 +- .../MQTT/{ => Parser}/ZoneCommands.cs | 2 +- OmniLinkBridge/MQTT/UnitType.cs | 9 +++ OmniLinkBridge/Modules/LoggerModule.cs | 70 +++++++++++++++---- OmniLinkBridge/Modules/MQTTModule.cs | 38 +++++++--- OmniLinkBridge/Modules/OmniLinkII.cs | 11 +-- OmniLinkBridge/Modules/TimeSyncModule.cs | 10 +-- OmniLinkBridge/OmniLinkBridge.csproj | 35 +++++----- OmniLinkBridge/OmniLinkBridge.csproj.user | 3 + OmniLinkBridge/OmniLinkBridge.ini | 15 +++- OmniLinkBridge/Properties/AssemblyInfo.cs | 4 +- OmniLinkBridge/Settings.cs | 49 ++++++++++++- OmniLinkBridgeTest/ExtensionTest.cs | 6 +- OmniLinkBridgeTest/MQTTTest.cs | 31 ++++++-- OmniLinkBridgeTest/Mock/MockOmniLinkII.cs | 4 -- .../Mock/SendCommandEventArgs.cs | 4 -- OmniLinkBridgeTest/NotificationTest.cs | 7 +- OmniLinkBridgeTest/SettingsTest.cs | 30 ++++++-- README.md | 6 +- 41 files changed, 388 insertions(+), 150 deletions(-) create mode 100644 OmniLinkBridge/MQTT/Extensions.cs rename OmniLinkBridge/MQTT/{ => HomeAssistant}/Alarm.cs (89%) rename OmniLinkBridge/MQTT/{ => HomeAssistant}/BinarySensor.cs (95%) rename OmniLinkBridge/MQTT/{ => HomeAssistant}/Climate.cs (96%) rename OmniLinkBridge/MQTT/{ => HomeAssistant}/Device.cs (96%) rename OmniLinkBridge/MQTT/{ => HomeAssistant}/DeviceRegistry.cs (85%) rename OmniLinkBridge/MQTT/{ => HomeAssistant}/Light.cs (85%) create mode 100644 OmniLinkBridge/MQTT/HomeAssistant/Number.cs rename OmniLinkBridge/MQTT/{ => HomeAssistant}/Sensor.cs (94%) rename OmniLinkBridge/MQTT/{ => HomeAssistant}/Switch.cs (91%) delete mode 100644 OmniLinkBridge/MQTT/Number.cs create mode 100644 OmniLinkBridge/MQTT/OverrideUnit.cs rename OmniLinkBridge/MQTT/{ => Parser}/AlarmCommands.cs (71%) rename OmniLinkBridge/MQTT/{ => Parser}/AreaCommands.cs (85%) rename OmniLinkBridge/MQTT/{ => Parser}/CommandTypes.cs (76%) rename OmniLinkBridge/MQTT/{ => Parser}/MessageCommands.cs (75%) rename OmniLinkBridge/MQTT/{ => Parser}/Topic.cs (90%) rename OmniLinkBridge/MQTT/{ => Parser}/UnitCommands.cs (60%) rename OmniLinkBridge/MQTT/{ => Parser}/ZoneCommands.cs (63%) create mode 100644 OmniLinkBridge/MQTT/UnitType.cs diff --git a/OmniLinkBridge/Extensions.cs b/OmniLinkBridge/Extensions.cs index ff7453c..117e719 100644 --- a/OmniLinkBridge/Extensions.cs +++ b/OmniLinkBridge/Extensions.cs @@ -1,5 +1,4 @@ -using OmniLinkBridge.MQTT; -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; @@ -24,39 +23,6 @@ namespace OmniLinkBridge { return (b & (1 << pos)) != 0; } - - public static AreaCommandCode ToCommandCode(this string payload, bool supportValidate = false) - { - string[] payloads = payload.Split(','); - int code = 0; - - AreaCommandCode ret = new AreaCommandCode() - { - Command = payloads[0] - }; - - if (payload.Length == 1) - return ret; - - if (payloads.Length == 2) - { - ret.Success = int.TryParse(payloads[1], out code); - } - else if (supportValidate && payloads.Length == 3) - { - if (string.Compare(payloads[1], "validate", true) == 0) - { - ret.Validate = true; - ret.Success = int.TryParse(payloads[2], out code); - } - else - ret.Success = false; - } - - ret.Code = code; - return ret; - } - public static string ToSpaceTitleCase(this string phrase) { return Regex.Replace(phrase, "(\\B[A-Z])", " $1"); diff --git a/OmniLinkBridge/Global.cs b/OmniLinkBridge/Global.cs index b52d525..1136103 100644 --- a/OmniLinkBridge/Global.cs +++ b/OmniLinkBridge/Global.cs @@ -55,6 +55,7 @@ namespace OmniLinkBridge public static HashSet mqtt_discovery_ignore_units; public static HashSet mqtt_discovery_area_code_required; public static ConcurrentDictionary mqtt_discovery_override_zone; + public static ConcurrentDictionary mqtt_discovery_override_unit; // Notifications public static bool notify_area; diff --git a/OmniLinkBridge/MQTT/Extensions.cs b/OmniLinkBridge/MQTT/Extensions.cs new file mode 100644 index 0000000..7dcf2f9 --- /dev/null +++ b/OmniLinkBridge/MQTT/Extensions.cs @@ -0,0 +1,65 @@ +using HAI_Shared; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace OmniLinkBridge.MQTT +{ + public static class Extensions + { + public static AreaCommandCode ToCommandCode(this string payload, bool supportValidate = false) + { + string[] payloads = payload.Split(','); + int code = 0; + + AreaCommandCode ret = new AreaCommandCode() + { + Command = payloads[0] + }; + + if (payload.Length == 1) + return ret; + + if (payloads.Length == 2) + { + ret.Success = int.TryParse(payloads[1], out code); + } + else if (supportValidate && payloads.Length == 3) + { + if (string.Compare(payloads[1], "validate", true) == 0) + { + ret.Validate = true; + ret.Success = int.TryParse(payloads[2], out code); + } + else + ret.Success = false; + } + + ret.Code = code; + return ret; + } + + public static UnitType ToUnitType(this clsUnit unit) + { + Global.mqtt_discovery_override_unit.TryGetValue(unit.Number, out OverrideUnit override_unit); + + if (unit.Type == enuOL2UnitType.Output) + return UnitType.@switch; + + if (unit.Type == enuOL2UnitType.Flag) + { + if (override_unit != null && override_unit.type == UnitType.number) + return UnitType.number; + + return UnitType.@switch; + } + + if (override_unit != null && override_unit.type == UnitType.@switch) + return UnitType.@switch; + + return UnitType.light; + } + } +} diff --git a/OmniLinkBridge/MQTT/Alarm.cs b/OmniLinkBridge/MQTT/HomeAssistant/Alarm.cs similarity index 89% rename from OmniLinkBridge/MQTT/Alarm.cs rename to OmniLinkBridge/MQTT/HomeAssistant/Alarm.cs index 9d2a9ef..51ec3d7 100644 --- a/OmniLinkBridge/MQTT/Alarm.cs +++ b/OmniLinkBridge/MQTT/HomeAssistant/Alarm.cs @@ -1,7 +1,7 @@ using Newtonsoft.Json; using Newtonsoft.Json.Converters; -namespace OmniLinkBridge.MQTT +namespace OmniLinkBridge.MQTT.HomeAssistant { public class Alarm : Device { diff --git a/OmniLinkBridge/MQTT/BinarySensor.cs b/OmniLinkBridge/MQTT/HomeAssistant/BinarySensor.cs similarity index 95% rename from OmniLinkBridge/MQTT/BinarySensor.cs rename to OmniLinkBridge/MQTT/HomeAssistant/BinarySensor.cs index 8dc1370..748d353 100644 --- a/OmniLinkBridge/MQTT/BinarySensor.cs +++ b/OmniLinkBridge/MQTT/HomeAssistant/BinarySensor.cs @@ -1,7 +1,7 @@ using Newtonsoft.Json; using Newtonsoft.Json.Converters; -namespace OmniLinkBridge.MQTT +namespace OmniLinkBridge.MQTT.HomeAssistant { public class BinarySensor : Device { diff --git a/OmniLinkBridge/MQTT/Climate.cs b/OmniLinkBridge/MQTT/HomeAssistant/Climate.cs similarity index 96% rename from OmniLinkBridge/MQTT/Climate.cs rename to OmniLinkBridge/MQTT/HomeAssistant/Climate.cs index 6eb260b..dba39fc 100644 --- a/OmniLinkBridge/MQTT/Climate.cs +++ b/OmniLinkBridge/MQTT/HomeAssistant/Climate.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; -namespace OmniLinkBridge.MQTT +namespace OmniLinkBridge.MQTT.HomeAssistant { public class Climate : Device { diff --git a/OmniLinkBridge/MQTT/Device.cs b/OmniLinkBridge/MQTT/HomeAssistant/Device.cs similarity index 96% rename from OmniLinkBridge/MQTT/Device.cs rename to OmniLinkBridge/MQTT/HomeAssistant/Device.cs index 1a9e4fd..a1a9541 100644 --- a/OmniLinkBridge/MQTT/Device.cs +++ b/OmniLinkBridge/MQTT/HomeAssistant/Device.cs @@ -3,7 +3,7 @@ using Newtonsoft.Json.Converters; using OmniLinkBridge.Modules; using System.Collections.Generic; -namespace OmniLinkBridge.MQTT +namespace OmniLinkBridge.MQTT.HomeAssistant { public class Device { diff --git a/OmniLinkBridge/MQTT/DeviceRegistry.cs b/OmniLinkBridge/MQTT/HomeAssistant/DeviceRegistry.cs similarity index 85% rename from OmniLinkBridge/MQTT/DeviceRegistry.cs rename to OmniLinkBridge/MQTT/HomeAssistant/DeviceRegistry.cs index 4b6e843..4b4fc4d 100644 --- a/OmniLinkBridge/MQTT/DeviceRegistry.cs +++ b/OmniLinkBridge/MQTT/HomeAssistant/DeviceRegistry.cs @@ -1,4 +1,4 @@ -namespace OmniLinkBridge.MQTT +namespace OmniLinkBridge.MQTT.HomeAssistant { public class DeviceRegistry { diff --git a/OmniLinkBridge/MQTT/Light.cs b/OmniLinkBridge/MQTT/HomeAssistant/Light.cs similarity index 85% rename from OmniLinkBridge/MQTT/Light.cs rename to OmniLinkBridge/MQTT/HomeAssistant/Light.cs index 6ffff7f..184f569 100644 --- a/OmniLinkBridge/MQTT/Light.cs +++ b/OmniLinkBridge/MQTT/HomeAssistant/Light.cs @@ -1,4 +1,4 @@ -namespace OmniLinkBridge.MQTT +namespace OmniLinkBridge.MQTT.HomeAssistant { public class Light : Device { diff --git a/OmniLinkBridge/MQTT/HomeAssistant/Number.cs b/OmniLinkBridge/MQTT/HomeAssistant/Number.cs new file mode 100644 index 0000000..060c5e8 --- /dev/null +++ b/OmniLinkBridge/MQTT/HomeAssistant/Number.cs @@ -0,0 +1,18 @@ +using Newtonsoft.Json; + +namespace OmniLinkBridge.MQTT.HomeAssistant +{ + public class Number : Device + { + public string command_topic { get; set; } + + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + public string icon { get; set; } + + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + public int? min { get; set; } + + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + public int? max { get; set; } + } +} diff --git a/OmniLinkBridge/MQTT/Sensor.cs b/OmniLinkBridge/MQTT/HomeAssistant/Sensor.cs similarity index 94% rename from OmniLinkBridge/MQTT/Sensor.cs rename to OmniLinkBridge/MQTT/HomeAssistant/Sensor.cs index 0d11500..f4b1f1a 100644 --- a/OmniLinkBridge/MQTT/Sensor.cs +++ b/OmniLinkBridge/MQTT/HomeAssistant/Sensor.cs @@ -1,7 +1,7 @@ using Newtonsoft.Json; using Newtonsoft.Json.Converters; -namespace OmniLinkBridge.MQTT +namespace OmniLinkBridge.MQTT.HomeAssistant { public class Sensor : Device { diff --git a/OmniLinkBridge/MQTT/Switch.cs b/OmniLinkBridge/MQTT/HomeAssistant/Switch.cs similarity index 91% rename from OmniLinkBridge/MQTT/Switch.cs rename to OmniLinkBridge/MQTT/HomeAssistant/Switch.cs index 5a1e332..454bba5 100644 --- a/OmniLinkBridge/MQTT/Switch.cs +++ b/OmniLinkBridge/MQTT/HomeAssistant/Switch.cs @@ -1,6 +1,6 @@ using Newtonsoft.Json; -namespace OmniLinkBridge.MQTT +namespace OmniLinkBridge.MQTT.HomeAssistant { public class Switch : Device { diff --git a/OmniLinkBridge/MQTT/MappingExtensions.cs b/OmniLinkBridge/MQTT/MappingExtensions.cs index 22288e4..b577d0a 100644 --- a/OmniLinkBridge/MQTT/MappingExtensions.cs +++ b/OmniLinkBridge/MQTT/MappingExtensions.cs @@ -1,6 +1,8 @@ using HAI_Shared; using Newtonsoft.Json; using System.Collections.Generic; +using OmniLinkBridge.MQTT.HomeAssistant; +using OmniLinkBridge.MQTT.Parser; namespace OmniLinkBridge.MQTT { @@ -399,6 +401,20 @@ namespace OmniLinkBridge.MQTT return ret; } + public static Number ToConfigNumber(this clsUnit unit) + { + Number ret = new Number + { + unique_id = $"{Global.mqtt_prefix}unit{unit.Number}number", + name = Global.mqtt_discovery_name_prefix + unit.Name, + state_topic = unit.ToTopic(Topic.flag_state), + command_topic = unit.ToTopic(Topic.flag_command), + min = 0, + max = 255 + }; + return ret; + } + public static string ToState(this clsUnit unit) { return unit.Status == 0 || unit.Status == 100 ? UnitCommands.OFF.ToString() : UnitCommands.ON.ToString(); diff --git a/OmniLinkBridge/MQTT/MessageProcessor.cs b/OmniLinkBridge/MQTT/MessageProcessor.cs index 519dac8..a1e96e6 100644 --- a/OmniLinkBridge/MQTT/MessageProcessor.cs +++ b/OmniLinkBridge/MQTT/MessageProcessor.cs @@ -1,4 +1,5 @@ using HAI_Shared; +using OmniLinkBridge.MQTT.Parser; using OmniLinkBridge.OmniLink; using Serilog; using System; @@ -167,10 +168,16 @@ namespace OmniLinkBridge.MQTT OmniLink.SendCommand(UnitMapping[cmd], 0, (ushort)unit.Number); } } - else if (command == Topic.brightness_command && int.TryParse(payload, out int unitValue)) + else if (unit.Type == enuOL2UnitType.Flag && + command == Topic.flag_command && int.TryParse(payload, out int flagValue)) + { + log.Debug("SetUnit: {id} to {value}", unit.Number, payload); + OmniLink.SendCommand(enuUnitCommand.Set, BitConverter.GetBytes(flagValue)[0], (ushort)unit.Number); + } + else if (unit.Type != enuOL2UnitType.Output && + command == Topic.brightness_command && int.TryParse(payload, out int unitValue)) { log.Debug("SetUnit: {id} to {value}%", unit.Number, payload); - OmniLink.SendCommand(enuUnitCommand.Level, BitConverter.GetBytes(unitValue)[0], (ushort)unit.Number); // Force status change instead of waiting on controller to update @@ -178,10 +185,10 @@ namespace OmniLinkBridge.MQTT // which will cause light to go to 100% brightness unit.Status = (byte)(100 + unitValue); } - else if (command == Topic.scene_command && char.TryParse(payload, out char scene)) + else if (unit.Type != enuOL2UnitType.Output && + command == Topic.scene_command && char.TryParse(payload, out char scene)) { log.Debug("SetUnit: {id} to {value}", unit.Number, payload); - OmniLink.SendCommand(enuUnitCommand.Compose, (byte)(scene - 63), (ushort)unit.Number); } } diff --git a/OmniLinkBridge/MQTT/Number.cs b/OmniLinkBridge/MQTT/Number.cs deleted file mode 100644 index 7f98065..0000000 --- a/OmniLinkBridge/MQTT/Number.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Newtonsoft.Json; - -namespace OmniLinkBridge.MQTT -{ - public class Number : Device - { - public string command_topic { get; set; } - - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] - public string icon { get; set; } - } -} diff --git a/OmniLinkBridge/MQTT/OverrideUnit.cs b/OmniLinkBridge/MQTT/OverrideUnit.cs new file mode 100644 index 0000000..22c480e --- /dev/null +++ b/OmniLinkBridge/MQTT/OverrideUnit.cs @@ -0,0 +1,7 @@ +namespace OmniLinkBridge.MQTT +{ + public class OverrideUnit + { + public UnitType type { get; set; } + } +} diff --git a/OmniLinkBridge/MQTT/OverrideZone.cs b/OmniLinkBridge/MQTT/OverrideZone.cs index 0d00e9d..b07cc88 100644 --- a/OmniLinkBridge/MQTT/OverrideZone.cs +++ b/OmniLinkBridge/MQTT/OverrideZone.cs @@ -1,4 +1,6 @@ -namespace OmniLinkBridge.MQTT +using OmniLinkBridge.MQTT.HomeAssistant; + +namespace OmniLinkBridge.MQTT { public class OverrideZone { diff --git a/OmniLinkBridge/MQTT/AlarmCommands.cs b/OmniLinkBridge/MQTT/Parser/AlarmCommands.cs similarity index 71% rename from OmniLinkBridge/MQTT/AlarmCommands.cs rename to OmniLinkBridge/MQTT/Parser/AlarmCommands.cs index ce12964..b063063 100644 --- a/OmniLinkBridge/MQTT/AlarmCommands.cs +++ b/OmniLinkBridge/MQTT/Parser/AlarmCommands.cs @@ -1,4 +1,4 @@ -namespace OmniLinkBridge.MQTT +namespace OmniLinkBridge.MQTT.Parser { enum AlarmCommands { diff --git a/OmniLinkBridge/MQTT/AreaCommands.cs b/OmniLinkBridge/MQTT/Parser/AreaCommands.cs similarity index 85% rename from OmniLinkBridge/MQTT/AreaCommands.cs rename to OmniLinkBridge/MQTT/Parser/AreaCommands.cs index 568b622..690a3fa 100644 --- a/OmniLinkBridge/MQTT/AreaCommands.cs +++ b/OmniLinkBridge/MQTT/Parser/AreaCommands.cs @@ -1,4 +1,4 @@ -namespace OmniLinkBridge.MQTT +namespace OmniLinkBridge.MQTT.Parser { enum AreaCommands { diff --git a/OmniLinkBridge/MQTT/CommandTypes.cs b/OmniLinkBridge/MQTT/Parser/CommandTypes.cs similarity index 76% rename from OmniLinkBridge/MQTT/CommandTypes.cs rename to OmniLinkBridge/MQTT/Parser/CommandTypes.cs index 693aaab..99e42f5 100644 --- a/OmniLinkBridge/MQTT/CommandTypes.cs +++ b/OmniLinkBridge/MQTT/Parser/CommandTypes.cs @@ -1,4 +1,4 @@ -namespace OmniLinkBridge.MQTT +namespace OmniLinkBridge.MQTT.Parser { enum CommandTypes { diff --git a/OmniLinkBridge/MQTT/MessageCommands.cs b/OmniLinkBridge/MQTT/Parser/MessageCommands.cs similarity index 75% rename from OmniLinkBridge/MQTT/MessageCommands.cs rename to OmniLinkBridge/MQTT/Parser/MessageCommands.cs index a5c44f8..bfb5039 100644 --- a/OmniLinkBridge/MQTT/MessageCommands.cs +++ b/OmniLinkBridge/MQTT/Parser/MessageCommands.cs @@ -1,4 +1,4 @@ -namespace OmniLinkBridge.MQTT +namespace OmniLinkBridge.MQTT.Parser { enum MessageCommands { diff --git a/OmniLinkBridge/MQTT/Topic.cs b/OmniLinkBridge/MQTT/Parser/Topic.cs similarity index 90% rename from OmniLinkBridge/MQTT/Topic.cs rename to OmniLinkBridge/MQTT/Parser/Topic.cs index 96f9af3..bea3ddb 100644 --- a/OmniLinkBridge/MQTT/Topic.cs +++ b/OmniLinkBridge/MQTT/Parser/Topic.cs @@ -1,4 +1,4 @@ -namespace OmniLinkBridge.MQTT +namespace OmniLinkBridge.MQTT.Parser { public enum Topic { @@ -11,6 +11,8 @@ json_state, brightness_state, brightness_command, + flag_state, + flag_command, scene_state, scene_command, current_operation, diff --git a/OmniLinkBridge/MQTT/UnitCommands.cs b/OmniLinkBridge/MQTT/Parser/UnitCommands.cs similarity index 60% rename from OmniLinkBridge/MQTT/UnitCommands.cs rename to OmniLinkBridge/MQTT/Parser/UnitCommands.cs index bcb7b78..5da93c1 100644 --- a/OmniLinkBridge/MQTT/UnitCommands.cs +++ b/OmniLinkBridge/MQTT/Parser/UnitCommands.cs @@ -1,4 +1,4 @@ -namespace OmniLinkBridge.MQTT +namespace OmniLinkBridge.MQTT.Parser { enum UnitCommands { diff --git a/OmniLinkBridge/MQTT/ZoneCommands.cs b/OmniLinkBridge/MQTT/Parser/ZoneCommands.cs similarity index 63% rename from OmniLinkBridge/MQTT/ZoneCommands.cs rename to OmniLinkBridge/MQTT/Parser/ZoneCommands.cs index 75d540c..c693820 100644 --- a/OmniLinkBridge/MQTT/ZoneCommands.cs +++ b/OmniLinkBridge/MQTT/Parser/ZoneCommands.cs @@ -1,4 +1,4 @@ -namespace OmniLinkBridge.MQTT +namespace OmniLinkBridge.MQTT.Parser { enum ZoneCommands { diff --git a/OmniLinkBridge/MQTT/UnitType.cs b/OmniLinkBridge/MQTT/UnitType.cs new file mode 100644 index 0000000..a15b872 --- /dev/null +++ b/OmniLinkBridge/MQTT/UnitType.cs @@ -0,0 +1,9 @@ +namespace OmniLinkBridge.MQTT +{ + public enum UnitType + { + @switch, + light, + number + } +} diff --git a/OmniLinkBridge/Modules/LoggerModule.cs b/OmniLinkBridge/Modules/LoggerModule.cs index fa9bc4c..0580c15 100644 --- a/OmniLinkBridge/Modules/LoggerModule.cs +++ b/OmniLinkBridge/Modules/LoggerModule.cs @@ -2,6 +2,7 @@ using OmniLinkBridge.Notifications; using OmniLinkBridge.OmniLink; using Serilog; +using Serilog.Context; using System; using System.Collections.Generic; using System.Data; @@ -125,15 +126,18 @@ namespace OmniLinkBridge.Modules private void Omnilink_OnConnect(object sender, EventArgs e) { - if (Global.verbose_area) + ushort areaUsage = 0; + for (ushort i = 1; i <= omnilink.Controller.Areas.Count; i++) { - for (ushort i = 1; i <= omnilink.Controller.Areas.Count; i++) + clsArea area = omnilink.Controller.Areas[i]; + + if (i > 1 && area.DefaultProperties == true) + continue; + + areaUsage++; + + if (Global.verbose_area) { - clsArea area = omnilink.Controller.Areas[i]; - - if (i > 1 && area.DefaultProperties == true) - continue; - string status = area.ModeText(); if (area.ExitTimer > 0) @@ -146,21 +150,59 @@ namespace OmniLinkBridge.Modules } } - if (Global.verbose_zone) + ushort zoneUsage = 0; + for (ushort i = 1; i <= omnilink.Controller.Zones.Count; i++) { - for (ushort i = 1; i <= omnilink.Controller.Zones.Count; i++) + clsZone zone = omnilink.Controller.Zones[i]; + + if (zone.DefaultProperties == true) + continue; + + zoneUsage++; + + if (Global.verbose_zone) { - clsZone zone = omnilink.Controller.Zones[i]; - - if (zone.DefaultProperties == true) - continue; - if (zone.IsTemperatureZone()) log.Verbose("Initial ZoneStatus {id} {name}, Temp: {temp}", i, zone.Name, zone.TempText()); else log.Verbose("Initial ZoneStatus {id} {name}, Status: {status}", i, zone.Name, zone.StatusText()); } } + + ushort unitUsage = 0, outputUsage = 0, flagUsage = 0; + for (ushort i = 1; i <= omnilink.Controller.Units.Count; i++) + { + clsUnit unit = omnilink.Controller.Units[i]; + + if (unit.DefaultProperties == true) + continue; + + if (unit.Type == enuOL2UnitType.Output) + outputUsage++; + else if (unit.Type == enuOL2UnitType.Flag) + flagUsage++; + else + unitUsage++; + + if (Global.verbose_unit) + log.Verbose("Initial UnitStatus {id} {name}, Status: {status}", i, unit.Name, unit.StatusText); + } + + ushort thermostatUsage = 0; + for (ushort i = 1; i <= omnilink.Controller.Thermostats.Count; i++) + { + clsThermostat thermostat = omnilink.Controller.Thermostats[i]; + + if (thermostat.DefaultProperties == true) + continue; + + thermostatUsage++; + } + + using (LogContext.PushProperty("Telemetry", "ControllerUsage")) + log.Debug("Controller has {AreaUsage} areas, {ZoneUsage} zones, {UnitUsage} units, " + + "{OutputUsage} outputs, {FlagUsage} flags, {ThermostatUsage} thermostats", + areaUsage, zoneUsage, unitUsage, outputUsage, flagUsage, thermostatUsage); } private void Omnilink_OnAreaStatus(object sender, AreaStatusEventArgs e) diff --git a/OmniLinkBridge/Modules/MQTTModule.cs b/OmniLinkBridge/Modules/MQTTModule.cs index 8ed796e..adaf4ea 100644 --- a/OmniLinkBridge/Modules/MQTTModule.cs +++ b/OmniLinkBridge/Modules/MQTTModule.cs @@ -9,10 +9,13 @@ using MQTTnet.Extensions.ManagedClient; using MQTTnet.Protocol; using Newtonsoft.Json; using OmniLinkBridge.MQTT; +using OmniLinkBridge.MQTT.HomeAssistant; +using OmniLinkBridge.MQTT.Parser; using OmniLinkBridge.OmniLink; using Serilog; using System; using System.Collections.Generic; +using System.Linq; using System.Reflection; using System.Text; using System.Threading; @@ -108,6 +111,7 @@ namespace OmniLinkBridge.Modules Topic.command, Topic.alarm_command, Topic.brightness_command, + Topic.flag_command, Topic.scene_command, Topic.temperature_heat_command, Topic.temperature_cool_command, @@ -216,8 +220,8 @@ namespace OmniLinkBridge.Modules { clsArea area = OmniLink.Controller.Areas[i]; - // PC Access doesn't let you customize the area name for the Omni LTe or Omni IIe - // (configured for 1 area). To workaround ignore default properties for the first area. + // PC Access doesn't let you customize the area name when configured for one area. + // Ignore default properties for the first area. if (i > 1 && area.DefaultProperties == true) { PublishAsync(area.ToTopic(Topic.name), null); @@ -308,6 +312,7 @@ namespace OmniLinkBridge.Modules for (ushort i = 1; i <= OmniLink.Controller.Units.Count; i++) { clsUnit unit = OmniLink.Controller.Units[i]; + UnitType unitType = unit.ToUnitType(); if (unit.DefaultProperties == true) { @@ -321,17 +326,26 @@ namespace OmniLinkBridge.Modules if (unit.DefaultProperties == true || Global.mqtt_discovery_ignore_units.Contains(unit.Number)) { - string type = i < 385 ? "light" : "switch"; - PublishAsync($"{Global.mqtt_discovery_prefix}/{type}/{Global.mqtt_prefix}/unit{i}/config", null); + foreach(UnitType entry in Enum.GetValues(typeof(UnitType))) + PublishAsync($"{Global.mqtt_discovery_prefix}/{entry}/{Global.mqtt_prefix}/unit{i}/config", null); + continue; } - if (i < 385) - PublishAsync($"{Global.mqtt_discovery_prefix}/light/{Global.mqtt_prefix}/unit{i}/config", - JsonConvert.SerializeObject(unit.ToConfig())); - else - PublishAsync($"{Global.mqtt_discovery_prefix}/switch/{Global.mqtt_prefix}/unit{i}/config", + foreach (UnitType entry in Enum.GetValues(typeof(UnitType)).Cast().Where(x => x != unitType)) + PublishAsync($"{Global.mqtt_discovery_prefix}/{entry}/{Global.mqtt_prefix}/unit{i}/config", null); + + log.Verbose("Publishing {type} {id} {name} as {unitType}", "units", i, unit.Name, unitType); + + if (unitType == UnitType.@switch) + PublishAsync($"{Global.mqtt_discovery_prefix}/{unitType}/{Global.mqtt_prefix}/unit{i}/config", JsonConvert.SerializeObject(unit.ToConfigSwitch())); + else if (unitType == UnitType.light) + PublishAsync($"{Global.mqtt_discovery_prefix}/{unitType}/{Global.mqtt_prefix}/unit{i}/config", + JsonConvert.SerializeObject(unit.ToConfig())); + else if (unitType == UnitType.number) + PublishAsync($"{Global.mqtt_discovery_prefix}/{unitType}/{Global.mqtt_prefix}/unit{i}/config", + JsonConvert.SerializeObject(unit.ToConfigNumber())); } } @@ -537,7 +551,11 @@ namespace OmniLinkBridge.Modules { PublishAsync(unit.ToTopic(Topic.state), unit.ToState()); - if (unit.Number < 385) + if (unit.Type == enuOL2UnitType.Flag) + { + PublishAsync(unit.ToTopic(Topic.flag_state), ((ushort)unit.Status).ToString()); + } + else if(unit.Type != enuOL2UnitType.Output) { PublishAsync(unit.ToTopic(Topic.brightness_state), unit.ToBrightnessState().ToString()); PublishAsync(unit.ToTopic(Topic.scene_state), unit.ToSceneState()); diff --git a/OmniLinkBridge/Modules/OmniLinkII.cs b/OmniLinkBridge/Modules/OmniLinkII.cs index b5a5efb..2c8a1df 100644 --- a/OmniLinkBridge/Modules/OmniLinkII.cs +++ b/OmniLinkBridge/Modules/OmniLinkII.cs @@ -51,7 +51,7 @@ namespace OmniLinkBridge.Modules Controller.Connection.NetworkAddress = address; Controller.Connection.NetworkPort = (ushort)port; - Controller.Connection.ControllerKey = clsUtil.HexString2ByteArray(String.Concat(key1, key2)); + Controller.Connection.ControllerKey = clsUtil.HexString2ByteArray(string.Concat(key1, key2)); Controller.PreferredNetworkProtocol = clsHAC.enuPreferredNetworkProtocol.TCP; Controller.Connection.ConnectionType = enuOmniLinkConnectionType.Network_TCP; @@ -316,7 +316,8 @@ namespace OmniLinkBridge.Modules Controller.Zones.CopyProperties(MSG); if (Controller.Zones[MSG.ObjectNumber].IsTemperatureZone() || Controller.Zones[MSG.ObjectNumber].IsHumidityZone()) - Controller.Connection.Send(new clsOL2MsgRequestExtendedStatus(Controller.Connection, enuObjectType.Auxillary, MSG.ObjectNumber, MSG.ObjectNumber), HandleRequestAuxillaryStatus); + Controller.Connection.Send(new clsOL2MsgRequestExtendedStatus(Controller.Connection, + enuObjectType.Auxillary, MSG.ObjectNumber, MSG.ObjectNumber), HandleRequestAuxillaryStatus); break; case enuObjectType.Thermostat: @@ -327,7 +328,8 @@ namespace OmniLinkBridge.Modules else tstats[MSG.ObjectNumber] = DateTime.MinValue; - Controller.Connection.Send(new clsOL2MsgRequestExtendedStatus(Controller.Connection, enuObjectType.Thermostat, MSG.ObjectNumber, MSG.ObjectNumber), HandleRequestThermostatStatus); + Controller.Connection.Send(new clsOL2MsgRequestExtendedStatus(Controller.Connection, + enuObjectType.Thermostat, MSG.ObjectNumber, MSG.ObjectNumber), HandleRequestThermostatStatus); log.Debug("Added thermostat to watch list {thermostatName}", Controller.Thermostats[MSG.ObjectNumber].Name); break; @@ -714,7 +716,8 @@ namespace OmniLinkBridge.Modules (Controller.Connection.ConnectionState == enuOmniLinkConnectionState.Online || Controller.Connection.ConnectionState == enuOmniLinkConnectionState.OnlineSecure)) { - Controller.Connection.Send(new clsOL2MsgRequestExtendedStatus(Controller.Connection, enuObjectType.Thermostat, tstat.Key, tstat.Key), HandleRequestThermostatStatus); + Controller.Connection.Send(new clsOL2MsgRequestExtendedStatus(Controller.Connection, + enuObjectType.Thermostat, tstat.Key, tstat.Key), HandleRequestThermostatStatus); if (Global.verbose_thermostat_timer) log.Debug("Polling status for Thermostat {thermostatName}", diff --git a/OmniLinkBridge/Modules/TimeSyncModule.cs b/OmniLinkBridge/Modules/TimeSyncModule.cs index 05c4e46..6bdac71 100644 --- a/OmniLinkBridge/Modules/TimeSyncModule.cs +++ b/OmniLinkBridge/Modules/TimeSyncModule.cs @@ -74,14 +74,15 @@ namespace OmniLinkBridge.Modules // Extract the 2 digit prefix to use when parsing the time int year = DateTime.Now.Year / 100; - time = new DateTime((int)MSG.Year + (year * 100), (int)MSG.Month, (int)MSG.Day, (int)MSG.Hour, (int)MSG.Minute, (int)MSG.Second); + time = new DateTime(MSG.Year + (year * 100), MSG.Month, MSG.Day, MSG.Hour, MSG.Minute, MSG.Second); } catch { log.Warning("Controller time could not be parsed"); DateTime now = DateTime.Now; - OmniLink.Controller.Connection.Send(new clsOL2MsgSetTime(OmniLink.Controller.Connection, (byte)(now.Year % 100), (byte)now.Month, (byte)now.Day, (byte)now.DayOfWeek, + OmniLink.Controller.Connection.Send(new clsOL2MsgSetTime(OmniLink.Controller.Connection, + (byte)(now.Year % 100), (byte)now.Month, (byte)now.Day, (byte)now.DayOfWeek, (byte)now.Hour, (byte)now.Minute, (byte)(now.IsDaylightSavingTime() ? 1 : 0)), HandleSetTime); return; @@ -92,10 +93,11 @@ namespace OmniLinkBridge.Modules if (adj > Global.time_drift) { log.Warning("Controller time {controllerTime} out of sync by {driftSeconds} seconds", - time.ToString("MM/dd/yyyy HH:mm:ss"), adj); + time.ToString("MM/dd/yyyy HH:mm:ss"), adj); DateTime now = DateTime.Now; - OmniLink.Controller.Connection.Send(new clsOL2MsgSetTime(OmniLink.Controller.Connection, (byte)(now.Year % 100), (byte)now.Month, (byte)now.Day, (byte)now.DayOfWeek, + OmniLink.Controller.Connection.Send(new clsOL2MsgSetTime(OmniLink.Controller.Connection, + (byte)(now.Year % 100), (byte)now.Month, (byte)now.Day, (byte)now.DayOfWeek, (byte)now.Hour, (byte)now.Minute, (byte)(now.IsDaylightSavingTime() ? 1 : 0)), HandleSetTime); } } diff --git a/OmniLinkBridge/OmniLinkBridge.csproj b/OmniLinkBridge/OmniLinkBridge.csproj index ac643a2..5090558 100644 --- a/OmniLinkBridge/OmniLinkBridge.csproj +++ b/OmniLinkBridge/OmniLinkBridge.csproj @@ -82,28 +82,31 @@ - - + + + - + - - - - - - + + + + + + + - + - - + + - - - - + + + + + diff --git a/OmniLinkBridge/OmniLinkBridge.csproj.user b/OmniLinkBridge/OmniLinkBridge.csproj.user index 29671f6..51c364d 100644 --- a/OmniLinkBridge/OmniLinkBridge.csproj.user +++ b/OmniLinkBridge/OmniLinkBridge.csproj.user @@ -4,4 +4,7 @@ + + ProjectFiles + \ No newline at end of file diff --git a/OmniLinkBridge/OmniLinkBridge.ini b/OmniLinkBridge/OmniLinkBridge.ini index aa0b157..817a21e 100644 --- a/OmniLinkBridge/OmniLinkBridge.ini +++ b/OmniLinkBridge/OmniLinkBridge.ini @@ -49,13 +49,24 @@ mqtt_prefix = omnilink mqtt_discovery_prefix = homeassistant # Prefix for Home Assistant entity names mqtt_discovery_name_prefix = -# Specify a range of numbers like 1,2,3,5-10 +# Skip publishing Home Assistant discovery topics for zones/units +# Specify a range of numbers 1,2,3,5-10 mqtt_discovery_ignore_zones = mqtt_discovery_ignore_units = +# Require Home Assistant to prompt for user code when arming/disarming area +# Specify a range of numbers 1,2,3,5-10 mqtt_discovery_area_code_required = -# device_class must be battery, door, garage_door, gas, moisture, motion, problem, smoke, or window +# Override the zone Home Assistant binary sensor device_class +# device_class: must be battery, cold, door, garage_door, gas, +# heat, moisture, motion, problem, safety, smoke, or window #mqtt_discovery_override_zone = id=5;device_class=garage_door #mqtt_discovery_override_zone = id=6;device_class=garage_door +# Override the unit Home Assistant device type +# type: +# Units (LTe 1-32, IIe 1-64, Pro 1-256) light or switch, defaults to light +# Flags (LTe 41-88, IIe 73-128, Pro 393-511) switch or number, defaults to switch +#mqtt_discovery_override_unit = id=1;type=switch +#mqtt_discovery_override_unit = id=395;type=number # Notifications (yes/no) # Always sent for area alarms and critical system events diff --git a/OmniLinkBridge/Properties/AssemblyInfo.cs b/OmniLinkBridge/Properties/AssemblyInfo.cs index cd82cb7..a6dd9c0 100644 --- a/OmniLinkBridge/Properties/AssemblyInfo.cs +++ b/OmniLinkBridge/Properties/AssemblyInfo.cs @@ -32,5 +32,5 @@ using System.Runtime.InteropServices; // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.1.13.0")] -[assembly: AssemblyFileVersion("1.1.13.0")] +[assembly: AssemblyVersion("1.1.14.0")] +[assembly: AssemblyFileVersion("1.1.14.0")] diff --git a/OmniLinkBridge/Settings.cs b/OmniLinkBridge/Settings.cs index 881777b..622ab3f 100644 --- a/OmniLinkBridge/Settings.cs +++ b/OmniLinkBridge/Settings.cs @@ -7,7 +7,7 @@ using System.IO; using System.Linq; using System.Net.Mail; using System.Reflection; -using System.Threading; +using ha = OmniLinkBridge.MQTT.HomeAssistant; namespace OmniLinkBridge { @@ -86,6 +86,7 @@ namespace OmniLinkBridge Global.mqtt_discovery_ignore_units = settings.ValidateRange("mqtt_discovery_ignore_units"); Global.mqtt_discovery_area_code_required = settings.ValidateRange("mqtt_discovery_area_code_required"); Global.mqtt_discovery_override_zone = settings.LoadOverrideZone("mqtt_discovery_override_zone"); + Global.mqtt_discovery_override_unit = settings.LoadOverrideUnit("mqtt_discovery_override_unit"); } // Notifications @@ -157,7 +158,7 @@ namespace OmniLinkBridge } else if (override_zone is MQTT.OverrideZone mqtt_zone) { - if (!attributes.ContainsKey("device_class") || !Enum.TryParse(attributes["device_class"], out MQTT.BinarySensor.DeviceClass attrib_device_class)) + if (!attributes.ContainsKey("device_class") || !Enum.TryParse(attributes["device_class"], out ha.BinarySensor.DeviceClass attrib_device_class)) throw new Exception("Missing or invalid device_class attribute"); mqtt_zone.device_class = attrib_device_class; @@ -175,6 +176,50 @@ namespace OmniLinkBridge } } + private static ConcurrentDictionary LoadOverrideUnit(this NameValueCollection settings, string section) where T : new() + { + try + { + ConcurrentDictionary ret = new ConcurrentDictionary(); + + string value = settings.CheckEnv(section); + + if (string.IsNullOrEmpty(value)) + return ret; + + string[] ids = value.Split(','); + + for (int i = 0; i < ids.Length; i++) + { + Dictionary attributes = ids[i].TrimEnd(new char[] { ';' }).Split(';') + .Select(s => s.Split('=')) + .ToDictionary(a => a[0].Trim(), a => a[1].Trim(), StringComparer.InvariantCultureIgnoreCase); + + if (!attributes.ContainsKey("id") || !int.TryParse(attributes["id"], out int attrib_id)) + throw new Exception("Missing or invalid id attribute"); + + T override_unit = new T(); + + if (override_unit is MQTT.OverrideUnit mqtt_unit) + { + if (!attributes.ContainsKey("type") || !Enum.TryParse(attributes["type"], out MQTT.UnitType attrib_type)) + throw new Exception("Missing or invalid type attribute"); + + mqtt_unit.type = attrib_type; + } + + ret.TryAdd(attrib_id, override_unit); + } + + return ret; + } + catch (Exception ex) + { + log.Error(ex, "Invalid override unit specified for {section}", section); + throw; + } + } + private static string ValidateHasValue(this NameValueCollection settings, string section) { string value = settings.CheckEnv(section); diff --git a/OmniLinkBridgeTest/ExtensionTest.cs b/OmniLinkBridgeTest/ExtensionTest.cs index 7be36db..9e5c983 100644 --- a/OmniLinkBridgeTest/ExtensionTest.cs +++ b/OmniLinkBridgeTest/ExtensionTest.cs @@ -1,9 +1,7 @@ -using System; -using System.Text; -using System.Collections.Generic; -using Microsoft.VisualStudio.TestTools.UnitTesting; +using Microsoft.VisualStudio.TestTools.UnitTesting; using OmniLinkBridge; using OmniLinkBridge.MQTT; +using System.Collections.Generic; namespace OmniLinkBridgeTest { diff --git a/OmniLinkBridgeTest/MQTTTest.cs b/OmniLinkBridgeTest/MQTTTest.cs index af30e07..9b997da 100644 --- a/OmniLinkBridgeTest/MQTTTest.cs +++ b/OmniLinkBridgeTest/MQTTTest.cs @@ -1,10 +1,9 @@ -using System; -using System.Text; -using System.Collections.Generic; -using HAI_Shared; +using HAI_Shared; using Microsoft.VisualStudio.TestTools.UnitTesting; +using OmniLinkBridge; using OmniLinkBridge.MQTT; using OmniLinkBridgeTest.Mock; +using System.Collections.Concurrent; namespace OmniLinkBridgeTest { @@ -19,6 +18,8 @@ namespace OmniLinkBridgeTest { omniLink = new MockOmniLinkII(); messageProcessor = new MessageProcessor(omniLink); + + omniLink.Controller.Units[395].Type = enuOL2UnitType.Flag; } [TestMethod] @@ -134,6 +135,28 @@ namespace OmniLinkBridgeTest check(2, "on", enuUnitCommand.On); } + [TestMethod] + public void UnitFlagCommand() + { + void check(ushort id, string payload, enuUnitCommand command, int value) + { + SendCommandEventArgs actual = null; + omniLink.OnSendCommand += (sender, e) => { actual = e; }; + messageProcessor.Process($"omnilink/unit{id}/flag_command", payload); + SendCommandEventArgs expected = new SendCommandEventArgs() + { + Cmd = command, + Par = (byte)value, + Pr2 = id + }; + Assert.AreEqual(expected, actual); + } + + check(395, "0", enuUnitCommand.Set, 0); + check(395, "1", enuUnitCommand.Set, 1); + check(395, "255", enuUnitCommand.Set, 255); + } + [TestMethod] public void UnitLevelCommand() { diff --git a/OmniLinkBridgeTest/Mock/MockOmniLinkII.cs b/OmniLinkBridgeTest/Mock/MockOmniLinkII.cs index 6df958c..6715ca3 100644 --- a/OmniLinkBridgeTest/Mock/MockOmniLinkII.cs +++ b/OmniLinkBridgeTest/Mock/MockOmniLinkII.cs @@ -1,10 +1,6 @@ using HAI_Shared; using OmniLinkBridge.OmniLink; using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace OmniLinkBridgeTest.Mock { diff --git a/OmniLinkBridgeTest/Mock/SendCommandEventArgs.cs b/OmniLinkBridgeTest/Mock/SendCommandEventArgs.cs index fbc5d05..c6b332d 100644 --- a/OmniLinkBridgeTest/Mock/SendCommandEventArgs.cs +++ b/OmniLinkBridgeTest/Mock/SendCommandEventArgs.cs @@ -1,9 +1,5 @@ using HAI_Shared; using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace OmniLinkBridgeTest.Mock { diff --git a/OmniLinkBridgeTest/NotificationTest.cs b/OmniLinkBridgeTest/NotificationTest.cs index 5486afc..07769ac 100644 --- a/OmniLinkBridgeTest/NotificationTest.cs +++ b/OmniLinkBridgeTest/NotificationTest.cs @@ -1,9 +1,6 @@ -using System; -using System.Text; -using System.Collections.Generic; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using OmniLinkBridge.Notifications; +using Microsoft.VisualStudio.TestTools.UnitTesting; using OmniLinkBridge; +using OmniLinkBridge.Notifications; using System.Net.Mail; namespace OmniLinkBridgeTest diff --git a/OmniLinkBridgeTest/SettingsTest.cs b/OmniLinkBridgeTest/SettingsTest.cs index dbbb396..ee73b04 100644 --- a/OmniLinkBridgeTest/SettingsTest.cs +++ b/OmniLinkBridgeTest/SettingsTest.cs @@ -1,9 +1,8 @@ -using System; -using System.Text; -using System.Collections.Generic; -using System.Collections.Concurrent; -using Microsoft.VisualStudio.TestTools.UnitTesting; +using Microsoft.VisualStudio.TestTools.UnitTesting; using OmniLinkBridge; +using System; +using System.Collections.Generic; +using ha = OmniLinkBridge.MQTT.HomeAssistant; namespace OmniLinkBridgeTest { @@ -156,8 +155,11 @@ namespace OmniLinkBridgeTest "mqtt_discovery_name_prefix = mynameprefix", "mqtt_discovery_ignore_zones = 1,2-3,4", "mqtt_discovery_ignore_units = 2-5,7", + "mqtt_discovery_area_code_required = 1", "mqtt_discovery_override_zone = id=5;device_class=garage_door", "mqtt_discovery_override_zone = id=7;device_class=motion", + "mqtt_discovery_override_unit = id=1;type=switch", + "mqtt_discovery_override_unit = id=395;type=light", }); Settings.LoadSettings(lines.ToArray()); Assert.AreEqual("myuser", Global.mqtt_username); @@ -167,11 +169,12 @@ namespace OmniLinkBridgeTest Assert.AreEqual("mynameprefix ", Global.mqtt_discovery_name_prefix); Assert.IsTrue(Global.mqtt_discovery_ignore_zones.SetEquals(new int[] { 1, 2, 3, 4 })); Assert.IsTrue(Global.mqtt_discovery_ignore_units.SetEquals(new int[] { 2, 3, 4, 5, 7 })); + Assert.IsTrue(Global.mqtt_discovery_area_code_required.SetEquals(new int[] { 1 })); Dictionary override_zone = new Dictionary() { - { 5, new OmniLinkBridge.MQTT.OverrideZone { device_class = OmniLinkBridge.MQTT.BinarySensor.DeviceClass.garage_door }}, - { 7, new OmniLinkBridge.MQTT.OverrideZone { device_class = OmniLinkBridge.MQTT.BinarySensor.DeviceClass.motion }} + { 5, new OmniLinkBridge.MQTT.OverrideZone { device_class = ha.BinarySensor.DeviceClass.garage_door }}, + { 7, new OmniLinkBridge.MQTT.OverrideZone { device_class = ha.BinarySensor.DeviceClass.motion }} }; Assert.AreEqual(override_zone.Count, Global.mqtt_discovery_override_zone.Count); @@ -180,6 +183,19 @@ namespace OmniLinkBridgeTest Global.mqtt_discovery_override_zone.TryGetValue(pair.Key, out OmniLinkBridge.MQTT.OverrideZone value); Assert.AreEqual(override_zone[pair.Key].device_class, value.device_class); } + + Dictionary override_unit = new Dictionary() + { + { 1, new OmniLinkBridge.MQTT.OverrideUnit { type = OmniLinkBridge.MQTT.UnitType.@switch }}, + { 395, new OmniLinkBridge.MQTT.OverrideUnit { type = OmniLinkBridge.MQTT.UnitType.light }} + }; + + Assert.AreEqual(override_unit.Count, Global.mqtt_discovery_override_unit.Count); + foreach (KeyValuePair pair in override_unit) + { + Global.mqtt_discovery_override_unit.TryGetValue(pair.Key, out OmniLinkBridge.MQTT.OverrideUnit value); + Assert.AreEqual(override_unit[pair.Key].type, value.type); + } } [TestMethod] diff --git a/README.md b/README.md index bc75088..6dd82e8 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ You can use docker to build an image from git or download the [binary here](http - .NET Framework 4.7.2 (or Mono equivalent) ## Operation -OmniLink Bridge is divided into the following modules and configurable settings. Configuration settings can also be set as environment variables by using their name in uppercase. Refer to [OmniLinkBridge.ini](https://github.com/excaliburpartners/OmniLinkBridge/blob/master/OmniLinkBridge/OmniLinkBridge.ini) for specifics. +OmniLink Bridge is divided into the following modules and configurable settings. Configuration settings can also be set as environment variables by using their name in uppercase. Refer to [OmniLinkBridge.ini](OmniLinkBridge/OmniLinkBridge.ini) for specifics. - OmniLinkII: controller_ - Maintains connection to the OmniLink controller @@ -232,6 +232,10 @@ SUB omnilink/unitX/brightness_state PUB omnilink/unitX/brightness_command int Level from 0 to 100 percent +SUB omnilink/unitX/flag_state +PUB omnilink/unitX/flag_command +int Level from 0 to 255 + SUB omnilink/unitX/scene_state PUB omnilink/unitX/scene_command string A-L