mirror of
https://github.com/excaliburpartners/OmniLinkBridge.git
synced 2025-04-19 21:07:20 +00:00
Compare commits
No commits in common. "master" and "1.1.13" have entirely different histories.
@ -1,16 +0,0 @@
|
||||
using System;
|
||||
using Serilog.Core;
|
||||
using Serilog.Events;
|
||||
|
||||
namespace OmniLinkBridge
|
||||
{
|
||||
public class ControllerEnricher : ILogEventEnricher
|
||||
{
|
||||
public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)
|
||||
{
|
||||
if(Global.controller_id != Guid.Empty)
|
||||
logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty(
|
||||
"ControllerId", Global.controller_id));
|
||||
}
|
||||
}
|
||||
}
|
@ -44,11 +44,9 @@ namespace OmniLinkBridge
|
||||
|
||||
startTime = DateTime.Now;
|
||||
|
||||
Program.ShowSendLogsWarning();
|
||||
|
||||
using (LogContext.PushProperty("Telemetry", "Startup"))
|
||||
log.Information("Started version {Version} in {Environment} on {OperatingSystem} with {Modules}",
|
||||
Assembly.GetExecutingAssembly().GetName().Version, Program.GetEnvironment(), Environment.OSVersion, modules);
|
||||
log.Information("Started version {Version} on {OperatingSystem} with {Modules}",
|
||||
Assembly.GetExecutingAssembly().GetName().Version, Environment.OSVersion, modules);
|
||||
|
||||
// Startup modules
|
||||
foreach (IModule module in modules)
|
||||
|
@ -1,19 +1,13 @@
|
||||
using System;
|
||||
using OmniLinkBridge.MQTT;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace OmniLinkBridge
|
||||
{
|
||||
public static class Extensions
|
||||
{
|
||||
public static string Truncate(this string value, int maxLength)
|
||||
{
|
||||
return value?.Length > maxLength ? value.Substring(0, maxLength) : value;
|
||||
}
|
||||
|
||||
public static double ToCelsius(this double f)
|
||||
{
|
||||
// Convert to celsius
|
||||
@ -30,6 +24,39 @@ 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");
|
||||
@ -50,14 +77,5 @@ namespace OmniLinkBridge
|
||||
.Select(t => int.Parse(t)).ToList(); // digit to int
|
||||
return RangeNums.Count.Equals(2) ? Enumerable.Range(RangeNums.Min(), (RangeNums.Max() + 1) - RangeNums.Min()).ToList() : RangeNums;
|
||||
}
|
||||
|
||||
public static Guid ComputeGuid(this string data)
|
||||
{
|
||||
using SHA256 hash = SHA256.Create();
|
||||
byte[] bytes = hash.ComputeHash(Encoding.UTF8.GetBytes(data));
|
||||
byte[] guidBytes = new byte[16];
|
||||
Array.Copy(bytes, guidBytes, 16);
|
||||
return new Guid(guidBytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,3 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Mail;
|
||||
@ -10,8 +9,6 @@ namespace OmniLinkBridge
|
||||
{
|
||||
public static bool DebugSettings { get; set; }
|
||||
public static bool UseEnvironment { get; set; }
|
||||
public static bool SendLogs { get; set; }
|
||||
public static Guid SessionID { get; } = Guid.NewGuid();
|
||||
|
||||
// HAI / Leviton Omni Controller
|
||||
public static string controller_address;
|
||||
@ -19,7 +16,6 @@ namespace OmniLinkBridge
|
||||
public static string controller_key1;
|
||||
public static string controller_key2;
|
||||
public static string controller_name;
|
||||
public static Guid controller_id;
|
||||
|
||||
// Time Sync
|
||||
public static bool time_sync;
|
||||
@ -35,8 +31,6 @@ namespace OmniLinkBridge
|
||||
public static bool verbose_thermostat;
|
||||
public static bool verbose_unit;
|
||||
public static bool verbose_message;
|
||||
public static bool verbose_lock;
|
||||
public static bool verbose_audio;
|
||||
|
||||
// mySQL Logging
|
||||
public static bool mysql_logging;
|
||||
@ -59,12 +53,8 @@ namespace OmniLinkBridge
|
||||
public static string mqtt_discovery_name_prefix;
|
||||
public static HashSet<int> mqtt_discovery_ignore_zones;
|
||||
public static HashSet<int> mqtt_discovery_ignore_units;
|
||||
public static ConcurrentDictionary<int, MQTT.OverrideArea> mqtt_discovery_override_area;
|
||||
public static HashSet<int> mqtt_discovery_area_code_required;
|
||||
public static ConcurrentDictionary<int, MQTT.OverrideZone> mqtt_discovery_override_zone;
|
||||
public static ConcurrentDictionary<int, MQTT.OverrideUnit> mqtt_discovery_override_unit;
|
||||
public static Type mqtt_discovery_button_type;
|
||||
public static bool mqtt_audio_local_mute;
|
||||
public static bool mqtt_audio_volume_media_player;
|
||||
|
||||
// Notifications
|
||||
public static bool notify_area;
|
||||
|
16
OmniLinkBridge/MQTT/Alarm.cs
Normal file
16
OmniLinkBridge/MQTT/Alarm.cs
Normal file
@ -0,0 +1,16 @@
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Converters;
|
||||
|
||||
namespace OmniLinkBridge.MQTT
|
||||
{
|
||||
public class Alarm : Device
|
||||
{
|
||||
public string command_topic { get; set; }
|
||||
|
||||
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string command_template { get; set; }
|
||||
|
||||
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string code { get; set; }
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
namespace OmniLinkBridge.MQTT.Parser
|
||||
namespace OmniLinkBridge.MQTT
|
||||
{
|
||||
enum AlarmCommands
|
||||
{
|
@ -1,4 +1,4 @@
|
||||
namespace OmniLinkBridge.MQTT.Parser
|
||||
namespace OmniLinkBridge.MQTT
|
||||
{
|
||||
enum AreaCommands
|
||||
{
|
@ -1,7 +0,0 @@
|
||||
namespace OmniLinkBridge.MQTT
|
||||
{
|
||||
public class Availability
|
||||
{
|
||||
public string topic { get; set; } = $"{Global.mqtt_prefix}/status";
|
||||
}
|
||||
}
|
@ -1,15 +1,10 @@
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Converters;
|
||||
|
||||
namespace OmniLinkBridge.MQTT.HomeAssistant
|
||||
namespace OmniLinkBridge.MQTT
|
||||
{
|
||||
public class BinarySensor : Device
|
||||
{
|
||||
public BinarySensor(DeviceRegistry deviceRegistry) : base(deviceRegistry)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
[JsonConverter(typeof(StringEnumConverter))]
|
||||
public enum DeviceClass
|
||||
{
|
@ -1,16 +1,9 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace OmniLinkBridge.MQTT.HomeAssistant
|
||||
namespace OmniLinkBridge.MQTT
|
||||
{
|
||||
public class Climate : Device
|
||||
{
|
||||
public Climate(DeviceRegistry deviceRegistry) : base(deviceRegistry)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public string status { get; set; }
|
||||
|
||||
public string action_topic { get; set; }
|
||||
public string current_temperature_topic { get; set; }
|
||||
|
@ -1,4 +1,4 @@
|
||||
namespace OmniLinkBridge.MQTT.Parser
|
||||
namespace OmniLinkBridge.MQTT
|
||||
{
|
||||
enum CommandTypes
|
||||
{
|
||||
@ -7,8 +7,6 @@
|
||||
unit,
|
||||
thermostat,
|
||||
button,
|
||||
message,
|
||||
@lock,
|
||||
audio
|
||||
message
|
||||
}
|
||||
}
|
20
OmniLinkBridge/MQTT/Device.cs
Normal file
20
OmniLinkBridge/MQTT/Device.cs
Normal file
@ -0,0 +1,20 @@
|
||||
using Newtonsoft.Json;
|
||||
using OmniLinkBridge.Modules;
|
||||
|
||||
namespace OmniLinkBridge.MQTT
|
||||
{
|
||||
public class Device
|
||||
{
|
||||
public string unique_id { get; set; }
|
||||
|
||||
public string name { get; set; }
|
||||
|
||||
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string state_topic { get; set; }
|
||||
|
||||
public string availability_topic { get; set; } = $"{Global.mqtt_prefix}/status";
|
||||
|
||||
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
|
||||
public DeviceRegistry device { get; set; } = MQTTModule.MqttDeviceRegistry;
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
namespace OmniLinkBridge.MQTT.HomeAssistant
|
||||
namespace OmniLinkBridge.MQTT
|
||||
{
|
||||
public class DeviceRegistry
|
||||
{
|
@ -1,66 +0,0 @@
|
||||
using HAI_Shared;
|
||||
|
||||
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)
|
||||
{
|
||||
// Special case for Home Assistant when code not required
|
||||
if (string.Compare(payloads[1], "validate", true) == 0 &&
|
||||
string.Compare(payloads[2], "None", true) == 0)
|
||||
{
|
||||
ret.Success = true;
|
||||
}
|
||||
else 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;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
using Newtonsoft.Json;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace OmniLinkBridge.MQTT.HomeAssistant
|
||||
{
|
||||
public class Alarm : Device
|
||||
{
|
||||
public Alarm(DeviceRegistry deviceRegistry) : base(deviceRegistry)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public string command_topic { get; set; }
|
||||
|
||||
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string command_template { get; set; }
|
||||
|
||||
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string code { get; set; }
|
||||
|
||||
public bool code_arm_required { get; set; } = false;
|
||||
|
||||
public bool code_disarm_required { get; set; } = false;
|
||||
|
||||
public bool code_trigger_required { get; set; } = false;
|
||||
|
||||
public List<string> supported_features { get; set; } = new List<string>(new string[] {
|
||||
"arm_home", "arm_away", "arm_night", "arm_vacation" });
|
||||
}
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace OmniLinkBridge.MQTT.HomeAssistant
|
||||
{
|
||||
public class Button : Device
|
||||
{
|
||||
public Button(DeviceRegistry deviceRegistry) : base(deviceRegistry)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public string command_topic { get; set; }
|
||||
|
||||
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string payload_press { get; set; }
|
||||
}
|
||||
}
|
@ -1,44 +0,0 @@
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Converters;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace OmniLinkBridge.MQTT.HomeAssistant
|
||||
{
|
||||
public class Device
|
||||
{
|
||||
public Device(DeviceRegistry deviceRegistry)
|
||||
{
|
||||
device = deviceRegistry;
|
||||
}
|
||||
|
||||
[JsonConverter(typeof(StringEnumConverter))]
|
||||
public enum AvailabilityMode
|
||||
{
|
||||
all,
|
||||
any,
|
||||
latest
|
||||
}
|
||||
|
||||
public string unique_id { get; set; }
|
||||
|
||||
public string name { get; set; }
|
||||
|
||||
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string icon { get; set; }
|
||||
|
||||
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string state_topic { get; set; }
|
||||
|
||||
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string availability_topic { get; set; } = $"{Global.mqtt_prefix}/status";
|
||||
|
||||
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
|
||||
public List<Availability> availability { get; set; }
|
||||
|
||||
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
|
||||
public AvailabilityMode? availability_mode { get; set; }
|
||||
|
||||
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
|
||||
public DeviceRegistry device { get; set; }
|
||||
}
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace OmniLinkBridge.MQTT.HomeAssistant
|
||||
{
|
||||
public class Lock : Device
|
||||
{
|
||||
public Lock(DeviceRegistry deviceRegistry) : base(deviceRegistry)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public string command_topic { get; set; }
|
||||
|
||||
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string payload_lock { get; set; }
|
||||
|
||||
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string payload_unlock { get; set; }
|
||||
|
||||
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string state_locked { get; set; }
|
||||
|
||||
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string state_unlocked { get; set; }
|
||||
}
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace OmniLinkBridge.MQTT.HomeAssistant
|
||||
{
|
||||
public class Number : Device
|
||||
{
|
||||
public Number(DeviceRegistry deviceRegistry) : base(deviceRegistry)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public string command_topic { get; set; }
|
||||
|
||||
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
|
||||
public int? min { get; set; }
|
||||
|
||||
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
|
||||
public int? max { get; set; }
|
||||
|
||||
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
|
||||
public double? step { get; set; }
|
||||
}
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace OmniLinkBridge.MQTT.HomeAssistant
|
||||
{
|
||||
public class Select : Device
|
||||
{
|
||||
public Select(DeviceRegistry deviceRegistry) : base(deviceRegistry)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public string command_topic { get; set; }
|
||||
|
||||
public List<string> options { get; set; } = null;
|
||||
}
|
||||
}
|
@ -1,12 +1,7 @@
|
||||
namespace OmniLinkBridge.MQTT.HomeAssistant
|
||||
namespace OmniLinkBridge.MQTT
|
||||
{
|
||||
public class Light : Device
|
||||
{
|
||||
public Light(DeviceRegistry deviceRegistry) : base(deviceRegistry)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public string command_topic { get; set; }
|
||||
|
||||
public string brightness_state_topic { get; set; }
|
@ -1,9 +1,6 @@
|
||||
using HAI_Shared;
|
||||
using Newtonsoft.Json;
|
||||
using System.Collections.Generic;
|
||||
using OmniLinkBridge.MQTT.HomeAssistant;
|
||||
using OmniLinkBridge.MQTT.Parser;
|
||||
using OmniLinkBridge.Modules;
|
||||
|
||||
namespace OmniLinkBridge.MQTT
|
||||
{
|
||||
@ -16,7 +13,7 @@ namespace OmniLinkBridge.MQTT
|
||||
|
||||
public static Alarm ToConfig(this clsArea area)
|
||||
{
|
||||
Alarm ret = new Alarm(MQTTModule.MqttDeviceRegistry)
|
||||
Alarm ret = new Alarm
|
||||
{
|
||||
unique_id = $"{Global.mqtt_prefix}area{area.Number}",
|
||||
name = Global.mqtt_discovery_name_prefix + area.Name,
|
||||
@ -25,27 +22,10 @@ namespace OmniLinkBridge.MQTT
|
||||
|
||||
};
|
||||
|
||||
Global.mqtt_discovery_override_area.TryGetValue(area.Number, out OverrideArea override_area);
|
||||
|
||||
if (override_area != null)
|
||||
if(Global.mqtt_discovery_area_code_required.Contains(area.Number))
|
||||
{
|
||||
if(override_area.code_arm || override_area.code_disarm)
|
||||
{
|
||||
ret.command_template = "{{ action }},validate,{{ code }}";
|
||||
ret.code = "REMOTE_CODE";
|
||||
}
|
||||
ret.code_arm_required = override_area.code_arm;
|
||||
ret.code_disarm_required = override_area.code_disarm;
|
||||
|
||||
ret.supported_features.Clear();
|
||||
if (override_area.arm_home)
|
||||
ret.supported_features.Add("arm_home");
|
||||
if (override_area.arm_away)
|
||||
ret.supported_features.Add("arm_away");
|
||||
if (override_area.arm_night)
|
||||
ret.supported_features.Add("arm_night");
|
||||
if (override_area.arm_vacation)
|
||||
ret.supported_features.Add("arm_vacation");
|
||||
ret.command_template = "{{ action }},validate,{{ code }}";
|
||||
ret.code = "REMOTE_CODE";
|
||||
}
|
||||
|
||||
return ret;
|
||||
@ -101,7 +81,7 @@ namespace OmniLinkBridge.MQTT
|
||||
|
||||
public static BinarySensor ToConfigBurglary(this clsArea area)
|
||||
{
|
||||
BinarySensor ret = new BinarySensor(MQTTModule.MqttDeviceRegistry)
|
||||
BinarySensor ret = new BinarySensor
|
||||
{
|
||||
unique_id = $"{Global.mqtt_prefix}area{area.Number}burglary",
|
||||
name = $"{Global.mqtt_discovery_name_prefix}{area.Name} Burglary",
|
||||
@ -114,7 +94,7 @@ namespace OmniLinkBridge.MQTT
|
||||
|
||||
public static BinarySensor ToConfigFire(this clsArea area)
|
||||
{
|
||||
BinarySensor ret = new BinarySensor(MQTTModule.MqttDeviceRegistry)
|
||||
BinarySensor ret = new BinarySensor
|
||||
{
|
||||
unique_id = $"{Global.mqtt_prefix}area{area.Number}fire",
|
||||
name = $"{Global.mqtt_discovery_name_prefix}{area.Name} Fire",
|
||||
@ -127,7 +107,7 @@ namespace OmniLinkBridge.MQTT
|
||||
|
||||
public static BinarySensor ToConfigGas(this clsArea area)
|
||||
{
|
||||
BinarySensor ret = new BinarySensor(MQTTModule.MqttDeviceRegistry)
|
||||
BinarySensor ret = new BinarySensor
|
||||
{
|
||||
unique_id = $"{Global.mqtt_prefix}area{area.Number}gas",
|
||||
name = $"{Global.mqtt_discovery_name_prefix}{area.Name} Gas",
|
||||
@ -140,7 +120,7 @@ namespace OmniLinkBridge.MQTT
|
||||
|
||||
public static BinarySensor ToConfigAux(this clsArea area)
|
||||
{
|
||||
BinarySensor ret = new BinarySensor(MQTTModule.MqttDeviceRegistry)
|
||||
BinarySensor ret = new BinarySensor
|
||||
{
|
||||
unique_id = $"{Global.mqtt_prefix}area{area.Number}auxiliary",
|
||||
name = $"{Global.mqtt_discovery_name_prefix}{area.Name} Auxiliary",
|
||||
@ -153,7 +133,7 @@ namespace OmniLinkBridge.MQTT
|
||||
|
||||
public static BinarySensor ToConfigFreeze(this clsArea area)
|
||||
{
|
||||
BinarySensor ret = new BinarySensor(MQTTModule.MqttDeviceRegistry)
|
||||
BinarySensor ret = new BinarySensor
|
||||
{
|
||||
unique_id = $"{Global.mqtt_prefix}area{area.Number}freeze",
|
||||
name = $"{Global.mqtt_discovery_name_prefix}{area.Name} Freeze",
|
||||
@ -166,7 +146,7 @@ namespace OmniLinkBridge.MQTT
|
||||
|
||||
public static BinarySensor ToConfigWater(this clsArea area)
|
||||
{
|
||||
BinarySensor ret = new BinarySensor(MQTTModule.MqttDeviceRegistry)
|
||||
BinarySensor ret = new BinarySensor
|
||||
{
|
||||
unique_id = $"{Global.mqtt_prefix}area{area.Number}water",
|
||||
name = $"{Global.mqtt_discovery_name_prefix}{area.Name} Water",
|
||||
@ -179,7 +159,7 @@ namespace OmniLinkBridge.MQTT
|
||||
|
||||
public static BinarySensor ToConfigDuress(this clsArea area)
|
||||
{
|
||||
BinarySensor ret = new BinarySensor(MQTTModule.MqttDeviceRegistry)
|
||||
BinarySensor ret = new BinarySensor
|
||||
{
|
||||
unique_id = $"{Global.mqtt_prefix}area{area.Number}duress",
|
||||
name = $"{Global.mqtt_discovery_name_prefix}{area.Name} Duress",
|
||||
@ -192,7 +172,7 @@ namespace OmniLinkBridge.MQTT
|
||||
|
||||
public static BinarySensor ToConfigTemp(this clsArea area)
|
||||
{
|
||||
BinarySensor ret = new BinarySensor(MQTTModule.MqttDeviceRegistry)
|
||||
BinarySensor ret = new BinarySensor
|
||||
{
|
||||
unique_id = $"{Global.mqtt_prefix}area{area.Number}temp",
|
||||
name = $"{Global.mqtt_discovery_name_prefix}{area.Name} Temp",
|
||||
@ -237,7 +217,7 @@ namespace OmniLinkBridge.MQTT
|
||||
|
||||
public static Sensor ToConfigTemp(this clsZone zone, enuTempFormat format)
|
||||
{
|
||||
Sensor ret = new Sensor(MQTTModule.MqttDeviceRegistry)
|
||||
Sensor ret = new Sensor
|
||||
{
|
||||
unique_id = $"{Global.mqtt_prefix}zone{zone.Number}temp",
|
||||
name = $"{Global.mqtt_discovery_name_prefix}{zone.Name} Temp",
|
||||
@ -250,7 +230,7 @@ namespace OmniLinkBridge.MQTT
|
||||
|
||||
public static Sensor ToConfigHumidity(this clsZone zone)
|
||||
{
|
||||
Sensor ret = new Sensor(MQTTModule.MqttDeviceRegistry)
|
||||
Sensor ret = new Sensor
|
||||
{
|
||||
unique_id = $"{Global.mqtt_prefix}zone{zone.Number}humidity",
|
||||
name = $"{Global.mqtt_discovery_name_prefix}{zone.Name} Humidity",
|
||||
@ -263,7 +243,7 @@ namespace OmniLinkBridge.MQTT
|
||||
|
||||
public static Sensor ToConfigSensor(this clsZone zone)
|
||||
{
|
||||
Sensor ret = new Sensor(MQTTModule.MqttDeviceRegistry)
|
||||
Sensor ret = new Sensor
|
||||
{
|
||||
unique_id = $"{Global.mqtt_prefix}zone{zone.Number}",
|
||||
name = Global.mqtt_discovery_name_prefix + zone.Name
|
||||
@ -305,7 +285,7 @@ namespace OmniLinkBridge.MQTT
|
||||
|
||||
public static Switch ToConfigSwitch(this clsZone zone)
|
||||
{
|
||||
Switch ret = new Switch(MQTTModule.MqttDeviceRegistry)
|
||||
Switch ret = new Switch
|
||||
{
|
||||
unique_id = $"{Global.mqtt_prefix}zone{zone.Number}switch",
|
||||
name = $"{Global.mqtt_discovery_name_prefix}{zone.Name} Bypass",
|
||||
@ -320,7 +300,7 @@ namespace OmniLinkBridge.MQTT
|
||||
|
||||
public static BinarySensor ToConfig(this clsZone zone)
|
||||
{
|
||||
BinarySensor ret = new BinarySensor(MQTTModule.MqttDeviceRegistry)
|
||||
BinarySensor ret = new BinarySensor
|
||||
{
|
||||
unique_id = $"{Global.mqtt_prefix}zone{zone.Number}binary",
|
||||
name = Global.mqtt_discovery_name_prefix + zone.Name
|
||||
@ -395,7 +375,7 @@ namespace OmniLinkBridge.MQTT
|
||||
|
||||
public static Light ToConfig(this clsUnit unit)
|
||||
{
|
||||
Light ret = new Light(MQTTModule.MqttDeviceRegistry)
|
||||
Light ret = new Light
|
||||
{
|
||||
unique_id = $"{Global.mqtt_prefix}unit{unit.Number}light",
|
||||
name = Global.mqtt_discovery_name_prefix + unit.Name,
|
||||
@ -409,7 +389,7 @@ namespace OmniLinkBridge.MQTT
|
||||
|
||||
public static Switch ToConfigSwitch(this clsUnit unit)
|
||||
{
|
||||
Switch ret = new Switch(MQTTModule.MqttDeviceRegistry)
|
||||
Switch ret = new Switch
|
||||
{
|
||||
unique_id = $"{Global.mqtt_prefix}unit{unit.Number}switch",
|
||||
name = Global.mqtt_discovery_name_prefix + unit.Name,
|
||||
@ -419,20 +399,6 @@ namespace OmniLinkBridge.MQTT
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static Number ToConfigNumber(this clsUnit unit)
|
||||
{
|
||||
Number ret = new Number(MQTTModule.MqttDeviceRegistry)
|
||||
{
|
||||
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();
|
||||
@ -464,7 +430,7 @@ namespace OmniLinkBridge.MQTT
|
||||
|
||||
public static Sensor ToConfigTemp(this clsThermostat thermostat, enuTempFormat format)
|
||||
{
|
||||
Sensor ret = new Sensor(MQTTModule.MqttDeviceRegistry)
|
||||
Sensor ret = new Sensor
|
||||
{
|
||||
unique_id = $"{Global.mqtt_prefix}thermostat{thermostat.Number}temp",
|
||||
name = $"{Global.mqtt_discovery_name_prefix}{thermostat.Name} Temp",
|
||||
@ -477,7 +443,7 @@ namespace OmniLinkBridge.MQTT
|
||||
|
||||
public static Number ToConfigHumidify(this clsThermostat thermostat)
|
||||
{
|
||||
Number ret = new Number(MQTTModule.MqttDeviceRegistry)
|
||||
Number ret = new Number
|
||||
{
|
||||
unique_id = $"{Global.mqtt_prefix}thermostat{thermostat.Number}humidify",
|
||||
name = $"{Global.mqtt_discovery_name_prefix}{thermostat.Name} Humidify",
|
||||
@ -490,7 +456,7 @@ namespace OmniLinkBridge.MQTT
|
||||
|
||||
public static Number ToConfigDehumidify(this clsThermostat thermostat)
|
||||
{
|
||||
Number ret = new Number(MQTTModule.MqttDeviceRegistry)
|
||||
Number ret = new Number
|
||||
{
|
||||
unique_id = $"{Global.mqtt_prefix}thermostat{thermostat.Number}dehumidify",
|
||||
name = $"{Global.mqtt_discovery_name_prefix}{thermostat.Name} Dehumidify",
|
||||
@ -503,7 +469,7 @@ namespace OmniLinkBridge.MQTT
|
||||
|
||||
public static Sensor ToConfigHumidity(this clsThermostat thermostat)
|
||||
{
|
||||
Sensor ret = new Sensor(MQTTModule.MqttDeviceRegistry)
|
||||
Sensor ret = new Sensor
|
||||
{
|
||||
unique_id = $"{Global.mqtt_prefix}thermostat{thermostat.Number}humidity",
|
||||
name = $"{Global.mqtt_discovery_name_prefix}{thermostat.Name} Humidity",
|
||||
@ -516,19 +482,8 @@ namespace OmniLinkBridge.MQTT
|
||||
|
||||
public static Climate ToConfig(this clsThermostat thermostat, enuTempFormat format)
|
||||
{
|
||||
Climate ret = new Climate(MQTTModule.MqttDeviceRegistry)
|
||||
Climate ret = new Climate
|
||||
{
|
||||
unique_id = $"{Global.mqtt_prefix}thermostat{thermostat.Number}",
|
||||
name = Global.mqtt_discovery_name_prefix + thermostat.Name,
|
||||
|
||||
availability_topic = null,
|
||||
availability_mode = Device.AvailabilityMode.all,
|
||||
availability = new List<Availability>()
|
||||
{
|
||||
new Availability(),
|
||||
new Availability() { topic = thermostat.ToTopic(Topic.status) }
|
||||
},
|
||||
|
||||
modes = thermostat.Type switch
|
||||
{
|
||||
enuThermostatType.AutoHeatCool => new List<string>(new string[] { "auto", "off", "cool", "heat" }),
|
||||
@ -536,25 +491,7 @@ namespace OmniLinkBridge.MQTT
|
||||
enuThermostatType.HeatOnly => new List<string>(new string[] { "off", "heat" }),
|
||||
enuThermostatType.CoolOnly => new List<string>(new string[] { "off", "cool" }),
|
||||
_ => new List<string>(new string[] { "off" }),
|
||||
},
|
||||
|
||||
action_topic = thermostat.ToTopic(Topic.current_operation),
|
||||
current_temperature_topic = thermostat.ToTopic(Topic.current_temperature),
|
||||
|
||||
temperature_low_state_topic = thermostat.ToTopic(Topic.temperature_heat_state),
|
||||
temperature_low_command_topic = thermostat.ToTopic(Topic.temperature_heat_command),
|
||||
|
||||
temperature_high_state_topic = thermostat.ToTopic(Topic.temperature_cool_state),
|
||||
temperature_high_command_topic = thermostat.ToTopic(Topic.temperature_cool_command),
|
||||
|
||||
mode_state_topic = thermostat.ToTopic(Topic.mode_basic_state),
|
||||
mode_command_topic = thermostat.ToTopic(Topic.mode_command),
|
||||
|
||||
fan_mode_state_topic = thermostat.ToTopic(Topic.fan_mode_state),
|
||||
fan_mode_command_topic = thermostat.ToTopic(Topic.fan_mode_command),
|
||||
|
||||
preset_mode_state_topic = thermostat.ToTopic(Topic.hold_state),
|
||||
preset_mode_command_topic = thermostat.ToTopic(Topic.hold_command)
|
||||
}
|
||||
};
|
||||
|
||||
if (format == enuTempFormat.Celsius)
|
||||
@ -563,6 +500,26 @@ namespace OmniLinkBridge.MQTT
|
||||
ret.max_temp = "35";
|
||||
}
|
||||
|
||||
ret.unique_id = $"{Global.mqtt_prefix}thermostat{thermostat.Number}";
|
||||
ret.name = Global.mqtt_discovery_name_prefix + thermostat.Name;
|
||||
|
||||
ret.action_topic = thermostat.ToTopic(Topic.current_operation);
|
||||
ret.current_temperature_topic = thermostat.ToTopic(Topic.current_temperature);
|
||||
|
||||
ret.temperature_low_state_topic = thermostat.ToTopic(Topic.temperature_heat_state);
|
||||
ret.temperature_low_command_topic = thermostat.ToTopic(Topic.temperature_heat_command);
|
||||
|
||||
ret.temperature_high_state_topic = thermostat.ToTopic(Topic.temperature_cool_state);
|
||||
ret.temperature_high_command_topic = thermostat.ToTopic(Topic.temperature_cool_command);
|
||||
|
||||
ret.mode_state_topic = thermostat.ToTopic(Topic.mode_basic_state);
|
||||
ret.mode_command_topic = thermostat.ToTopic(Topic.mode_command);
|
||||
|
||||
ret.fan_mode_state_topic = thermostat.ToTopic(Topic.fan_mode_state);
|
||||
ret.fan_mode_command_topic = thermostat.ToTopic(Topic.fan_mode_command);
|
||||
|
||||
ret.preset_mode_state_topic = thermostat.ToTopic(Topic.hold_state);
|
||||
ret.preset_mode_command_topic = thermostat.ToTopic(Topic.hold_command);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -597,9 +554,9 @@ namespace OmniLinkBridge.MQTT
|
||||
return $"{Global.mqtt_prefix}/button{button.Number}/{topic}";
|
||||
}
|
||||
|
||||
public static Switch ToConfigSwitch(this clsButton button)
|
||||
public static Switch ToConfig(this clsButton button)
|
||||
{
|
||||
Switch ret = new Switch(MQTTModule.MqttDeviceRegistry)
|
||||
Switch ret = new Switch
|
||||
{
|
||||
unique_id = $"{Global.mqtt_prefix}button{button.Number}",
|
||||
name = Global.mqtt_discovery_name_prefix + button.Name,
|
||||
@ -609,18 +566,6 @@ namespace OmniLinkBridge.MQTT
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static Button ToConfigButton(this clsButton button)
|
||||
{
|
||||
Button ret = new Button(MQTTModule.MqttDeviceRegistry)
|
||||
{
|
||||
unique_id = $"{Global.mqtt_prefix}button{button.Number}",
|
||||
name = Global.mqtt_discovery_name_prefix + button.Name,
|
||||
command_topic = button.ToTopic(Topic.command),
|
||||
payload_press = "ON"
|
||||
};
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static string ToTopic(this clsMessage message, Topic topic)
|
||||
{
|
||||
return $"{Global.mqtt_prefix}/message{message.Number}/{topic}";
|
||||
@ -635,135 +580,5 @@ namespace OmniLinkBridge.MQTT
|
||||
else
|
||||
return "off";
|
||||
}
|
||||
|
||||
public static string ToTopic(this clsAccessControlReader reader, Topic topic)
|
||||
{
|
||||
return $"{Global.mqtt_prefix}/lock{reader.Number}/{topic}";
|
||||
}
|
||||
|
||||
public static Lock ToConfig(this clsAccessControlReader reader)
|
||||
{
|
||||
Lock ret = new Lock(MQTTModule.MqttDeviceRegistry)
|
||||
{
|
||||
unique_id = $"{Global.mqtt_prefix}lock{reader.Number}",
|
||||
name = Global.mqtt_discovery_name_prefix + reader.Name,
|
||||
state_topic = reader.ToTopic(Topic.state),
|
||||
command_topic = reader.ToTopic(Topic.command),
|
||||
payload_lock = "lock",
|
||||
payload_unlock = "unlock",
|
||||
state_locked = "locked",
|
||||
state_unlocked = "unlocked"
|
||||
};
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static string ToState(this clsAccessControlReader reader)
|
||||
{
|
||||
if (reader.LockStatus == 0)
|
||||
return "locked";
|
||||
else
|
||||
return "unlocked";
|
||||
}
|
||||
|
||||
public static string ToTopic(this clsAudioSource audioSource, Topic topic)
|
||||
{
|
||||
return $"{Global.mqtt_prefix}/source{audioSource.Number}/{topic}";
|
||||
}
|
||||
|
||||
public static string ToTopic(this clsAudioZone audioZone, Topic topic)
|
||||
{
|
||||
return $"{Global.mqtt_prefix}/audio{audioZone.Number}/{topic}";
|
||||
}
|
||||
|
||||
public static Switch ToConfig(this clsAudioZone audioZone)
|
||||
{
|
||||
Switch ret = new Switch(MQTTModule.MqttDeviceRegistry)
|
||||
{
|
||||
unique_id = $"{Global.mqtt_prefix}audio{audioZone.Number}",
|
||||
name = Global.mqtt_discovery_name_prefix + audioZone.rawName,
|
||||
icon = "mdi:speaker",
|
||||
state_topic = audioZone.ToTopic(Topic.state),
|
||||
command_topic = audioZone.ToTopic(Topic.command)
|
||||
};
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static string ToState(this clsAudioZone audioZone)
|
||||
{
|
||||
return audioZone.Power ? "ON" : "OFF";
|
||||
}
|
||||
|
||||
public static Switch ToConfigMute(this clsAudioZone audioZone)
|
||||
{
|
||||
Switch ret = new Switch(MQTTModule.MqttDeviceRegistry)
|
||||
{
|
||||
unique_id = $"{Global.mqtt_prefix}audio{audioZone.Number}mute",
|
||||
name = $"{Global.mqtt_discovery_name_prefix}{audioZone.rawName} Mute",
|
||||
icon = "mdi:volume-mute",
|
||||
state_topic = audioZone.ToTopic(Topic.mute_state),
|
||||
command_topic = audioZone.ToTopic(Topic.mute_command)
|
||||
};
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static string ToMuteState(this clsAudioZone audioZone)
|
||||
{
|
||||
if(Global.mqtt_audio_local_mute)
|
||||
return audioZone.Volume == 0 ? "ON" : "OFF";
|
||||
else
|
||||
return audioZone.Mute ? "ON" : "OFF";
|
||||
}
|
||||
|
||||
public static Select ToConfigSource(this clsAudioZone audioZone, List<string> audioSources)
|
||||
{
|
||||
Select ret = new Select(MQTTModule.MqttDeviceRegistry)
|
||||
{
|
||||
unique_id = $"{Global.mqtt_prefix}audio{audioZone.Number}source",
|
||||
name = $"{Global.mqtt_discovery_name_prefix}{audioZone.rawName} Source",
|
||||
icon = "mdi:volume-source",
|
||||
state_topic = audioZone.ToTopic(Topic.source_state),
|
||||
command_topic = audioZone.ToTopic(Topic.source_command),
|
||||
options = audioSources
|
||||
};
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static int ToSourceState(this clsAudioZone audioZone)
|
||||
{
|
||||
return audioZone.Source;
|
||||
}
|
||||
|
||||
public static Number ToConfigVolume(this clsAudioZone audioZone)
|
||||
{
|
||||
Number ret = new Number(MQTTModule.MqttDeviceRegistry)
|
||||
{
|
||||
unique_id = $"{Global.mqtt_prefix}audio{audioZone.Number}volume",
|
||||
name = $"{Global.mqtt_discovery_name_prefix}{audioZone.rawName} Volume",
|
||||
icon = "mdi:volume-low",
|
||||
state_topic = audioZone.ToTopic(Topic.volume_state),
|
||||
command_topic = audioZone.ToTopic(Topic.volume_command),
|
||||
min = 0,
|
||||
max = 100,
|
||||
step = 1,
|
||||
};
|
||||
|
||||
if(Global.mqtt_audio_volume_media_player)
|
||||
{
|
||||
ret.min = 0;
|
||||
ret.max = 1;
|
||||
ret.step = 0.01;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static double ToVolumeState(this clsAudioZone audioZone)
|
||||
{
|
||||
if (Global.mqtt_audio_volume_media_player)
|
||||
return audioZone.Volume * 0.01;
|
||||
else
|
||||
return audioZone.Volume;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
namespace OmniLinkBridge.MQTT.Parser
|
||||
namespace OmniLinkBridge.MQTT
|
||||
{
|
||||
enum MessageCommands
|
||||
{
|
@ -1,12 +1,10 @@
|
||||
using HAI_Shared;
|
||||
using OmniLinkBridge.MQTT.Parser;
|
||||
using OmniLinkBridge.OmniLink;
|
||||
using Serilog;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
|
||||
namespace OmniLinkBridge.MQTT
|
||||
{
|
||||
@ -16,18 +14,11 @@ namespace OmniLinkBridge.MQTT
|
||||
|
||||
private readonly Regex regexTopic = new Regex(Global.mqtt_prefix + "/([A-Za-z]+)([0-9]+)/(.*)", RegexOptions.Compiled);
|
||||
|
||||
private readonly int[] audioMuteVolumes;
|
||||
private const int VOLUME_DEFAULT = 10;
|
||||
private IOmniLinkII OmniLink { get; set; }
|
||||
|
||||
private IOmniLinkII OmniLink { get; }
|
||||
private Dictionary<string, int> AudioSources { get; }
|
||||
|
||||
public MessageProcessor(IOmniLinkII omni, Dictionary<string, int> audioSources, int numAudioZones)
|
||||
public MessageProcessor(IOmniLinkII omni)
|
||||
{
|
||||
OmniLink = omni;
|
||||
AudioSources = audioSources;
|
||||
|
||||
audioMuteVolumes = new int[numAudioZones];
|
||||
}
|
||||
|
||||
public void Process(string messageTopic, string payload)
|
||||
@ -37,8 +28,8 @@ namespace OmniLinkBridge.MQTT
|
||||
if (!match.Success)
|
||||
return;
|
||||
|
||||
if (!Enum.TryParse(match.Groups[1].Value, true, out CommandTypes type)
|
||||
|| !Enum.TryParse(match.Groups[3].Value, true, out Topic topic)
|
||||
if (!Enum.TryParse(match.Groups[1].Value, true, out CommandTypes type)
|
||||
|| !Enum.TryParse(match.Groups[3].Value, true, out Topic topic)
|
||||
|| !ushort.TryParse(match.Groups[2].Value, out ushort id))
|
||||
return;
|
||||
|
||||
@ -57,10 +48,6 @@ namespace OmniLinkBridge.MQTT
|
||||
ProcessButtonReceived(OmniLink.Controller.Buttons[id], topic, payload);
|
||||
else if (type == CommandTypes.message && id > 0 && id <= OmniLink.Controller.Messages.Count)
|
||||
ProcessMessageReceived(OmniLink.Controller.Messages[id], topic, payload);
|
||||
else if (type == CommandTypes.@lock && id <= OmniLink.Controller.AccessControlReaders.Count)
|
||||
ProcessLockReceived(OmniLink.Controller.AccessControlReaders[id], topic, payload);
|
||||
else if (type == CommandTypes.audio && id <= OmniLink.Controller.AudioZones.Count)
|
||||
ProcessAudioReceived(OmniLink.Controller.AudioZones[id], topic, payload);
|
||||
}
|
||||
|
||||
private static readonly IDictionary<AreaCommands, enuUnitCommand> AreaMapping = new Dictionary<AreaCommands, enuUnitCommand>
|
||||
@ -88,7 +75,7 @@ namespace OmniLinkBridge.MQTT
|
||||
{
|
||||
string sCode = parser.Code.ToString();
|
||||
|
||||
if (sCode.Length != 4)
|
||||
if(sCode.Length != 4)
|
||||
{
|
||||
log.Warning("SetArea: {id}, Invalid security code: must be 4 digits", area.Number);
|
||||
return;
|
||||
@ -108,7 +95,7 @@ namespace OmniLinkBridge.MQTT
|
||||
|
||||
var validateCode = new clsOL2MsgValidateCode(OmniLink.Controller.Connection, B);
|
||||
|
||||
if (validateCode.AuthorityLevel == 0)
|
||||
if(validateCode.AuthorityLevel == 0)
|
||||
{
|
||||
log.Warning("SetArea: {id}, Invalid security code: validation failed", area.Number);
|
||||
return;
|
||||
@ -153,7 +140,7 @@ namespace OmniLinkBridge.MQTT
|
||||
{
|
||||
AreaCommandCode parser = payload.ToCommandCode();
|
||||
|
||||
if (parser.Success && command == Topic.command && Enum.TryParse(parser.Command, true, out ZoneCommands cmd) &&
|
||||
if (parser.Success && command == Topic.command && Enum.TryParse(parser.Command, true, out ZoneCommands cmd) &&
|
||||
!(zone.Number == 0 && cmd == ZoneCommands.bypass))
|
||||
{
|
||||
if (zone.Number == 0)
|
||||
@ -180,16 +167,10 @@ namespace OmniLinkBridge.MQTT
|
||||
OmniLink.SendCommand(UnitMapping[cmd], 0, (ushort)unit.Number);
|
||||
}
|
||||
}
|
||||
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))
|
||||
else if (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
|
||||
@ -197,10 +178,10 @@ namespace OmniLinkBridge.MQTT
|
||||
// which will cause light to go to 100% brightness
|
||||
unit.Status = (byte)(100 + unitValue);
|
||||
}
|
||||
else if (unit.Type != enuOL2UnitType.Output &&
|
||||
command == Topic.scene_command && char.TryParse(payload, out char scene))
|
||||
else if (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);
|
||||
}
|
||||
}
|
||||
@ -306,111 +287,5 @@ namespace OmniLinkBridge.MQTT
|
||||
OmniLink.SendCommand(MessageMapping[cmd], par, (ushort)message.Number);
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly IDictionary<LockCommands, enuUnitCommand> LockMapping = new Dictionary<LockCommands, enuUnitCommand>
|
||||
{
|
||||
{ LockCommands.@lock, enuUnitCommand.Lock },
|
||||
{ LockCommands.unlock, enuUnitCommand.Unlock },
|
||||
};
|
||||
|
||||
private void ProcessLockReceived(clsAccessControlReader reader, Topic command, string payload)
|
||||
{
|
||||
if (command == Topic.command && Enum.TryParse(payload, true, out LockCommands cmd))
|
||||
{
|
||||
if (reader.Number == 0)
|
||||
log.Debug("SetLock: 0 implies all locks will be changed");
|
||||
|
||||
log.Debug("SetLock: {id} to {value}", reader.Number, payload);
|
||||
|
||||
OmniLink.SendCommand(LockMapping[cmd], 0, (ushort)reader.Number);
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessAudioReceived(clsAudioZone audioZone, Topic command, string payload)
|
||||
{
|
||||
if (command == Topic.command && Enum.TryParse(payload, true, out UnitCommands cmd))
|
||||
{
|
||||
if (audioZone.Number == 0)
|
||||
log.Debug("SetAudio: 0 implies all audio zones will be changed");
|
||||
|
||||
log.Debug("SetAudio: {id} to {value}", audioZone.Number, payload);
|
||||
|
||||
OmniLink.SendCommand(enuUnitCommand.AudioZone, (byte)cmd, (ushort)audioZone.Number);
|
||||
|
||||
// Send power ON twice to workaround Russound standby
|
||||
if(cmd == UnitCommands.ON)
|
||||
{
|
||||
Thread.Sleep(500);
|
||||
OmniLink.SendCommand(enuUnitCommand.AudioZone, (byte)cmd, (ushort)audioZone.Number);
|
||||
}
|
||||
}
|
||||
else if (command == Topic.mute_command && Enum.TryParse(payload, true, out UnitCommands mute))
|
||||
{
|
||||
if (audioZone.Number == 0)
|
||||
{
|
||||
if (Global.mqtt_audio_local_mute)
|
||||
{
|
||||
log.Warning("SetAudioMute: 0 not supported with local mute");
|
||||
return;
|
||||
}
|
||||
else
|
||||
log.Debug("SetAudioMute: 0 implies all audio zones will be changed");
|
||||
}
|
||||
|
||||
if (Global.mqtt_audio_local_mute)
|
||||
{
|
||||
if (mute == UnitCommands.ON)
|
||||
{
|
||||
log.Debug("SetAudioMute: {id} local mute, previous volume {level}",
|
||||
audioZone.Number, audioZone.Volume);
|
||||
audioMuteVolumes[audioZone.Number] = audioZone.Volume;
|
||||
|
||||
OmniLink.SendCommand(enuUnitCommand.AudioVolume, 0, (ushort)audioZone.Number);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (audioMuteVolumes[audioZone.Number] == 0)
|
||||
{
|
||||
log.Debug("SetAudioMute: {id} local mute, defaulting to volume {level}",
|
||||
audioZone.Number, VOLUME_DEFAULT);
|
||||
audioMuteVolumes[audioZone.Number] = VOLUME_DEFAULT;
|
||||
}
|
||||
else
|
||||
{
|
||||
log.Debug("SetAudioMute: {id} local mute, restoring to volume {level}",
|
||||
audioZone.Number, audioMuteVolumes[audioZone.Number]);
|
||||
}
|
||||
|
||||
OmniLink.SendCommand(enuUnitCommand.AudioVolume, (byte)audioMuteVolumes[audioZone.Number], (ushort)audioZone.Number);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
log.Debug("SetAudioMute: {id} to {value}", audioZone.Number, payload);
|
||||
|
||||
OmniLink.SendCommand(enuUnitCommand.AudioZone, (byte)(mute + 2), (ushort)audioZone.Number);
|
||||
}
|
||||
}
|
||||
else if (command == Topic.source_command && AudioSources.TryGetValue(payload, out int source))
|
||||
{
|
||||
log.Debug("SetAudioSource: {id} to {value}", audioZone.Number, payload);
|
||||
|
||||
OmniLink.SendCommand(enuUnitCommand.AudioSource, (byte)source, (ushort)audioZone.Number);
|
||||
}
|
||||
else if (command == Topic.volume_command && double.TryParse(payload, out double volume))
|
||||
{
|
||||
if (Global.mqtt_audio_volume_media_player)
|
||||
volume *= 100;
|
||||
|
||||
if (volume > 100)
|
||||
volume = 100;
|
||||
else if (volume < 0)
|
||||
volume = 0;
|
||||
|
||||
log.Debug("SetAudioVolume: {id} to {value}", audioZone.Number, volume);
|
||||
|
||||
OmniLink.SendCommand(enuUnitCommand.AudioVolume, (byte)volume, (ushort)audioZone.Number);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
12
OmniLinkBridge/MQTT/Number.cs
Normal file
12
OmniLinkBridge/MQTT/Number.cs
Normal file
@ -0,0 +1,12 @@
|
||||
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; }
|
||||
}
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace OmniLinkBridge.MQTT
|
||||
{
|
||||
public class OverrideArea
|
||||
{
|
||||
public bool code_arm { get; set; }
|
||||
|
||||
public bool code_disarm { get; set; }
|
||||
|
||||
public bool arm_home { get; set; } = true;
|
||||
|
||||
public bool arm_away { get; set; } = true;
|
||||
|
||||
public bool arm_night { get; set; } = true;
|
||||
|
||||
public bool arm_vacation { get; set; } = true;
|
||||
}
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
namespace OmniLinkBridge.MQTT
|
||||
{
|
||||
public class OverrideUnit
|
||||
{
|
||||
public UnitType type { get; set; }
|
||||
}
|
||||
}
|
@ -1,6 +1,4 @@
|
||||
using OmniLinkBridge.MQTT.HomeAssistant;
|
||||
|
||||
namespace OmniLinkBridge.MQTT
|
||||
namespace OmniLinkBridge.MQTT
|
||||
{
|
||||
public class OverrideZone
|
||||
{
|
||||
|
@ -1,8 +0,0 @@
|
||||
namespace OmniLinkBridge.MQTT.Parser
|
||||
{
|
||||
enum LockCommands
|
||||
{
|
||||
@lock,
|
||||
unlock
|
||||
}
|
||||
}
|
@ -1,15 +1,10 @@
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Converters;
|
||||
|
||||
namespace OmniLinkBridge.MQTT.HomeAssistant
|
||||
namespace OmniLinkBridge.MQTT
|
||||
{
|
||||
public class Sensor : Device
|
||||
{
|
||||
public Sensor(DeviceRegistry deviceRegistry) : base(deviceRegistry)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
[JsonConverter(typeof(StringEnumConverter))]
|
||||
public enum DeviceClass
|
||||
{
|
||||
@ -20,6 +15,9 @@ namespace OmniLinkBridge.MQTT.HomeAssistant
|
||||
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
|
||||
public DeviceClass? device_class { get; set; }
|
||||
|
||||
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string icon { get; set; }
|
||||
|
||||
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string unit_of_measurement { get; set; }
|
||||
|
@ -1,14 +1,9 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace OmniLinkBridge.MQTT.HomeAssistant
|
||||
namespace OmniLinkBridge.MQTT
|
||||
{
|
||||
public class Switch : Device
|
||||
{
|
||||
public Switch(DeviceRegistry deviceRegistry) : base(deviceRegistry)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public string command_topic { get; set; }
|
||||
|
||||
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
|
@ -1,9 +1,8 @@
|
||||
namespace OmniLinkBridge.MQTT.Parser
|
||||
namespace OmniLinkBridge.MQTT
|
||||
{
|
||||
public enum Topic
|
||||
{
|
||||
name,
|
||||
status,
|
||||
state,
|
||||
command,
|
||||
alarm_command,
|
||||
@ -11,8 +10,6 @@
|
||||
json_state,
|
||||
brightness_state,
|
||||
brightness_command,
|
||||
flag_state,
|
||||
flag_command,
|
||||
scene_state,
|
||||
scene_command,
|
||||
current_operation,
|
||||
@ -33,11 +30,5 @@
|
||||
fan_mode_command,
|
||||
hold_state,
|
||||
hold_command,
|
||||
mute_state,
|
||||
mute_command,
|
||||
source_state,
|
||||
source_command,
|
||||
volume_state,
|
||||
volume_command,
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
namespace OmniLinkBridge.MQTT.Parser
|
||||
namespace OmniLinkBridge.MQTT
|
||||
{
|
||||
enum UnitCommands
|
||||
{
|
@ -1,9 +0,0 @@
|
||||
namespace OmniLinkBridge.MQTT
|
||||
{
|
||||
public enum UnitType
|
||||
{
|
||||
@switch,
|
||||
light,
|
||||
number
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
namespace OmniLinkBridge.MQTT.Parser
|
||||
namespace OmniLinkBridge.MQTT
|
||||
{
|
||||
enum ZoneCommands
|
||||
{
|
@ -2,7 +2,6 @@
|
||||
using OmniLinkBridge.Notifications;
|
||||
using OmniLinkBridge.OmniLink;
|
||||
using Serilog;
|
||||
using Serilog.Context;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
@ -39,8 +38,6 @@ namespace OmniLinkBridge.Modules
|
||||
omnilink.OnThermostatStatus += Omnilink_OnThermostatStatus;
|
||||
omnilink.OnUnitStatus += Omnilink_OnUnitStatus;
|
||||
omnilink.OnMessageStatus += Omnilink_OnMessageStatus;
|
||||
omnilink.OnLockStatus += Omnilink_OnLockStatus;
|
||||
omnilink.OnAudioZoneStatus += Omnilink_OnAudioZoneStatus;
|
||||
omnilink.OnSystemStatus += Omnilink_OnSystemStatus;
|
||||
}
|
||||
|
||||
@ -48,7 +45,6 @@ namespace OmniLinkBridge.Modules
|
||||
{
|
||||
if (Global.mysql_logging)
|
||||
{
|
||||
log.Warning("MySQL logging is deprecated");
|
||||
log.Information("Connecting to database");
|
||||
|
||||
mysql_conn = new OdbcConnection(Global.mysql_connection);
|
||||
@ -129,18 +125,15 @@ namespace OmniLinkBridge.Modules
|
||||
|
||||
private void Omnilink_OnConnect(object sender, EventArgs e)
|
||||
{
|
||||
ushort areaUsage = 0;
|
||||
for (ushort i = 1; i <= omnilink.Controller.Areas.Count; i++)
|
||||
if (Global.verbose_area)
|
||||
{
|
||||
clsArea area = omnilink.Controller.Areas[i];
|
||||
|
||||
if (i > 1 && area.DefaultProperties == true)
|
||||
continue;
|
||||
|
||||
areaUsage++;
|
||||
|
||||
if (Global.verbose_area)
|
||||
for (ushort i = 1; i <= omnilink.Controller.Areas.Count; i++)
|
||||
{
|
||||
clsArea area = omnilink.Controller.Areas[i];
|
||||
|
||||
if (i > 1 && area.DefaultProperties == true)
|
||||
continue;
|
||||
|
||||
string status = area.ModeText();
|
||||
|
||||
if (area.ExitTimer > 0)
|
||||
@ -153,104 +146,21 @@ namespace OmniLinkBridge.Modules
|
||||
}
|
||||
}
|
||||
|
||||
ushort zoneUsage = 0;
|
||||
for (ushort i = 1; i <= omnilink.Controller.Zones.Count; i++)
|
||||
if (Global.verbose_zone)
|
||||
{
|
||||
clsZone zone = omnilink.Controller.Zones[i];
|
||||
|
||||
if (zone.DefaultProperties == true)
|
||||
continue;
|
||||
|
||||
zoneUsage++;
|
||||
|
||||
if (Global.verbose_zone)
|
||||
for (ushort i = 1; i <= omnilink.Controller.Zones.Count; i++)
|
||||
{
|
||||
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++;
|
||||
}
|
||||
|
||||
ushort lockUsage = 0;
|
||||
for (ushort i = 1; i <= omnilink.Controller.AccessControlReaders.Count; i++)
|
||||
{
|
||||
clsAccessControlReader reader = omnilink.Controller.AccessControlReaders[i];
|
||||
|
||||
if (reader.DefaultProperties == true)
|
||||
continue;
|
||||
|
||||
lockUsage++;
|
||||
|
||||
if(Global.verbose_lock)
|
||||
log.Verbose("Initial LockStatus {id} {name}, Status: {status}", i, reader.Name, reader.LockStatusText());
|
||||
}
|
||||
|
||||
ushort audioSourceUsage = 0;
|
||||
for (ushort i = 1; i <= omnilink.Controller.AudioSources.Count; i++)
|
||||
{
|
||||
clsAudioSource audioSource = omnilink.Controller.AudioSources[i];
|
||||
|
||||
if (audioSource.DefaultProperties == true)
|
||||
continue;
|
||||
|
||||
audioSourceUsage++;
|
||||
|
||||
if (Global.verbose_audio)
|
||||
log.Verbose("Initial AudioSource {id} {name}", i, audioSource.rawName);
|
||||
}
|
||||
|
||||
ushort audioZoneUsage = 0;
|
||||
for (ushort i = 1; i <= omnilink.Controller.AudioZones.Count; i++)
|
||||
{
|
||||
clsAudioZone audioZone = omnilink.Controller.AudioZones[i];
|
||||
|
||||
if (audioZone.DefaultProperties == true)
|
||||
continue;
|
||||
|
||||
audioZoneUsage++;
|
||||
|
||||
if (Global.verbose_audio)
|
||||
log.Verbose("Initial AudioZoneStatus {id} {name}, Power: {power}, Source: {source}, Volume: {volume}, Mute: {mute}",
|
||||
i, audioZone.rawName, audioZone.Power, audioZone.Source, audioZone.Volume, audioZone.Mute);
|
||||
}
|
||||
|
||||
using (LogContext.PushProperty("Telemetry", "ControllerUsage"))
|
||||
log.Debug("Controller has {AreaUsage} areas, {ZoneUsage} zones, {UnitUsage} units, " +
|
||||
"{OutputUsage} outputs, {FlagUsage} flags, {ThermostatUsage} thermostats, {LockUsage} locks, " +
|
||||
"{AudioSourceUsage} audio sources, {AudioZoneUsage} audio zones",
|
||||
areaUsage, zoneUsage, unitUsage, outputUsage, flagUsage, thermostatUsage, lockUsage,
|
||||
audioSourceUsage, audioZoneUsage);
|
||||
}
|
||||
|
||||
private void Omnilink_OnAreaStatus(object sender, AreaStatusEventArgs e)
|
||||
@ -278,7 +188,7 @@ namespace OmniLinkBridge.Modules
|
||||
e.Area.AreaDuressAlarmText + "','" + status + "')");
|
||||
|
||||
if (Global.verbose_area)
|
||||
log.Verbose("AreaStatus {id} {name}, Status: {status}, Alarms: {alarms}", e.ID, e.Area.Name, status, e.Area.AreaAlarms);
|
||||
log.Verbose("AreaStatus {id} {name}, Status: {status}, Alarams: {alarms}", e.ID, e.Area.Name, status, e.Area.AreaAlarms);
|
||||
|
||||
if (Global.notify_area && e.Area.LastMode != e.Area.AreaMode)
|
||||
Notification.Notify("Security", e.Area.Name + " " + e.Area.ModeText());
|
||||
@ -336,10 +246,6 @@ namespace OmniLinkBridge.Modules
|
||||
humidity + "','" + humidify + "','" + dehumidify + "','" +
|
||||
e.Thermostat.ModeText() + "','" + e.Thermostat.FanModeText() + "','" + e.Thermostat.HoldStatusText() + "')");
|
||||
|
||||
if (e.Offline)
|
||||
log.Warning("Unknown temp for Thermostat {thermostatName}, verify thermostat is online",
|
||||
e.Thermostat.Name);
|
||||
|
||||
// Ignore events fired by thermostat polling
|
||||
if (!e.EventTimer && Global.verbose_thermostat)
|
||||
log.Verbose("ThermostatStatus {id} {name}, Status: {temp} {status}, " +
|
||||
@ -385,19 +291,6 @@ namespace OmniLinkBridge.Modules
|
||||
Notification.Notify("Message", e.ID + " " + e.Message.Name + ", " + e.Message.StatusText());
|
||||
}
|
||||
|
||||
private void Omnilink_OnLockStatus(object sender, LockStatusEventArgs e)
|
||||
{
|
||||
if (Global.verbose_lock)
|
||||
log.Verbose("LockStatus {id} {name}, Status: {status}", e.ID, e.Reader.Name, e.Reader.LockStatusText());
|
||||
}
|
||||
|
||||
private void Omnilink_OnAudioZoneStatus(object sender, AudioZoneStatusEventArgs e)
|
||||
{
|
||||
if (Global.verbose_audio)
|
||||
log.Verbose("AudioZoneStatus {id} {name}, Power: {power}, Source: {source}, Volume: {volume}, Mute: {mute}",
|
||||
e.ID, e.AudioZone.rawName, e.AudioZone.Power, e.AudioZone.Source, e.AudioZone.Volume, e.AudioZone.Mute);
|
||||
}
|
||||
|
||||
private void Omnilink_OnSystemStatus(object sender, SystemStatusEventArgs e)
|
||||
{
|
||||
DBQueue(@"
|
||||
|
@ -9,13 +9,10 @@ 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;
|
||||
@ -34,16 +31,11 @@ namespace OmniLinkBridge.Modules
|
||||
private bool ControllerConnected { get; set; }
|
||||
private MessageProcessor MessageProcessor { get; set; }
|
||||
|
||||
private Dictionary<string, int> AudioSources { get; set; } = new Dictionary<string, int>();
|
||||
|
||||
private readonly AutoResetEvent trigger = new AutoResetEvent(false);
|
||||
|
||||
private const string ONLINE = "online";
|
||||
private const string OFFLINE = "offline";
|
||||
|
||||
private const string SECURE = "secure";
|
||||
private const string TROUBLE = "trouble";
|
||||
|
||||
public MQTTModule(OmniLinkII omni)
|
||||
{
|
||||
OmniLink = omni;
|
||||
@ -55,11 +47,9 @@ namespace OmniLinkBridge.Modules
|
||||
OmniLink.OnThermostatStatus += Omnilink_OnThermostatStatus;
|
||||
OmniLink.OnButtonStatus += OmniLink_OnButtonStatus;
|
||||
OmniLink.OnMessageStatus += OmniLink_OnMessageStatus;
|
||||
OmniLink.OnLockStatus += OmniLink_OnLockStatus;
|
||||
OmniLink.OnAudioZoneStatus += OmniLink_OnAudioZoneStatus;
|
||||
OmniLink.OnSystemStatus += OmniLink_OnSystemStatus;
|
||||
|
||||
MessageProcessor = new MessageProcessor(omni, AudioSources, omni.Controller.CAP.numAudioZones);
|
||||
MessageProcessor = new MessageProcessor(omni);
|
||||
}
|
||||
|
||||
public void Startup()
|
||||
@ -118,7 +108,6 @@ 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,
|
||||
@ -126,10 +115,7 @@ namespace OmniLinkBridge.Modules
|
||||
Topic.dehumidify_command,
|
||||
Topic.mode_command,
|
||||
Topic.fan_mode_command,
|
||||
Topic.hold_command,
|
||||
Topic.mute_command,
|
||||
Topic.source_command,
|
||||
Topic.volume_command
|
||||
Topic.hold_command
|
||||
};
|
||||
|
||||
toSubscribe.ForEach((command) => MqttClient.SubscribeAsync(
|
||||
@ -167,7 +153,7 @@ namespace OmniLinkBridge.Modules
|
||||
private void PublishControllerStatus(string status)
|
||||
{
|
||||
log.Information("Publishing controller {status}", status);
|
||||
PublishAsync($"{Global.mqtt_prefix}/{Topic.status}", status);
|
||||
PublishAsync($"{Global.mqtt_prefix}/status", status);
|
||||
}
|
||||
|
||||
private void PublishConfig()
|
||||
@ -179,9 +165,6 @@ namespace OmniLinkBridge.Modules
|
||||
PublishThermostats();
|
||||
PublishButtons();
|
||||
PublishMessages();
|
||||
PublishLocks();
|
||||
PublishAudioSources();
|
||||
PublishAudioZones();
|
||||
|
||||
PublishControllerStatus(ONLINE);
|
||||
PublishAsync($"{Global.mqtt_prefix}/model", OmniLink.Controller.GetModelText());
|
||||
@ -201,10 +184,10 @@ namespace OmniLinkBridge.Modules
|
||||
PublishAsync($"{Global.mqtt_discovery_prefix}/binary_sensor/{Global.mqtt_prefix}/system_dcm/config",
|
||||
JsonConvert.SerializeObject(SystemTroubleConfig("dcm", "DCM")));
|
||||
|
||||
PublishAsync(SystemTroubleTopic("phone"), OmniLink.TroublePhone ? TROUBLE : SECURE);
|
||||
PublishAsync(SystemTroubleTopic("ac"), OmniLink.TroubleAC ? TROUBLE : SECURE);
|
||||
PublishAsync(SystemTroubleTopic("battery"), OmniLink.TroubleBattery ? TROUBLE : SECURE);
|
||||
PublishAsync(SystemTroubleTopic("dcm"), OmniLink.TroubleDCM ? TROUBLE : SECURE);
|
||||
PublishAsync(SystemTroubleTopic("phone"), OmniLink.TroublePhone ? "trouble" : "secure");
|
||||
PublishAsync(SystemTroubleTopic("ac"), OmniLink.TroubleAC ? "trouble" : "secure");
|
||||
PublishAsync(SystemTroubleTopic("battery"), OmniLink.TroubleBattery ? "trouble" : "secure");
|
||||
PublishAsync(SystemTroubleTopic("dcm"), OmniLink.TroubleDCM ? "trouble" : "secure");
|
||||
}
|
||||
|
||||
public string SystemTroubleTopic(string type)
|
||||
@ -214,14 +197,14 @@ namespace OmniLinkBridge.Modules
|
||||
|
||||
public BinarySensor SystemTroubleConfig(string type, string name)
|
||||
{
|
||||
return new BinarySensor(MQTTModule.MqttDeviceRegistry)
|
||||
return new BinarySensor
|
||||
{
|
||||
unique_id = $"{Global.mqtt_prefix}system{type}",
|
||||
name = $"{Global.mqtt_discovery_name_prefix}System {name}",
|
||||
state_topic = SystemTroubleTopic(type),
|
||||
device_class = BinarySensor.DeviceClass.problem,
|
||||
payload_off = SECURE,
|
||||
payload_on = TROUBLE
|
||||
payload_off = "secure",
|
||||
payload_on = "trouble"
|
||||
};
|
||||
}
|
||||
|
||||
@ -233,8 +216,8 @@ namespace OmniLinkBridge.Modules
|
||||
{
|
||||
clsArea area = OmniLink.Controller.Areas[i];
|
||||
|
||||
// PC Access doesn't let you customize the area name when configured for one area.
|
||||
// Ignore default properties for the first area.
|
||||
// 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.
|
||||
if (i > 1 && area.DefaultProperties == true)
|
||||
{
|
||||
PublishAsync(area.ToTopic(Topic.name), null);
|
||||
@ -325,7 +308,6 @@ 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)
|
||||
{
|
||||
@ -339,26 +321,17 @@ namespace OmniLinkBridge.Modules
|
||||
|
||||
if (unit.DefaultProperties == true || Global.mqtt_discovery_ignore_units.Contains(unit.Number))
|
||||
{
|
||||
foreach(UnitType entry in Enum.GetValues(typeof(UnitType)))
|
||||
PublishAsync($"{Global.mqtt_discovery_prefix}/{entry}/{Global.mqtt_prefix}/unit{i}/config", null);
|
||||
|
||||
string type = i < 385 ? "light" : "switch";
|
||||
PublishAsync($"{Global.mqtt_discovery_prefix}/{type}/{Global.mqtt_prefix}/unit{i}/config", null);
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (UnitType entry in Enum.GetValues(typeof(UnitType)).Cast<UnitType>().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",
|
||||
if (i < 385)
|
||||
PublishAsync($"{Global.mqtt_discovery_prefix}/light/{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()));
|
||||
else
|
||||
PublishAsync($"{Global.mqtt_discovery_prefix}/switch/{Global.mqtt_prefix}/unit{i}/config",
|
||||
JsonConvert.SerializeObject(unit.ToConfigSwitch()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -384,7 +357,6 @@ namespace OmniLinkBridge.Modules
|
||||
PublishThermostatState(thermostat);
|
||||
|
||||
PublishAsync(thermostat.ToTopic(Topic.name), thermostat.Name);
|
||||
PublishAsync(thermostat.ToTopic(Topic.status), ONLINE);
|
||||
PublishAsync($"{Global.mqtt_discovery_prefix}/climate/{Global.mqtt_prefix}/thermostat{i}/config",
|
||||
JsonConvert.SerializeObject(thermostat.ToConfig(OmniLink.Controller.TempFormat)));
|
||||
PublishAsync($"{Global.mqtt_discovery_prefix}/number/{Global.mqtt_prefix}/thermostat{i}humidify/config",
|
||||
@ -402,9 +374,6 @@ namespace OmniLinkBridge.Modules
|
||||
{
|
||||
log.Debug("Publishing {type}", "buttons");
|
||||
|
||||
if (Global.mqtt_discovery_button_type == typeof(Switch))
|
||||
log.Information("See {setting} for new option when publishing {type}", "mqtt_discovery_button_type", "buttons");
|
||||
|
||||
for (ushort i = 1; i <= OmniLink.Controller.Buttons.Count; i++)
|
||||
{
|
||||
clsButton button = OmniLink.Controller.Buttons[i];
|
||||
@ -413,7 +382,6 @@ namespace OmniLinkBridge.Modules
|
||||
{
|
||||
PublishAsync(button.ToTopic(Topic.name), null);
|
||||
PublishAsync($"{Global.mqtt_discovery_prefix}/switch/{Global.mqtt_prefix}/button{i}/config", null);
|
||||
PublishAsync($"{Global.mqtt_discovery_prefix}/button/{Global.mqtt_prefix}/button{i}/config", null);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -421,19 +389,8 @@ namespace OmniLinkBridge.Modules
|
||||
PublishAsync(button.ToTopic(Topic.state), "OFF");
|
||||
|
||||
PublishAsync(button.ToTopic(Topic.name), button.Name);
|
||||
|
||||
if (Global.mqtt_discovery_button_type == typeof(Switch))
|
||||
{
|
||||
PublishAsync($"{Global.mqtt_discovery_prefix}/button/{Global.mqtt_prefix}/button{i}/config", null);
|
||||
PublishAsync($"{Global.mqtt_discovery_prefix}/switch/{Global.mqtt_prefix}/button{i}/config",
|
||||
JsonConvert.SerializeObject(button.ToConfigSwitch()));
|
||||
}
|
||||
else if (Global.mqtt_discovery_button_type == typeof(Button))
|
||||
{
|
||||
PublishAsync($"{Global.mqtt_discovery_prefix}/switch/{Global.mqtt_prefix}/button{i}/config", null);
|
||||
PublishAsync($"{Global.mqtt_discovery_prefix}/button/{Global.mqtt_prefix}/button{i}/config",
|
||||
JsonConvert.SerializeObject(button.ToConfigButton()));
|
||||
}
|
||||
PublishAsync($"{Global.mqtt_discovery_prefix}/switch/{Global.mqtt_prefix}/button{i}/config",
|
||||
JsonConvert.SerializeObject(button.ToConfig()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -457,97 +414,6 @@ namespace OmniLinkBridge.Modules
|
||||
}
|
||||
}
|
||||
|
||||
private void PublishLocks()
|
||||
{
|
||||
log.Debug("Publishing {type}", "locks");
|
||||
|
||||
for (ushort i = 1; i <= OmniLink.Controller.AccessControlReaders.Count; i++)
|
||||
{
|
||||
clsAccessControlReader reader = OmniLink.Controller.AccessControlReaders[i];
|
||||
|
||||
if (reader.DefaultProperties == true)
|
||||
{
|
||||
PublishAsync(reader.ToTopic(Topic.name), null);
|
||||
PublishAsync($"{Global.mqtt_discovery_prefix}/lock/{Global.mqtt_prefix}/lock{i}/config", null);
|
||||
continue;
|
||||
}
|
||||
|
||||
PublishLockStateAsync(reader);
|
||||
|
||||
PublishAsync(reader.ToTopic(Topic.name), reader.Name);
|
||||
PublishAsync($"{Global.mqtt_discovery_prefix}/lock/{Global.mqtt_prefix}/lock{i}/config",
|
||||
JsonConvert.SerializeObject(reader.ToConfig()));
|
||||
}
|
||||
}
|
||||
|
||||
private void PublishAudioSources()
|
||||
{
|
||||
log.Debug("Publishing {type}", "audio sources");
|
||||
|
||||
for (ushort i = 1; i <= OmniLink.Controller.AudioSources.Count; i++)
|
||||
{
|
||||
clsAudioSource audioSource = OmniLink.Controller.AudioSources[i];
|
||||
|
||||
if (audioSource.DefaultProperties == true)
|
||||
{
|
||||
PublishAsync(audioSource.ToTopic(Topic.name), null);
|
||||
continue;
|
||||
}
|
||||
|
||||
PublishAsync(audioSource.ToTopic(Topic.name), audioSource.rawName);
|
||||
|
||||
if (AudioSources.ContainsKey(audioSource.rawName))
|
||||
{
|
||||
log.Warning("Duplicate audio source name {name}", audioSource.rawName);
|
||||
continue;
|
||||
}
|
||||
|
||||
AudioSources.Add(audioSource.rawName, i);
|
||||
}
|
||||
}
|
||||
|
||||
private void PublishAudioZones()
|
||||
{
|
||||
log.Debug("Publishing {type}", "audio zones");
|
||||
|
||||
for (ushort i = 1; i <= OmniLink.Controller.AudioZones.Count; i++)
|
||||
{
|
||||
clsAudioZone audioZone = OmniLink.Controller.AudioZones[i];
|
||||
|
||||
if (audioZone.DefaultProperties == true)
|
||||
{
|
||||
PublishAsync(audioZone.ToTopic(Topic.name), null);
|
||||
PublishAsync($"{Global.mqtt_discovery_prefix}/switch/{Global.mqtt_prefix}/audio{i}/config", null);
|
||||
PublishAsync($"{Global.mqtt_discovery_prefix}/switch/{Global.mqtt_prefix}/audio{i}mute/config", null);
|
||||
PublishAsync($"{Global.mqtt_discovery_prefix}/select/{Global.mqtt_prefix}/audio{i}source/config", null);
|
||||
PublishAsync($"{Global.mqtt_discovery_prefix}/number/{Global.mqtt_prefix}/audio{i}volume/config", null);
|
||||
continue;
|
||||
}
|
||||
|
||||
PublishAudioZoneStateAsync(audioZone);
|
||||
|
||||
PublishAsync(audioZone.ToTopic(Topic.name), audioZone.rawName);
|
||||
PublishAsync($"{Global.mqtt_discovery_prefix}/switch/{Global.mqtt_prefix}/audio{i}/config",
|
||||
JsonConvert.SerializeObject(audioZone.ToConfig()));
|
||||
PublishAsync($"{Global.mqtt_discovery_prefix}/switch/{Global.mqtt_prefix}/audio{i}mute/config",
|
||||
JsonConvert.SerializeObject(audioZone.ToConfigMute()));
|
||||
PublishAsync($"{Global.mqtt_discovery_prefix}/select/{Global.mqtt_prefix}/audio{i}source/config",
|
||||
JsonConvert.SerializeObject(audioZone.ToConfigSource(new List<string>(AudioSources.Keys))));
|
||||
PublishAsync($"{Global.mqtt_discovery_prefix}/number/{Global.mqtt_prefix}/audio{i}volume/config",
|
||||
JsonConvert.SerializeObject(audioZone.ToConfigVolume()));
|
||||
}
|
||||
|
||||
PublishAsync($"{Global.mqtt_discovery_prefix}/button/{Global.mqtt_prefix}/audio0/config",
|
||||
JsonConvert.SerializeObject(new Button(MqttDeviceRegistry)
|
||||
{
|
||||
unique_id = $"{Global.mqtt_prefix}audio0",
|
||||
name = Global.mqtt_discovery_name_prefix + "Audio All Off",
|
||||
icon = "mdi:speaker",
|
||||
command_topic = $"{Global.mqtt_prefix}/audio0/{Topic.command}",
|
||||
payload_press = "OFF"
|
||||
}));
|
||||
}
|
||||
|
||||
private void Omnilink_OnAreaStatus(object sender, AreaStatusEventArgs e)
|
||||
{
|
||||
if (!MqttClient.IsConnected)
|
||||
@ -604,17 +470,8 @@ namespace OmniLinkBridge.Modules
|
||||
return;
|
||||
|
||||
// Ignore events fired by thermostat polling
|
||||
if (e.EventTimer)
|
||||
return;
|
||||
|
||||
if (e.Offline)
|
||||
{
|
||||
PublishAsync(e.Thermostat.ToTopic(Topic.status), OFFLINE);
|
||||
return;
|
||||
}
|
||||
|
||||
PublishAsync(e.Thermostat.ToTopic(Topic.status), ONLINE);
|
||||
PublishThermostatState(e.Thermostat);
|
||||
if (!e.EventTimer)
|
||||
PublishThermostatState(e.Thermostat);
|
||||
}
|
||||
|
||||
private async void OmniLink_OnButtonStatus(object sender, ButtonStatusEventArgs e)
|
||||
@ -633,35 +490,19 @@ namespace OmniLinkBridge.Modules
|
||||
PublishMessageStateAsync(e.Message);
|
||||
}
|
||||
|
||||
private void OmniLink_OnLockStatus(object sender, LockStatusEventArgs e)
|
||||
{
|
||||
if (!MqttClient.IsConnected)
|
||||
return;
|
||||
|
||||
PublishLockStateAsync(e.Reader);
|
||||
}
|
||||
|
||||
private void OmniLink_OnAudioZoneStatus(object sender, AudioZoneStatusEventArgs e)
|
||||
{
|
||||
if (!MqttClient.IsConnected)
|
||||
return;
|
||||
|
||||
PublishAudioZoneStateAsync(e.AudioZone);
|
||||
}
|
||||
|
||||
private void OmniLink_OnSystemStatus(object sender, SystemStatusEventArgs e)
|
||||
{
|
||||
if (!MqttClient.IsConnected)
|
||||
return;
|
||||
|
||||
if(e.Type == SystemEventType.Phone)
|
||||
PublishAsync(SystemTroubleTopic("phone"), e.Trouble ? TROUBLE : SECURE);
|
||||
PublishAsync(SystemTroubleTopic("phone"), e.Trouble ? "trouble" : "secure");
|
||||
else if (e.Type == SystemEventType.AC)
|
||||
PublishAsync(SystemTroubleTopic("ac"), e.Trouble ? TROUBLE : SECURE);
|
||||
PublishAsync(SystemTroubleTopic("ac"), e.Trouble ? "trouble" : "secure");
|
||||
else if (e.Type == SystemEventType.Button)
|
||||
PublishAsync(SystemTroubleTopic("battery"), e.Trouble ? TROUBLE : SECURE);
|
||||
PublishAsync(SystemTroubleTopic("battery"), e.Trouble ? "trouble" : "secure");
|
||||
else if (e.Type == SystemEventType.DCM)
|
||||
PublishAsync(SystemTroubleTopic("dcm"), e.Trouble ? TROUBLE : SECURE);
|
||||
PublishAsync(SystemTroubleTopic("dcm"), e.Trouble ? "trouble" : "secure");
|
||||
}
|
||||
|
||||
private void PublishAreaState(clsArea area)
|
||||
@ -686,11 +527,7 @@ namespace OmniLinkBridge.Modules
|
||||
{
|
||||
PublishAsync(unit.ToTopic(Topic.state), unit.ToState());
|
||||
|
||||
if (unit.Type == enuOL2UnitType.Flag)
|
||||
{
|
||||
PublishAsync(unit.ToTopic(Topic.flag_state), ((ushort)unit.Status).ToString());
|
||||
}
|
||||
else if(unit.Type != enuOL2UnitType.Output)
|
||||
if (unit.Number < 385)
|
||||
{
|
||||
PublishAsync(unit.ToTopic(Topic.brightness_state), unit.ToBrightnessState().ToString());
|
||||
PublishAsync(unit.ToTopic(Topic.scene_state), unit.ToSceneState());
|
||||
@ -725,20 +562,6 @@ namespace OmniLinkBridge.Modules
|
||||
return PublishAsync(message.ToTopic(Topic.state), message.ToState());
|
||||
}
|
||||
|
||||
private Task PublishLockStateAsync(clsAccessControlReader reader)
|
||||
{
|
||||
return PublishAsync(reader.ToTopic(Topic.state), reader.ToState());
|
||||
}
|
||||
|
||||
private void PublishAudioZoneStateAsync(clsAudioZone audioZone)
|
||||
{
|
||||
PublishAsync(audioZone.ToTopic(Topic.state), audioZone.ToState());
|
||||
PublishAsync(audioZone.ToTopic(Topic.mute_state), audioZone.ToMuteState());
|
||||
PublishAsync(audioZone.ToTopic(Topic.source_state),
|
||||
OmniLink.Controller.AudioSources[audioZone.ToSourceState()].rawName);
|
||||
PublishAsync(audioZone.ToTopic(Topic.volume_state), audioZone.ToVolumeState().ToString());
|
||||
}
|
||||
|
||||
private Task PublishAsync(string topic, string payload)
|
||||
{
|
||||
return MqttClient.PublishAsync(topic, payload, MqttQualityOfServiceLevel.AtMostOnce, true);
|
||||
|
@ -40,8 +40,6 @@ namespace OmniLinkBridge.Modules
|
||||
public event EventHandler<UnitStatusEventArgs> OnUnitStatus;
|
||||
public event EventHandler<ButtonStatusEventArgs> OnButtonStatus;
|
||||
public event EventHandler<MessageStatusEventArgs> OnMessageStatus;
|
||||
public event EventHandler<LockStatusEventArgs> OnLockStatus;
|
||||
public event EventHandler<AudioZoneStatusEventArgs> OnAudioZoneStatus;
|
||||
public event EventHandler<SystemStatusEventArgs> OnSystemStatus;
|
||||
|
||||
private readonly AutoResetEvent trigger = new AutoResetEvent(false);
|
||||
@ -53,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;
|
||||
@ -87,7 +85,6 @@ namespace OmniLinkBridge.Modules
|
||||
|
||||
public bool SendCommand(enuUnitCommand Cmd, byte Par, ushort Pr2)
|
||||
{
|
||||
log.Verbose("Sending: {command}, Par1: {par1}, Par2: {par2}", Cmd, Par, Pr2);
|
||||
return Controller.SendCommand(Cmd, Par, Pr2);
|
||||
}
|
||||
|
||||
@ -201,8 +198,6 @@ namespace OmniLinkBridge.Modules
|
||||
tstat_timer.Start();
|
||||
|
||||
OnConnect?.Invoke(this, new EventArgs());
|
||||
|
||||
Program.ShowSendLogsWarning();
|
||||
}
|
||||
#endregion
|
||||
|
||||
@ -219,9 +214,6 @@ namespace OmniLinkBridge.Modules
|
||||
await GetNamed(enuObjectType.Unit);
|
||||
await GetNamed(enuObjectType.Message);
|
||||
await GetNamed(enuObjectType.Button);
|
||||
await GetNamed(enuObjectType.AccessControlReader);
|
||||
await GetNamed(enuObjectType.AudioSource);
|
||||
await GetNamed(enuObjectType.AudioZone);
|
||||
}
|
||||
|
||||
private async Task GetSystemFormats()
|
||||
@ -233,8 +225,7 @@ namespace OmniLinkBridge.Modules
|
||||
|
||||
await Task.Run(() =>
|
||||
{
|
||||
if(!nameWait.WaitOne(new TimeSpan(0, 0, 10)))
|
||||
log.Error("Timeout occurred waiting system formats");
|
||||
nameWait.WaitOne(new TimeSpan(0, 0, 10));
|
||||
});
|
||||
}
|
||||
|
||||
@ -247,8 +238,7 @@ namespace OmniLinkBridge.Modules
|
||||
|
||||
await Task.Run(() =>
|
||||
{
|
||||
if(!nameWait.WaitOne(new TimeSpan(0, 0, 10)))
|
||||
log.Error("Timeout occurred waiting for system troubles");
|
||||
nameWait.WaitOne(new TimeSpan(0, 0, 10));
|
||||
});
|
||||
}
|
||||
|
||||
@ -260,8 +250,7 @@ namespace OmniLinkBridge.Modules
|
||||
|
||||
await Task.Run(() =>
|
||||
{
|
||||
if (!nameWait.WaitOne(new TimeSpan(0, 0, 30)))
|
||||
log.Error("Timeout occurred waiting for named units {unitType}", type.ToString());
|
||||
nameWait.WaitOne(new TimeSpan(0, 0, 10));
|
||||
});
|
||||
}
|
||||
|
||||
@ -327,8 +316,7 @@ 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:
|
||||
@ -339,8 +327,7 @@ 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;
|
||||
@ -353,17 +340,6 @@ namespace OmniLinkBridge.Modules
|
||||
case enuObjectType.Button:
|
||||
Controller.Buttons.CopyProperties(MSG);
|
||||
break;
|
||||
case enuObjectType.AccessControlReader:
|
||||
Controller.AccessControlReaders.CopyProperties(MSG);
|
||||
break;
|
||||
case enuObjectType.AudioSource:
|
||||
Controller.AudioSources.CopyProperties(MSG);
|
||||
Controller.AudioSources[MSG.ObjectNumber].rawName = MSG.ObjectName;
|
||||
break;
|
||||
case enuObjectType.AudioZone:
|
||||
Controller.AudioZones.CopyProperties(MSG);
|
||||
Controller.AudioZones[MSG.ObjectNumber].rawName = MSG.ObjectName;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -444,8 +420,6 @@ namespace OmniLinkBridge.Modules
|
||||
case enuOmniLink2MessageType.CmdExtSecurity:
|
||||
break;
|
||||
case enuOmniLink2MessageType.AudioSourceStatus:
|
||||
// Ignore audio source metadata status updates
|
||||
handled = true;
|
||||
break;
|
||||
case enuOmniLink2MessageType.SystemEvents:
|
||||
HandleUnsolicitedSystemEvent(B);
|
||||
@ -662,13 +636,19 @@ namespace OmniLinkBridge.Modules
|
||||
{
|
||||
Controller.Thermostats[MSG.ObjectNumber(i)].CopyExtendedStatus(MSG, i);
|
||||
|
||||
OnThermostatStatus?.Invoke(this, new ThermostatStatusEventArgs()
|
||||
// Don't fire event when invalid temperature of 0 is sometimes received
|
||||
if (Controller.Thermostats[MSG.ObjectNumber(i)].Temp > 0)
|
||||
{
|
||||
ID = MSG.ObjectNumber(i),
|
||||
Thermostat = Controller.Thermostats[MSG.ObjectNumber(i)],
|
||||
Offline = Controller.Thermostats[MSG.ObjectNumber(i)].Temp == 0,
|
||||
EventTimer = false
|
||||
});
|
||||
OnThermostatStatus?.Invoke(this, new ThermostatStatusEventArgs()
|
||||
{
|
||||
ID = MSG.ObjectNumber(i),
|
||||
Thermostat = Controller.Thermostats[MSG.ObjectNumber(i)],
|
||||
EventTimer = false
|
||||
});
|
||||
}
|
||||
else if (Global.verbose_thermostat_timer)
|
||||
log.Debug("Ignoring unsolicited unknown temp for Thermostat {thermostatName}",
|
||||
Controller.Thermostats[MSG.ObjectNumber(i)].Name);
|
||||
|
||||
if (!tstats.ContainsKey(MSG.ObjectNumber(i)))
|
||||
tstats.Add(MSG.ObjectNumber(i), DateTime.Now);
|
||||
@ -703,28 +683,6 @@ namespace OmniLinkBridge.Modules
|
||||
});
|
||||
}
|
||||
break;
|
||||
case enuObjectType.AccessControlLock:
|
||||
for (byte i = 0; i < MSG.AccessControlLockCount(); i++)
|
||||
{
|
||||
Controller.AccessControlReaders[MSG.ObjectNumber(i)].CopyExtendedStatus(MSG, i);
|
||||
OnLockStatus?.Invoke(this, new LockStatusEventArgs()
|
||||
{
|
||||
ID = MSG.ObjectNumber(i),
|
||||
Reader = Controller.AccessControlReaders[MSG.ObjectNumber(i)]
|
||||
});
|
||||
}
|
||||
break;
|
||||
case enuObjectType.AudioZone:
|
||||
for (byte i = 0; i < MSG.AudioZoneStatusCount(); i++)
|
||||
{
|
||||
Controller.AudioZones[MSG.ObjectNumber(i)].CopyExtendedStatus(MSG, i);
|
||||
OnAudioZoneStatus?.Invoke(this, new AudioZoneStatusEventArgs()
|
||||
{
|
||||
ID = MSG.ObjectNumber(i),
|
||||
AudioZone = Controller.AudioZones[MSG.ObjectNumber(i)]
|
||||
});
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (Global.verbose_unhandled)
|
||||
{
|
||||
@ -762,8 +720,7 @@ 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}",
|
||||
@ -775,13 +732,19 @@ namespace OmniLinkBridge.Modules
|
||||
(Controller.Connection.ConnectionState == enuOmniLinkConnectionState.Online ||
|
||||
Controller.Connection.ConnectionState == enuOmniLinkConnectionState.OnlineSecure))
|
||||
{
|
||||
OnThermostatStatus?.Invoke(this, new ThermostatStatusEventArgs()
|
||||
// Don't fire event when invalid temperature of 0 is sometimes received
|
||||
if (Controller.Thermostats[tstat.Key].Temp > 0)
|
||||
{
|
||||
ID = tstat.Key,
|
||||
Thermostat = Controller.Thermostats[tstat.Key],
|
||||
Offline = Controller.Thermostats[tstat.Key].Temp == 0,
|
||||
EventTimer = true
|
||||
});
|
||||
OnThermostatStatus?.Invoke(this, new ThermostatStatusEventArgs()
|
||||
{
|
||||
ID = tstat.Key,
|
||||
Thermostat = Controller.Thermostats[tstat.Key],
|
||||
EventTimer = true
|
||||
});
|
||||
}
|
||||
else if (Global.verbose_thermostat_timer)
|
||||
log.Warning("Ignoring unknown temp for Thermostat {thermostatName}",
|
||||
Controller.Thermostats[tstat.Key].Name);
|
||||
}
|
||||
else if (Global.verbose_thermostat_timer)
|
||||
log.Warning("Not logging out of date status for Thermostat {thermostatName}",
|
||||
|
@ -74,15 +74,14 @@ namespace OmniLinkBridge.Modules
|
||||
// Extract the 2 digit prefix to use when parsing the time
|
||||
int year = DateTime.Now.Year / 100;
|
||||
|
||||
time = new DateTime(MSG.Year + (year * 100), MSG.Month, MSG.Day, MSG.Hour, MSG.Minute, MSG.Second);
|
||||
time = new DateTime((int)MSG.Year + (year * 100), (int)MSG.Month, (int)MSG.Day, (int)MSG.Hour, (int)MSG.Minute, (int)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;
|
||||
@ -93,11 +92,10 @@ 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);
|
||||
}
|
||||
}
|
||||
|
@ -33,8 +33,6 @@ namespace OmniLinkBridge
|
||||
|
||||
public void Startup()
|
||||
{
|
||||
log.Warning("WebAPI is deprecated");
|
||||
|
||||
WebNotification.RestoreSubscriptions();
|
||||
|
||||
Uri uri = new Uri("http://0.0.0.0:" + Global.webapi_port + "/");
|
||||
|
@ -1,11 +0,0 @@
|
||||
using HAI_Shared;
|
||||
using System;
|
||||
|
||||
namespace OmniLinkBridge.OmniLink
|
||||
{
|
||||
public class AudioZoneStatusEventArgs : EventArgs
|
||||
{
|
||||
public ushort ID { get; set; }
|
||||
public clsAudioZone AudioZone { get; set; }
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
using HAI_Shared;
|
||||
using System;
|
||||
|
||||
namespace OmniLinkBridge.OmniLink
|
||||
{
|
||||
public class LockStatusEventArgs : EventArgs
|
||||
{
|
||||
public ushort ID { get; set; }
|
||||
public clsAccessControlReader Reader { get; set; }
|
||||
}
|
||||
}
|
@ -1,4 +1,10 @@
|
||||
namespace OmniLinkBridge.OmniLink
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace OmniLinkBridge.OmniLink
|
||||
{
|
||||
public enum SystemEventType
|
||||
{
|
||||
|
@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using HAI_Shared;
|
||||
using System;
|
||||
|
||||
namespace OmniLinkBridge.OmniLink
|
||||
{
|
||||
|
@ -8,11 +8,6 @@ namespace OmniLinkBridge.OmniLink
|
||||
public ushort ID { get; set; }
|
||||
public clsThermostat Thermostat { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Set to true when thermostat is offline, indicated by a temperature of 0
|
||||
/// </summary>
|
||||
public bool Offline { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Set to true when fired by thermostat polling
|
||||
/// </summary>
|
||||
|
@ -80,39 +80,29 @@
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="ControllerEnricher.cs" />
|
||||
<Compile Include="CoreServer.cs" />
|
||||
<Compile Include="Modules\TimeSyncModule.cs" />
|
||||
<Compile Include="MQTT\HomeAssistant\Button.cs" />
|
||||
<Compile Include="MQTT\HomeAssistant\Alarm.cs" />
|
||||
<Compile Include="MQTT\HomeAssistant\Lock.cs" />
|
||||
<Compile Include="MQTT\HomeAssistant\Select.cs" />
|
||||
<Compile Include="MQTT\OverrideArea.cs" />
|
||||
<Compile Include="MQTT\OverrideUnit.cs" />
|
||||
<Compile Include="MQTT\Parser\AlarmCommands.cs" />
|
||||
<Compile Include="MQTT\Alarm.cs" />
|
||||
<Compile Include="MQTT\AlarmCommands.cs" />
|
||||
<Compile Include="MQTT\AreaCommandCode.cs" />
|
||||
<Compile Include="MQTT\Parser\AreaCommands.cs" />
|
||||
<Compile Include="MQTT\AreaCommands.cs" />
|
||||
<Compile Include="MQTT\AreaState.cs" />
|
||||
<Compile Include="MQTT\Availability.cs" />
|
||||
<Compile Include="MQTT\HomeAssistant\BinarySensor.cs" />
|
||||
<Compile Include="MQTT\Parser\CommandTypes.cs" />
|
||||
<Compile Include="MQTT\HomeAssistant\Device.cs" />
|
||||
<Compile Include="MQTT\HomeAssistant\Climate.cs" />
|
||||
<Compile Include="MQTT\HomeAssistant\DeviceRegistry.cs" />
|
||||
<Compile Include="MQTT\Extensions.cs" />
|
||||
<Compile Include="MQTT\Parser\LockCommands.cs" />
|
||||
<Compile Include="MQTT\Parser\MessageCommands.cs" />
|
||||
<Compile Include="MQTT\BinarySensor.cs" />
|
||||
<Compile Include="MQTT\CommandTypes.cs" />
|
||||
<Compile Include="MQTT\Device.cs" />
|
||||
<Compile Include="MQTT\Climate.cs" />
|
||||
<Compile Include="MQTT\DeviceRegistry.cs" />
|
||||
<Compile Include="MQTT\MessageCommands.cs" />
|
||||
<Compile Include="MQTT\MessageProcessor.cs" />
|
||||
<Compile Include="MQTT\HomeAssistant\Number.cs" />
|
||||
<Compile Include="MQTT\Number.cs" />
|
||||
<Compile Include="MQTT\OverrideZone.cs" />
|
||||
<Compile Include="MQTT\HomeAssistant\Switch.cs" />
|
||||
<Compile Include="MQTT\HomeAssistant\Light.cs" />
|
||||
<Compile Include="MQTT\Switch.cs" />
|
||||
<Compile Include="MQTT\Light.cs" />
|
||||
<Compile Include="MQTT\MappingExtensions.cs" />
|
||||
<Compile Include="MQTT\HomeAssistant\Sensor.cs" />
|
||||
<Compile Include="MQTT\Parser\Topic.cs" />
|
||||
<Compile Include="MQTT\Parser\UnitCommands.cs" />
|
||||
<Compile Include="MQTT\Parser\ZoneCommands.cs" />
|
||||
<Compile Include="MQTT\UnitType.cs" />
|
||||
<Compile Include="MQTT\Sensor.cs" />
|
||||
<Compile Include="MQTT\Topic.cs" />
|
||||
<Compile Include="MQTT\UnitCommands.cs" />
|
||||
<Compile Include="MQTT\ZoneCommands.cs" />
|
||||
<Compile Include="Notifications\EmailNotification.cs" />
|
||||
<Compile Include="Notifications\INotification.cs" />
|
||||
<Compile Include="Notifications\Notification.cs" />
|
||||
@ -120,9 +110,7 @@
|
||||
<Compile Include="Notifications\PushoverNotification.cs" />
|
||||
<Compile Include="OmniLink\ButtonStatusEventArgs.cs" />
|
||||
<Compile Include="OmniLink\IOmniLinkII.cs" />
|
||||
<Compile Include="OmniLink\AudioZoneStatusEventArgs.cs" />
|
||||
<Compile Include="OmniLink\SystemEventType.cs" />
|
||||
<Compile Include="OmniLink\LockStatusEventArgs.cs" />
|
||||
<Compile Include="OmniLink\UnitStatusEventArgs.cs" />
|
||||
<Compile Include="OmniLink\ThermostatStatusEventArgs.cs" />
|
||||
<Compile Include="OmniLink\MessageStatusEventArgs.cs" />
|
||||
@ -190,19 +178,19 @@
|
||||
<Version>3.1.2</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Newtonsoft.Json">
|
||||
<Version>13.0.3</Version>
|
||||
<Version>13.0.1</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Serilog">
|
||||
<Version>3.1.1</Version>
|
||||
<Version>2.12.0</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Serilog.Formatting.Compact">
|
||||
<Version>2.0.0</Version>
|
||||
<Version>1.1.0</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Serilog.Sinks.Async">
|
||||
<Version>1.5.0</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Serilog.Sinks.Console">
|
||||
<Version>5.0.1</Version>
|
||||
<Version>4.1.0</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Serilog.Sinks.File">
|
||||
<Version>5.0.0</Version>
|
||||
|
@ -4,7 +4,4 @@
|
||||
<StartArguments>
|
||||
</StartArguments>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<ProjectView>ProjectFiles</ProjectView>
|
||||
</PropertyGroup>
|
||||
</Project>
|
@ -22,8 +22,6 @@ verbose_thermostat_timer = yes
|
||||
verbose_thermostat = yes
|
||||
verbose_unit = yes
|
||||
verbose_message = yes
|
||||
verbose_lock = yes
|
||||
verbose_audio = yes
|
||||
|
||||
# mySQL Logging (yes/no)
|
||||
mysql_logging = no
|
||||
@ -51,44 +49,14 @@ mqtt_prefix = omnilink
|
||||
mqtt_discovery_prefix = homeassistant
|
||||
# Prefix for Home Assistant entity names
|
||||
mqtt_discovery_name_prefix =
|
||||
# Skip publishing Home Assistant discovery topics for zones/units
|
||||
# Specify a range of numbers 1,2,3,5-10
|
||||
# Specify a range of numbers like 1,2,3,5-10
|
||||
mqtt_discovery_ignore_zones =
|
||||
mqtt_discovery_ignore_units =
|
||||
|
||||
# Override the area Home Assistant alarm control panel
|
||||
# Prompt for user code
|
||||
# code_arm: true or false, defaults to false
|
||||
# code_disarm: true or false, defaults to false
|
||||
# Show these modes
|
||||
# arm_home: true or false, defaults to true
|
||||
# arm_away: true or false, defaults to true
|
||||
# arm_night: true or false, defaults to true
|
||||
# arm_vacation: true or false, defaults to true
|
||||
#mqtt_discovery_override_area = id=1;code_disarm=true;arm_vacation=false
|
||||
|
||||
# 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_area_code_required =
|
||||
# device_class must be battery, door, garage_door, gas, moisture, motion, problem, 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
|
||||
|
||||
# Publish buttons as this Home Assistant device type
|
||||
# must be button (recommended) or switch (default, previous behavior)
|
||||
mqtt_discovery_button_type = switch
|
||||
# Handle mute locally by setting volume to 0 and restoring to previous value
|
||||
mqtt_audio_local_mute = no
|
||||
# Change audio volume scaling for Home Assistant media player
|
||||
# yes 0.00-1.00, no 0-100 (default, previous behavior)
|
||||
mqtt_audio_volume_media_player = no
|
||||
|
||||
# Notifications (yes/no)
|
||||
# Always sent for area alarms and critical system events
|
||||
# Optionally enable for area status changes and console messages
|
||||
|
@ -4,9 +4,7 @@ using Serilog.Events;
|
||||
using Serilog.Filters;
|
||||
using Serilog.Formatting.Compact;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Reflection;
|
||||
using System.ServiceProcess;
|
||||
@ -14,11 +12,11 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace OmniLinkBridge
|
||||
{
|
||||
internal class Program
|
||||
class Program
|
||||
{
|
||||
private static CoreServer server;
|
||||
static CoreServer server;
|
||||
|
||||
private static int Main(string[] args)
|
||||
static int Main(string[] args)
|
||||
{
|
||||
bool interactive = false;
|
||||
|
||||
@ -57,10 +55,6 @@ namespace OmniLinkBridge
|
||||
case "-ll":
|
||||
Enum.TryParse(args[++i], out log_level);
|
||||
break;
|
||||
case "-ld":
|
||||
Global.DebugSettings = true;
|
||||
Global.SendLogs = true;
|
||||
break;
|
||||
case "-s":
|
||||
Global.webapi_subscriptions_file = args[++i];
|
||||
break;
|
||||
@ -70,12 +64,6 @@ namespace OmniLinkBridge
|
||||
}
|
||||
}
|
||||
|
||||
if (string.Compare(Environment.GetEnvironmentVariable("SEND_LOGS"), "1") == 0)
|
||||
{
|
||||
Global.DebugSettings = true;
|
||||
Global.SendLogs = true;
|
||||
}
|
||||
|
||||
config_file = GetFullPath(config_file);
|
||||
|
||||
Global.webapi_subscriptions_file = GetFullPath(Global.webapi_subscriptions_file ?? "WebSubscriptions.json");
|
||||
@ -88,8 +76,8 @@ namespace OmniLinkBridge
|
||||
var log_config = new LoggerConfiguration()
|
||||
.MinimumLevel.Verbose()
|
||||
.Enrich.WithProperty("Application", "OmniLinkBridge")
|
||||
.Enrich.WithProperty("Session", Global.SessionID)
|
||||
.Enrich.With<ControllerEnricher>()
|
||||
.Enrich.WithProperty("Session", Guid.NewGuid())
|
||||
.Enrich.WithProperty("User", (Environment.UserName + Environment.MachineName).GetHashCode())
|
||||
.Enrich.FromLogContext();
|
||||
|
||||
if (log_file != null)
|
||||
@ -104,10 +92,7 @@ namespace OmniLinkBridge
|
||||
rollingInterval: RollingInterval.Day, retainedFileCountLimit: 15));
|
||||
}
|
||||
|
||||
if (Global.SendLogs)
|
||||
log_config = log_config.WriteTo.Logger(lc => lc
|
||||
.WriteTo.Http("https://telemetry.excalibur-partners.com"));
|
||||
else if (UseTelemetry())
|
||||
if (UseTelemetry())
|
||||
log_config = log_config.WriteTo.Logger(lc => lc
|
||||
.Filter.ByIncludingOnly(Matching.WithProperty("Telemetry"))
|
||||
.WriteTo.Http("https://telemetry.excalibur-partners.com"));
|
||||
@ -170,7 +155,7 @@ namespace OmniLinkBridge
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static string GetFullPath(string file)
|
||||
static string GetFullPath(string file)
|
||||
{
|
||||
if (Path.IsPathRooted(file))
|
||||
return file;
|
||||
@ -184,38 +169,21 @@ namespace OmniLinkBridge
|
||||
args.Cancel = true;
|
||||
}
|
||||
|
||||
private static bool IsRunningOnMono()
|
||||
static bool IsRunningOnMono()
|
||||
{
|
||||
return Type.GetType("Mono.Runtime") != null;
|
||||
}
|
||||
|
||||
public static string GetEnvironment()
|
||||
{
|
||||
if (Environment.GetEnvironmentVariable("HASSIO_TOKEN") != null)
|
||||
return "Home Assistant";
|
||||
else if (IsRunningOnMono())
|
||||
return Process.GetProcesses().Any(w => w.Id == 2) ? "Mono" : "Docker";
|
||||
else
|
||||
return "Native";
|
||||
}
|
||||
|
||||
private static bool UseTelemetry()
|
||||
static bool UseTelemetry()
|
||||
{
|
||||
return string.Compare(Environment.GetEnvironmentVariable("TELEMETRY_OPTOUT"), "1") != 0;
|
||||
}
|
||||
|
||||
public static void ShowSendLogsWarning()
|
||||
{
|
||||
if (Global.SendLogs)
|
||||
Log.Warning("SENDING LOGS TO DEVELOPER Controller: {ControllerID}, Session: {Session}",
|
||||
Global.controller_id, Global.SessionID);
|
||||
}
|
||||
|
||||
private static void ShowHelp()
|
||||
static void ShowHelp()
|
||||
{
|
||||
Console.WriteLine(
|
||||
AppDomain.CurrentDomain.FriendlyName + " [-c config_file] [-e] [-d] [-j] [-s subscriptions_file]\n" +
|
||||
"\t[-lf log_file|disable] [-lj [-ll verbose|debug|information|warning|error] [-ld] [-i]\n" +
|
||||
"\t[-lf log_file|disable] [-lj [-ll verbose|debug|information|warning|error] [-i]\n" +
|
||||
"\t-c Specifies the configuration file. Default is OmniLinkBridge.ini\n" +
|
||||
"\t-e Check environment variables for configuration settings\n" +
|
||||
"\t-d Show debug ouput for configuration loading\n" +
|
||||
@ -223,14 +191,8 @@ namespace OmniLinkBridge
|
||||
"\t-lf Specifies the rolling log file. Retention is 15 days. Default is log.txt.\n" +
|
||||
"\t-lj Write logs as CLEF (compact log event format) JSON.\n" +
|
||||
"\t-ll Minimum level at which events will be logged. Default is information.\n" +
|
||||
"\t-ld Send logs to developer. ONLY USE WHEN ASKED.\n" +
|
||||
"\t Also enabled by setting a SEND_LOGS environment variable to 1.\n" +
|
||||
"\t-i Run in interactive mode");
|
||||
|
||||
Console.WriteLine(
|
||||
"\nVersion: " + Assembly.GetExecutingAssembly().GetName().Version +
|
||||
"\nEnvironment: " + GetEnvironment());
|
||||
|
||||
Console.WriteLine(
|
||||
"\nOmniLink Bridge collects anonymous telemetry data to help improve the software.\n" +
|
||||
"You can opt of telemetry by setting a TELEMETRY_OPTOUT environment variable to 1.");
|
||||
|
@ -10,7 +10,7 @@ using System.Runtime.InteropServices;
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("Excalibur Partners, LLC")]
|
||||
[assembly: AssemblyProduct("OmniLinkBridge")]
|
||||
[assembly: AssemblyCopyright("Copyright © Excalibur Partners, LLC 2024")]
|
||||
[assembly: AssemblyCopyright("Copyright © Excalibur Partners, LLC 2022")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
@ -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.19.0")]
|
||||
[assembly: AssemblyFileVersion("1.1.19.0")]
|
||||
[assembly: AssemblyVersion("1.1.13.0")]
|
||||
[assembly: AssemblyFileVersion("1.1.13.0")]
|
||||
|
@ -1,4 +1,3 @@
|
||||
using OmniLinkBridge.MQTT.HomeAssistant;
|
||||
using Serilog;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
@ -8,7 +7,7 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net.Mail;
|
||||
using System.Reflection;
|
||||
using ha = OmniLinkBridge.MQTT.HomeAssistant;
|
||||
using System.Threading;
|
||||
|
||||
namespace OmniLinkBridge
|
||||
{
|
||||
@ -31,10 +30,9 @@ namespace OmniLinkBridge
|
||||
// HAI / Leviton Omni Controller
|
||||
Global.controller_address = settings.ValidateHasValue("controller_address");
|
||||
Global.controller_port = settings.ValidatePort("controller_port");
|
||||
Global.controller_key1 = settings.ValidateEncryptionKey("controller_key1");
|
||||
Global.controller_key2 = settings.ValidateEncryptionKey("controller_key2");
|
||||
Global.controller_key1 = settings.ValidateHasValue("controller_key1");
|
||||
Global.controller_key2 = settings.ValidateHasValue("controller_key2");
|
||||
Global.controller_name = settings.CheckEnv("controller_name") ?? "OmniLinkBridge";
|
||||
Global.controller_id = (Global.controller_address + Global.controller_key1 + Global.controller_key2).ComputeGuid();
|
||||
|
||||
// Controller Time Sync
|
||||
Global.time_sync = settings.ValidateBool("time_sync");
|
||||
@ -54,12 +52,10 @@ namespace OmniLinkBridge
|
||||
Global.verbose_thermostat = settings.ValidateBool("verbose_thermostat");
|
||||
Global.verbose_unit = settings.ValidateBool("verbose_unit");
|
||||
Global.verbose_message = settings.ValidateBool("verbose_message");
|
||||
Global.verbose_lock = settings.ValidateBool("verbose_lock");
|
||||
Global.verbose_audio = settings.ValidateBool("verbose_audio");
|
||||
|
||||
// mySQL Logging
|
||||
Global.mysql_logging = settings.ValidateBool("mysql_logging");
|
||||
Global.mysql_connection = settings.CheckEnv("mysql_connection", true);
|
||||
Global.mysql_connection = settings.CheckEnv("mysql_connection");
|
||||
|
||||
// Web Service
|
||||
Global.webapi_enabled = settings.ValidateBool("webapi_enabled");
|
||||
@ -77,8 +73,8 @@ namespace OmniLinkBridge
|
||||
{
|
||||
Global.mqtt_server = settings.CheckEnv("mqtt_server");
|
||||
Global.mqtt_port = settings.ValidatePort("mqtt_port");
|
||||
Global.mqtt_username = settings.CheckEnv("mqtt_username", true);
|
||||
Global.mqtt_password = settings.CheckEnv("mqtt_password", true);
|
||||
Global.mqtt_username = settings.CheckEnv("mqtt_username");
|
||||
Global.mqtt_password = settings.CheckEnv("mqtt_password");
|
||||
Global.mqtt_prefix = settings.CheckEnv("mqtt_prefix") ?? "omnilink";
|
||||
Global.mqtt_discovery_prefix = settings.CheckEnv("mqtt_discovery_prefix") ?? "homeassistant";
|
||||
Global.mqtt_discovery_name_prefix = settings.CheckEnv("mqtt_discovery_name_prefix") ?? string.Empty;
|
||||
@ -88,12 +84,8 @@ namespace OmniLinkBridge
|
||||
|
||||
Global.mqtt_discovery_ignore_zones = settings.ValidateRange("mqtt_discovery_ignore_zones");
|
||||
Global.mqtt_discovery_ignore_units = settings.ValidateRange("mqtt_discovery_ignore_units");
|
||||
Global.mqtt_discovery_override_area = settings.LoadOverrideArea<MQTT.OverrideArea>("mqtt_discovery_override_area");
|
||||
Global.mqtt_discovery_area_code_required = settings.ValidateRange("mqtt_discovery_area_code_required");
|
||||
Global.mqtt_discovery_override_zone = settings.LoadOverrideZone<MQTT.OverrideZone>("mqtt_discovery_override_zone");
|
||||
Global.mqtt_discovery_override_unit = settings.LoadOverrideUnit<MQTT.OverrideUnit>("mqtt_discovery_override_unit");
|
||||
Global.mqtt_discovery_button_type = settings.ValidateType("mqtt_discovery_button_type", typeof(Switch), typeof(Button));
|
||||
Global.mqtt_audio_local_mute = settings.ValidateBool("mqtt_audio_local_mute");
|
||||
Global.mqtt_audio_volume_media_player = settings.ValidateBool("mqtt_audio_volume_media_player");
|
||||
}
|
||||
|
||||
// Notifications
|
||||
@ -107,113 +99,31 @@ namespace OmniLinkBridge
|
||||
{
|
||||
Global.mail_tls = settings.ValidateBool("mail_tls");
|
||||
Global.mail_port = settings.ValidatePort("mail_port");
|
||||
Global.mail_username = settings.CheckEnv("mail_username", true);
|
||||
Global.mail_password = settings.CheckEnv("mail_password", true);
|
||||
Global.mail_username = settings.CheckEnv("mail_username");
|
||||
Global.mail_password = settings.CheckEnv("mail_password");
|
||||
Global.mail_from = settings.ValidateMailFrom("mail_from");
|
||||
Global.mail_to = settings.ValidateMailTo("mail_to");
|
||||
}
|
||||
|
||||
// Prowl Notifications
|
||||
Global.prowl_key = settings.ValidateMultipleStrings("prowl_key", true);
|
||||
Global.prowl_key = settings.ValidateMultipleStrings("prowl_key");
|
||||
|
||||
// Pushover Notifications
|
||||
Global.pushover_token = settings.CheckEnv("pushover_token", true);
|
||||
Global.pushover_user = settings.ValidateMultipleStrings("pushover_user", true);
|
||||
Global.pushover_token = settings.CheckEnv("pushover_token");
|
||||
Global.pushover_user = settings.ValidateMultipleStrings("pushover_user");
|
||||
}
|
||||
|
||||
private static string CheckEnv(this NameValueCollection settings, string name, bool sensitive = false)
|
||||
private static string CheckEnv(this NameValueCollection settings, string name)
|
||||
{
|
||||
string env = Global.UseEnvironment ? Environment.GetEnvironmentVariable(name.ToUpper()) : null;
|
||||
string value = !string.IsNullOrEmpty(env) ? env : settings[name];
|
||||
|
||||
if (Global.DebugSettings)
|
||||
log.Debug("{ConfigType} {ConfigName}: {ConfigValue}",
|
||||
(!string.IsNullOrEmpty(env) ? "ENV" : "CONF").PadRight(4), name,
|
||||
sensitive && value != null ? value.Truncate(3) + "***MASKED***" : value);
|
||||
log.Debug((!string.IsNullOrEmpty(env) ? "ENV" : "CONF").PadRight(5) + $"{name}: {value}");
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
private static ConcurrentDictionary<int, T> LoadOverrideArea<T>(this NameValueCollection settings, string section) where T : new()
|
||||
{
|
||||
try
|
||||
{
|
||||
ConcurrentDictionary<int, T> ret = new ConcurrentDictionary<int, T>();
|
||||
|
||||
string value = settings.CheckEnv(section);
|
||||
|
||||
if (string.IsNullOrEmpty(value))
|
||||
return ret;
|
||||
|
||||
string[] ids = value.Split(',');
|
||||
|
||||
for (int i = 0; i < ids.Length; i++)
|
||||
{
|
||||
Dictionary<string, string> 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_area = new T();
|
||||
|
||||
if (override_area is MQTT.OverrideArea mqtt_area)
|
||||
{
|
||||
foreach (string attribute in attributes.Keys)
|
||||
{
|
||||
switch(attribute)
|
||||
{
|
||||
case "id":
|
||||
continue;
|
||||
case "code_arm":
|
||||
if (!bool.TryParse(attributes["code_arm"], out bool code_arm))
|
||||
throw new Exception("Invalid code_arm attribute");
|
||||
mqtt_area.code_arm = code_arm;
|
||||
break;
|
||||
case "code_disarm":
|
||||
if (!bool.TryParse(attributes["code_disarm"], out bool code_disarm))
|
||||
throw new Exception("Invalid code_disarm attribute");
|
||||
mqtt_area.code_disarm = code_disarm;
|
||||
break;
|
||||
case "arm_home":
|
||||
if (!bool.TryParse(attributes["arm_home"], out bool arm_home))
|
||||
throw new Exception("Invalid arm_home attribute");
|
||||
mqtt_area.arm_home = arm_home;
|
||||
break;
|
||||
case "arm_away":
|
||||
if (!bool.TryParse(attributes["arm_away"], out bool arm_away))
|
||||
throw new Exception("Invalid arm_away attribute");
|
||||
mqtt_area.arm_away = arm_away;
|
||||
break;
|
||||
case "arm_night":
|
||||
if (!bool.TryParse(attributes["arm_night"], out bool arm_night))
|
||||
throw new Exception("Invalid arm_night attribute");
|
||||
mqtt_area.arm_night = arm_night;
|
||||
break;
|
||||
case "arm_vacation":
|
||||
if (!bool.TryParse(attributes["arm_vacation"], out bool arm_vacation))
|
||||
throw new Exception("Invalid arm_vacation attribute");
|
||||
mqtt_area.arm_vacation = arm_vacation;
|
||||
break;
|
||||
default:
|
||||
throw new Exception($"Unknown attribute {attribute}" );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ret.TryAdd(attrib_id, override_area);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
log.Error(ex, "Invalid override area specified for {section}", section);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
private static ConcurrentDictionary<int, T> LoadOverrideZone<T>(this NameValueCollection settings, string section) where T : new()
|
||||
{
|
||||
try
|
||||
@ -247,7 +157,7 @@ namespace OmniLinkBridge
|
||||
}
|
||||
else if (override_zone is MQTT.OverrideZone mqtt_zone)
|
||||
{
|
||||
if (!attributes.ContainsKey("device_class") || !Enum.TryParse(attributes["device_class"], out ha.BinarySensor.DeviceClass attrib_device_class))
|
||||
if (!attributes.ContainsKey("device_class") || !Enum.TryParse(attributes["device_class"], out MQTT.BinarySensor.DeviceClass attrib_device_class))
|
||||
throw new Exception("Missing or invalid device_class attribute");
|
||||
|
||||
mqtt_zone.device_class = attrib_device_class;
|
||||
@ -265,50 +175,6 @@ namespace OmniLinkBridge
|
||||
}
|
||||
}
|
||||
|
||||
private static ConcurrentDictionary<int, T> LoadOverrideUnit<T>(this NameValueCollection settings, string section) where T : new()
|
||||
{
|
||||
try
|
||||
{
|
||||
ConcurrentDictionary<int, T> ret = new ConcurrentDictionary<int, T>();
|
||||
|
||||
string value = settings.CheckEnv(section);
|
||||
|
||||
if (string.IsNullOrEmpty(value))
|
||||
return ret;
|
||||
|
||||
string[] ids = value.Split(',');
|
||||
|
||||
for (int i = 0; i < ids.Length; i++)
|
||||
{
|
||||
Dictionary<string, string> 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);
|
||||
@ -322,19 +188,6 @@ namespace OmniLinkBridge
|
||||
return value;
|
||||
}
|
||||
|
||||
private static string ValidateEncryptionKey(this NameValueCollection settings, string section)
|
||||
{
|
||||
string value = settings.CheckEnv(section, true).Replace("-","");
|
||||
|
||||
if (string.IsNullOrEmpty(value) || value.Length != 16)
|
||||
{
|
||||
log.Error("Invalid encryption key specified for {section}", section);
|
||||
throw new Exception();
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
private static int ValidateInt(this NameValueCollection settings, string section)
|
||||
{
|
||||
try
|
||||
@ -421,14 +274,14 @@ namespace OmniLinkBridge
|
||||
}
|
||||
}
|
||||
|
||||
private static string[] ValidateMultipleStrings(this NameValueCollection settings, string section, bool sensitive = false)
|
||||
private static string[] ValidateMultipleStrings(this NameValueCollection settings, string section)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (settings.CheckEnv(section, true) == null)
|
||||
if (settings.CheckEnv(section) == null)
|
||||
return new string[] { };
|
||||
|
||||
return settings.CheckEnv(section, sensitive).Split(',');
|
||||
return settings.CheckEnv(section).Split(',');
|
||||
}
|
||||
catch
|
||||
{
|
||||
@ -454,21 +307,6 @@ namespace OmniLinkBridge
|
||||
}
|
||||
}
|
||||
|
||||
private static Type ValidateType(this NameValueCollection settings, string section, params Type[] types)
|
||||
{
|
||||
string value = settings.CheckEnv(section);
|
||||
|
||||
if (value == null)
|
||||
return types[0];
|
||||
|
||||
foreach (Type type in types)
|
||||
if (string.Compare(value, type.Name, true) == 0)
|
||||
return type;
|
||||
|
||||
log.Error("Invalid type specified for {section}", section);
|
||||
throw new Exception();
|
||||
}
|
||||
|
||||
private static NameValueCollection LoadCollection(string[] lines)
|
||||
{
|
||||
NameValueCollection settings = new NameValueCollection();
|
||||
|
@ -1,4 +1,10 @@
|
||||
namespace OmniLinkBridge.WebAPI
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace OmniLinkBridge.WebAPI
|
||||
{
|
||||
public enum DeviceType
|
||||
{
|
||||
|
@ -1,4 +1,9 @@
|
||||
using HAI_Shared;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace OmniLinkBridge.WebAPI
|
||||
{
|
||||
|
@ -1,4 +1,5 @@
|
||||
using HAI_Shared;
|
||||
using OmniLinkBridge.WebAPI;
|
||||
using Serilog;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
@ -1,4 +1,10 @@
|
||||
namespace OmniLinkBridge.WebAPI
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace OmniLinkBridge.WebAPI
|
||||
{
|
||||
public class OverrideZone
|
||||
{
|
||||
|
@ -1,7 +1,9 @@
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using System;
|
||||
using System.Text;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using OmniLinkBridge;
|
||||
using OmniLinkBridge.MQTT;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace OmniLinkBridgeTest
|
||||
{
|
||||
@ -64,14 +66,6 @@ namespace OmniLinkBridgeTest
|
||||
Assert.AreEqual(parser.Validate, true);
|
||||
Assert.AreEqual(parser.Code, 1234);
|
||||
|
||||
// Special case for Home Assistant when code not required
|
||||
payload = "disarm,validate,None";
|
||||
parser = payload.ToCommandCode(supportValidate: true);
|
||||
Assert.AreEqual(parser.Success, true);
|
||||
Assert.AreEqual(parser.Command, "disarm");
|
||||
Assert.AreEqual(parser.Validate, false);
|
||||
Assert.AreEqual(parser.Code, 0);
|
||||
|
||||
// Falures
|
||||
payload = "disarm,1a";
|
||||
parser = payload.ToCommandCode(supportValidate: true);
|
||||
|
@ -1,13 +1,10 @@
|
||||
using HAI_Shared;
|
||||
using System;
|
||||
using System.Text;
|
||||
using System.Collections.Generic;
|
||||
using HAI_Shared;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using OmniLinkBridge;
|
||||
using OmniLinkBridge.Modules;
|
||||
using OmniLinkBridge.MQTT;
|
||||
using OmniLinkBridgeTest.Mock;
|
||||
using Serilog;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace OmniLinkBridgeTest
|
||||
{
|
||||
@ -20,26 +17,8 @@ namespace OmniLinkBridgeTest
|
||||
[TestInitialize]
|
||||
public void Initialize()
|
||||
{
|
||||
string log_format = "{Timestamp:yyyy-MM-dd HH:mm:ss} [{SourceContext} {Level:u3}] {Message:lj}{NewLine}{Exception}";
|
||||
|
||||
var log_config = new LoggerConfiguration()
|
||||
.MinimumLevel.Verbose()
|
||||
.Enrich.FromLogContext()
|
||||
.WriteTo.Console(outputTemplate: log_format);
|
||||
|
||||
Log.Logger = log_config.CreateLogger();
|
||||
|
||||
Dictionary<string, int> audioSources = new Dictionary<string, int>
|
||||
{
|
||||
{ "Radio", 1 },
|
||||
{ "Streaming", 2 },
|
||||
{ "TV", 4 }
|
||||
};
|
||||
|
||||
omniLink = new MockOmniLinkII();
|
||||
messageProcessor = new MessageProcessor(omniLink, audioSources, 8);
|
||||
|
||||
omniLink.Controller.Units[395].Type = enuOL2UnitType.Flag;
|
||||
messageProcessor = new MessageProcessor(omniLink);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
@ -155,28 +134,6 @@ 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()
|
||||
{
|
||||
@ -306,140 +263,6 @@ namespace OmniLinkBridgeTest
|
||||
|
||||
check(2, "SHOW", enuUnitCommand.ShowMsgWBeep, 0);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void LockCommand()
|
||||
{
|
||||
void check(ushort id, string payload, enuUnitCommand command)
|
||||
{
|
||||
SendCommandEventArgs actual = null;
|
||||
omniLink.OnSendCommand += (sender, e) => { actual = e; };
|
||||
messageProcessor.Process($"omnilink/lock{id}/command", payload);
|
||||
SendCommandEventArgs expected = new SendCommandEventArgs()
|
||||
{
|
||||
Cmd = command,
|
||||
Par = 0,
|
||||
Pr2 = id
|
||||
};
|
||||
Assert.AreEqual(expected, actual);
|
||||
}
|
||||
|
||||
check(1, "lock", enuUnitCommand.Lock);
|
||||
check(1, "unlock", enuUnitCommand.Unlock);
|
||||
|
||||
// Check all locks
|
||||
check(0, "lock", enuUnitCommand.Lock);
|
||||
|
||||
// Check case insensitivity
|
||||
check(2, "LOCK", enuUnitCommand.Lock);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void AudioCommand()
|
||||
{
|
||||
void check(ushort id, string payload, enuUnitCommand command, int value)
|
||||
{
|
||||
SendCommandEventArgs actual = null;
|
||||
omniLink.OnSendCommand += (sender, e) => { actual = e; };
|
||||
messageProcessor.Process($"omnilink/audio{id}/command", payload);
|
||||
SendCommandEventArgs expected = new SendCommandEventArgs()
|
||||
{
|
||||
Cmd = command,
|
||||
Par = (byte)value,
|
||||
Pr2 = id
|
||||
};
|
||||
Assert.AreEqual(expected, actual);
|
||||
}
|
||||
|
||||
check(1, "ON", enuUnitCommand.AudioZone, 1);
|
||||
check(1, "OFF", enuUnitCommand.AudioZone, 0);
|
||||
|
||||
check(2, "on", enuUnitCommand.AudioZone, 1);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void AudioMuteCommand()
|
||||
{
|
||||
void check(ushort id, string payload, enuUnitCommand command, int value)
|
||||
{
|
||||
SendCommandEventArgs actual = null;
|
||||
omniLink.OnSendCommand += (sender, e) => { actual = e; };
|
||||
messageProcessor.Process($"omnilink/audio{id}/mute_command", payload);
|
||||
SendCommandEventArgs expected = new SendCommandEventArgs()
|
||||
{
|
||||
Cmd = command,
|
||||
Par = (byte)value,
|
||||
Pr2 = id
|
||||
};
|
||||
Assert.AreEqual(expected, actual);
|
||||
}
|
||||
|
||||
check(1, "ON", enuUnitCommand.AudioZone, 3);
|
||||
check(1, "OFF", enuUnitCommand.AudioZone, 2);
|
||||
|
||||
Global.mqtt_audio_local_mute = true;
|
||||
omniLink.Controller.AudioZones[2].Volume = 50;
|
||||
|
||||
check(2, "on", enuUnitCommand.AudioVolume, 0);
|
||||
check(2, "off", enuUnitCommand.AudioVolume, 50);
|
||||
|
||||
omniLink.Controller.AudioZones[2].Volume = 0;
|
||||
|
||||
check(2, "on", enuUnitCommand.AudioVolume, 0);
|
||||
check(2, "off", enuUnitCommand.AudioVolume, 10);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void AudioSourceCommand()
|
||||
{
|
||||
void check(ushort id, string payload, enuUnitCommand command, int value)
|
||||
{
|
||||
SendCommandEventArgs actual = null;
|
||||
omniLink.OnSendCommand += (sender, e) => { actual = e; };
|
||||
messageProcessor.Process($"omnilink/audio{id}/source_command", payload);
|
||||
SendCommandEventArgs expected = new SendCommandEventArgs()
|
||||
{
|
||||
Cmd = command,
|
||||
Par = (byte)value,
|
||||
Pr2 = id
|
||||
};
|
||||
Assert.AreEqual(expected, actual);
|
||||
}
|
||||
|
||||
check(1, "Radio", enuUnitCommand.AudioSource, 1);
|
||||
check(1, "Streaming", enuUnitCommand.AudioSource, 2);
|
||||
|
||||
check(2, "TV", enuUnitCommand.AudioSource, 4);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void AudioVolumeCommand()
|
||||
{
|
||||
void check(ushort id, string payload, enuUnitCommand command, int value)
|
||||
{
|
||||
SendCommandEventArgs actual = null;
|
||||
omniLink.OnSendCommand += (sender, e) => { actual = e; };
|
||||
messageProcessor.Process($"omnilink/audio{id}/volume_command", payload);
|
||||
SendCommandEventArgs expected = new SendCommandEventArgs()
|
||||
{
|
||||
Cmd = command,
|
||||
Par = (byte)value,
|
||||
Pr2 = id
|
||||
};
|
||||
Assert.AreEqual(expected, actual);
|
||||
}
|
||||
|
||||
check(1, "100", enuUnitCommand.AudioVolume, 100);
|
||||
check(1, "75", enuUnitCommand.AudioVolume, 75);
|
||||
|
||||
check(2, "0", enuUnitCommand.AudioVolume, 0);
|
||||
|
||||
Global.mqtt_audio_volume_media_player = true;
|
||||
|
||||
check(2, "1", enuUnitCommand.AudioVolume, 100);
|
||||
check(2, "0.75", enuUnitCommand.AudioVolume, 75);
|
||||
check(2, "0", enuUnitCommand.AudioVolume, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,15 +1,15 @@
|
||||
using HAI_Shared;
|
||||
using OmniLinkBridge.OmniLink;
|
||||
using Serilog;
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace OmniLinkBridgeTest.Mock
|
||||
{
|
||||
class MockOmniLinkII : IOmniLinkII
|
||||
{
|
||||
private static readonly ILogger log = Log.Logger.ForContext(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
|
||||
public clsHAC Controller { get; private set; }
|
||||
|
||||
public event EventHandler<SendCommandEventArgs> OnSendCommand;
|
||||
@ -25,7 +25,6 @@ namespace OmniLinkBridgeTest.Mock
|
||||
|
||||
public bool SendCommand(enuUnitCommand Cmd, byte Par, ushort Pr2)
|
||||
{
|
||||
log.Verbose("Sending: {command}, Par1: {par1}, Par2: {par2}", Cmd, Par, Pr2);
|
||||
OnSendCommand?.Invoke(null, new SendCommandEventArgs() { Cmd = Cmd, Par = Par, Pr2 = Pr2 });
|
||||
return true;
|
||||
}
|
||||
|
@ -1,5 +1,9 @@
|
||||
using HAI_Shared;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace OmniLinkBridgeTest.Mock
|
||||
{
|
||||
@ -9,18 +13,6 @@ namespace OmniLinkBridgeTest.Mock
|
||||
public byte Par;
|
||||
public ushort Pr2;
|
||||
|
||||
public SendCommandEventArgs()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public SendCommandEventArgs(enuUnitCommand cmd, byte par, ushort pr2)
|
||||
{
|
||||
Cmd = cmd;
|
||||
Par = par;
|
||||
Pr2 = pr2;
|
||||
}
|
||||
|
||||
public override bool Equals(object other)
|
||||
{
|
||||
if (!(other is SendCommandEventArgs toCompareWith))
|
||||
|
@ -1,6 +1,9 @@
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using OmniLinkBridge;
|
||||
using System;
|
||||
using System.Text;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using OmniLinkBridge.Notifications;
|
||||
using OmniLinkBridge;
|
||||
using System.Net.Mail;
|
||||
|
||||
namespace OmniLinkBridgeTest
|
||||
|
@ -7,7 +7,7 @@ using System.Runtime.InteropServices;
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("Excalibur Partners, LLC")]
|
||||
[assembly: AssemblyProduct("OmniLinkBridgeTest")]
|
||||
[assembly: AssemblyCopyright("Copyright © Excalibur Partners, LLC 2024")]
|
||||
[assembly: AssemblyCopyright("Copyright © Excalibur Partners, LLC 2022")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
|
@ -1,9 +1,9 @@
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using OmniLinkBridge;
|
||||
using OmniLinkBridge.MQTT.HomeAssistant;
|
||||
using System;
|
||||
using System;
|
||||
using System.Text;
|
||||
using System.Collections.Generic;
|
||||
using ha = OmniLinkBridge.MQTT.HomeAssistant;
|
||||
using System.Collections.Concurrent;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using OmniLinkBridge;
|
||||
|
||||
namespace OmniLinkBridgeTest
|
||||
{
|
||||
@ -37,8 +37,8 @@ namespace OmniLinkBridgeTest
|
||||
Settings.LoadSettings(lines.ToArray());
|
||||
Assert.AreEqual("1.1.1.1", Global.controller_address);
|
||||
Assert.AreEqual(4369, Global.controller_port);
|
||||
Assert.AreEqual("0000000000000001", Global.controller_key1);
|
||||
Assert.AreEqual("0000000000000002", Global.controller_key2);
|
||||
Assert.AreEqual("00-00-00-00-00-00-00-01", Global.controller_key1);
|
||||
Assert.AreEqual("00-00-00-00-00-00-00-02", Global.controller_key2);
|
||||
Assert.AreEqual("MyController", Global.controller_name);
|
||||
}
|
||||
|
||||
@ -79,8 +79,7 @@ namespace OmniLinkBridgeTest
|
||||
"verbose_thermostat_timer",
|
||||
"verbose_thermostat",
|
||||
"verbose_unit",
|
||||
"verbose_message",
|
||||
"verbose_lock"
|
||||
"verbose_message"
|
||||
})
|
||||
{
|
||||
List<string> lines = new List<string>(RequiredSettings())
|
||||
@ -157,12 +156,8 @@ namespace OmniLinkBridgeTest
|
||||
"mqtt_discovery_name_prefix = mynameprefix",
|
||||
"mqtt_discovery_ignore_zones = 1,2-3,4",
|
||||
"mqtt_discovery_ignore_units = 2-5,7",
|
||||
"mqtt_discovery_override_area = id=1",
|
||||
"mqtt_discovery_override_area = id=2;code_arm=true;code_disarm=true;arm_home=false;arm_away=false;arm_night=false;arm_vacation=false",
|
||||
"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);
|
||||
@ -173,29 +168,10 @@ namespace OmniLinkBridgeTest
|
||||
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 }));
|
||||
|
||||
Dictionary<int, OmniLinkBridge.MQTT.OverrideArea> override_area = new Dictionary<int, OmniLinkBridge.MQTT.OverrideArea>()
|
||||
{
|
||||
{ 1, new OmniLinkBridge.MQTT.OverrideArea { }},
|
||||
{ 2, new OmniLinkBridge.MQTT.OverrideArea { code_arm = true, code_disarm = true,
|
||||
arm_home = false, arm_away = false, arm_night = false, arm_vacation = false }},
|
||||
};
|
||||
|
||||
Assert.AreEqual(override_area.Count, Global.mqtt_discovery_override_area.Count);
|
||||
foreach (KeyValuePair<int, OmniLinkBridge.MQTT.OverrideArea> pair in override_area)
|
||||
{
|
||||
Global.mqtt_discovery_override_area.TryGetValue(pair.Key, out OmniLinkBridge.MQTT.OverrideArea value);
|
||||
Assert.AreEqual(override_area[pair.Key].code_arm, value.code_arm);
|
||||
Assert.AreEqual(override_area[pair.Key].code_disarm, value.code_disarm);
|
||||
Assert.AreEqual(override_area[pair.Key].arm_home, value.arm_home);
|
||||
Assert.AreEqual(override_area[pair.Key].arm_away, value.arm_away);
|
||||
Assert.AreEqual(override_area[pair.Key].arm_night, value.arm_night);
|
||||
Assert.AreEqual(override_area[pair.Key].arm_vacation, value.arm_vacation);
|
||||
}
|
||||
|
||||
Dictionary<int, OmniLinkBridge.MQTT.OverrideZone> override_zone = new Dictionary<int, OmniLinkBridge.MQTT.OverrideZone>()
|
||||
{
|
||||
{ 5, new OmniLinkBridge.MQTT.OverrideZone { device_class = ha.BinarySensor.DeviceClass.garage_door }},
|
||||
{ 7, new OmniLinkBridge.MQTT.OverrideZone { device_class = ha.BinarySensor.DeviceClass.motion }}
|
||||
{ 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 }}
|
||||
};
|
||||
|
||||
Assert.AreEqual(override_zone.Count, Global.mqtt_discovery_override_zone.Count);
|
||||
@ -204,30 +180,6 @@ 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<int, OmniLinkBridge.MQTT.OverrideUnit> override_unit = new Dictionary<int, OmniLinkBridge.MQTT.OverrideUnit>()
|
||||
{
|
||||
{ 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<int, OmniLinkBridge.MQTT.OverrideUnit> 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);
|
||||
}
|
||||
|
||||
Assert.AreEqual(Global.mqtt_discovery_button_type, typeof(Switch));
|
||||
|
||||
// Test additional settings
|
||||
lines.AddRange(new string[]
|
||||
{
|
||||
"mqtt_discovery_button_type = button"
|
||||
});
|
||||
Settings.LoadSettings(lines.ToArray());
|
||||
|
||||
Assert.AreEqual(Global.mqtt_discovery_button_type, typeof(Button));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
|
74
README.md
74
README.md
@ -1,23 +1,21 @@
|
||||
# OmniLink Bridge
|
||||
Provides MQTT bridge, web service API, time sync, and logging for [HAI/Leviton OmniPro II controllers](https://www.leviton.com/en/products/brands/omni-security-automation). Provides integration with [Samsung SmartThings via web service API](https://github.com/excaliburpartners/SmartThings-OmniPro) and [Home Assistant via MQTT](https://www.home-assistant.io/components/mqtt/).
|
||||
|
||||
Please note that OmniLink Bridge is not in active development. The MQTT and Home Assistant integrations are in maintenance mode. The SmartThings Web API and MySQL logging are deprecated and not feature consistent with MQTT.
|
||||
|
||||
## Download
|
||||
You can use docker to build an image from git or download the [binary here](https://github.com/excaliburpartners/OmniLinkBridge/releases/latest/download/OmniLinkBridge.zip). You can also install it as a [Home Assistant Add-on](https://github.com/excaliburpartners/hassio-addons).
|
||||
You can use docker to build an image from git or download the [binary here](https://github.com/excaliburpartners/OmniLinkBridge/releases/latest/download/OmniLinkBridge.zip).
|
||||
|
||||
## Requirements
|
||||
- [Docker](https://www.docker.com/)
|
||||
- .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](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](https://github.com/excaliburpartners/OmniLinkBridge/blob/master/OmniLinkBridge/OmniLinkBridge.ini) for specifics.
|
||||
|
||||
- OmniLinkII: controller_
|
||||
- Maintains connection to the OmniLink controller
|
||||
- Thermostats
|
||||
- If no status update has been received after 4 minutes a request is issued
|
||||
- A status update containing a temperature of 0 marks the thermostat offline
|
||||
- A status update containing a temperature of 0 is ignored
|
||||
- This can occur when a ZigBee thermostat has lost communication
|
||||
- Time Sync: time_
|
||||
- Controller time is checked and compared to the local computer time disregarding time zones
|
||||
@ -30,7 +28,7 @@ OmniLink Bridge is divided into the following modules and configurable settings.
|
||||
- Provides integration with [Samsung SmartThings](https://github.com/excaliburpartners/SmartThings-OmniPro)
|
||||
- Allows an application to subscribe to receive POST notifications status updates are received from the OmniLinkII module
|
||||
- On failure to POST to callback URL subscription is removed
|
||||
- Recommended for application to send subscribe requests every few minutes
|
||||
- Recommended for application to send subscribe reqeusts every few minutes
|
||||
- Requests to GET endpoints return status from the OmniLinkII module
|
||||
- Requests to POST endpoints send commands to the OmniLinkII module
|
||||
- Logger
|
||||
@ -148,17 +146,6 @@ systemctl start omnilinkbridge.service
|
||||
```
|
||||
|
||||
## MQTT
|
||||
```
|
||||
SUB omnilink/status
|
||||
string online, offline
|
||||
|
||||
SUB omnilink/model
|
||||
string Controller model
|
||||
|
||||
SUB omnilink/version
|
||||
string Controller version
|
||||
```
|
||||
|
||||
### System
|
||||
```
|
||||
SUB omnilink/system/phone/state
|
||||
@ -234,10 +221,6 @@ 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
|
||||
@ -248,9 +231,6 @@ string A-L
|
||||
SUB omnilink/thermostatX/name
|
||||
string Thermostat name
|
||||
|
||||
SUB omnilink/thermostatX/status
|
||||
string online, offline
|
||||
|
||||
SUB omnilink/thermostatX/current_operation
|
||||
string idle, cooling, heating
|
||||
|
||||
@ -314,50 +294,6 @@ PUB omnilink/messageX/command
|
||||
string show, show_no_beep, show_no_beep_or_led, clear
|
||||
```
|
||||
|
||||
### Locks
|
||||
```
|
||||
SUB omnilink/lockX/name
|
||||
string Lock name
|
||||
|
||||
SUB omnilink/lockX/state
|
||||
string locked, unlocked
|
||||
|
||||
PUB omnilink/lockX/command
|
||||
string lock, unlock
|
||||
```
|
||||
|
||||
### Audio Sources
|
||||
```
|
||||
SUB omnilink/sourceXX/name
|
||||
string Audio source name
|
||||
```
|
||||
|
||||
### Audio Zones
|
||||
```
|
||||
SUB omnilink/audioXX/name
|
||||
string Audio zone name
|
||||
|
||||
SUB omnilink/audioXX/state
|
||||
PUB omnilink/audioXX/command
|
||||
string OFF, ON
|
||||
note Use audio 0 to change all audio zones
|
||||
|
||||
SUB omnilink/audioXX/mute_state
|
||||
PUB omnilink/audioXX/mute_command
|
||||
string OFF, ON
|
||||
note Use audio 0 to change all audio zones
|
||||
|
||||
SUB omnilink/audioXX/source_state
|
||||
PUB omnilink/audioXX/source_command
|
||||
string Source name
|
||||
note Refer to omnilink/sourceXX/name
|
||||
|
||||
SUB omnilink/audioXX/volume_state
|
||||
PUB omnilink/audioXX/volume_command
|
||||
int Level from 0 to 100 percent
|
||||
double Level from 0.00 to 1.00 (mqtt_audio_volume_media_player = yes)
|
||||
```
|
||||
|
||||
## Web API
|
||||
To test the web service API you can use your browser to view a page or PowerShell (see below) to change a value.
|
||||
|
||||
@ -422,7 +358,7 @@ POST /PushButton
|
||||
```
|
||||
|
||||
## MySQL
|
||||
The [MySQL ODBC Connector](http://dev.mysql.com/downloads/connector/odbc/) is required for MySQL logging. The docker image comes with the MySQL ODBC connector installed. For Windows and Linux you will need to download and install it. The Home Assistant Add-on does not support MySQL logging.
|
||||
The [MySQL ODBC Connector](http://dev.mysql.com/downloads/connector/odbc/) is required for MySQL logging. The docker image comes with the MySQL ODBC connector installed. For Windows and Linux you will need to download and install it.
|
||||
|
||||
Configure mysql_connection in OmniLinkBridge.ini. For Windows change DRIVER={MySQL} to name of the driver shown in the ODBC Data Source Administrator.
|
||||
```
|
||||
|
Loading…
x
Reference in New Issue
Block a user