Skip to content

Commit

Permalink
- Update MQTT, add console messages and button presses
Browse files Browse the repository at this point in the history
  • Loading branch information
rwagoner committed Dec 24, 2019
1 parent c3aa886 commit 314ea42
Show file tree
Hide file tree
Showing 13 changed files with 230 additions and 30 deletions.
3 changes: 2 additions & 1 deletion OmniLinkBridge/MQTT/CommandTypes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ enum CommandTypes
zone,
unit,
thermostat,
button
button,
message
}
}
17 changes: 16 additions & 1 deletion OmniLinkBridge/MQTT/MappingExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ public static BinarySensor ToConfigWater(this clsArea area)
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();
Expand Down Expand Up @@ -468,5 +468,20 @@ public static Switch ToConfig(this clsButton button)
ret.command_topic = button.ToTopic(Topic.command);
return ret;
}

public static string ToTopic(this clsMessage message, Topic topic)
{
return $"{Global.mqtt_prefix}/message{message.Number.ToString()}/{topic.ToString()}";
}

public static string ToState(this clsMessage message)
{
if (message.Status == enuMessageStatus.Displayed)
return "displayed";
else if (message.Status == enuMessageStatus.NotAcked)
return "displayed_not_acknowledged";
else
return "off";
}
}
}
10 changes: 10 additions & 0 deletions OmniLinkBridge/MQTT/MessageCommands.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
namespace OmniLinkBridge.MQTT
{
enum MessageCommands
{
show,
show_no_beep,
show_no_beep_or_led,
clear
}
}
34 changes: 30 additions & 4 deletions OmniLinkBridge/MQTT/MessageProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace OmniLinkBridge.MQTT
{
public class MessageProcessor
{
private static ILog log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private static readonly ILog log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);

private readonly Regex regexTopic = new Regex(Global.mqtt_prefix + "/([A-Za-z]+)([0-9]+)/(.*)", RegexOptions.Compiled);

Expand Down Expand Up @@ -45,9 +45,11 @@ public void Process(string messageTopic, string payload)
ProcessThermostatReceived(OmniLink.Controller.Thermostats[id], topic, payload);
else if (type == CommandTypes.button && id > 0 && id <= OmniLink.Controller.Buttons.Count)
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);
}

private IDictionary<AreaCommands, enuUnitCommand> AreaMapping = new Dictionary<AreaCommands, enuUnitCommand>
private static readonly IDictionary<AreaCommands, enuUnitCommand> AreaMapping = new Dictionary<AreaCommands, enuUnitCommand>
{
{ AreaCommands.disarm, enuUnitCommand.SecurityOff },
{ AreaCommands.arm_home, enuUnitCommand.SecurityDay },
Expand All @@ -71,7 +73,7 @@ private void ProcessAreaReceived(clsArea area, Topic command, string payload)
}
}

private IDictionary<ZoneCommands, enuUnitCommand> ZoneMapping = new Dictionary<ZoneCommands, enuUnitCommand>
private static readonly IDictionary<ZoneCommands, enuUnitCommand> ZoneMapping = new Dictionary<ZoneCommands, enuUnitCommand>
{
{ ZoneCommands.restore, enuUnitCommand.Restore },
{ ZoneCommands.bypass, enuUnitCommand.Bypass },
Expand All @@ -86,7 +88,7 @@ private void ProcessZoneReceived(clsZone zone, Topic command, string payload)
}
}

private IDictionary<UnitCommands, enuUnitCommand> UnitMapping = new Dictionary<UnitCommands, enuUnitCommand>
private static readonly IDictionary<UnitCommands, enuUnitCommand> UnitMapping = new Dictionary<UnitCommands, enuUnitCommand>
{
{ UnitCommands.OFF, enuUnitCommand.Off },
{ UnitCommands.ON, enuUnitCommand.On }
Expand Down Expand Up @@ -181,5 +183,29 @@ private void ProcessButtonReceived(clsButton button, Topic command, string paylo
OmniLink.SendCommand(enuUnitCommand.Button, 0, (ushort)button.Number);
}
}

private static readonly IDictionary<MessageCommands, enuUnitCommand> MessageMapping = new Dictionary<MessageCommands, enuUnitCommand>
{
{ MessageCommands.show, enuUnitCommand.ShowMsgWBeep },
{ MessageCommands.show_no_beep, enuUnitCommand.ShowMsgNoBeep },
{ MessageCommands.show_no_beep_or_led, enuUnitCommand.ShowMsgNoBeep },
{ MessageCommands.clear, enuUnitCommand.ClearMsg },
};

private void ProcessMessageReceived(clsMessage message, Topic command, string payload)
{
if (command == Topic.command && Enum.TryParse(payload, true, out MessageCommands cmd))
{
log.Debug("SetMessage: " + message.Number + " to " + cmd.ToString().Replace("_", " "));

byte par = 0;
if (cmd == MessageCommands.show_no_beep)
par = 1;
else if (cmd == MessageCommands.show_no_beep_or_led)
par = 2;

OmniLink.SendCommand(MessageMapping[cmd], par, (ushort)message.Number);
}
}
}
}
1 change: 1 addition & 0 deletions OmniLinkBridge/MQTT/Topic.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
{
public enum Topic
{
name,
state,
command,
basic_state,
Expand Down
2 changes: 1 addition & 1 deletion OmniLinkBridge/Modules/LoggerModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,7 @@ INSERT INTO log_messages (timestamp, id, name, status)
VALUES ('" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "','" + e.ID + "','" + e.Message.Name + "','" + e.Message.StatusText() + "')");

if (Global.verbose_message)
log.Debug("MessageStatus " + e.Message.Name + ", " + e.Message.StatusText());
log.Debug("MessageStatus " + e.ID + " " + e.Message.Name + ", " + e.Message.StatusText());

if (Global.notify_message)
Notification.Notify("Message", e.ID + " " + e.Message.Name + ", " + e.Message.StatusText());
Expand Down
110 changes: 92 additions & 18 deletions OmniLinkBridge/Modules/MQTTModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
using log4net;
using MQTTnet;
using MQTTnet.Client;
using MQTTnet.Client.Connecting;
using MQTTnet.Client.Disconnecting;
using MQTTnet.Client.Options;
using MQTTnet.Client.Receiving;
using MQTTnet.Extensions.ManagedClient;
using MQTTnet.Protocol;
using Newtonsoft.Json;
Expand Down Expand Up @@ -38,6 +42,8 @@ public MQTTModule(OmniLinkII omni)
OmniLink.OnZoneStatus += Omnilink_OnZoneStatus;
OmniLink.OnUnitStatus += Omnilink_OnUnitStatus;
OmniLink.OnThermostatStatus += Omnilink_OnThermostatStatus;
OmniLink.OnButtonStatus += OmniLink_OnButtonStatus;
OmniLink.OnMessageStatus += OmniLink_OnMessageStatus;

MessageProcessor = new MessageProcessor(omni);
}
Expand Down Expand Up @@ -66,7 +72,7 @@ public void Startup()
.Build();

MqttClient = new MqttFactory().CreateManagedMqttClient();
MqttClient.Connected += (sender, e) =>
MqttClient.ConnectedHandler = new MqttClientConnectedHandlerDelegate((e) =>
{
log.Debug("Connected");

Expand All @@ -83,13 +89,14 @@ public void Startup()
// For subsequent connections publish config immediately
if (ControllerConnected)
PublishConfig();
};
MqttClient.ConnectingFailed += (sender, e) => { log.Debug("Error connecting " + e.Exception.Message); };
MqttClient.Disconnected += (sender, e) => { log.Debug("Disconnected"); };
});
MqttClient.ConnectingFailedHandler = new ConnectingFailedHandlerDelegate((e) => log.Debug("Error connecting " + e.Exception.Message));
MqttClient.DisconnectedHandler = new MqttClientDisconnectedHandlerDelegate((e) => log.Debug("Disconnected"));

MqttClient.StartAsync(manoptions);

MqttClient.ApplicationMessageReceived += MqttClient_ApplicationMessageReceived;
MqttClient.ApplicationMessageReceivedHandler = new MqttApplicationMessageReceivedHandlerDelegate((e) =>
MessageProcessor.Process(e.ApplicationMessage.Topic, Encoding.UTF8.GetString(e.ApplicationMessage.Payload)));

// Subscribe to notifications for these command topics
List<Topic> toSubscribe = new List<Topic>()
Expand Down Expand Up @@ -117,11 +124,6 @@ public void Startup()
MqttClient.StopAsync();
}

private void MqttClient_ApplicationMessageReceived(object sender, MqttApplicationMessageReceivedEventArgs e)
{
MessageProcessor.Process(e.ApplicationMessage.Topic, Encoding.UTF8.GetString(e.ApplicationMessage.Payload));
}

public void Shutdown()
{
trigger.Set();
Expand Down Expand Up @@ -153,6 +155,7 @@ private void PublishConfig()
PublishUnits();
PublishThermostats();
PublishButtons();
PublishMessages();

log.Debug("Publishing controller online");
PublishAsync($"{Global.mqtt_prefix}/status", "online");
Expand All @@ -172,6 +175,7 @@ private void PublishAreas()
// (configured for 1 area). To workaround ignore default properties for the first area.
if (i > 1 && area.DefaultProperties == true)
{
PublishAsync(area.ToTopic(Topic.name), null);
PublishAsync($"{Global.mqtt_discovery_prefix}/alarm_control_panel/{Global.mqtt_prefix}/area{i.ToString()}/config", null);
PublishAsync($"{Global.mqtt_discovery_prefix}/binary_sensor/{Global.mqtt_prefix}/area{i.ToString()}burglary/config", null);
PublishAsync($"{Global.mqtt_discovery_prefix}/binary_sensor/{Global.mqtt_prefix}/area{i.ToString()}fire/config", null);
Expand All @@ -186,6 +190,7 @@ private void PublishAreas()

PublishAreaState(area);

PublishAsync(area.ToTopic(Topic.name), area.Name);
PublishAsync($"{Global.mqtt_discovery_prefix}/alarm_control_panel/{Global.mqtt_prefix}/area{i.ToString()}/config",
JsonConvert.SerializeObject(area.ToConfig()));
PublishAsync($"{Global.mqtt_discovery_prefix}/binary_sensor/{Global.mqtt_prefix}/area{i.ToString()}burglary/config",
Expand Down Expand Up @@ -215,17 +220,25 @@ private void PublishZones()
{
clsZone zone = OmniLink.Controller.Zones[i];

if (zone.DefaultProperties == true || Global.mqtt_discovery_ignore_zones.Contains(zone.Number))
if (zone.DefaultProperties == true)
{
PublishAsync(zone.ToTopic(Topic.name), null);
}
else
{
PublishZoneState(zone);
PublishAsync(zone.ToTopic(Topic.name), zone.Name);
}

if (zone.DefaultProperties == true || Global.mqtt_discovery_ignore_zones.Contains(zone.Number))
{
PublishAsync($"{Global.mqtt_discovery_prefix}/binary_sensor/{Global.mqtt_prefix}/zone{i.ToString()}/config", null);
PublishAsync($"{Global.mqtt_discovery_prefix}/sensor/{Global.mqtt_prefix}/zone{i.ToString()}/config", null);
PublishAsync($"{Global.mqtt_discovery_prefix}/sensor/{Global.mqtt_prefix}/zone{i.ToString()}temp/config", null);
PublishAsync($"{Global.mqtt_discovery_prefix}/sensor/{Global.mqtt_prefix}/zone{i.ToString()}humidity/config", null);
continue;
}

PublishZoneState(zone);

PublishAsync($"{Global.mqtt_discovery_prefix}/binary_sensor/{Global.mqtt_prefix}/zone{i.ToString()}/config",
JsonConvert.SerializeObject(zone.ToConfig()));
PublishAsync($"{Global.mqtt_discovery_prefix}/sensor/{Global.mqtt_prefix}/zone{i.ToString()}/config",
Expand All @@ -247,17 +260,25 @@ private void PublishUnits()
for (ushort i = 1; i <= OmniLink.Controller.Units.Count; i++)
{
clsUnit unit = OmniLink.Controller.Units[i];


if (unit.DefaultProperties == true)
{
PublishAsync(unit.ToTopic(Topic.name), null);
}
else
{
PublishUnitState(unit);
PublishAsync(unit.ToTopic(Topic.name), unit.Name);
}

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.ToString()}/config", null);
continue;
}

PublishUnitState(unit);

if(i < 385)
if (i < 385)
PublishAsync($"{Global.mqtt_discovery_prefix}/light/{Global.mqtt_prefix}/unit{i.ToString()}/config",
JsonConvert.SerializeObject(unit.ToConfig()));
else
Expand All @@ -276,6 +297,7 @@ private void PublishThermostats()

if (thermostat.DefaultProperties == true)
{
PublishAsync(thermostat.ToTopic(Topic.name), null);
PublishAsync($"{Global.mqtt_discovery_prefix}/climate/{Global.mqtt_prefix}/thermostat{i.ToString()}/config", null);
PublishAsync($"{Global.mqtt_discovery_prefix}/sensor/{Global.mqtt_prefix}/thermostat{i.ToString()}temp/config", null);
PublishAsync($"{Global.mqtt_discovery_prefix}/sensor/{Global.mqtt_prefix}/thermostat{i.ToString()}humidity/config", null);
Expand All @@ -284,6 +306,7 @@ private void PublishThermostats()

PublishThermostatState(thermostat);

PublishAsync(thermostat.ToTopic(Topic.name), thermostat.Name);
PublishAsync($"{Global.mqtt_discovery_prefix}/climate/{Global.mqtt_prefix}/thermostat{i.ToString()}/config",
JsonConvert.SerializeObject(thermostat.ToConfig(OmniLink.Controller.TempFormat)));
PublishAsync($"{Global.mqtt_discovery_prefix}/sensor/{Global.mqtt_prefix}/thermostat{i.ToString()}temp/config",
Expand All @@ -303,18 +326,40 @@ private void PublishButtons()

if (button.DefaultProperties == true)
{
PublishAsync(button.ToTopic(Topic.name), null);
PublishAsync($"{Global.mqtt_discovery_prefix}/switch/{Global.mqtt_prefix}/button{i.ToString()}/config", null);
continue;
}

// Buttons are always off
// Buttons are off unless momentarily pressed
PublishAsync(button.ToTopic(Topic.state), "OFF");

PublishAsync(button.ToTopic(Topic.name), button.Name);
PublishAsync($"{Global.mqtt_discovery_prefix}/switch/{Global.mqtt_prefix}/button{i.ToString()}/config",
JsonConvert.SerializeObject(button.ToConfig()));
}
}

private void PublishMessages()
{
log.Debug("Publishing messages");

for (ushort i = 1; i <= OmniLink.Controller.Messages.Count; i++)
{
clsMessage message = OmniLink.Controller.Messages[i];

if (message.DefaultProperties == true)
{
PublishAsync(message.ToTopic(Topic.name), null);
continue;
}

PublishMessageState(message);

PublishAsync(message.ToTopic(Topic.name), message.Name);
}
}

private void Omnilink_OnAreaStatus(object sender, AreaStatusEventArgs e)
{
if (!MqttClient.IsConnected)
Expand Down Expand Up @@ -375,6 +420,22 @@ private void Omnilink_OnThermostatStatus(object sender, ThermostatStatusEventArg
PublishThermostatState(e.Thermostat);
}

private async void OmniLink_OnButtonStatus(object sender, ButtonStatusEventArgs e)
{
if (!MqttClient.IsConnected)
return;

await PublishButtonState(e.Button);
}

private void OmniLink_OnMessageStatus(object sender, MessageStatusEventArgs e)
{
if (!MqttClient.IsConnected)
return;

PublishMessageState(e.Message);
}

private void PublishAreaState(clsArea area)
{
PublishAsync(area.ToTopic(Topic.state), area.ToState());
Expand Down Expand Up @@ -415,6 +476,19 @@ private void PublishThermostatState(clsThermostat thermostat)
PublishAsync(thermostat.ToTopic(Topic.hold_state), thermostat.HoldStatusText().ToLower());
}

private async Task PublishButtonState(clsButton button)
{
// Simulate a momentary press
await PublishAsync(button.ToTopic(Topic.state), "ON");
await Task.Delay(1000);
await PublishAsync(button.ToTopic(Topic.state), "OFF");
}

private void PublishMessageState(clsMessage message)
{
PublishAsync(message.ToTopic(Topic.state), message.ToState());
}

private Task PublishAsync(string topic, string payload)
{
return MqttClient.PublishAsync(topic, payload, MqttQualityOfServiceLevel.AtMostOnce, true);
Expand Down
Loading

0 comments on commit 314ea42

Please sign in to comment.