mirror of
https://github.com/excaliburpartners/OmniLinkBridge.git
synced 2025-04-20 05:17:19 +00:00
Compare commits
No commits in common. "master" and "1.1.14" 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,12 @@
|
||||
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
|
||||
@ -50,14 +43,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,9 @@ 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;
|
||||
|
@ -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.MQTT
|
||||
{
|
||||
@ -23,13 +28,7 @@ namespace OmniLinkBridge.MQTT
|
||||
}
|
||||
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)
|
||||
if (string.Compare(payloads[1], "validate", true) == 0)
|
||||
{
|
||||
ret.Validate = true;
|
||||
ret.Success = int.TryParse(payloads[2], out code);
|
||||
|
@ -1,15 +1,10 @@
|
||||
using Newtonsoft.Json;
|
||||
using System.Collections.Generic;
|
||||
using Newtonsoft.Json.Converters;
|
||||
|
||||
namespace OmniLinkBridge.MQTT.HomeAssistant
|
||||
{
|
||||
public class Alarm : Device
|
||||
{
|
||||
public Alarm(DeviceRegistry deviceRegistry) : base(deviceRegistry)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public string command_topic { get; set; }
|
||||
|
||||
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
|
||||
@ -17,14 +12,5 @@ namespace OmniLinkBridge.MQTT.HomeAssistant
|
||||
|
||||
[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" });
|
||||
}
|
||||
}
|
||||
|
@ -5,11 +5,6 @@ namespace OmniLinkBridge.MQTT.HomeAssistant
|
||||
{
|
||||
public class BinarySensor : Device
|
||||
{
|
||||
public BinarySensor(DeviceRegistry deviceRegistry) : base(deviceRegistry)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
[JsonConverter(typeof(StringEnumConverter))]
|
||||
public enum DeviceClass
|
||||
{
|
||||
|
@ -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; }
|
||||
}
|
||||
}
|
@ -4,11 +4,6 @@ namespace OmniLinkBridge.MQTT.HomeAssistant
|
||||
{
|
||||
public class Climate : Device
|
||||
{
|
||||
public Climate(DeviceRegistry deviceRegistry) : base(deviceRegistry)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public string status { get; set; }
|
||||
|
||||
public string action_topic { get; set; }
|
||||
|
@ -1,16 +1,12 @@
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Converters;
|
||||
using OmniLinkBridge.Modules;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace OmniLinkBridge.MQTT.HomeAssistant
|
||||
{
|
||||
public class Device
|
||||
{
|
||||
public Device(DeviceRegistry deviceRegistry)
|
||||
{
|
||||
device = deviceRegistry;
|
||||
}
|
||||
|
||||
[JsonConverter(typeof(StringEnumConverter))]
|
||||
public enum AvailabilityMode
|
||||
{
|
||||
@ -23,9 +19,6 @@ namespace OmniLinkBridge.MQTT.HomeAssistant
|
||||
|
||||
public string name { get; set; }
|
||||
|
||||
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string icon { get; set; }
|
||||
|
||||
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string state_topic { get; set; }
|
||||
|
||||
@ -39,6 +32,6 @@ namespace OmniLinkBridge.MQTT.HomeAssistant
|
||||
public AvailabilityMode? availability_mode { get; set; }
|
||||
|
||||
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
|
||||
public DeviceRegistry device { get; set; }
|
||||
public DeviceRegistry device { get; set; } = MQTTModule.MqttDeviceRegistry;
|
||||
}
|
||||
}
|
||||
|
@ -2,11 +2,6 @@
|
||||
{
|
||||
public class Light : Device
|
||||
{
|
||||
public Light(DeviceRegistry deviceRegistry) : base(deviceRegistry)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public string command_topic { get; set; }
|
||||
|
||||
public string brightness_state_topic { 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; }
|
||||
}
|
||||
}
|
@ -4,20 +4,15 @@ 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; }
|
||||
public string icon { 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;
|
||||
}
|
||||
}
|
@ -5,11 +5,6 @@ namespace OmniLinkBridge.MQTT.HomeAssistant
|
||||
{
|
||||
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; }
|
||||
|
||||
|
@ -4,11 +4,6 @@ namespace OmniLinkBridge.MQTT.HomeAssistant
|
||||
{
|
||||
public class Switch : Device
|
||||
{
|
||||
public Switch(DeviceRegistry deviceRegistry) : base(deviceRegistry)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public string command_topic { get; set; }
|
||||
|
||||
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
|
||||
|
@ -3,7 +3,6 @@ using Newtonsoft.Json;
|
||||
using System.Collections.Generic;
|
||||
using OmniLinkBridge.MQTT.HomeAssistant;
|
||||
using OmniLinkBridge.MQTT.Parser;
|
||||
using OmniLinkBridge.Modules;
|
||||
|
||||
namespace OmniLinkBridge.MQTT
|
||||
{
|
||||
@ -16,7 +15,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 +24,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 +83,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 +96,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 +109,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 +122,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 +135,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 +148,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 +161,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 +174,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 +219,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 +232,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 +245,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 +287,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 +302,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 +377,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 +391,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,
|
||||
@ -421,7 +403,7 @@ namespace OmniLinkBridge.MQTT
|
||||
|
||||
public static Number ToConfigNumber(this clsUnit unit)
|
||||
{
|
||||
Number ret = new Number(MQTTModule.MqttDeviceRegistry)
|
||||
Number ret = new Number
|
||||
{
|
||||
unique_id = $"{Global.mqtt_prefix}unit{unit.Number}number",
|
||||
name = Global.mqtt_discovery_name_prefix + unit.Name,
|
||||
@ -464,7 +446,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 +459,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 +472,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 +485,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,7 +498,7 @@ 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,
|
||||
@ -597,9 +579,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 +591,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 +605,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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,6 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
|
||||
namespace OmniLinkBridge.MQTT
|
||||
{
|
||||
@ -16,18 +15,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 +29,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 +49,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 +76,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 +96,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 +141,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)
|
||||
@ -186,7 +174,7 @@ namespace OmniLinkBridge.MQTT
|
||||
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 &&
|
||||
else if (unit.Type != enuOL2UnitType.Output &&
|
||||
command == Topic.brightness_command && int.TryParse(payload, out int unitValue))
|
||||
{
|
||||
log.Debug("SetUnit: {id} to {value}%", unit.Number, payload);
|
||||
@ -197,7 +185,7 @@ namespace OmniLinkBridge.MQTT
|
||||
// which will cause light to go to 100% brightness
|
||||
unit.Status = (byte)(100 + unitValue);
|
||||
}
|
||||
else if (unit.Type != enuOL2UnitType.Output &&
|
||||
else if (unit.Type != enuOL2UnitType.Output &&
|
||||
command == Topic.scene_command && char.TryParse(payload, out char scene))
|
||||
{
|
||||
log.Debug("SetUnit: {id} to {value}", unit.Number, payload);
|
||||
@ -306,111 +294,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -7,8 +7,6 @@
|
||||
unit,
|
||||
thermostat,
|
||||
button,
|
||||
message,
|
||||
@lock,
|
||||
audio
|
||||
message
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +0,0 @@
|
||||
namespace OmniLinkBridge.MQTT.Parser
|
||||
{
|
||||
enum LockCommands
|
||||
{
|
||||
@lock,
|
||||
unlock
|
||||
}
|
||||
}
|
@ -33,11 +33,5 @@
|
||||
fan_mode_command,
|
||||
hold_state,
|
||||
hold_command,
|
||||
mute_state,
|
||||
mute_command,
|
||||
source_state,
|
||||
source_command,
|
||||
volume_state,
|
||||
volume_command,
|
||||
}
|
||||
}
|
||||
|
@ -39,8 +39,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 +46,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);
|
||||
@ -202,55 +199,10 @@ namespace OmniLinkBridge.Modules
|
||||
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);
|
||||
"{OutputUsage} outputs, {FlagUsage} flags, {ThermostatUsage} thermostats",
|
||||
areaUsage, zoneUsage, unitUsage, outputUsage, flagUsage, thermostatUsage);
|
||||
}
|
||||
|
||||
private void Omnilink_OnAreaStatus(object sender, AreaStatusEventArgs e)
|
||||
@ -278,7 +230,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());
|
||||
@ -385,19 +337,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(@"
|
||||
|
@ -34,16 +34,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 +50,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()
|
||||
@ -126,10 +119,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(
|
||||
@ -179,9 +169,6 @@ namespace OmniLinkBridge.Modules
|
||||
PublishThermostats();
|
||||
PublishButtons();
|
||||
PublishMessages();
|
||||
PublishLocks();
|
||||
PublishAudioSources();
|
||||
PublishAudioZones();
|
||||
|
||||
PublishControllerStatus(ONLINE);
|
||||
PublishAsync($"{Global.mqtt_prefix}/model", OmniLink.Controller.GetModelText());
|
||||
@ -201,10 +188,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 +201,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"
|
||||
};
|
||||
}
|
||||
|
||||
@ -402,9 +389,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 +397,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 +404,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 +429,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)
|
||||
@ -633,35 +514,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)
|
||||
@ -725,20 +590,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);
|
||||
@ -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));
|
||||
});
|
||||
}
|
||||
|
||||
@ -353,17 +342,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 +422,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);
|
||||
@ -703,28 +679,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)
|
||||
{
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -80,14 +80,9 @@
|
||||
<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\AreaCommandCode.cs" />
|
||||
@ -100,7 +95,6 @@
|
||||
<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\MessageProcessor.cs" />
|
||||
<Compile Include="MQTT\HomeAssistant\Number.cs" />
|
||||
@ -120,9 +114,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 +182,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>
|
||||
|
@ -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
|
||||
@ -55,24 +53,14 @@ mqtt_discovery_name_prefix =
|
||||
# Specify a range of numbers 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
|
||||
|
||||
# Require Home Assistant to prompt for user code when arming/disarming area
|
||||
# Specify a range of numbers 1,2,3,5-10
|
||||
mqtt_discovery_area_code_required =
|
||||
# Override the zone Home Assistant binary sensor device_class
|
||||
# device_class: must be battery, cold, door, garage_door, gas,
|
||||
# heat, moisture, motion, problem, safety, smoke, or window
|
||||
#mqtt_discovery_override_zone = id=5;device_class=garage_door
|
||||
#mqtt_discovery_override_zone = id=6;device_class=garage_door
|
||||
|
||||
# Override the unit Home Assistant device type
|
||||
# type:
|
||||
# Units (LTe 1-32, IIe 1-64, Pro 1-256) light or switch, defaults to light
|
||||
@ -80,15 +68,6 @@ mqtt_discovery_ignore_units =
|
||||
#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.14.0")]
|
||||
[assembly: AssemblyFileVersion("1.1.14.0")]
|
||||
|
@ -1,4 +1,3 @@
|
||||
using OmniLinkBridge.MQTT.HomeAssistant;
|
||||
using Serilog;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
@ -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,9 @@ 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 +100,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
|
||||
@ -322,19 +233,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 +319,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 +352,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
|
||||
{
|
||||
|
@ -64,14 +64,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,9 @@
|
||||
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,24 +16,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);
|
||||
messageProcessor = new MessageProcessor(omniLink);
|
||||
|
||||
omniLink.Controller.Units[395].Type = enuOL2UnitType.Flag;
|
||||
}
|
||||
@ -306,140 +286,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,11 @@
|
||||
using HAI_Shared;
|
||||
using OmniLinkBridge.OmniLink;
|
||||
using Serilog;
|
||||
using System;
|
||||
using System.Reflection;
|
||||
|
||||
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 +21,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;
|
||||
}
|
||||
|
@ -9,18 +9,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))
|
||||
|
@ -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,6 +1,5 @@
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using OmniLinkBridge;
|
||||
using OmniLinkBridge.MQTT.HomeAssistant;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using ha = OmniLinkBridge.MQTT.HomeAssistant;
|
||||
@ -37,8 +36,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 +78,7 @@ namespace OmniLinkBridgeTest
|
||||
"verbose_thermostat_timer",
|
||||
"verbose_thermostat",
|
||||
"verbose_unit",
|
||||
"verbose_message",
|
||||
"verbose_lock"
|
||||
"verbose_message"
|
||||
})
|
||||
{
|
||||
List<string> lines = new List<string>(RequiredSettings())
|
||||
@ -157,8 +155,7 @@ 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_area_code_required = 1",
|
||||
"mqtt_discovery_override_zone = id=5;device_class=garage_door",
|
||||
"mqtt_discovery_override_zone = id=7;device_class=motion",
|
||||
"mqtt_discovery_override_unit = id=1;type=switch",
|
||||
@ -172,25 +169,7 @@ namespace OmniLinkBridgeTest
|
||||
Assert.AreEqual("mynameprefix ", Global.mqtt_discovery_name_prefix);
|
||||
Assert.IsTrue(Global.mqtt_discovery_ignore_zones.SetEquals(new int[] { 1, 2, 3, 4 }));
|
||||
Assert.IsTrue(Global.mqtt_discovery_ignore_units.SetEquals(new int[] { 2, 3, 4, 5, 7 }));
|
||||
|
||||
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);
|
||||
}
|
||||
Assert.IsTrue(Global.mqtt_discovery_area_code_required.SetEquals(new int[] { 1 }));
|
||||
|
||||
Dictionary<int, OmniLinkBridge.MQTT.OverrideZone> override_zone = new Dictionary<int, OmniLinkBridge.MQTT.OverrideZone>()
|
||||
{
|
||||
@ -217,17 +196,6 @@ namespace OmniLinkBridgeTest
|
||||
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]
|
||||
|
52
README.md
52
README.md
@ -1,10 +1,8 @@
|
||||
# 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/)
|
||||
@ -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
|
||||
@ -314,50 +312,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 +376,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