diff --git a/OmniLinkBridge/MQTT/AreaState.cs b/OmniLinkBridge/MQTT/AreaState.cs new file mode 100644 index 0000000..7e90746 --- /dev/null +++ b/OmniLinkBridge/MQTT/AreaState.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace OmniLinkBridge.MQTT +{ + public class AreaState + { + public string mode { get; set; } + public bool arming { get; set; } + public bool burglary_alarm { get; set; } + public bool fire_alarm { get; set; } + public bool gas_alarm { get; set; } + public bool auxiliary_alarm { get; set; } + public bool freeze_alarm { get; set; } + public bool water_alarm { get; set; } + public bool duress_alarm { get; set; } + public bool temperature_alarm { get; set; } + } +} diff --git a/OmniLinkBridge/MQTT/BinarySensor.cs b/OmniLinkBridge/MQTT/BinarySensor.cs index 4e82da8..7565b02 100644 --- a/OmniLinkBridge/MQTT/BinarySensor.cs +++ b/OmniLinkBridge/MQTT/BinarySensor.cs @@ -14,17 +14,23 @@ namespace OmniLinkBridge.MQTT public enum DeviceClass { battery, + cold, door, garage_door, gas, + heat, moisture, motion, problem, + safety, smoke, window } [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public DeviceClass? device_class { get; set; } + + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + public string value_template { get; set; } } } diff --git a/OmniLinkBridge/MQTT/MappingExtensions.cs b/OmniLinkBridge/MQTT/MappingExtensions.cs index 4517730..6436981 100644 --- a/OmniLinkBridge/MQTT/MappingExtensions.cs +++ b/OmniLinkBridge/MQTT/MappingExtensions.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; using HAI_Shared; +using Newtonsoft.Json; namespace OmniLinkBridge.MQTT { @@ -25,7 +26,9 @@ namespace OmniLinkBridge.MQTT public static string ToState(this clsArea area) { - if (area.AreaBurglaryAlarmText != "OK") + if (area.AreaAlarms.IsBitSet(0) || // Burgulary + area.AreaAlarms.IsBitSet(3) || // Auxiliary + area.AreaAlarms.IsBitSet(6)) // Duress return "triggered"; else if (area.ExitTimer > 0) return "pending"; @@ -52,7 +55,9 @@ namespace OmniLinkBridge.MQTT public static string ToBasicState(this clsArea area) { - if (area.AreaBurglaryAlarmText != "OK") + if (area.AreaAlarms.IsBitSet(0) || // Burgulary + area.AreaAlarms.IsBitSet(3) || // Auxiliary + area.AreaAlarms.IsBitSet(6)) // Duress return "triggered"; else if (area.ExitTimer > 0) return "pending"; @@ -74,6 +79,130 @@ namespace OmniLinkBridge.MQTT } } + public static BinarySensor ToConfigBurglary(this clsArea area) + { + BinarySensor ret = new BinarySensor(); + ret.name = $"{Global.mqtt_discovery_name_prefix}{area.Name} Burglary"; + ret.device_class = BinarySensor.DeviceClass.safety; + ret.state_topic = area.ToTopic(Topic.json_state); + ret.value_template = "{% if value_json.burglary_alarm %} ON {%- else -%} OFF {%- endif %}"; + return ret; + } + + public static BinarySensor ToConfigFire(this clsArea area) + { + BinarySensor ret = new BinarySensor(); + ret.name = $"{Global.mqtt_discovery_name_prefix}{area.Name} Fire"; + ret.device_class = BinarySensor.DeviceClass.smoke; + ret.state_topic = area.ToTopic(Topic.json_state); + ret.value_template = "{% if value_json.fire_alarm %} ON {%- else -%} OFF {%- endif %}"; + return ret; + } + + public static BinarySensor ToConfigGas(this clsArea area) + { + BinarySensor ret = new BinarySensor(); + ret.name = $"{Global.mqtt_discovery_name_prefix}{area.Name} Gas"; + ret.device_class = BinarySensor.DeviceClass.gas; + ret.state_topic = area.ToTopic(Topic.json_state); + ret.value_template = "{% if value_json.gas_alarm %} ON {%- else -%} OFF {%- endif %}"; + return ret; + } + + public static BinarySensor ToConfigAux(this clsArea area) + { + BinarySensor ret = new BinarySensor(); + ret.name = $"{Global.mqtt_discovery_name_prefix}{area.Name} Auxiliary"; + ret.device_class = BinarySensor.DeviceClass.problem; + ret.state_topic = area.ToTopic(Topic.json_state); + ret.value_template = "{% if value_json.burglary_alarm %} ON {%- else -%} OFF {%- endif %}"; + return ret; + } + + public static BinarySensor ToConfigFreeze(this clsArea area) + { + BinarySensor ret = new BinarySensor(); + ret.name = $"{Global.mqtt_discovery_name_prefix}{area.Name} Freeze"; + ret.device_class = BinarySensor.DeviceClass.cold; + ret.state_topic = area.ToTopic(Topic.json_state); + ret.value_template = "{% if value_json.freeze_alarm %} ON {%- else -%} OFF {%- endif %}"; + return ret; + } + + public static BinarySensor ToConfigWater(this clsArea area) + { + BinarySensor ret = new BinarySensor(); + ret.name = $"{Global.mqtt_discovery_name_prefix}{area.Name} Water"; + ret.device_class = BinarySensor.DeviceClass.moisture; + ret.state_topic = area.ToTopic(Topic.json_state); + ret.value_template = "{% if value_json.water_alarm %} ON {%- else -%} OFF {%- endif %}"; + return ret; + } + + public static BinarySensor ToConfigDuress(this clsArea area) + { + BinarySensor ret = new BinarySensor(); + ret.name = $"{Global.mqtt_discovery_name_prefix}{area.Name} Duress"; + ret.device_class = BinarySensor.DeviceClass.safety; + ret.state_topic = area.ToTopic(Topic.json_state); + ret.value_template = "{% if value_json.duress_alarm %} ON {%- else -%} OFF {%- endif %}"; + return ret; + } + + public static BinarySensor ToConfigTemp(this clsArea area) + { + BinarySensor ret = new BinarySensor(); + ret.name = $"{Global.mqtt_discovery_name_prefix}{area.Name} Temp"; + ret.device_class = BinarySensor.DeviceClass.heat; + ret.state_topic = area.ToTopic(Topic.json_state); + ret.value_template = "{% if value_json.temperature_alarm %} ON {%- else -%} OFF {%- endif %}"; + return ret; + } + + public static string ToJsonState(this clsArea area) + { + AreaState state = new AreaState() + { + arming = area.ExitTimer > 0, + burglary_alarm = area.AreaAlarms.IsBitSet(0), + fire_alarm = area.AreaAlarms.IsBitSet(1), + gas_alarm = area.AreaAlarms.IsBitSet(2), + auxiliary_alarm = area.AreaAlarms.IsBitSet(3), + freeze_alarm = area.AreaAlarms.IsBitSet(4), + water_alarm = area.AreaAlarms.IsBitSet(5), + duress_alarm = area.AreaAlarms.IsBitSet(6), + temperature_alarm = area.AreaAlarms.IsBitSet(7) + }; + + switch (area.AreaMode) + { + case enuSecurityMode.Night: + state.mode = "night"; + break; + case enuSecurityMode.NightDly: + state.mode = "night_delay"; + break; + case enuSecurityMode.Day: + state.mode = "home"; + break; + case enuSecurityMode.DayInst: + state.mode = "home_instant"; + break; + case enuSecurityMode.Away: + state.mode = "away"; + break; + case enuSecurityMode.Vacation: + state.mode = "vacation"; + break; + case enuSecurityMode.Off: + default: + state.mode = "off"; + break; + } + + return JsonConvert.SerializeObject(state); + } + public static string ToTopic(this clsZone zone, Topic topic) { return $"{Global.mqtt_prefix}/zone{zone.Number.ToString()}/{topic.ToString()}"; @@ -250,10 +379,20 @@ namespace OmniLinkBridge.MQTT return $"{Global.mqtt_prefix}/thermostat{thermostat.Number.ToString()}/{topic.ToString()}"; } + public static Sensor ToConfigTemp(this clsThermostat zone) + { + Sensor ret = new Sensor(); + ret.name = $"{Global.mqtt_discovery_name_prefix}{zone.Name} Temp"; + ret.device_class = Sensor.DeviceClass.temperature; + ret.state_topic = zone.ToTopic(Topic.current_temperature); + ret.unit_of_measurement = "°F"; + return ret; + } + public static Sensor ToConfigHumidity(this clsThermostat zone) { Sensor ret = new Sensor(); - ret.name = Global.mqtt_discovery_name_prefix + zone.Name; + ret.name = $"{Global.mqtt_discovery_name_prefix}{zone.Name} Humidity"; ret.device_class = Sensor.DeviceClass.humidity; ret.state_topic = zone.ToTopic(Topic.current_humidity); ret.unit_of_measurement = "%"; diff --git a/OmniLinkBridge/MQTT/Topics.cs b/OmniLinkBridge/MQTT/Topics.cs index 3af3003..cd1858e 100644 --- a/OmniLinkBridge/MQTT/Topics.cs +++ b/OmniLinkBridge/MQTT/Topics.cs @@ -26,6 +26,7 @@ namespace OmniLinkBridge.MQTT public static Topic command { get { return new Topic("command"); } } public static Topic basic_state { get { return new Topic("basic_state"); } } + public static Topic json_state { get { return new Topic("json_state"); } } public static Topic brightness_state { get { return new Topic("brightness_state"); } } public static Topic brightness_command { get { return new Topic("brightness_command"); } } diff --git a/OmniLinkBridge/Modules/MQTTModule.cs b/OmniLinkBridge/Modules/MQTTModule.cs index 810bb9f..44028ca 100644 --- a/OmniLinkBridge/Modules/MQTTModule.cs +++ b/OmniLinkBridge/Modules/MQTTModule.cs @@ -290,6 +290,14 @@ namespace OmniLinkBridge.Modules if (area.DefaultProperties == true) { MqttClient.PublishAsync($"{Global.mqtt_discovery_prefix}/alarm_control_panel/{Global.mqtt_prefix}/area{i.ToString()}/config", null, MqttQualityOfServiceLevel.AtMostOnce, true); + MqttClient.PublishAsync($"{Global.mqtt_discovery_prefix}/binary_sensor/{Global.mqtt_prefix}/area{i.ToString()}burglary/config", null, MqttQualityOfServiceLevel.AtMostOnce, true); + MqttClient.PublishAsync($"{Global.mqtt_discovery_prefix}/binary_sensor/{Global.mqtt_prefix}/area{i.ToString()}fire/config", null, MqttQualityOfServiceLevel.AtMostOnce, true); + MqttClient.PublishAsync($"{Global.mqtt_discovery_prefix}/binary_sensor/{Global.mqtt_prefix}/area{i.ToString()}gas/config", null, MqttQualityOfServiceLevel.AtMostOnce, true); + MqttClient.PublishAsync($"{Global.mqtt_discovery_prefix}/binary_sensor/{Global.mqtt_prefix}/area{i.ToString()}aux/config", null, MqttQualityOfServiceLevel.AtMostOnce, true); + MqttClient.PublishAsync($"{Global.mqtt_discovery_prefix}/binary_sensor/{Global.mqtt_prefix}/area{i.ToString()}freeze/config", null, MqttQualityOfServiceLevel.AtMostOnce, true); + MqttClient.PublishAsync($"{Global.mqtt_discovery_prefix}/binary_sensor/{Global.mqtt_prefix}/area{i.ToString()}water/config", null, MqttQualityOfServiceLevel.AtMostOnce, true); + MqttClient.PublishAsync($"{Global.mqtt_discovery_prefix}/binary_sensor/{Global.mqtt_prefix}/area{i.ToString()}duress/config", null, MqttQualityOfServiceLevel.AtMostOnce, true); + MqttClient.PublishAsync($"{Global.mqtt_discovery_prefix}/binary_sensor/{Global.mqtt_prefix}/area{i.ToString()}temp/config", null, MqttQualityOfServiceLevel.AtMostOnce, true); continue; } @@ -297,6 +305,22 @@ namespace OmniLinkBridge.Modules MqttClient.PublishAsync($"{Global.mqtt_discovery_prefix}/alarm_control_panel/{Global.mqtt_prefix}/area{i.ToString()}/config", JsonConvert.SerializeObject(area.ToConfig()), MqttQualityOfServiceLevel.AtMostOnce, true); + MqttClient.PublishAsync($"{Global.mqtt_discovery_prefix}/binary_sensor/{Global.mqtt_prefix}/area{i.ToString()}burglary/config", + JsonConvert.SerializeObject(area.ToConfigBurglary()), MqttQualityOfServiceLevel.AtMostOnce, true); + MqttClient.PublishAsync($"{Global.mqtt_discovery_prefix}/binary_sensor/{Global.mqtt_prefix}/area{i.ToString()}fire/config", + JsonConvert.SerializeObject(area.ToConfigFire()), MqttQualityOfServiceLevel.AtMostOnce, true); + MqttClient.PublishAsync($"{Global.mqtt_discovery_prefix}/binary_sensor/{Global.mqtt_prefix}/area{i.ToString()}gas/config", + JsonConvert.SerializeObject(area.ToConfigGas()), MqttQualityOfServiceLevel.AtMostOnce, true); + MqttClient.PublishAsync($"{Global.mqtt_discovery_prefix}/binary_sensor/{Global.mqtt_prefix}/area{i.ToString()}aux/config", + JsonConvert.SerializeObject(area.ToConfigAux()), MqttQualityOfServiceLevel.AtMostOnce, true); + MqttClient.PublishAsync($"{Global.mqtt_discovery_prefix}/binary_sensor/{Global.mqtt_prefix}/area{i.ToString()}freeze/config", + JsonConvert.SerializeObject(area.ToConfigFreeze()), MqttQualityOfServiceLevel.AtMostOnce, true); + MqttClient.PublishAsync($"{Global.mqtt_discovery_prefix}/binary_sensor/{Global.mqtt_prefix}/area{i.ToString()}water/config", + JsonConvert.SerializeObject(area.ToConfigWater()), MqttQualityOfServiceLevel.AtMostOnce, true); + MqttClient.PublishAsync($"{Global.mqtt_discovery_prefix}/binary_sensor/{Global.mqtt_prefix}/area{i.ToString()}duress/config", + JsonConvert.SerializeObject(area.ToConfigDuress()), MqttQualityOfServiceLevel.AtMostOnce, true); + MqttClient.PublishAsync($"{Global.mqtt_discovery_prefix}/binary_sensor/{Global.mqtt_prefix}/area{i.ToString()}temp/config", + JsonConvert.SerializeObject(area.ToConfigTemp()), MqttQualityOfServiceLevel.AtMostOnce, true); } } @@ -367,6 +391,7 @@ namespace OmniLinkBridge.Modules if (thermostat.DefaultProperties == true) { MqttClient.PublishAsync($"{Global.mqtt_discovery_prefix}/climate/{Global.mqtt_prefix}/thermostat{i.ToString()}/config", null, MqttQualityOfServiceLevel.AtMostOnce, true); + MqttClient.PublishAsync($"{Global.mqtt_discovery_prefix}/sensor/{Global.mqtt_prefix}/thermostat{i.ToString()}temp/config", null, MqttQualityOfServiceLevel.AtMostOnce, true); MqttClient.PublishAsync($"{Global.mqtt_discovery_prefix}/sensor/{Global.mqtt_prefix}/thermostat{i.ToString()}humidity/config", null, MqttQualityOfServiceLevel.AtMostOnce, true); continue; } @@ -375,6 +400,8 @@ namespace OmniLinkBridge.Modules MqttClient.PublishAsync($"{Global.mqtt_discovery_prefix}/climate/{Global.mqtt_prefix}/thermostat{i.ToString()}/config", JsonConvert.SerializeObject(thermostat.ToConfig()), MqttQualityOfServiceLevel.AtMostOnce, true); + MqttClient.PublishAsync($"{Global.mqtt_discovery_prefix}/sensor/{Global.mqtt_prefix}/thermostat{i.ToString()}temp/config", + JsonConvert.SerializeObject(thermostat.ToConfigTemp()), MqttQualityOfServiceLevel.AtMostOnce, true); MqttClient.PublishAsync($"{Global.mqtt_discovery_prefix}/sensor/{Global.mqtt_prefix}/thermostat{i.ToString()}humidity/config", JsonConvert.SerializeObject(thermostat.ToConfigHumidity()), MqttQualityOfServiceLevel.AtMostOnce, true); } @@ -452,6 +479,7 @@ namespace OmniLinkBridge.Modules { MqttClient.PublishAsync(area.ToTopic(Topic.state), area.ToState(), MqttQualityOfServiceLevel.AtMostOnce, true); MqttClient.PublishAsync(area.ToTopic(Topic.basic_state), area.ToBasicState(), MqttQualityOfServiceLevel.AtMostOnce, true); + MqttClient.PublishAsync(area.ToTopic(Topic.json_state), area.ToJsonState(), MqttQualityOfServiceLevel.AtMostOnce, true); } private void PublishZoneState(clsZone zone) diff --git a/OmniLinkBridge/OmniLinkBridge.csproj b/OmniLinkBridge/OmniLinkBridge.csproj index 43b7675..e6e61f7 100644 --- a/OmniLinkBridge/OmniLinkBridge.csproj +++ b/OmniLinkBridge/OmniLinkBridge.csproj @@ -77,6 +77,7 @@ +