mirror of
https://github.com/excaliburpartners/OmniLinkBridge
synced 2024-12-22 10:42:24 +00:00
1.1.14 - Improve MQTT unit, output and flag capabilities
This commit is contained in:
parent
a016e1cd64
commit
495ce74149
|
@ -1,5 +1,4 @@
|
|||
using OmniLinkBridge.MQTT;
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
|
@ -24,39 +23,6 @@ namespace OmniLinkBridge
|
|||
{
|
||||
return (b & (1 << pos)) != 0;
|
||||
}
|
||||
|
||||
public static AreaCommandCode ToCommandCode(this string payload, bool supportValidate = false)
|
||||
{
|
||||
string[] payloads = payload.Split(',');
|
||||
int code = 0;
|
||||
|
||||
AreaCommandCode ret = new AreaCommandCode()
|
||||
{
|
||||
Command = payloads[0]
|
||||
};
|
||||
|
||||
if (payload.Length == 1)
|
||||
return ret;
|
||||
|
||||
if (payloads.Length == 2)
|
||||
{
|
||||
ret.Success = int.TryParse(payloads[1], out code);
|
||||
}
|
||||
else if (supportValidate && payloads.Length == 3)
|
||||
{
|
||||
if (string.Compare(payloads[1], "validate", true) == 0)
|
||||
{
|
||||
ret.Validate = true;
|
||||
ret.Success = int.TryParse(payloads[2], out code);
|
||||
}
|
||||
else
|
||||
ret.Success = false;
|
||||
}
|
||||
|
||||
ret.Code = code;
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static string ToSpaceTitleCase(this string phrase)
|
||||
{
|
||||
return Regex.Replace(phrase, "(\\B[A-Z])", " $1");
|
||||
|
|
|
@ -55,6 +55,7 @@ namespace OmniLinkBridge
|
|||
public static HashSet<int> mqtt_discovery_ignore_units;
|
||||
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;
|
||||
|
||||
// Notifications
|
||||
public static bool notify_area;
|
||||
|
|
65
OmniLinkBridge/MQTT/Extensions.cs
Normal file
65
OmniLinkBridge/MQTT/Extensions.cs
Normal file
|
@ -0,0 +1,65 @@
|
|||
using HAI_Shared;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace OmniLinkBridge.MQTT
|
||||
{
|
||||
public static class Extensions
|
||||
{
|
||||
public static AreaCommandCode ToCommandCode(this string payload, bool supportValidate = false)
|
||||
{
|
||||
string[] payloads = payload.Split(',');
|
||||
int code = 0;
|
||||
|
||||
AreaCommandCode ret = new AreaCommandCode()
|
||||
{
|
||||
Command = payloads[0]
|
||||
};
|
||||
|
||||
if (payload.Length == 1)
|
||||
return ret;
|
||||
|
||||
if (payloads.Length == 2)
|
||||
{
|
||||
ret.Success = int.TryParse(payloads[1], out code);
|
||||
}
|
||||
else if (supportValidate && payloads.Length == 3)
|
||||
{
|
||||
if (string.Compare(payloads[1], "validate", true) == 0)
|
||||
{
|
||||
ret.Validate = true;
|
||||
ret.Success = int.TryParse(payloads[2], out code);
|
||||
}
|
||||
else
|
||||
ret.Success = false;
|
||||
}
|
||||
|
||||
ret.Code = code;
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static UnitType ToUnitType(this clsUnit unit)
|
||||
{
|
||||
Global.mqtt_discovery_override_unit.TryGetValue(unit.Number, out OverrideUnit override_unit);
|
||||
|
||||
if (unit.Type == enuOL2UnitType.Output)
|
||||
return UnitType.@switch;
|
||||
|
||||
if (unit.Type == enuOL2UnitType.Flag)
|
||||
{
|
||||
if (override_unit != null && override_unit.type == UnitType.number)
|
||||
return UnitType.number;
|
||||
|
||||
return UnitType.@switch;
|
||||
}
|
||||
|
||||
if (override_unit != null && override_unit.type == UnitType.@switch)
|
||||
return UnitType.@switch;
|
||||
|
||||
return UnitType.light;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Converters;
|
||||
|
||||
namespace OmniLinkBridge.MQTT
|
||||
namespace OmniLinkBridge.MQTT.HomeAssistant
|
||||
{
|
||||
public class Alarm : Device
|
||||
{
|
|
@ -1,7 +1,7 @@
|
|||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Converters;
|
||||
|
||||
namespace OmniLinkBridge.MQTT
|
||||
namespace OmniLinkBridge.MQTT.HomeAssistant
|
||||
{
|
||||
public class BinarySensor : Device
|
||||
{
|
|
@ -1,6 +1,6 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace OmniLinkBridge.MQTT
|
||||
namespace OmniLinkBridge.MQTT.HomeAssistant
|
||||
{
|
||||
public class Climate : Device
|
||||
{
|
|
@ -3,7 +3,7 @@ using Newtonsoft.Json.Converters;
|
|||
using OmniLinkBridge.Modules;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace OmniLinkBridge.MQTT
|
||||
namespace OmniLinkBridge.MQTT.HomeAssistant
|
||||
{
|
||||
public class Device
|
||||
{
|
|
@ -1,4 +1,4 @@
|
|||
namespace OmniLinkBridge.MQTT
|
||||
namespace OmniLinkBridge.MQTT.HomeAssistant
|
||||
{
|
||||
public class DeviceRegistry
|
||||
{
|
|
@ -1,4 +1,4 @@
|
|||
namespace OmniLinkBridge.MQTT
|
||||
namespace OmniLinkBridge.MQTT.HomeAssistant
|
||||
{
|
||||
public class Light : Device
|
||||
{
|
18
OmniLinkBridge/MQTT/HomeAssistant/Number.cs
Normal file
18
OmniLinkBridge/MQTT/HomeAssistant/Number.cs
Normal file
|
@ -0,0 +1,18 @@
|
|||
using Newtonsoft.Json;
|
||||
|
||||
namespace OmniLinkBridge.MQTT.HomeAssistant
|
||||
{
|
||||
public class Number : Device
|
||||
{
|
||||
public string command_topic { get; set; }
|
||||
|
||||
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string icon { get; set; }
|
||||
|
||||
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
|
||||
public int? min { get; set; }
|
||||
|
||||
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
|
||||
public int? max { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Converters;
|
||||
|
||||
namespace OmniLinkBridge.MQTT
|
||||
namespace OmniLinkBridge.MQTT.HomeAssistant
|
||||
{
|
||||
public class Sensor : Device
|
||||
{
|
|
@ -1,6 +1,6 @@
|
|||
using Newtonsoft.Json;
|
||||
|
||||
namespace OmniLinkBridge.MQTT
|
||||
namespace OmniLinkBridge.MQTT.HomeAssistant
|
||||
{
|
||||
public class Switch : Device
|
||||
{
|
|
@ -1,6 +1,8 @@
|
|||
using HAI_Shared;
|
||||
using Newtonsoft.Json;
|
||||
using System.Collections.Generic;
|
||||
using OmniLinkBridge.MQTT.HomeAssistant;
|
||||
using OmniLinkBridge.MQTT.Parser;
|
||||
|
||||
namespace OmniLinkBridge.MQTT
|
||||
{
|
||||
|
@ -399,6 +401,20 @@ namespace OmniLinkBridge.MQTT
|
|||
return ret;
|
||||
}
|
||||
|
||||
public static Number ToConfigNumber(this clsUnit unit)
|
||||
{
|
||||
Number ret = new Number
|
||||
{
|
||||
unique_id = $"{Global.mqtt_prefix}unit{unit.Number}number",
|
||||
name = Global.mqtt_discovery_name_prefix + unit.Name,
|
||||
state_topic = unit.ToTopic(Topic.flag_state),
|
||||
command_topic = unit.ToTopic(Topic.flag_command),
|
||||
min = 0,
|
||||
max = 255
|
||||
};
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static string ToState(this clsUnit unit)
|
||||
{
|
||||
return unit.Status == 0 || unit.Status == 100 ? UnitCommands.OFF.ToString() : UnitCommands.ON.ToString();
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using HAI_Shared;
|
||||
using OmniLinkBridge.MQTT.Parser;
|
||||
using OmniLinkBridge.OmniLink;
|
||||
using Serilog;
|
||||
using System;
|
||||
|
@ -167,10 +168,16 @@ namespace OmniLinkBridge.MQTT
|
|||
OmniLink.SendCommand(UnitMapping[cmd], 0, (ushort)unit.Number);
|
||||
}
|
||||
}
|
||||
else if (command == Topic.brightness_command && int.TryParse(payload, out int unitValue))
|
||||
else if (unit.Type == enuOL2UnitType.Flag &&
|
||||
command == Topic.flag_command && int.TryParse(payload, out int flagValue))
|
||||
{
|
||||
log.Debug("SetUnit: {id} to {value}", unit.Number, payload);
|
||||
OmniLink.SendCommand(enuUnitCommand.Set, BitConverter.GetBytes(flagValue)[0], (ushort)unit.Number);
|
||||
}
|
||||
else if (unit.Type != enuOL2UnitType.Output &&
|
||||
command == Topic.brightness_command && int.TryParse(payload, out int unitValue))
|
||||
{
|
||||
log.Debug("SetUnit: {id} to {value}%", unit.Number, payload);
|
||||
|
||||
OmniLink.SendCommand(enuUnitCommand.Level, BitConverter.GetBytes(unitValue)[0], (ushort)unit.Number);
|
||||
|
||||
// Force status change instead of waiting on controller to update
|
||||
|
@ -178,10 +185,10 @@ namespace OmniLinkBridge.MQTT
|
|||
// which will cause light to go to 100% brightness
|
||||
unit.Status = (byte)(100 + unitValue);
|
||||
}
|
||||
else if (command == Topic.scene_command && char.TryParse(payload, out char scene))
|
||||
else if (unit.Type != enuOL2UnitType.Output &&
|
||||
command == Topic.scene_command && char.TryParse(payload, out char scene))
|
||||
{
|
||||
log.Debug("SetUnit: {id} to {value}", unit.Number, payload);
|
||||
|
||||
OmniLink.SendCommand(enuUnitCommand.Compose, (byte)(scene - 63), (ushort)unit.Number);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
using Newtonsoft.Json;
|
||||
|
||||
namespace OmniLinkBridge.MQTT
|
||||
{
|
||||
public class Number : Device
|
||||
{
|
||||
public string command_topic { get; set; }
|
||||
|
||||
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string icon { get; set; }
|
||||
}
|
||||
}
|
7
OmniLinkBridge/MQTT/OverrideUnit.cs
Normal file
7
OmniLinkBridge/MQTT/OverrideUnit.cs
Normal file
|
@ -0,0 +1,7 @@
|
|||
namespace OmniLinkBridge.MQTT
|
||||
{
|
||||
public class OverrideUnit
|
||||
{
|
||||
public UnitType type { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,4 +1,6 @@
|
|||
namespace OmniLinkBridge.MQTT
|
||||
using OmniLinkBridge.MQTT.HomeAssistant;
|
||||
|
||||
namespace OmniLinkBridge.MQTT
|
||||
{
|
||||
public class OverrideZone
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
namespace OmniLinkBridge.MQTT
|
||||
namespace OmniLinkBridge.MQTT.Parser
|
||||
{
|
||||
enum AlarmCommands
|
||||
{
|
|
@ -1,4 +1,4 @@
|
|||
namespace OmniLinkBridge.MQTT
|
||||
namespace OmniLinkBridge.MQTT.Parser
|
||||
{
|
||||
enum AreaCommands
|
||||
{
|
|
@ -1,4 +1,4 @@
|
|||
namespace OmniLinkBridge.MQTT
|
||||
namespace OmniLinkBridge.MQTT.Parser
|
||||
{
|
||||
enum CommandTypes
|
||||
{
|
|
@ -1,4 +1,4 @@
|
|||
namespace OmniLinkBridge.MQTT
|
||||
namespace OmniLinkBridge.MQTT.Parser
|
||||
{
|
||||
enum MessageCommands
|
||||
{
|
|
@ -1,4 +1,4 @@
|
|||
namespace OmniLinkBridge.MQTT
|
||||
namespace OmniLinkBridge.MQTT.Parser
|
||||
{
|
||||
public enum Topic
|
||||
{
|
||||
|
@ -11,6 +11,8 @@
|
|||
json_state,
|
||||
brightness_state,
|
||||
brightness_command,
|
||||
flag_state,
|
||||
flag_command,
|
||||
scene_state,
|
||||
scene_command,
|
||||
current_operation,
|
|
@ -1,4 +1,4 @@
|
|||
namespace OmniLinkBridge.MQTT
|
||||
namespace OmniLinkBridge.MQTT.Parser
|
||||
{
|
||||
enum UnitCommands
|
||||
{
|
|
@ -1,4 +1,4 @@
|
|||
namespace OmniLinkBridge.MQTT
|
||||
namespace OmniLinkBridge.MQTT.Parser
|
||||
{
|
||||
enum ZoneCommands
|
||||
{
|
9
OmniLinkBridge/MQTT/UnitType.cs
Normal file
9
OmniLinkBridge/MQTT/UnitType.cs
Normal file
|
@ -0,0 +1,9 @@
|
|||
namespace OmniLinkBridge.MQTT
|
||||
{
|
||||
public enum UnitType
|
||||
{
|
||||
@switch,
|
||||
light,
|
||||
number
|
||||
}
|
||||
}
|
|
@ -2,6 +2,7 @@
|
|||
using OmniLinkBridge.Notifications;
|
||||
using OmniLinkBridge.OmniLink;
|
||||
using Serilog;
|
||||
using Serilog.Context;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
|
@ -125,8 +126,7 @@ namespace OmniLinkBridge.Modules
|
|||
|
||||
private void Omnilink_OnConnect(object sender, EventArgs e)
|
||||
{
|
||||
if (Global.verbose_area)
|
||||
{
|
||||
ushort areaUsage = 0;
|
||||
for (ushort i = 1; i <= omnilink.Controller.Areas.Count; i++)
|
||||
{
|
||||
clsArea area = omnilink.Controller.Areas[i];
|
||||
|
@ -134,6 +134,10 @@ namespace OmniLinkBridge.Modules
|
|||
if (i > 1 && area.DefaultProperties == true)
|
||||
continue;
|
||||
|
||||
areaUsage++;
|
||||
|
||||
if (Global.verbose_area)
|
||||
{
|
||||
string status = area.ModeText();
|
||||
|
||||
if (area.ExitTimer > 0)
|
||||
|
@ -146,8 +150,7 @@ namespace OmniLinkBridge.Modules
|
|||
}
|
||||
}
|
||||
|
||||
if (Global.verbose_zone)
|
||||
{
|
||||
ushort zoneUsage = 0;
|
||||
for (ushort i = 1; i <= omnilink.Controller.Zones.Count; i++)
|
||||
{
|
||||
clsZone zone = omnilink.Controller.Zones[i];
|
||||
|
@ -155,12 +158,51 @@ namespace OmniLinkBridge.Modules
|
|||
if (zone.DefaultProperties == true)
|
||||
continue;
|
||||
|
||||
zoneUsage++;
|
||||
|
||||
if (Global.verbose_zone)
|
||||
{
|
||||
if (zone.IsTemperatureZone())
|
||||
log.Verbose("Initial ZoneStatus {id} {name}, Temp: {temp}", i, zone.Name, zone.TempText());
|
||||
else
|
||||
log.Verbose("Initial ZoneStatus {id} {name}, Status: {status}", i, zone.Name, zone.StatusText());
|
||||
}
|
||||
}
|
||||
|
||||
ushort unitUsage = 0, outputUsage = 0, flagUsage = 0;
|
||||
for (ushort i = 1; i <= omnilink.Controller.Units.Count; i++)
|
||||
{
|
||||
clsUnit unit = omnilink.Controller.Units[i];
|
||||
|
||||
if (unit.DefaultProperties == true)
|
||||
continue;
|
||||
|
||||
if (unit.Type == enuOL2UnitType.Output)
|
||||
outputUsage++;
|
||||
else if (unit.Type == enuOL2UnitType.Flag)
|
||||
flagUsage++;
|
||||
else
|
||||
unitUsage++;
|
||||
|
||||
if (Global.verbose_unit)
|
||||
log.Verbose("Initial UnitStatus {id} {name}, Status: {status}", i, unit.Name, unit.StatusText);
|
||||
}
|
||||
|
||||
ushort thermostatUsage = 0;
|
||||
for (ushort i = 1; i <= omnilink.Controller.Thermostats.Count; i++)
|
||||
{
|
||||
clsThermostat thermostat = omnilink.Controller.Thermostats[i];
|
||||
|
||||
if (thermostat.DefaultProperties == true)
|
||||
continue;
|
||||
|
||||
thermostatUsage++;
|
||||
}
|
||||
|
||||
using (LogContext.PushProperty("Telemetry", "ControllerUsage"))
|
||||
log.Debug("Controller has {AreaUsage} areas, {ZoneUsage} zones, {UnitUsage} units, " +
|
||||
"{OutputUsage} outputs, {FlagUsage} flags, {ThermostatUsage} thermostats",
|
||||
areaUsage, zoneUsage, unitUsage, outputUsage, flagUsage, thermostatUsage);
|
||||
}
|
||||
|
||||
private void Omnilink_OnAreaStatus(object sender, AreaStatusEventArgs e)
|
||||
|
|
|
@ -9,10 +9,13 @@ using MQTTnet.Extensions.ManagedClient;
|
|||
using MQTTnet.Protocol;
|
||||
using Newtonsoft.Json;
|
||||
using OmniLinkBridge.MQTT;
|
||||
using OmniLinkBridge.MQTT.HomeAssistant;
|
||||
using OmniLinkBridge.MQTT.Parser;
|
||||
using OmniLinkBridge.OmniLink;
|
||||
using Serilog;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
@ -108,6 +111,7 @@ namespace OmniLinkBridge.Modules
|
|||
Topic.command,
|
||||
Topic.alarm_command,
|
||||
Topic.brightness_command,
|
||||
Topic.flag_command,
|
||||
Topic.scene_command,
|
||||
Topic.temperature_heat_command,
|
||||
Topic.temperature_cool_command,
|
||||
|
@ -216,8 +220,8 @@ namespace OmniLinkBridge.Modules
|
|||
{
|
||||
clsArea area = OmniLink.Controller.Areas[i];
|
||||
|
||||
// PC Access doesn't let you customize the area name for the Omni LTe or Omni IIe
|
||||
// (configured for 1 area). To workaround ignore default properties for the first area.
|
||||
// PC Access doesn't let you customize the area name when configured for one area.
|
||||
// Ignore default properties for the first area.
|
||||
if (i > 1 && area.DefaultProperties == true)
|
||||
{
|
||||
PublishAsync(area.ToTopic(Topic.name), null);
|
||||
|
@ -308,6 +312,7 @@ namespace OmniLinkBridge.Modules
|
|||
for (ushort i = 1; i <= OmniLink.Controller.Units.Count; i++)
|
||||
{
|
||||
clsUnit unit = OmniLink.Controller.Units[i];
|
||||
UnitType unitType = unit.ToUnitType();
|
||||
|
||||
if (unit.DefaultProperties == true)
|
||||
{
|
||||
|
@ -321,17 +326,26 @@ namespace OmniLinkBridge.Modules
|
|||
|
||||
if (unit.DefaultProperties == true || Global.mqtt_discovery_ignore_units.Contains(unit.Number))
|
||||
{
|
||||
string type = i < 385 ? "light" : "switch";
|
||||
PublishAsync($"{Global.mqtt_discovery_prefix}/{type}/{Global.mqtt_prefix}/unit{i}/config", null);
|
||||
foreach(UnitType entry in Enum.GetValues(typeof(UnitType)))
|
||||
PublishAsync($"{Global.mqtt_discovery_prefix}/{entry}/{Global.mqtt_prefix}/unit{i}/config", null);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (i < 385)
|
||||
PublishAsync($"{Global.mqtt_discovery_prefix}/light/{Global.mqtt_prefix}/unit{i}/config",
|
||||
JsonConvert.SerializeObject(unit.ToConfig()));
|
||||
else
|
||||
PublishAsync($"{Global.mqtt_discovery_prefix}/switch/{Global.mqtt_prefix}/unit{i}/config",
|
||||
foreach (UnitType entry in Enum.GetValues(typeof(UnitType)).Cast<UnitType>().Where(x => x != unitType))
|
||||
PublishAsync($"{Global.mqtt_discovery_prefix}/{entry}/{Global.mqtt_prefix}/unit{i}/config", null);
|
||||
|
||||
log.Verbose("Publishing {type} {id} {name} as {unitType}", "units", i, unit.Name, unitType);
|
||||
|
||||
if (unitType == UnitType.@switch)
|
||||
PublishAsync($"{Global.mqtt_discovery_prefix}/{unitType}/{Global.mqtt_prefix}/unit{i}/config",
|
||||
JsonConvert.SerializeObject(unit.ToConfigSwitch()));
|
||||
else if (unitType == UnitType.light)
|
||||
PublishAsync($"{Global.mqtt_discovery_prefix}/{unitType}/{Global.mqtt_prefix}/unit{i}/config",
|
||||
JsonConvert.SerializeObject(unit.ToConfig()));
|
||||
else if (unitType == UnitType.number)
|
||||
PublishAsync($"{Global.mqtt_discovery_prefix}/{unitType}/{Global.mqtt_prefix}/unit{i}/config",
|
||||
JsonConvert.SerializeObject(unit.ToConfigNumber()));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -537,7 +551,11 @@ namespace OmniLinkBridge.Modules
|
|||
{
|
||||
PublishAsync(unit.ToTopic(Topic.state), unit.ToState());
|
||||
|
||||
if (unit.Number < 385)
|
||||
if (unit.Type == enuOL2UnitType.Flag)
|
||||
{
|
||||
PublishAsync(unit.ToTopic(Topic.flag_state), ((ushort)unit.Status).ToString());
|
||||
}
|
||||
else if(unit.Type != enuOL2UnitType.Output)
|
||||
{
|
||||
PublishAsync(unit.ToTopic(Topic.brightness_state), unit.ToBrightnessState().ToString());
|
||||
PublishAsync(unit.ToTopic(Topic.scene_state), unit.ToSceneState());
|
||||
|
|
|
@ -51,7 +51,7 @@ namespace OmniLinkBridge.Modules
|
|||
|
||||
Controller.Connection.NetworkAddress = address;
|
||||
Controller.Connection.NetworkPort = (ushort)port;
|
||||
Controller.Connection.ControllerKey = clsUtil.HexString2ByteArray(String.Concat(key1, key2));
|
||||
Controller.Connection.ControllerKey = clsUtil.HexString2ByteArray(string.Concat(key1, key2));
|
||||
|
||||
Controller.PreferredNetworkProtocol = clsHAC.enuPreferredNetworkProtocol.TCP;
|
||||
Controller.Connection.ConnectionType = enuOmniLinkConnectionType.Network_TCP;
|
||||
|
@ -316,7 +316,8 @@ namespace OmniLinkBridge.Modules
|
|||
Controller.Zones.CopyProperties(MSG);
|
||||
|
||||
if (Controller.Zones[MSG.ObjectNumber].IsTemperatureZone() || Controller.Zones[MSG.ObjectNumber].IsHumidityZone())
|
||||
Controller.Connection.Send(new clsOL2MsgRequestExtendedStatus(Controller.Connection, enuObjectType.Auxillary, MSG.ObjectNumber, MSG.ObjectNumber), HandleRequestAuxillaryStatus);
|
||||
Controller.Connection.Send(new clsOL2MsgRequestExtendedStatus(Controller.Connection,
|
||||
enuObjectType.Auxillary, MSG.ObjectNumber, MSG.ObjectNumber), HandleRequestAuxillaryStatus);
|
||||
|
||||
break;
|
||||
case enuObjectType.Thermostat:
|
||||
|
@ -327,7 +328,8 @@ namespace OmniLinkBridge.Modules
|
|||
else
|
||||
tstats[MSG.ObjectNumber] = DateTime.MinValue;
|
||||
|
||||
Controller.Connection.Send(new clsOL2MsgRequestExtendedStatus(Controller.Connection, enuObjectType.Thermostat, MSG.ObjectNumber, MSG.ObjectNumber), HandleRequestThermostatStatus);
|
||||
Controller.Connection.Send(new clsOL2MsgRequestExtendedStatus(Controller.Connection,
|
||||
enuObjectType.Thermostat, MSG.ObjectNumber, MSG.ObjectNumber), HandleRequestThermostatStatus);
|
||||
log.Debug("Added thermostat to watch list {thermostatName}",
|
||||
Controller.Thermostats[MSG.ObjectNumber].Name);
|
||||
break;
|
||||
|
@ -714,7 +716,8 @@ namespace OmniLinkBridge.Modules
|
|||
(Controller.Connection.ConnectionState == enuOmniLinkConnectionState.Online ||
|
||||
Controller.Connection.ConnectionState == enuOmniLinkConnectionState.OnlineSecure))
|
||||
{
|
||||
Controller.Connection.Send(new clsOL2MsgRequestExtendedStatus(Controller.Connection, enuObjectType.Thermostat, tstat.Key, tstat.Key), HandleRequestThermostatStatus);
|
||||
Controller.Connection.Send(new clsOL2MsgRequestExtendedStatus(Controller.Connection,
|
||||
enuObjectType.Thermostat, tstat.Key, tstat.Key), HandleRequestThermostatStatus);
|
||||
|
||||
if (Global.verbose_thermostat_timer)
|
||||
log.Debug("Polling status for Thermostat {thermostatName}",
|
||||
|
|
|
@ -74,14 +74,15 @@ namespace OmniLinkBridge.Modules
|
|||
// Extract the 2 digit prefix to use when parsing the time
|
||||
int year = DateTime.Now.Year / 100;
|
||||
|
||||
time = new DateTime((int)MSG.Year + (year * 100), (int)MSG.Month, (int)MSG.Day, (int)MSG.Hour, (int)MSG.Minute, (int)MSG.Second);
|
||||
time = new DateTime(MSG.Year + (year * 100), MSG.Month, MSG.Day, MSG.Hour, MSG.Minute, MSG.Second);
|
||||
}
|
||||
catch
|
||||
{
|
||||
log.Warning("Controller time could not be parsed");
|
||||
|
||||
DateTime now = DateTime.Now;
|
||||
OmniLink.Controller.Connection.Send(new clsOL2MsgSetTime(OmniLink.Controller.Connection, (byte)(now.Year % 100), (byte)now.Month, (byte)now.Day, (byte)now.DayOfWeek,
|
||||
OmniLink.Controller.Connection.Send(new clsOL2MsgSetTime(OmniLink.Controller.Connection,
|
||||
(byte)(now.Year % 100), (byte)now.Month, (byte)now.Day, (byte)now.DayOfWeek,
|
||||
(byte)now.Hour, (byte)now.Minute, (byte)(now.IsDaylightSavingTime() ? 1 : 0)), HandleSetTime);
|
||||
|
||||
return;
|
||||
|
@ -95,7 +96,8 @@ namespace OmniLinkBridge.Modules
|
|||
time.ToString("MM/dd/yyyy HH:mm:ss"), adj);
|
||||
|
||||
DateTime now = DateTime.Now;
|
||||
OmniLink.Controller.Connection.Send(new clsOL2MsgSetTime(OmniLink.Controller.Connection, (byte)(now.Year % 100), (byte)now.Month, (byte)now.Day, (byte)now.DayOfWeek,
|
||||
OmniLink.Controller.Connection.Send(new clsOL2MsgSetTime(OmniLink.Controller.Connection,
|
||||
(byte)(now.Year % 100), (byte)now.Month, (byte)now.Day, (byte)now.DayOfWeek,
|
||||
(byte)now.Hour, (byte)now.Minute, (byte)(now.IsDaylightSavingTime() ? 1 : 0)), HandleSetTime);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -82,28 +82,31 @@
|
|||
<ItemGroup>
|
||||
<Compile Include="CoreServer.cs" />
|
||||
<Compile Include="Modules\TimeSyncModule.cs" />
|
||||
<Compile Include="MQTT\Alarm.cs" />
|
||||
<Compile Include="MQTT\AlarmCommands.cs" />
|
||||
<Compile Include="MQTT\HomeAssistant\Alarm.cs" />
|
||||
<Compile Include="MQTT\OverrideUnit.cs" />
|
||||
<Compile Include="MQTT\Parser\AlarmCommands.cs" />
|
||||
<Compile Include="MQTT\AreaCommandCode.cs" />
|
||||
<Compile Include="MQTT\AreaCommands.cs" />
|
||||
<Compile Include="MQTT\Parser\AreaCommands.cs" />
|
||||
<Compile Include="MQTT\AreaState.cs" />
|
||||
<Compile Include="MQTT\Availability.cs" />
|
||||
<Compile Include="MQTT\BinarySensor.cs" />
|
||||
<Compile Include="MQTT\CommandTypes.cs" />
|
||||
<Compile Include="MQTT\Device.cs" />
|
||||
<Compile Include="MQTT\Climate.cs" />
|
||||
<Compile Include="MQTT\DeviceRegistry.cs" />
|
||||
<Compile Include="MQTT\MessageCommands.cs" />
|
||||
<Compile Include="MQTT\HomeAssistant\BinarySensor.cs" />
|
||||
<Compile Include="MQTT\Parser\CommandTypes.cs" />
|
||||
<Compile Include="MQTT\HomeAssistant\Device.cs" />
|
||||
<Compile Include="MQTT\HomeAssistant\Climate.cs" />
|
||||
<Compile Include="MQTT\HomeAssistant\DeviceRegistry.cs" />
|
||||
<Compile Include="MQTT\Extensions.cs" />
|
||||
<Compile Include="MQTT\Parser\MessageCommands.cs" />
|
||||
<Compile Include="MQTT\MessageProcessor.cs" />
|
||||
<Compile Include="MQTT\Number.cs" />
|
||||
<Compile Include="MQTT\HomeAssistant\Number.cs" />
|
||||
<Compile Include="MQTT\OverrideZone.cs" />
|
||||
<Compile Include="MQTT\Switch.cs" />
|
||||
<Compile Include="MQTT\Light.cs" />
|
||||
<Compile Include="MQTT\HomeAssistant\Switch.cs" />
|
||||
<Compile Include="MQTT\HomeAssistant\Light.cs" />
|
||||
<Compile Include="MQTT\MappingExtensions.cs" />
|
||||
<Compile Include="MQTT\Sensor.cs" />
|
||||
<Compile Include="MQTT\Topic.cs" />
|
||||
<Compile Include="MQTT\UnitCommands.cs" />
|
||||
<Compile Include="MQTT\ZoneCommands.cs" />
|
||||
<Compile Include="MQTT\HomeAssistant\Sensor.cs" />
|
||||
<Compile Include="MQTT\Parser\Topic.cs" />
|
||||
<Compile Include="MQTT\Parser\UnitCommands.cs" />
|
||||
<Compile Include="MQTT\Parser\ZoneCommands.cs" />
|
||||
<Compile Include="MQTT\UnitType.cs" />
|
||||
<Compile Include="Notifications\EmailNotification.cs" />
|
||||
<Compile Include="Notifications\INotification.cs" />
|
||||
<Compile Include="Notifications\Notification.cs" />
|
||||
|
|
|
@ -4,4 +4,7 @@
|
|||
<StartArguments>
|
||||
</StartArguments>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<ProjectView>ProjectFiles</ProjectView>
|
||||
</PropertyGroup>
|
||||
</Project>
|
|
@ -49,13 +49,24 @@ mqtt_prefix = omnilink
|
|||
mqtt_discovery_prefix = homeassistant
|
||||
# Prefix for Home Assistant entity names
|
||||
mqtt_discovery_name_prefix =
|
||||
# Specify a range of numbers like 1,2,3,5-10
|
||||
# Skip publishing Home Assistant discovery topics for zones/units
|
||||
# Specify a range of numbers 1,2,3,5-10
|
||||
mqtt_discovery_ignore_zones =
|
||||
mqtt_discovery_ignore_units =
|
||||
# Require Home Assistant to prompt for user code when arming/disarming area
|
||||
# Specify a range of numbers 1,2,3,5-10
|
||||
mqtt_discovery_area_code_required =
|
||||
# device_class must be battery, door, garage_door, gas, moisture, motion, problem, smoke, or window
|
||||
# Override the zone Home Assistant binary sensor device_class
|
||||
# device_class: must be battery, cold, door, garage_door, gas,
|
||||
# heat, moisture, motion, problem, safety, smoke, or window
|
||||
#mqtt_discovery_override_zone = id=5;device_class=garage_door
|
||||
#mqtt_discovery_override_zone = id=6;device_class=garage_door
|
||||
# Override the unit Home Assistant device type
|
||||
# type:
|
||||
# Units (LTe 1-32, IIe 1-64, Pro 1-256) light or switch, defaults to light
|
||||
# Flags (LTe 41-88, IIe 73-128, Pro 393-511) switch or number, defaults to switch
|
||||
#mqtt_discovery_override_unit = id=1;type=switch
|
||||
#mqtt_discovery_override_unit = id=395;type=number
|
||||
|
||||
# Notifications (yes/no)
|
||||
# Always sent for area alarms and critical system events
|
||||
|
|
|
@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
|
|||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.1.13.0")]
|
||||
[assembly: AssemblyFileVersion("1.1.13.0")]
|
||||
[assembly: AssemblyVersion("1.1.14.0")]
|
||||
[assembly: AssemblyFileVersion("1.1.14.0")]
|
||||
|
|
|
@ -7,7 +7,7 @@ using System.IO;
|
|||
using System.Linq;
|
||||
using System.Net.Mail;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
using ha = OmniLinkBridge.MQTT.HomeAssistant;
|
||||
|
||||
namespace OmniLinkBridge
|
||||
{
|
||||
|
@ -86,6 +86,7 @@ namespace OmniLinkBridge
|
|||
Global.mqtt_discovery_ignore_units = settings.ValidateRange("mqtt_discovery_ignore_units");
|
||||
Global.mqtt_discovery_area_code_required = settings.ValidateRange("mqtt_discovery_area_code_required");
|
||||
Global.mqtt_discovery_override_zone = settings.LoadOverrideZone<MQTT.OverrideZone>("mqtt_discovery_override_zone");
|
||||
Global.mqtt_discovery_override_unit = settings.LoadOverrideUnit<MQTT.OverrideUnit>("mqtt_discovery_override_unit");
|
||||
}
|
||||
|
||||
// Notifications
|
||||
|
@ -157,7 +158,7 @@ namespace OmniLinkBridge
|
|||
}
|
||||
else if (override_zone is MQTT.OverrideZone mqtt_zone)
|
||||
{
|
||||
if (!attributes.ContainsKey("device_class") || !Enum.TryParse(attributes["device_class"], out MQTT.BinarySensor.DeviceClass attrib_device_class))
|
||||
if (!attributes.ContainsKey("device_class") || !Enum.TryParse(attributes["device_class"], out ha.BinarySensor.DeviceClass attrib_device_class))
|
||||
throw new Exception("Missing or invalid device_class attribute");
|
||||
|
||||
mqtt_zone.device_class = attrib_device_class;
|
||||
|
@ -175,6 +176,50 @@ namespace OmniLinkBridge
|
|||
}
|
||||
}
|
||||
|
||||
private static ConcurrentDictionary<int, T> LoadOverrideUnit<T>(this NameValueCollection settings, string section) where T : new()
|
||||
{
|
||||
try
|
||||
{
|
||||
ConcurrentDictionary<int, T> ret = new ConcurrentDictionary<int, T>();
|
||||
|
||||
string value = settings.CheckEnv(section);
|
||||
|
||||
if (string.IsNullOrEmpty(value))
|
||||
return ret;
|
||||
|
||||
string[] ids = value.Split(',');
|
||||
|
||||
for (int i = 0; i < ids.Length; i++)
|
||||
{
|
||||
Dictionary<string, string> attributes = ids[i].TrimEnd(new char[] { ';' }).Split(';')
|
||||
.Select(s => s.Split('='))
|
||||
.ToDictionary(a => a[0].Trim(), a => a[1].Trim(), StringComparer.InvariantCultureIgnoreCase);
|
||||
|
||||
if (!attributes.ContainsKey("id") || !int.TryParse(attributes["id"], out int attrib_id))
|
||||
throw new Exception("Missing or invalid id attribute");
|
||||
|
||||
T override_unit = new T();
|
||||
|
||||
if (override_unit is MQTT.OverrideUnit mqtt_unit)
|
||||
{
|
||||
if (!attributes.ContainsKey("type") || !Enum.TryParse(attributes["type"], out MQTT.UnitType attrib_type))
|
||||
throw new Exception("Missing or invalid type attribute");
|
||||
|
||||
mqtt_unit.type = attrib_type;
|
||||
}
|
||||
|
||||
ret.TryAdd(attrib_id, override_unit);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
log.Error(ex, "Invalid override unit specified for {section}", section);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
private static string ValidateHasValue(this NameValueCollection settings, string section)
|
||||
{
|
||||
string value = settings.CheckEnv(section);
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
using System;
|
||||
using System.Text;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using OmniLinkBridge;
|
||||
using OmniLinkBridge.MQTT;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace OmniLinkBridgeTest
|
||||
{
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
using System;
|
||||
using System.Text;
|
||||
using System.Collections.Generic;
|
||||
using HAI_Shared;
|
||||
using HAI_Shared;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using OmniLinkBridge;
|
||||
using OmniLinkBridge.MQTT;
|
||||
using OmniLinkBridgeTest.Mock;
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
namespace OmniLinkBridgeTest
|
||||
{
|
||||
|
@ -19,6 +18,8 @@ namespace OmniLinkBridgeTest
|
|||
{
|
||||
omniLink = new MockOmniLinkII();
|
||||
messageProcessor = new MessageProcessor(omniLink);
|
||||
|
||||
omniLink.Controller.Units[395].Type = enuOL2UnitType.Flag;
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
|
@ -134,6 +135,28 @@ namespace OmniLinkBridgeTest
|
|||
check(2, "on", enuUnitCommand.On);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void UnitFlagCommand()
|
||||
{
|
||||
void check(ushort id, string payload, enuUnitCommand command, int value)
|
||||
{
|
||||
SendCommandEventArgs actual = null;
|
||||
omniLink.OnSendCommand += (sender, e) => { actual = e; };
|
||||
messageProcessor.Process($"omnilink/unit{id}/flag_command", payload);
|
||||
SendCommandEventArgs expected = new SendCommandEventArgs()
|
||||
{
|
||||
Cmd = command,
|
||||
Par = (byte)value,
|
||||
Pr2 = id
|
||||
};
|
||||
Assert.AreEqual(expected, actual);
|
||||
}
|
||||
|
||||
check(395, "0", enuUnitCommand.Set, 0);
|
||||
check(395, "1", enuUnitCommand.Set, 1);
|
||||
check(395, "255", enuUnitCommand.Set, 255);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void UnitLevelCommand()
|
||||
{
|
||||
|
|
|
@ -1,10 +1,6 @@
|
|||
using HAI_Shared;
|
||||
using OmniLinkBridge.OmniLink;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace OmniLinkBridgeTest.Mock
|
||||
{
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
using HAI_Shared;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace OmniLinkBridgeTest.Mock
|
||||
{
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
using System;
|
||||
using System.Text;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using OmniLinkBridge.Notifications;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using OmniLinkBridge;
|
||||
using OmniLinkBridge.Notifications;
|
||||
using System.Net.Mail;
|
||||
|
||||
namespace OmniLinkBridgeTest
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
using System;
|
||||
using System.Text;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Concurrent;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using OmniLinkBridge;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using ha = OmniLinkBridge.MQTT.HomeAssistant;
|
||||
|
||||
namespace OmniLinkBridgeTest
|
||||
{
|
||||
|
@ -156,8 +155,11 @@ namespace OmniLinkBridgeTest
|
|||
"mqtt_discovery_name_prefix = mynameprefix",
|
||||
"mqtt_discovery_ignore_zones = 1,2-3,4",
|
||||
"mqtt_discovery_ignore_units = 2-5,7",
|
||||
"mqtt_discovery_area_code_required = 1",
|
||||
"mqtt_discovery_override_zone = id=5;device_class=garage_door",
|
||||
"mqtt_discovery_override_zone = id=7;device_class=motion",
|
||||
"mqtt_discovery_override_unit = id=1;type=switch",
|
||||
"mqtt_discovery_override_unit = id=395;type=light",
|
||||
});
|
||||
Settings.LoadSettings(lines.ToArray());
|
||||
Assert.AreEqual("myuser", Global.mqtt_username);
|
||||
|
@ -167,11 +169,12 @@ namespace OmniLinkBridgeTest
|
|||
Assert.AreEqual("mynameprefix ", Global.mqtt_discovery_name_prefix);
|
||||
Assert.IsTrue(Global.mqtt_discovery_ignore_zones.SetEquals(new int[] { 1, 2, 3, 4 }));
|
||||
Assert.IsTrue(Global.mqtt_discovery_ignore_units.SetEquals(new int[] { 2, 3, 4, 5, 7 }));
|
||||
Assert.IsTrue(Global.mqtt_discovery_area_code_required.SetEquals(new int[] { 1 }));
|
||||
|
||||
Dictionary<int, OmniLinkBridge.MQTT.OverrideZone> override_zone = new Dictionary<int, OmniLinkBridge.MQTT.OverrideZone>()
|
||||
{
|
||||
{ 5, new OmniLinkBridge.MQTT.OverrideZone { device_class = OmniLinkBridge.MQTT.BinarySensor.DeviceClass.garage_door }},
|
||||
{ 7, new OmniLinkBridge.MQTT.OverrideZone { device_class = OmniLinkBridge.MQTT.BinarySensor.DeviceClass.motion }}
|
||||
{ 5, new OmniLinkBridge.MQTT.OverrideZone { device_class = ha.BinarySensor.DeviceClass.garage_door }},
|
||||
{ 7, new OmniLinkBridge.MQTT.OverrideZone { device_class = ha.BinarySensor.DeviceClass.motion }}
|
||||
};
|
||||
|
||||
Assert.AreEqual(override_zone.Count, Global.mqtt_discovery_override_zone.Count);
|
||||
|
@ -180,6 +183,19 @@ namespace OmniLinkBridgeTest
|
|||
Global.mqtt_discovery_override_zone.TryGetValue(pair.Key, out OmniLinkBridge.MQTT.OverrideZone value);
|
||||
Assert.AreEqual(override_zone[pair.Key].device_class, value.device_class);
|
||||
}
|
||||
|
||||
Dictionary<int, OmniLinkBridge.MQTT.OverrideUnit> override_unit = new Dictionary<int, OmniLinkBridge.MQTT.OverrideUnit>()
|
||||
{
|
||||
{ 1, new OmniLinkBridge.MQTT.OverrideUnit { type = OmniLinkBridge.MQTT.UnitType.@switch }},
|
||||
{ 395, new OmniLinkBridge.MQTT.OverrideUnit { type = OmniLinkBridge.MQTT.UnitType.light }}
|
||||
};
|
||||
|
||||
Assert.AreEqual(override_unit.Count, Global.mqtt_discovery_override_unit.Count);
|
||||
foreach (KeyValuePair<int, OmniLinkBridge.MQTT.OverrideUnit> pair in override_unit)
|
||||
{
|
||||
Global.mqtt_discovery_override_unit.TryGetValue(pair.Key, out OmniLinkBridge.MQTT.OverrideUnit value);
|
||||
Assert.AreEqual(override_unit[pair.Key].type, value.type);
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
|
|
|
@ -9,7 +9,7 @@ You can use docker to build an image from git or download the [binary here](http
|
|||
- .NET Framework 4.7.2 (or Mono equivalent)
|
||||
|
||||
## Operation
|
||||
OmniLink Bridge is divided into the following modules and configurable settings. Configuration settings can also be set as environment variables by using their name in uppercase. Refer to [OmniLinkBridge.ini](https://github.com/excaliburpartners/OmniLinkBridge/blob/master/OmniLinkBridge/OmniLinkBridge.ini) for specifics.
|
||||
OmniLink Bridge is divided into the following modules and configurable settings. Configuration settings can also be set as environment variables by using their name in uppercase. Refer to [OmniLinkBridge.ini](OmniLinkBridge/OmniLinkBridge.ini) for specifics.
|
||||
|
||||
- OmniLinkII: controller_
|
||||
- Maintains connection to the OmniLink controller
|
||||
|
@ -232,6 +232,10 @@ SUB omnilink/unitX/brightness_state
|
|||
PUB omnilink/unitX/brightness_command
|
||||
int Level from 0 to 100 percent
|
||||
|
||||
SUB omnilink/unitX/flag_state
|
||||
PUB omnilink/unitX/flag_command
|
||||
int Level from 0 to 255
|
||||
|
||||
SUB omnilink/unitX/scene_state
|
||||
PUB omnilink/unitX/scene_command
|
||||
string A-L
|
||||
|
|
Loading…
Reference in a new issue